summaryrefslogtreecommitdiff
path: root/src/werkzeug/utils.py
diff options
context:
space:
mode:
authorDavid Lord <davidism@gmail.com>2022-02-07 07:33:31 -0800
committerDavid Lord <davidism@gmail.com>2022-02-07 07:41:58 -0800
commit87d5dd167d1fae08365749874bdc07cabb67e53d (patch)
tree434dd31b3e6afc87da8b45a9f7b7deffe0dbe2c3 /src/werkzeug/utils.py
parent27cc7651ece0e84c7ccca837832e31b28c8fef52 (diff)
downloadwerkzeug-87d5dd167d1fae08365749874bdc07cabb67e53d.tar.gz
cached_property for __slots__
Diffstat (limited to 'src/werkzeug/utils.py')
-rw-r--r--src/werkzeug/utils.py31
1 files changed, 26 insertions, 5 deletions
diff --git a/src/werkzeug/utils.py b/src/werkzeug/utils.py
index c13ab586..eb8b5172 100644
--- a/src/werkzeug/utils.py
+++ b/src/werkzeug/utils.py
@@ -64,7 +64,12 @@ class cached_property(property, t.Generic[_T]):
e.value = 16 # sets cache
del e.value # clears cache
- The class must have a ``__dict__`` for this to work.
+ If the class defines ``__slots__``, it must add ``_cache_{name}`` as
+ a slot. Alternatively, it can add ``__dict__``, but that's usually
+ not desirable.
+
+ .. versionchanged:: 2.1
+ Works with ``__slots__``.
.. versionchanged:: 2.0
``del obj.name`` clears the cached value.
@@ -78,25 +83,41 @@ class cached_property(property, t.Generic[_T]):
) -> None:
super().__init__(fget, doc=doc)
self.__name__ = name or fget.__name__
+ self.slot_name = f"_cache_{self.__name__}"
self.__module__ = fget.__module__
def __set__(self, obj: object, value: _T) -> None:
- obj.__dict__[self.__name__] = value
+ if hasattr(obj, "__dict__"):
+ obj.__dict__[self.__name__] = value
+ else:
+ setattr(obj, self.slot_name, value)
def __get__(self, obj: object, type: type = None) -> _T: # type: ignore
if obj is None:
return self # type: ignore
- value: _T = obj.__dict__.get(self.__name__, _missing)
+ obj_dict = getattr(obj, "__dict__", None)
+
+ if obj_dict is not None:
+ value: _T = obj_dict.get(self.__name__, _missing)
+ else:
+ value = getattr(obj, self.slot_name, _missing) # type: ignore[arg-type]
if value is _missing:
value = self.fget(obj) # type: ignore
- obj.__dict__[self.__name__] = value
+
+ if obj_dict is not None:
+ obj.__dict__[self.__name__] = value
+ else:
+ setattr(obj, self.slot_name, value)
return value
def __delete__(self, obj: object) -> None:
- del obj.__dict__[self.__name__]
+ if hasattr(obj, "__dict__"):
+ del obj.__dict__[self.__name__]
+ else:
+ setattr(obj, self.slot_name, _missing)
class environ_property(_DictAccessorProperty[_TAccessorValue]):