183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh"""Weak reference support for Python. 283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew HsiehThis module is an implementation of PEP 205: 483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehhttp://www.python.org/dev/peps/pep-0205/ 683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh""" 783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# Naming convention: Variables named "wr" are weak reference objects; 983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# they are called this instead of "ref" to avoid name collisions with 1083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# the module-global ref() function imported from _weakref. 1183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 1283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehimport UserDict 1383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 1483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehfrom _weakref import ( 1583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh getweakrefcount, 1683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh getweakrefs, 1783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh ref, 1883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh proxy, 1983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh CallableProxyType, 2083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh ProxyType, 2183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh ReferenceType) 2283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 2383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehfrom _weakrefset import WeakSet 2483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 2583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehfrom exceptions import ReferenceError 2683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 2783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 2883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew HsiehProxyTypes = (ProxyType, CallableProxyType) 2983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 3083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh__all__ = ["ref", "proxy", "getweakrefcount", "getweakrefs", 3183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh "WeakKeyDictionary", "ReferenceError", "ReferenceType", "ProxyType", 3283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh "CallableProxyType", "ProxyTypes", "WeakValueDictionary", 'WeakSet'] 3383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 3483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 3583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehclass WeakValueDictionary(UserDict.UserDict): 3683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """Mapping class that references values weakly. 3783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 3883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Entries in the dictionary will be discarded when no strong 3983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh reference to the value exists anymore 4083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 4183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # We inherit the constructor without worrying about the input 4283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # dictionary; since it uses our .update() method, we get the right 4383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # checks (if the other dictionary is a WeakValueDictionary, 4483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # objects are unwrapped on the way out, and we always wrap on the 4583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # way in). 4683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 4783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __init__(self, *args, **kw): 4883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def remove(wr, selfref=ref(self)): 4983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self = selfref() 5083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if self is not None: 5183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh del self.data[wr.key] 5283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._remove = remove 5383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh UserDict.UserDict.__init__(self, *args, **kw) 5483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 5583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __getitem__(self, key): 5683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh o = self.data[key]() 5783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if o is None: 5883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh raise KeyError, key 5983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh else: 6083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return o 6183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 6283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __contains__(self, key): 6383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh try: 6483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh o = self.data[key]() 6583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh except KeyError: 6683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return False 6783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return o is not None 6883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 6983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def has_key(self, key): 7083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh try: 7183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh o = self.data[key]() 7283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh except KeyError: 7383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return False 7483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return o is not None 7583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 7683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __repr__(self): 7783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return "<WeakValueDictionary at %s>" % id(self) 7883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 7983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __setitem__(self, key, value): 8083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.data[key] = KeyedRef(value, self._remove, key) 8183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 8283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def copy(self): 8383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh new = WeakValueDictionary() 8483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for key, wr in self.data.items(): 8583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh o = wr() 8683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if o is not None: 8783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh new[key] = o 8883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return new 8983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 9083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh __copy__ = copy 9183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 9283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __deepcopy__(self, memo): 9383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh from copy import deepcopy 9483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh new = self.__class__() 9583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for key, wr in self.data.items(): 9683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh o = wr() 9783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if o is not None: 9883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh new[deepcopy(key, memo)] = o 9983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return new 10083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 10183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def get(self, key, default=None): 10283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh try: 10383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh wr = self.data[key] 10483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh except KeyError: 10583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return default 10683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh else: 10783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh o = wr() 10883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if o is None: 10983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # This should only happen 11083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return default 11183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh else: 11283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return o 11383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 11483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def items(self): 11583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh L = [] 11683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for key, wr in self.data.items(): 11783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh o = wr() 11883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if o is not None: 11983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh L.append((key, o)) 12083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return L 12183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 12283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def iteritems(self): 12383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for wr in self.data.itervalues(): 12483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh value = wr() 12583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if value is not None: 12683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh yield wr.key, value 12783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 12883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def iterkeys(self): 12983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return self.data.iterkeys() 13083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 13183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __iter__(self): 13283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return self.data.iterkeys() 13383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 13483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def itervaluerefs(self): 13583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """Return an iterator that yields the weak references to the values. 13683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 13783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh The references are not guaranteed to be 'live' at the time 13883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh they are used, so the result of calling the references needs 13983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh to be checked before being used. This can be used to avoid 14083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh creating references that will cause the garbage collector to 14183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh keep the values around longer than needed. 14283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 14383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 14483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return self.data.itervalues() 14583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 14683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def itervalues(self): 14783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for wr in self.data.itervalues(): 14883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh obj = wr() 14983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if obj is not None: 15083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh yield obj 15183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 15283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def popitem(self): 15383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh while 1: 15483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh key, wr = self.data.popitem() 15583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh o = wr() 15683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if o is not None: 15783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return key, o 15883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 15983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def pop(self, key, *args): 16083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh try: 16183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh o = self.data.pop(key)() 16283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh except KeyError: 16383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if args: 16483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return args[0] 16583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh raise 16683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if o is None: 16783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh raise KeyError, key 16883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh else: 16983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return o 17083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 17183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def setdefault(self, key, default=None): 17283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh try: 17383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh wr = self.data[key] 17483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh except KeyError: 17583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.data[key] = KeyedRef(default, self._remove, key) 17683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return default 17783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh else: 17883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return wr() 17983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 18083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def update(self, dict=None, **kwargs): 18183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh d = self.data 18283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if dict is not None: 18383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if not hasattr(dict, "items"): 18483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh dict = type({})(dict) 18583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for key, o in dict.items(): 18683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh d[key] = KeyedRef(o, self._remove, key) 18783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if len(kwargs): 18883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.update(kwargs) 18983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 19083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def valuerefs(self): 19183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """Return a list of weak references to the values. 19283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 19383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh The references are not guaranteed to be 'live' at the time 19483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh they are used, so the result of calling the references needs 19583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh to be checked before being used. This can be used to avoid 19683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh creating references that will cause the garbage collector to 19783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh keep the values around longer than needed. 19883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 19983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 20083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return self.data.values() 20183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 20283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def values(self): 20383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh L = [] 20483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for wr in self.data.values(): 20583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh o = wr() 20683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if o is not None: 20783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh L.append(o) 20883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return L 20983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 21083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 21183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehclass KeyedRef(ref): 21283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """Specialized reference that includes a key corresponding to the value. 21383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 21483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh This is used in the WeakValueDictionary to avoid having to create 21583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh a function object for each key stored in the mapping. A shared 21683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh callback object can use the 'key' attribute of a KeyedRef instead 21783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh of getting a reference to the key from an enclosing scope. 21883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 21983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 22083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 22183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh __slots__ = "key", 22283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 22383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __new__(type, ob, callback, key): 22483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self = ref.__new__(type, ob, callback) 22583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.key = key 22683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return self 22783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 22883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __init__(self, ob, callback, key): 22983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh super(KeyedRef, self).__init__(ob, callback) 23083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 23183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 23283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehclass WeakKeyDictionary(UserDict.UserDict): 23383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ Mapping class that references keys weakly. 23483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 23583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Entries in the dictionary will be discarded when there is no 23683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh longer a strong reference to the key. This can be used to 23783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh associate additional data with an object owned by other parts of 23883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh an application without adding attributes to those objects. This 23983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh can be especially useful with objects that override attribute 24083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh accesses. 24183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 24283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 24383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __init__(self, dict=None): 24483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.data = {} 24583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def remove(k, selfref=ref(self)): 24683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self = selfref() 24783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if self is not None: 24883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh del self.data[k] 24983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._remove = remove 25083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if dict is not None: self.update(dict) 25183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 25283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __delitem__(self, key): 25383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh del self.data[ref(key)] 25483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 25583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __getitem__(self, key): 25683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return self.data[ref(key)] 25783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 25883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __repr__(self): 25983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return "<WeakKeyDictionary at %s>" % id(self) 26083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 26183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __setitem__(self, key, value): 26283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.data[ref(key, self._remove)] = value 26383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 26483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def copy(self): 26583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh new = WeakKeyDictionary() 26683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for key, value in self.data.items(): 26783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh o = key() 26883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if o is not None: 26983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh new[o] = value 27083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return new 27183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 27283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh __copy__ = copy 27383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 27483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __deepcopy__(self, memo): 27583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh from copy import deepcopy 27683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh new = self.__class__() 27783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for key, value in self.data.items(): 27883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh o = key() 27983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if o is not None: 28083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh new[o] = deepcopy(value, memo) 28183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return new 28283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 28383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def get(self, key, default=None): 28483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return self.data.get(ref(key),default) 28583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 28683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def has_key(self, key): 28783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh try: 28883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh wr = ref(key) 28983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh except TypeError: 29083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return 0 29183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return wr in self.data 29283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 29383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __contains__(self, key): 29483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh try: 29583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh wr = ref(key) 29683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh except TypeError: 29783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return 0 29883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return wr in self.data 29983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 30083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def items(self): 30183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh L = [] 30283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for key, value in self.data.items(): 30383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh o = key() 30483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if o is not None: 30583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh L.append((o, value)) 30683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return L 30783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 30883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def iteritems(self): 30983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for wr, value in self.data.iteritems(): 31083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh key = wr() 31183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if key is not None: 31283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh yield key, value 31383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 31483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def iterkeyrefs(self): 31583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """Return an iterator that yields the weak references to the keys. 31683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 31783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh The references are not guaranteed to be 'live' at the time 31883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh they are used, so the result of calling the references needs 31983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh to be checked before being used. This can be used to avoid 32083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh creating references that will cause the garbage collector to 32183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh keep the keys around longer than needed. 32283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 32383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 32483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return self.data.iterkeys() 32583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 32683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def iterkeys(self): 32783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for wr in self.data.iterkeys(): 32883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh obj = wr() 32983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if obj is not None: 33083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh yield obj 33183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 33283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __iter__(self): 33383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return self.iterkeys() 33483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 33583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def itervalues(self): 33683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return self.data.itervalues() 33783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 33883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def keyrefs(self): 33983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """Return a list of weak references to the keys. 34083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 34183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh The references are not guaranteed to be 'live' at the time 34283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh they are used, so the result of calling the references needs 34383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh to be checked before being used. This can be used to avoid 34483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh creating references that will cause the garbage collector to 34583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh keep the keys around longer than needed. 34683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 34783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 34883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return self.data.keys() 34983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 35083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def keys(self): 35183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh L = [] 35283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for wr in self.data.keys(): 35383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh o = wr() 35483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if o is not None: 35583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh L.append(o) 35683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return L 35783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 35883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def popitem(self): 35983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh while 1: 36083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh key, value = self.data.popitem() 36183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh o = key() 36283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if o is not None: 36383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return o, value 36483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 36583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def pop(self, key, *args): 36683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return self.data.pop(ref(key), *args) 36783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 36883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def setdefault(self, key, default=None): 36983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return self.data.setdefault(ref(key, self._remove),default) 37083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 37183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def update(self, dict=None, **kwargs): 37283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh d = self.data 37383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if dict is not None: 37483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if not hasattr(dict, "items"): 37583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh dict = type({})(dict) 37683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for key, value in dict.items(): 37783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh d[ref(key, self._remove)] = value 37883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if len(kwargs): 37983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.update(kwargs) 380