memoize.py (3433B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\caching\memoize.py 2 import numbers, time 3 try: 4 from locks import Lock 5 except ImportError: 6 Lock = None 7 8 CACHE_FOREVER = 108000 9 10 def Memoize(minutes): 11 cache_seconds = CACHE_FOREVER 12 13 def deco(fn): 14 _cache = _MemoizeCache(cache_seconds) 15 16 def inner_deco(*args, **kwargs): 17 key = _cache.make_key(*args, **kwargs) 18 try: 19 value = _cache.get_value_if_key_is_present_and_not_expired(key) 20 except KeyError: 21 value = fn(*args, **kwargs) 22 _cache.store(key, value) 23 24 return value 25 26 inner_deco.clear_memoized = _cache.clear_cache 27 return inner_deco 28 29 if callable(minutes): 30 return deco(minutes) 31 if isinstance(minutes, numbers.Number): 32 cache_seconds = minutes * 60 33 return deco 34 raise ValueError("Wrong usage of 'Memoized' decorator. Either use no arguments or specify a number of minutes.") 35 36 37 def MemoizeWithLock(minutes): 38 if Lock is None: 39 raise RuntimeError('MemoizeWithLock requires a Stackless execution environment') 40 cache_seconds = CACHE_FOREVER 41 42 def deco(fn): 43 _cache = _MemoizeCache(cache_seconds) 44 _lock = Lock('MemoizeWithLock._lock %s' % fn) 45 46 def inner_deco_with_lock(*args, **kwargs): 47 key = _cache.make_key(*args, **kwargs) 48 try: 49 value = _cache.get_value_if_key_is_present_and_not_expired(key) 50 except KeyError: 51 with _lock: 52 try: 53 value = _cache.get_value_if_key_is_present_and_not_expired(key) 54 except KeyError: 55 value = fn(*args, **kwargs) 56 _cache.store(key, value) 57 58 return value 59 60 inner_deco_with_lock.clear_memoized = _cache.clear_cache 61 return inner_deco_with_lock 62 63 if callable(minutes): 64 return deco(minutes) 65 if isinstance(minutes, numbers.Number): 66 cache_seconds = minutes * 60 67 return deco 68 raise ValueError("Wrong usage of 'MemoizeWithLock' decorator. Either use no arguments or specify a number of minutes.") 69 70 71 class _MemoizeCache(object): 72 73 def __init__(self, cache_seconds): 74 self._cache = {} 75 self._cache_seconds = cache_seconds 76 77 @staticmethod 78 def make_key(*args, **kwargs): 79 hargs = [] 80 for a in args: 81 if getattr(a, '__hash__', None): 82 hargs.append(a) 83 elif hasattr(a, 'iteritems'): 84 hargs.append(frozenset(a.iteritems())) 85 else: 86 hargs.append(tuple(a) if hasattr(a, '__iter__') else repr(a)) 87 88 return (tuple(hargs) if hargs else None, frozenset(kwargs.iteritems()) if kwargs else None) 89 90 def get_value_if_key_is_present_and_not_expired(self, key): 91 value, saved_time = self._cache[key] 92 if saved_time + self._cache_seconds < time.time(): 93 raise KeyError 94 return value 95 96 def store(self, key, value): 97 saved_time = time.time() 98 self._cache[key] = (value, saved_time) 99 100 def clear_cache(self, *args, **kwargs): 101 if not args and not kwargs: 102 self._cache.clear() 103 else: 104 try: 105 del self._cache[self.make_key(*args, **kwargs)] 106 except KeyError: 107 pass