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