| 979 | ) |
| 980 | |
| 981 | def __get__(self, instance, owner=None): |
| 982 | if instance is None: |
| 983 | return self |
| 984 | if self.attrname is None: |
| 985 | raise TypeError( |
| 986 | "Cannot use cached_property instance without calling __set_name__ on it.") |
| 987 | try: |
| 988 | cache = instance.__dict__ |
| 989 | except AttributeError: # not all objects have __dict__ (e.g. class defines slots) |
| 990 | msg = ( |
| 991 | f"No '__dict__' attribute on {type(instance).__name__!r} " |
| 992 | f"instance to cache {self.attrname!r} property." |
| 993 | ) |
| 994 | raise TypeError(msg) from None |
| 995 | val = cache.get(self.attrname, _NOT_FOUND) |
| 996 | if val is _NOT_FOUND: |
| 997 | with self.lock: |
| 998 | # check if another thread filled cache while we awaited lock |
| 999 | val = cache.get(self.attrname, _NOT_FOUND) |
| 1000 | if val is _NOT_FOUND: |
| 1001 | val = self.func(instance) |
| 1002 | try: |
| 1003 | cache[self.attrname] = val |
| 1004 | except TypeError: |
| 1005 | msg = ( |
| 1006 | f"The '__dict__' attribute on {type(instance).__name__!r} instance " |
| 1007 | f"does not support item assignment for caching {self.attrname!r} property." |
| 1008 | ) |
| 1009 | raise TypeError(msg) from None |
| 1010 | return val |
| 1011 | |
| 1012 | __class_getitem__ = classmethod(GenericAlias) |