from datetime import datetime class ExpiresEntry(object): """ A single entry under a ExpiresDict. """ def __init__(self, value, expires=None): self.value = value self._expiration = expires @property def expired(self): if self._expiration is None: return False return datetime.now() >= self._expiration class ExpiresDict(object): """ ExpiresDict defines a dictionary-like class whose keys have expiration. The rebuilder is a function that returns the full contents of the cached dictionary as a dict of the keys and whose values are TTLEntry's. """ def __init__(self, rebuilder): self._rebuilder = rebuilder self._items = {} def __getitem__(self, key): found = self.get(key) if found is None: raise KeyError return found def get(self, key, default_value=None): # Check the cache first. If the key is found and it has not yet expired, # return it. found = self._items.get(key) if found is not None and not found.expired: return found.value # Otherwise the key has expired or was not found. Rebuild the cache and check it again. self._rebuild() found = self._items.get(key) if found is None: return default_value return found.value def __contains__(self, key): return self.get(key) is not None def _rebuild(self): self._items = self._rebuilder() def set(self, key, value, expires=None): self._items[key] = ExpiresEntry(value, expires=expires)