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