team-10/venv/Lib/site-packages/cachetools/_cachedmethod.py
2025-08-02 02:00:33 +02:00

128 lines
3.3 KiB
Python

"""Method decorator helpers."""
import functools
import weakref
def warn_cache_none():
from warnings import warn
warn(
"returning `None` from `cache(self)` is deprecated",
DeprecationWarning,
stacklevel=3,
)
def _condition(method, cache, key, lock, cond):
pending = weakref.WeakKeyDictionary()
def wrapper(self, *args, **kwargs):
c = cache(self)
if c is None:
warn_cache_none()
return method(self, *args, **kwargs)
k = key(self, *args, **kwargs)
with lock(self):
p = pending.setdefault(self, set())
cond(self).wait_for(lambda: k not in p)
try:
return c[k]
except KeyError:
p.add(k)
try:
v = method(self, *args, **kwargs)
with lock(self):
try:
c[k] = v
except ValueError:
pass # value too large
return v
finally:
with lock(self):
pending[self].remove(k)
cond(self).notify_all()
def cache_clear(self):
c = cache(self)
if c is not None:
with lock(self):
c.clear()
wrapper.cache_clear = cache_clear
return wrapper
def _locked(method, cache, key, lock):
def wrapper(self, *args, **kwargs):
c = cache(self)
if c is None:
warn_cache_none()
return method(self, *args, **kwargs)
k = key(self, *args, **kwargs)
with lock(self):
try:
return c[k]
except KeyError:
pass # key not found
v = method(self, *args, **kwargs)
# in case of a race, prefer the item already in the cache
with lock(self):
try:
return c.setdefault(k, v)
except ValueError:
return v # value too large
def cache_clear(self):
c = cache(self)
if c is not None:
with lock(self):
c.clear()
wrapper.cache_clear = cache_clear
return wrapper
def _unlocked(method, cache, key):
def wrapper(self, *args, **kwargs):
c = cache(self)
if c is None:
warn_cache_none()
return method(self, *args, **kwargs)
k = key(self, *args, **kwargs)
try:
return c[k]
except KeyError:
pass # key not found
v = method(self, *args, **kwargs)
try:
c[k] = v
except ValueError:
pass # value too large
return v
def cache_clear(self):
c = cache(self)
if c is not None:
c.clear()
wrapper.cache_clear = cache_clear
return wrapper
def _wrapper(method, cache, key, lock=None, cond=None):
if cond is not None and lock is not None:
wrapper = _condition(method, cache, key, lock, cond)
elif cond is not None:
wrapper = _condition(method, cache, key, cond, cond)
elif lock is not None:
wrapper = _locked(method, cache, key, lock)
else:
wrapper = _unlocked(method, cache, key)
wrapper.cache = cache
wrapper.cache_key = key
wrapper.cache_lock = lock if lock is not None else cond
wrapper.cache_condition = cond
return functools.update_wrapper(wrapper, method)