def addLazySingleton(self, item_key, value_callable, *pargs, **kwargs): """This is like addLazyItem except value_callable will only be called a maximum of 1 time and the result will be cached for future requests.""" self.lazy_items[item_key] = \ self._LazyItem(value_callable, pargs, kwargs, True) # make it show up in self.keys(), etc... UserDict.__setitem__(self, item_key, None)
def addLazyItem(self, item_key, value_callable, *pargs, **kwargs): """Add a lazy item for the given key. When the item is requested, value_callable will be called with *pargs and **kwargs arguments.""" self.lazy_items[item_key] = \ self._LazyItem(value_callable, pargs, kwargs, False) # make it show up in self.keys(), etc... UserDict.__setitem__(self, item_key, None)
def __init__(self, loader): """ @param loader: A class that has a load() that returns two dicts the first being a data dict, the second being a dict of errors. """ UserDict.__init__(self) self._loader = loader
def __deepcopy__(self, memo=None): """ This forces evaluation of each contained lazy item, and deepcopy of the result. A TypeError is raised if any contained lazy item is not a singleton, since it is not necessarily possible for the behavior of this type of item to be safely preserved. """ if memo is None: memo = {} result = self.__class__() memo[id(self)] = result for k in self: k_copy = deepcopy(k, memo) lazy_item = self.lazy_items.get(k) if lazy_item is not None: if not lazy_item.singleton: raise TypeError(_unicode_decode("LazyItemsDict " + \ "deepcopy is unsafe with lazy items that are " + \ "not singletons: key=%s value=%s") % (k, lazy_item,)) UserDict.__setitem__(result, k_copy, deepcopy(self[k], memo)) return result
def __getitem__(self, item_key): if item_key in self.lazy_items: lazy_item = self.lazy_items[item_key] pargs = lazy_item.pargs if pargs is None: pargs = () kwargs = lazy_item.kwargs if kwargs is None: kwargs = {} result = lazy_item.func(*pargs, **kwargs) if lazy_item.singleton: self[item_key] = result return result else: return UserDict.__getitem__(self, item_key)
def update(self, *args, **kwargs): if len(args) > 1: raise TypeError( "expected at most 1 positional argument, got " + \ repr(len(args))) if args: map_obj = args[0] else: map_obj = None if map_obj is None: pass elif isinstance(map_obj, LazyItemsDict): for k in map_obj: if k in map_obj.lazy_items: UserDict.__setitem__(self, k, None) else: UserDict.__setitem__(self, k, map_obj[k]) self.lazy_items.update(map_obj.lazy_items) else: UserDict.update(self, map_obj) if kwargs: UserDict.update(self, kwargs)
def __deepcopy__(self, memo=None): """ WARNING: If any of the lazy items contains a bound method then it's typical for deepcopy() to raise an exception like this: File "/usr/lib/python2.5/copy.py", line 189, in deepcopy y = _reconstruct(x, rv, 1, memo) File "/usr/lib/python2.5/copy.py", line 322, in _reconstruct y = callable(*args) File "/usr/lib/python2.5/copy_reg.py", line 92, in __newobj__ return cls.__new__(cls, *args) TypeError: instancemethod expected at least 2 arguments, got 0 If deepcopy() needs to work, this problem can be avoided by implementing lazy items with normal (non-bound) functions. If deepcopy() raises a TypeError for a lazy item that has been added via a call to addLazySingleton(), the singleton will be automatically evaluated and deepcopy() will instead be called on the result. """ if memo is None: memo = {} result = self.__class__() memo[id(self)] = result for k in self: k_copy = deepcopy(k, memo) if k in self.lazy_items: lazy_item = self.lazy_items[k] try: result.lazy_items[k_copy] = deepcopy(lazy_item, memo) except TypeError: if not lazy_item.singleton: raise UserDict.__setitem__(result, k_copy, deepcopy(self[k], memo)) else: UserDict.__setitem__(result, k_copy, None) else: UserDict.__setitem__(result, k_copy, deepcopy(self[k], memo)) return result
def __delitem__(self, item_key): if item_key in self.lazy_items: del self.lazy_items[item_key] UserDict.__delitem__(self, item_key)
def clear(self): self.lazy_items.clear() UserDict.clear(self)
def __setitem__(self, item_key, value): if item_key in self.lazy_items: del self.lazy_items[item_key] UserDict.__setitem__(self, item_key, value)
def __init__(self, *args, **kwargs): self.lazy_items = {} UserDict.__init__(self, *args, **kwargs)
def __init__(self, filename): UserDict.__init__(self) self.filename = filename