Spaces:
Sleeping
Sleeping
| """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) | |