13257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel"""Weak reference support for Python. 23257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 33257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielThis module is an implementation of PEP 205: 43257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 53257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielhttp://www.python.org/dev/peps/pep-0205/ 63257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel""" 73257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 83257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel# Naming convention: Variables named "wr" are weak reference objects; 93257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel# they are called this instead of "ref" to avoid name collisions with 103257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel# the module-global ref() function imported from _weakref. 113257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 123257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielimport UserDict 133257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 143257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielfrom _weakref import ( 153257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel getweakrefcount, 163257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel getweakrefs, 173257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel ref, 183257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel proxy, 193257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel CallableProxyType, 203257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel ProxyType, 213257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel ReferenceType) 223257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 233257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielfrom _weakrefset import WeakSet, _IterationGuard 243257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 253257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielfrom exceptions import ReferenceError 263257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 273257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 283257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielProxyTypes = (ProxyType, CallableProxyType) 293257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 303257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel__all__ = ["ref", "proxy", "getweakrefcount", "getweakrefs", 313257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel "WeakKeyDictionary", "ReferenceError", "ReferenceType", "ProxyType", 323257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel "CallableProxyType", "ProxyTypes", "WeakValueDictionary", 'WeakSet'] 333257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 343257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 353257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielclass WeakValueDictionary(UserDict.UserDict): 363257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel """Mapping class that references values weakly. 373257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 383257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel Entries in the dictionary will be discarded when no strong 393257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel reference to the value exists anymore 403257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel """ 413257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel # We inherit the constructor without worrying about the input 423257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel # dictionary; since it uses our .update() method, we get the right 433257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel # checks (if the other dictionary is a WeakValueDictionary, 443257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel # objects are unwrapped on the way out, and we always wrap on the 453257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel # way in). 463257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 473257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def __init__(self, *args, **kw): 483257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def remove(wr, selfref=ref(self)): 493257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self = selfref() 503257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if self is not None: 513257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if self._iterating: 523257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self._pending_removals.append(wr.key) 533257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel else: 543257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel del self.data[wr.key] 553257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self._remove = remove 563257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel # A list of keys to be removed 573257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self._pending_removals = [] 583257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self._iterating = set() 593257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel UserDict.UserDict.__init__(self, *args, **kw) 603257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 613257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def _commit_removals(self): 623257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel l = self._pending_removals 633257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel d = self.data 643257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel # We shouldn't encounter any KeyError, because this method should 653257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel # always be called *before* mutating the dict. 663257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel while l: 673257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel del d[l.pop()] 683257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 693257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def __getitem__(self, key): 703257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel o = self.data[key]() 713257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if o is None: 723257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel raise KeyError, key 733257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel else: 743257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel return o 753257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 763257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def __delitem__(self, key): 773257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if self._pending_removals: 783257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self._commit_removals() 793257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel del self.data[key] 803257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 813257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def __contains__(self, key): 823257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel try: 833257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel o = self.data[key]() 843257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel except KeyError: 853257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel return False 863257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel return o is not None 873257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 883257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def has_key(self, key): 893257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel try: 903257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel o = self.data[key]() 913257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel except KeyError: 923257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel return False 933257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel return o is not None 943257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 953257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def __repr__(self): 963257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel return "<WeakValueDictionary at %s>" % id(self) 973257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 983257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def __setitem__(self, key, value): 993257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if self._pending_removals: 1003257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self._commit_removals() 1013257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self.data[key] = KeyedRef(value, self._remove, key) 1023257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 1033257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def clear(self): 1043257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if self._pending_removals: 1053257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self._commit_removals() 1063257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self.data.clear() 1073257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 1083257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def copy(self): 1093257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel new = WeakValueDictionary() 1103257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel for key, wr in self.data.items(): 1113257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel o = wr() 1123257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if o is not None: 1133257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel new[key] = o 1143257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel return new 1153257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 1163257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel __copy__ = copy 1173257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 1183257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def __deepcopy__(self, memo): 1193257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel from copy import deepcopy 1203257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel new = self.__class__() 1213257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel for key, wr in self.data.items(): 1223257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel o = wr() 1233257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if o is not None: 1243257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel new[deepcopy(key, memo)] = o 1253257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel return new 1263257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 1273257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def get(self, key, default=None): 1283257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel try: 1293257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel wr = self.data[key] 1303257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel except KeyError: 1313257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel return default 1323257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel else: 1333257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel o = wr() 1343257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if o is None: 1353257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel # This should only happen 1363257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel return default 1373257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel else: 1383257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel return o 1393257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 1403257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def items(self): 1413257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel L = [] 1423257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel for key, wr in self.data.items(): 1433257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel o = wr() 1443257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if o is not None: 1453257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel L.append((key, o)) 1463257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel return L 1473257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 1483257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def iteritems(self): 1493257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel with _IterationGuard(self): 1503257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel for wr in self.data.itervalues(): 1513257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel value = wr() 1523257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if value is not None: 1533257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel yield wr.key, value 1543257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 1553257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def iterkeys(self): 1563257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel with _IterationGuard(self): 1573257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel for k in self.data.iterkeys(): 1583257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel yield k 1593257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 1603257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel __iter__ = iterkeys 1613257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 1623257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def itervaluerefs(self): 1633257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel """Return an iterator that yields the weak references to the values. 1643257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 1653257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel The references are not guaranteed to be 'live' at the time 1663257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel they are used, so the result of calling the references needs 1673257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel to be checked before being used. This can be used to avoid 1683257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel creating references that will cause the garbage collector to 1693257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel keep the values around longer than needed. 1703257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 1713257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel """ 1723257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel with _IterationGuard(self): 1733257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel for wr in self.data.itervalues(): 1743257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel yield wr 1753257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 1763257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def itervalues(self): 1773257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel with _IterationGuard(self): 1783257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel for wr in self.data.itervalues(): 1793257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel obj = wr() 1803257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if obj is not None: 1813257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel yield obj 1823257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 1833257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def popitem(self): 1843257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if self._pending_removals: 1853257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self._commit_removals() 1863257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel while 1: 1873257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel key, wr = self.data.popitem() 1883257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel o = wr() 1893257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if o is not None: 1903257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel return key, o 1913257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 1923257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def pop(self, key, *args): 1933257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if self._pending_removals: 1943257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self._commit_removals() 1953257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel try: 1963257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel o = self.data.pop(key)() 1973257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel except KeyError: 1983257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if args: 1993257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel return args[0] 2003257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel raise 2013257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if o is None: 2023257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel raise KeyError, key 2033257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel else: 2043257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel return o 2053257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 2063257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def setdefault(self, key, default=None): 2073257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel try: 2083257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel wr = self.data[key] 2093257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel except KeyError: 2103257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if self._pending_removals: 2113257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self._commit_removals() 2123257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self.data[key] = KeyedRef(default, self._remove, key) 2133257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel return default 2143257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel else: 2153257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel return wr() 2163257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 2173257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def update(self, dict=None, **kwargs): 2183257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if self._pending_removals: 2193257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self._commit_removals() 2203257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel d = self.data 2213257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if dict is not None: 2223257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if not hasattr(dict, "items"): 2233257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel dict = type({})(dict) 2243257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel for key, o in dict.items(): 2253257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel d[key] = KeyedRef(o, self._remove, key) 2263257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if len(kwargs): 2273257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self.update(kwargs) 2283257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 2293257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def valuerefs(self): 2303257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel """Return a list of weak references to the values. 2313257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 2323257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel The references are not guaranteed to be 'live' at the time 2333257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel they are used, so the result of calling the references needs 2343257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel to be checked before being used. This can be used to avoid 2353257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel creating references that will cause the garbage collector to 2363257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel keep the values around longer than needed. 2373257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 2383257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel """ 2393257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel return self.data.values() 2403257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 2413257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def values(self): 2423257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel L = [] 2433257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel for wr in self.data.values(): 2443257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel o = wr() 2453257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if o is not None: 2463257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel L.append(o) 2473257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel return L 2483257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 2493257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 2503257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielclass KeyedRef(ref): 2513257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel """Specialized reference that includes a key corresponding to the value. 2523257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 2533257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel This is used in the WeakValueDictionary to avoid having to create 2543257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel a function object for each key stored in the mapping. A shared 2553257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel callback object can use the 'key' attribute of a KeyedRef instead 2563257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel of getting a reference to the key from an enclosing scope. 2573257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 2583257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel """ 2593257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 2603257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel __slots__ = "key", 2613257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 2623257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def __new__(type, ob, callback, key): 2633257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self = ref.__new__(type, ob, callback) 2643257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self.key = key 2653257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel return self 2663257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 2673257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def __init__(self, ob, callback, key): 2683257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel super(KeyedRef, self).__init__(ob, callback) 2693257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 2703257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 2713257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielclass WeakKeyDictionary(UserDict.UserDict): 2723257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel """ Mapping class that references keys weakly. 2733257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 2743257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel Entries in the dictionary will be discarded when there is no 2753257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel longer a strong reference to the key. This can be used to 2763257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel associate additional data with an object owned by other parts of 2773257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel an application without adding attributes to those objects. This 2783257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel can be especially useful with objects that override attribute 2793257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel accesses. 2803257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel """ 2813257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 2823257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def __init__(self, dict=None): 2833257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self.data = {} 2843257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def remove(k, selfref=ref(self)): 2853257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self = selfref() 2863257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if self is not None: 2873257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if self._iterating: 2883257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self._pending_removals.append(k) 2893257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel else: 2903257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel del self.data[k] 2913257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self._remove = remove 2923257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel # A list of dead weakrefs (keys to be removed) 2933257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self._pending_removals = [] 2943257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self._iterating = set() 2953257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if dict is not None: 2963257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self.update(dict) 2973257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 2983257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def _commit_removals(self): 2993257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel # NOTE: We don't need to call this method before mutating the dict, 3003257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel # because a dead weakref never compares equal to a live weakref, 3013257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel # even if they happened to refer to equal objects. 3023257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel # However, it means keys may already have been removed. 3033257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel l = self._pending_removals 3043257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel d = self.data 3053257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel while l: 3063257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel try: 3073257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel del d[l.pop()] 3083257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel except KeyError: 3093257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel pass 3103257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 3113257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def __delitem__(self, key): 3123257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel del self.data[ref(key)] 3133257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 3143257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def __getitem__(self, key): 3153257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel return self.data[ref(key)] 3163257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 3173257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def __repr__(self): 3183257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel return "<WeakKeyDictionary at %s>" % id(self) 3193257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 3203257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def __setitem__(self, key, value): 3213257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self.data[ref(key, self._remove)] = value 3223257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 3233257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def copy(self): 3243257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel new = WeakKeyDictionary() 3253257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel for key, value in self.data.items(): 3263257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel o = key() 3273257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if o is not None: 3283257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel new[o] = value 3293257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel return new 3303257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 3313257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel __copy__ = copy 3323257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 3333257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def __deepcopy__(self, memo): 3343257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel from copy import deepcopy 3353257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel new = self.__class__() 3363257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel for key, value in self.data.items(): 3373257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel o = key() 3383257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if o is not None: 3393257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel new[o] = deepcopy(value, memo) 3403257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel return new 3413257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 3423257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def get(self, key, default=None): 3433257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel return self.data.get(ref(key),default) 3443257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 3453257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def has_key(self, key): 3463257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel try: 3473257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel wr = ref(key) 3483257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel except TypeError: 3493257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel return 0 3503257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel return wr in self.data 3513257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 3523257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def __contains__(self, key): 3533257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel try: 3543257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel wr = ref(key) 3553257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel except TypeError: 3563257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel return 0 3573257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel return wr in self.data 3583257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 3593257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def items(self): 3603257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel L = [] 3613257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel for key, value in self.data.items(): 3623257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel o = key() 3633257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if o is not None: 3643257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel L.append((o, value)) 3653257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel return L 3663257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 3673257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def iteritems(self): 3683257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel with _IterationGuard(self): 3693257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel for wr, value in self.data.iteritems(): 3703257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel key = wr() 3713257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if key is not None: 3723257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel yield key, value 3733257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 3743257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def iterkeyrefs(self): 3753257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel """Return an iterator that yields the weak references to the keys. 3763257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 3773257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel The references are not guaranteed to be 'live' at the time 3783257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel they are used, so the result of calling the references needs 3793257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel to be checked before being used. This can be used to avoid 3803257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel creating references that will cause the garbage collector to 3813257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel keep the keys around longer than needed. 3823257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 3833257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel """ 3843257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel with _IterationGuard(self): 3853257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel for wr in self.data.iterkeys(): 3863257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel yield wr 3873257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 3883257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def iterkeys(self): 3893257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel with _IterationGuard(self): 3903257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel for wr in self.data.iterkeys(): 3913257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel obj = wr() 3923257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if obj is not None: 3933257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel yield obj 3943257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 3953257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel __iter__ = iterkeys 3963257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 3973257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def itervalues(self): 3983257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel with _IterationGuard(self): 3993257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel for value in self.data.itervalues(): 4003257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel yield value 4013257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 4023257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def keyrefs(self): 4033257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel """Return a list of weak references to the keys. 4043257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 4053257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel The references are not guaranteed to be 'live' at the time 4063257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel they are used, so the result of calling the references needs 4073257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel to be checked before being used. This can be used to avoid 4083257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel creating references that will cause the garbage collector to 4093257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel keep the keys around longer than needed. 4103257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 4113257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel """ 4123257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel return self.data.keys() 4133257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 4143257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def keys(self): 4153257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel L = [] 4163257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel for wr in self.data.keys(): 4173257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel o = wr() 4183257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if o is not None: 4193257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel L.append(o) 4203257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel return L 4213257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 4223257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def popitem(self): 4233257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel while 1: 4243257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel key, value = self.data.popitem() 4253257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel o = key() 4263257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if o is not None: 4273257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel return o, value 4283257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 4293257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def pop(self, key, *args): 4303257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel return self.data.pop(ref(key), *args) 4313257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 4323257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def setdefault(self, key, default=None): 4333257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel return self.data.setdefault(ref(key, self._remove),default) 4343257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 4353257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def update(self, dict=None, **kwargs): 4363257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel d = self.data 4373257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if dict is not None: 4383257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if not hasattr(dict, "items"): 4393257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel dict = type({})(dict) 4403257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel for key, value in dict.items(): 4413257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel d[ref(key, self._remove)] = value 4423257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if len(kwargs): 4433257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self.update(kwargs) 444