codekingpro/portable-devtools
114k
1from threading import RLock2try:3 from collections.abc import Mapping as DictMixin4except ImportError: # Python < 3.35 try:6 from UserDict import DictMixin # Python 27 except ImportError: # Python 3.0-3.38 from collections import Mapping as DictMixin9 10 11# With lazy loading, we might end up with multiple threads triggering12# it at the same time. We need a lock.13_fill_lock = RLock()14 15 16class LazyDict(DictMixin):17 """Dictionary populated on first use."""18 data = None19 20 def __getitem__(self, key):21 if self.data is None:22 _fill_lock.acquire()23 try:24 if self.data is None:25 self._fill()26 finally:27 _fill_lock.release()28 return self.data[key.upper()]29 30 def __contains__(self, key):31 if self.data is None:32 _fill_lock.acquire()33 try:34 if self.data is None:35 self._fill()36 finally:37 _fill_lock.release()38 return key in self.data39 40 def __iter__(self):41 if self.data is None:42 _fill_lock.acquire()43 try:44 if self.data is None:45 self._fill()46 finally:47 _fill_lock.release()48 return iter(self.data)49 50 def __len__(self):51 if self.data is None:52 _fill_lock.acquire()53 try:54 if self.data is None:55 self._fill()56 finally:57 _fill_lock.release()58 return len(self.data)59 60 def keys(self):61 if self.data is None:62 _fill_lock.acquire()63 try:64 if self.data is None:65 self._fill()66 finally:67 _fill_lock.release()68 return self.data.keys()69 70 71class LazyList(list):72 """List populated on first use."""73 74 _props = [75 '__str__', '__repr__', '__unicode__',76 '__hash__', '__sizeof__', '__cmp__',77 '__lt__', '__le__', '__eq__', '__ne__', '__gt__', '__ge__',78 'append', 'count', 'index', 'extend', 'insert', 'pop', 'remove',79 'reverse', 'sort', '__add__', '__radd__', '__iadd__', '__mul__',80 '__rmul__', '__imul__', '__contains__', '__len__', '__nonzero__',81 '__getitem__', '__setitem__', '__delitem__', '__iter__',82 '__reversed__', '__getslice__', '__setslice__', '__delslice__']83 84 def __new__(cls, fill_iter=None):85 86 if fill_iter is None:87 return list()88 89 # We need a new class as we will be dynamically messing with its90 # methods.91 class LazyList(list):92 pass93 94 fill_iter = [fill_iter]95 96 def lazy(name):97 def _lazy(self, *args, **kw):98 _fill_lock.acquire()99 try:100 if len(fill_iter) > 0:101 list.extend(self, fill_iter.pop())102 for method_name in cls._props:103 delattr(LazyList, method_name)104 finally:105 _fill_lock.release()106 return getattr(list, name)(self, *args, **kw)107 return _lazy108 109 for name in cls._props:110 setattr(LazyList, name, lazy(name))111 112 new_list = LazyList()113 return new_list114 115# Not all versions of Python declare the same magic methods.116# Filter out properties that don't exist in this version of Python117# from the list.118LazyList._props = [prop for prop in LazyList._props if hasattr(list, prop)]119 120 121class LazySet(set):122 """Set populated on first use."""123 124 _props = (125 '__str__', '__repr__', '__unicode__',126 '__hash__', '__sizeof__', '__cmp__',127 '__lt__', '__le__', '__eq__', '__ne__', '__gt__', '__ge__',128 '__contains__', '__len__', '__nonzero__',129 '__getitem__', '__setitem__', '__delitem__', '__iter__',130 '__sub__', '__and__', '__xor__', '__or__',131 '__rsub__', '__rand__', '__rxor__', '__ror__',132 '__isub__', '__iand__', '__ixor__', '__ior__',133 'add', 'clear', 'copy', 'difference', 'difference_update',134 'discard', 'intersection', 'intersection_update', 'isdisjoint',135 'issubset', 'issuperset', 'pop', 'remove',136 'symmetric_difference', 'symmetric_difference_update',137 'union', 'update')138 139 def __new__(cls, fill_iter=None):140 141 if fill_iter is None:142 return set()143 144 class LazySet(set):145 pass146 147 fill_iter = [fill_iter]148 149 def lazy(name):150 def _lazy(self, *args, **kw):151 _fill_lock.acquire()152 try:153 if len(fill_iter) > 0:154 for i in fill_iter.pop():155 set.add(self, i)156 for method_name in cls._props:157 delattr(LazySet, method_name)158 finally:159 _fill_lock.release()160 return getattr(set, name)(self, *args, **kw)161 return _lazy162 163 for name in cls._props:164 setattr(LazySet, name, lazy(name))165 166 new_set = LazySet()167 return new_set168 169# Not all versions of Python declare the same magic methods.170# Filter out properties that don't exist in this version of Python171# from the list.172LazySet._props = [prop for prop in LazySet._props if hasattr(set, prop)]173 