OLD | NEW |
(Empty) | |
| 1 """Extensible memoizing collections and decorators.""" |
| 2 |
| 3 from __future__ import absolute_import |
| 4 |
| 5 import functools |
| 6 |
| 7 from . import keys |
| 8 from .cache import Cache |
| 9 from .lfu import LFUCache |
| 10 from .lru import LRUCache |
| 11 from .rr import RRCache |
| 12 from .ttl import TTLCache |
| 13 |
| 14 __all__ = ( |
| 15 'Cache', 'LFUCache', 'LRUCache', 'RRCache', 'TTLCache', |
| 16 'cached', 'cachedmethod' |
| 17 ) |
| 18 |
| 19 __version__ = '2.0.0' |
| 20 |
| 21 if hasattr(functools.update_wrapper(lambda f: f(), lambda: 42), '__wrapped__'): |
| 22 _update_wrapper = functools.update_wrapper |
| 23 else: |
| 24 def _update_wrapper(wrapper, wrapped): |
| 25 functools.update_wrapper(wrapper, wrapped) |
| 26 wrapper.__wrapped__ = wrapped |
| 27 return wrapper |
| 28 |
| 29 |
| 30 def cached(cache, key=keys.hashkey, lock=None): |
| 31 """Decorator to wrap a function with a memoizing callable that saves |
| 32 results in a cache. |
| 33 |
| 34 """ |
| 35 def decorator(func): |
| 36 if cache is None: |
| 37 def wrapper(*args, **kwargs): |
| 38 return func(*args, **kwargs) |
| 39 elif lock is None: |
| 40 def wrapper(*args, **kwargs): |
| 41 k = key(*args, **kwargs) |
| 42 try: |
| 43 return cache[k] |
| 44 except KeyError: |
| 45 pass # key not found |
| 46 v = func(*args, **kwargs) |
| 47 try: |
| 48 cache[k] = v |
| 49 except ValueError: |
| 50 pass # value too large |
| 51 return v |
| 52 else: |
| 53 def wrapper(*args, **kwargs): |
| 54 k = key(*args, **kwargs) |
| 55 try: |
| 56 with lock: |
| 57 return cache[k] |
| 58 except KeyError: |
| 59 pass # key not found |
| 60 v = func(*args, **kwargs) |
| 61 try: |
| 62 with lock: |
| 63 cache[k] = v |
| 64 except ValueError: |
| 65 pass # value too large |
| 66 return v |
| 67 return _update_wrapper(wrapper, func) |
| 68 return decorator |
| 69 |
| 70 |
| 71 def cachedmethod(cache, key=keys.hashkey, lock=None): |
| 72 """Decorator to wrap a class or instance method with a memoizing |
| 73 callable that saves results in a cache. |
| 74 |
| 75 """ |
| 76 def decorator(method): |
| 77 if lock is None: |
| 78 def wrapper(self, *args, **kwargs): |
| 79 c = cache(self) |
| 80 if c is None: |
| 81 return method(self, *args, **kwargs) |
| 82 k = key(self, *args, **kwargs) |
| 83 try: |
| 84 return c[k] |
| 85 except KeyError: |
| 86 pass # key not found |
| 87 v = method(self, *args, **kwargs) |
| 88 try: |
| 89 c[k] = v |
| 90 except ValueError: |
| 91 pass # value too large |
| 92 return v |
| 93 else: |
| 94 def wrapper(self, *args, **kwargs): |
| 95 c = cache(self) |
| 96 if c is None: |
| 97 return method(self, *args, **kwargs) |
| 98 k = key(self, *args, **kwargs) |
| 99 try: |
| 100 with lock(self): |
| 101 return c[k] |
| 102 except KeyError: |
| 103 pass # key not found |
| 104 v = method(self, *args, **kwargs) |
| 105 try: |
| 106 with lock(self): |
| 107 c[k] = v |
| 108 except ValueError: |
| 109 pass # value too large |
| 110 return v |
| 111 return _update_wrapper(wrapper, method) |
| 112 return decorator |
OLD | NEW |