77from rez .packages import iter_packages , Package
88from rez .exceptions import ConfigurationError
99from rez .config import config
10- from rez . utils . data_utils import cached_property , cached_class_property
10+ from functools import cached_property
1111from rez .version import VersionedObject , VersionRange , Requirement
1212from hashlib import sha1
13- from typing import Any , Iterator , Pattern , TYPE_CHECKING , ClassVar
13+ from typing import cast , Any , Iterator , Pattern , TYPE_CHECKING , ClassVar
1414import fnmatch
1515import re
1616
1717if TYPE_CHECKING :
1818 from typing import Self
1919
20+ import functools
21+ from typing import Callable , Generic , TypeVar
22+ T = TypeVar ("T" )
23+ TypeT = TypeVar ("TypeT" , bound = type )
24+
25+ class cached_class_property (Generic [T ]):
26+ """Simple class property caching descriptor.
27+
28+ Example:
29+
30+ >>> class Foo(object):
31+ >>> @cached_class_property
32+ >>> def bah(cls):
33+ >>> print('bah')
34+ >>> return 1
35+ >>>
36+ >>> Foo.bah
37+ bah
38+ 1
39+ >>> Foo.bah
40+ 1
41+ """
42+ def __init__ (self , func : Callable [[], T ], name : str | None = None ) -> None :
43+ self .func = func
44+ # Make sure that Sphinx autodoc can follow and get the docstring from our wrapped function.
45+ # TODO: Doesn't work...
46+ functools .update_wrapper (self , func ) # type: ignore[arg-type]
47+
48+ def __get__ (self , instance : Any , owner : Any | None = None ) -> T :
49+ assert owner
50+ name = "_class_property_" + self .func .__name__
51+ result : T | type [KeyError ] = getattr (owner , name , KeyError )
52+
53+ if result is KeyError :
54+ result = self .func ()
55+ setattr (owner , name , result )
56+ return cast (T , result )
57+
2058
2159class PackageFilterBase (object ):
2260 """Base class for package filters."""
@@ -58,7 +96,6 @@ def to_pod(self) -> Any:
5896 """Convert to POD type, suitable for storing in an rxt file.
5997
6098 Return type depends on subclass implementation
61- dict[str, list[str]]:
6299 """
63100 raise NotImplementedError
64101
@@ -220,7 +257,8 @@ def _add_rule(self, rules_dict: dict[str | None, list[Rule]], rule: Rule) -> Non
220257 family = rule .family ()
221258 rules_ = rules_dict .get (family , [])
222259 rules_dict [family ] = sorted (rules_ + [rule ], key = lambda x : x .cost ())
223- cached_property .uncache (self , "cost" ) # type: ignore[attr-defined]
260+ # invalidate the functools.cached_property cache entry
261+ self .__dict__ .pop ("cost" , None )
224262
225263 def __str__ (self ) -> str :
226264 def sortkey (rule_items : tuple [str | None , list [Rule ]]) -> tuple [str , list [Rule ]]:
@@ -233,6 +271,15 @@ def sortkey(rule_items: tuple[str | None, list[Rule]]) -> tuple[str, list[Rule]]
233271 sorted (self ._includes .items (), key = sortkey )))
234272
235273
274+ def _singleton () -> PackageFilterList :
275+ """Filter list as configured by :data:`package_filter`.
276+
277+ Returns:
278+ PackageFilterList:
279+ """
280+ return PackageFilterList .from_pod (config .package_filter )
281+
282+
236283class PackageFilterList (PackageFilterBase ):
237284 """A list of package filters.
238285
@@ -318,7 +365,7 @@ def __str__(self) -> str:
318365 filters = sorted (self .filters , key = lambda x : (x .cost , str (x )))
319366 return str (tuple (filters ))
320367
321- @cached_class_property
368+ @classmethod
322369 def singleton (cls ) -> PackageFilterList :
323370 """Filter list as configured by :data:`package_filter`.
324371
@@ -327,6 +374,8 @@ def singleton(cls) -> PackageFilterList:
327374 """
328375 return cls .from_pod (config .package_filter )
329376
377+ # singleton = cached_class_property(_singleton)
378+
330379
331380#: filter that does not exclude any packages
332381no_filter = PackageFilterList ()
0 commit comments