Merge pull request #3962 from pallets/cached-property

locked_cached_property subclasses Werkzeug's cached_property
This commit is contained in:
David Lord 2021-04-15 23:14:24 -07:00 committed by GitHub
commit f3ed1322a6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -18,10 +18,6 @@ from .globals import request
from .globals import session from .globals import session
from .signals import message_flashed from .signals import message_flashed
# sentinel
_missing = object()
# what separators does this operating system provide that are not a slash? # what separators does this operating system provide that are not a slash?
# this is used by the send_from_directory function to ensure that nobody is # this is used by the send_from_directory function to ensure that nobody is
# able to access files from outside the filesystem. # able to access files from outside the filesystem.
@ -677,30 +673,33 @@ def send_from_directory(directory, path, **kwargs):
) )
class locked_cached_property: class locked_cached_property(werkzeug.utils.cached_property):
"""A decorator that converts a function into a lazy property. The """A :func:`property` that is only evaluated once. Like
function wrapped is called the first time to retrieve the result :class:`werkzeug.utils.cached_property` except access uses a lock
and then that calculated result is used the next time you access for thread safety.
the value. Works like the one in Werkzeug but has a lock for
thread safety. .. versionchanged:: 2.0
Inherits from Werkzeug's ``cached_property`` (and ``property``).
""" """
def __init__(self, func, name=None, doc=None): def __init__(self, fget, name=None, doc=None):
self.__name__ = name or func.__name__ super().__init__(fget, name=name, doc=doc)
self.__module__ = func.__module__
self.__doc__ = doc or func.__doc__
self.func = func
self.lock = RLock() self.lock = RLock()
def __get__(self, obj, type=None): def __get__(self, obj, type=None):
if obj is None: if obj is None:
return self return self
with self.lock: with self.lock:
value = obj.__dict__.get(self.__name__, _missing) return super().__get__(obj, type=type)
if value is _missing:
value = self.func(obj) def __set__(self, obj, value):
obj.__dict__[self.__name__] = value with self.lock:
return value super().__set__(obj, value)
def __delete__(self, obj):
with self.lock:
super().__delete__(obj)
def total_seconds(td): def total_seconds(td):