| """Weak reference support for Python. | |
| This module is an implementation of PEP 205: | |
| http://www.python.org/dev/peps/pep-0205/ | |
| """ | |
| # Naming convention: Variables named "wr" are weak reference objects; | |
| # they are called this instead of "ref" to avoid name collisions with | |
| # the module-global ref() function imported from _weakref. | |
| import UserDict | |
| from _weakref import ( | |
| getweakrefcount, | |
| getweakrefs, | |
| ref, | |
| proxy, | |
| CallableProxyType, | |
| ProxyType, | |
| ReferenceType) | |
| from _weakrefset import WeakSet | |
| from exceptions import ReferenceError | |
| ProxyTypes = (ProxyType, CallableProxyType) | |
| __all__ = ["ref", "proxy", "getweakrefcount", "getweakrefs", | |
| "WeakKeyDictionary", "ReferenceError", "ReferenceType", "ProxyType", | |
| "CallableProxyType", "ProxyTypes", "WeakValueDictionary", 'WeakSet'] | |
| class WeakValueDictionary(UserDict.UserDict): | |
| """Mapping class that references values weakly. | |
| Entries in the dictionary will be discarded when no strong | |
| reference to the value exists anymore | |
| """ | |
| # We inherit the constructor without worrying about the input | |
| # dictionary; since it uses our .update() method, we get the right | |
| # checks (if the other dictionary is a WeakValueDictionary, | |
| # objects are unwrapped on the way out, and we always wrap on the | |
| # way in). | |
| def __init__(self, *args, **kw): | |
| def remove(wr, selfref=ref(self)): | |
| self = selfref() | |
| if self is not None: | |
| del self.data[wr.key] | |
| self._remove = remove | |
| UserDict.UserDict.__init__(self, *args, **kw) | |
| def __getitem__(self, key): | |
| o = self.data[key]() | |
| if o is None: | |
| raise KeyError, key | |
| else: | |
| return o | |
| def __contains__(self, key): | |
| try: | |
| o = self.data[key]() | |
| except KeyError: | |
| return False | |
| return o is not None | |
| def has_key(self, key): | |
| try: | |
| o = self.data[key]() | |
| except KeyError: | |
| return False | |
| return o is not None | |
| def __repr__(self): | |
| return "<WeakValueDictionary at %s>" % id(self) | |
| def __setitem__(self, key, value): | |
| self.data[key] = KeyedRef(value, self._remove, key) | |
| def copy(self): | |
| new = WeakValueDictionary() | |
| for key, wr in self.data.items(): | |
| o = wr() | |
| if o is not None: | |
| new[key] = o | |
| return new | |
| __copy__ = copy | |
| def __deepcopy__(self, memo): | |
| from copy import deepcopy | |
| new = self.__class__() | |
| for key, wr in self.data.items(): | |
| o = wr() | |
| if o is not None: | |
| new[deepcopy(key, memo)] = o | |
| return new | |
| def get(self, key, default=None): | |
| try: | |
| wr = self.data[key] | |
| except KeyError: | |
| return default | |
| else: | |
| o = wr() | |
| if o is None: | |
| # This should only happen | |
| return default | |
| else: | |
| return o | |
| def items(self): | |
| L = [] | |
| for key, wr in self.data.items(): | |
| o = wr() | |
| if o is not None: | |
| L.append((key, o)) | |
| return L | |
| def iteritems(self): | |
| for wr in self.data.itervalues(): | |
| value = wr() | |
| if value is not None: | |
| yield wr.key, value | |
| def iterkeys(self): | |
| return self.data.iterkeys() | |
| def __iter__(self): | |
| return self.data.iterkeys() | |
| def itervaluerefs(self): | |
| """Return an iterator that yields the weak references to the values. | |
| The references are not guaranteed to be 'live' at the time | |
| they are used, so the result of calling the references needs | |
| to be checked before being used. This can be used to avoid | |
| creating references that will cause the garbage collector to | |
| keep the values around longer than needed. | |
| """ | |
| return self.data.itervalues() | |
| def itervalues(self): | |
| for wr in self.data.itervalues(): | |
| obj = wr() | |
| if obj is not None: | |
| yield obj | |
| def popitem(self): | |
| while 1: | |
| key, wr = self.data.popitem() | |
| o = wr() | |
| if o is not None: | |
| return key, o | |
| def pop(self, key, *args): | |
| try: | |
| o = self.data.pop(key)() | |
| except KeyError: | |
| if args: | |
| return args[0] | |
| raise | |
| if o is None: | |
| raise KeyError, key | |
| else: | |
| return o | |
| def setdefault(self, key, default=None): | |
| try: | |
| wr = self.data[key] | |
| except KeyError: | |
| self.data[key] = KeyedRef(default, self._remove, key) | |
| return default | |
| else: | |
| return wr() | |
| def update(self, dict=None, **kwargs): | |
| d = self.data | |
| if dict is not None: | |
| if not hasattr(dict, "items"): | |
| dict = type({})(dict) | |
| for key, o in dict.items(): | |
| d[key] = KeyedRef(o, self._remove, key) | |
| if len(kwargs): | |
| self.update(kwargs) | |
| def valuerefs(self): | |
| """Return a list of weak references to the values. | |
| The references are not guaranteed to be 'live' at the time | |
| they are used, so the result of calling the references needs | |
| to be checked before being used. This can be used to avoid | |
| creating references that will cause the garbage collector to | |
| keep the values around longer than needed. | |
| """ | |
| return self.data.values() | |
| def values(self): | |
| L = [] | |
| for wr in self.data.values(): | |
| o = wr() | |
| if o is not None: | |
| L.append(o) | |
| return L | |
| class KeyedRef(ref): | |
| """Specialized reference that includes a key corresponding to the value. | |
| This is used in the WeakValueDictionary to avoid having to create | |
| a function object for each key stored in the mapping. A shared | |
| callback object can use the 'key' attribute of a KeyedRef instead | |
| of getting a reference to the key from an enclosing scope. | |
| """ | |
| __slots__ = "key", | |
| def __new__(type, ob, callback, key): | |
| self = ref.__new__(type, ob, callback) | |
| self.key = key | |
| return self | |
| def __init__(self, ob, callback, key): | |
| super(KeyedRef, self).__init__(ob, callback) | |
| class WeakKeyDictionary(UserDict.UserDict): | |
| """ Mapping class that references keys weakly. | |
| Entries in the dictionary will be discarded when there is no | |
| longer a strong reference to the key. This can be used to | |
| associate additional data with an object owned by other parts of | |
| an application without adding attributes to those objects. This | |
| can be especially useful with objects that override attribute | |
| accesses. | |
| """ | |
| def __init__(self, dict=None): | |
| self.data = {} | |
| def remove(k, selfref=ref(self)): | |
| self = selfref() | |
| if self is not None: | |
| del self.data[k] | |
| self._remove = remove | |
| if dict is not None: self.update(dict) | |
| def __delitem__(self, key): | |
| del self.data[ref(key)] | |
| def __getitem__(self, key): | |
| return self.data[ref(key)] | |
| def __repr__(self): | |
| return "<WeakKeyDictionary at %s>" % id(self) | |
| def __setitem__(self, key, value): | |
| self.data[ref(key, self._remove)] = value | |
| def copy(self): | |
| new = WeakKeyDictionary() | |
| for key, value in self.data.items(): | |
| o = key() | |
| if o is not None: | |
| new[o] = value | |
| return new | |
| __copy__ = copy | |
| def __deepcopy__(self, memo): | |
| from copy import deepcopy | |
| new = self.__class__() | |
| for key, value in self.data.items(): | |
| o = key() | |
| if o is not None: | |
| new[o] = deepcopy(value, memo) | |
| return new | |
| def get(self, key, default=None): | |
| return self.data.get(ref(key),default) | |
| def has_key(self, key): | |
| try: | |
| wr = ref(key) | |
| except TypeError: | |
| return 0 | |
| return wr in self.data | |
| def __contains__(self, key): | |
| try: | |
| wr = ref(key) | |
| except TypeError: | |
| return 0 | |
| return wr in self.data | |
| def items(self): | |
| L = [] | |
| for key, value in self.data.items(): | |
| o = key() | |
| if o is not None: | |
| L.append((o, value)) | |
| return L | |
| def iteritems(self): | |
| for wr, value in self.data.iteritems(): | |
| key = wr() | |
| if key is not None: | |
| yield key, value | |
| def iterkeyrefs(self): | |
| """Return an iterator that yields the weak references to the keys. | |
| The references are not guaranteed to be 'live' at the time | |
| they are used, so the result of calling the references needs | |
| to be checked before being used. This can be used to avoid | |
| creating references that will cause the garbage collector to | |
| keep the keys around longer than needed. | |
| """ | |
| return self.data.iterkeys() | |
| def iterkeys(self): | |
| for wr in self.data.iterkeys(): | |
| obj = wr() | |
| if obj is not None: | |
| yield obj | |
| def __iter__(self): | |
| return self.iterkeys() | |
| def itervalues(self): | |
| return self.data.itervalues() | |
| def keyrefs(self): | |
| """Return a list of weak references to the keys. | |
| The references are not guaranteed to be 'live' at the time | |
| they are used, so the result of calling the references needs | |
| to be checked before being used. This can be used to avoid | |
| creating references that will cause the garbage collector to | |
| keep the keys around longer than needed. | |
| """ | |
| return self.data.keys() | |
| def keys(self): | |
| L = [] | |
| for wr in self.data.keys(): | |
| o = wr() | |
| if o is not None: | |
| L.append(o) | |
| return L | |
| def popitem(self): | |
| while 1: | |
| key, value = self.data.popitem() | |
| o = key() | |
| if o is not None: | |
| return o, value | |
| def pop(self, key, *args): | |
| return self.data.pop(ref(key), *args) | |
| def setdefault(self, key, default=None): | |
| return self.data.setdefault(ref(key, self._remove),default) | |
| def update(self, dict=None, **kwargs): | |
| d = self.data | |
| if dict is not None: | |
| if not hasattr(dict, "items"): | |
| dict = type({})(dict) | |
| for key, value in dict.items(): | |
| d[ref(key, self._remove)] = value | |
| if len(kwargs): | |
| self.update(kwargs) |