123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173 |
- from threading import RLock
- try:
- from collections.abc import Mapping as DictMixin
- except ImportError: # Python < 3.3
- try:
- from UserDict import DictMixin # Python 2
- except ImportError: # Python 3.0-3.3
- from collections import Mapping as DictMixin
- # With lazy loading, we might end up with multiple threads triggering
- # it at the same time. We need a lock.
- _fill_lock = RLock()
- class LazyDict(DictMixin):
- """Dictionary populated on first use."""
- data = None
- def __getitem__(self, key):
- if self.data is None:
- _fill_lock.acquire()
- try:
- if self.data is None:
- self._fill()
- finally:
- _fill_lock.release()
- return self.data[key.upper()]
- def __contains__(self, key):
- if self.data is None:
- _fill_lock.acquire()
- try:
- if self.data is None:
- self._fill()
- finally:
- _fill_lock.release()
- return key in self.data
- def __iter__(self):
- if self.data is None:
- _fill_lock.acquire()
- try:
- if self.data is None:
- self._fill()
- finally:
- _fill_lock.release()
- return iter(self.data)
- def __len__(self):
- if self.data is None:
- _fill_lock.acquire()
- try:
- if self.data is None:
- self._fill()
- finally:
- _fill_lock.release()
- return len(self.data)
- def keys(self):
- if self.data is None:
- _fill_lock.acquire()
- try:
- if self.data is None:
- self._fill()
- finally:
- _fill_lock.release()
- return self.data.keys()
- class LazyList(list):
- """List populated on first use."""
- _props = [
- '__str__', '__repr__', '__unicode__',
- '__hash__', '__sizeof__', '__cmp__',
- '__lt__', '__le__', '__eq__', '__ne__', '__gt__', '__ge__',
- 'append', 'count', 'index', 'extend', 'insert', 'pop', 'remove',
- 'reverse', 'sort', '__add__', '__radd__', '__iadd__', '__mul__',
- '__rmul__', '__imul__', '__contains__', '__len__', '__nonzero__',
- '__getitem__', '__setitem__', '__delitem__', '__iter__',
- '__reversed__', '__getslice__', '__setslice__', '__delslice__']
- def __new__(cls, fill_iter=None):
- if fill_iter is None:
- return list()
- # We need a new class as we will be dynamically messing with its
- # methods.
- class LazyList(list):
- pass
- fill_iter = [fill_iter]
- def lazy(name):
- def _lazy(self, *args, **kw):
- _fill_lock.acquire()
- try:
- if len(fill_iter) > 0:
- list.extend(self, fill_iter.pop())
- for method_name in cls._props:
- delattr(LazyList, method_name)
- finally:
- _fill_lock.release()
- return getattr(list, name)(self, *args, **kw)
- return _lazy
- for name in cls._props:
- setattr(LazyList, name, lazy(name))
- new_list = LazyList()
- return new_list
- # Not all versions of Python declare the same magic methods.
- # Filter out properties that don't exist in this version of Python
- # from the list.
- LazyList._props = [prop for prop in LazyList._props if hasattr(list, prop)]
- class LazySet(set):
- """Set populated on first use."""
- _props = (
- '__str__', '__repr__', '__unicode__',
- '__hash__', '__sizeof__', '__cmp__',
- '__lt__', '__le__', '__eq__', '__ne__', '__gt__', '__ge__',
- '__contains__', '__len__', '__nonzero__',
- '__getitem__', '__setitem__', '__delitem__', '__iter__',
- '__sub__', '__and__', '__xor__', '__or__',
- '__rsub__', '__rand__', '__rxor__', '__ror__',
- '__isub__', '__iand__', '__ixor__', '__ior__',
- 'add', 'clear', 'copy', 'difference', 'difference_update',
- 'discard', 'intersection', 'intersection_update', 'isdisjoint',
- 'issubset', 'issuperset', 'pop', 'remove',
- 'symmetric_difference', 'symmetric_difference_update',
- 'union', 'update')
- def __new__(cls, fill_iter=None):
- if fill_iter is None:
- return set()
- class LazySet(set):
- pass
- fill_iter = [fill_iter]
- def lazy(name):
- def _lazy(self, *args, **kw):
- _fill_lock.acquire()
- try:
- if len(fill_iter) > 0:
- for i in fill_iter.pop():
- set.add(self, i)
- for method_name in cls._props:
- delattr(LazySet, method_name)
- finally:
- _fill_lock.release()
- return getattr(set, name)(self, *args, **kw)
- return _lazy
- for name in cls._props:
- setattr(LazySet, name, lazy(name))
- new_set = LazySet()
- return new_set
- # Not all versions of Python declare the same magic methods.
- # Filter out properties that don't exist in this version of Python
- # from the list.
- LazySet._props = [prop for prop in LazySet._props if hasattr(set, prop)]
|