17db96d56Sopenharmony_ci"""Weak reference support for Python.
27db96d56Sopenharmony_ci
37db96d56Sopenharmony_ciThis module is an implementation of PEP 205:
47db96d56Sopenharmony_ci
57db96d56Sopenharmony_cihttps://peps.python.org/pep-0205/
67db96d56Sopenharmony_ci"""
77db96d56Sopenharmony_ci
87db96d56Sopenharmony_ci# Naming convention: Variables named "wr" are weak reference objects;
97db96d56Sopenharmony_ci# they are called this instead of "ref" to avoid name collisions with
107db96d56Sopenharmony_ci# the module-global ref() function imported from _weakref.
117db96d56Sopenharmony_ci
127db96d56Sopenharmony_cifrom _weakref import (
137db96d56Sopenharmony_ci     getweakrefcount,
147db96d56Sopenharmony_ci     getweakrefs,
157db96d56Sopenharmony_ci     ref,
167db96d56Sopenharmony_ci     proxy,
177db96d56Sopenharmony_ci     CallableProxyType,
187db96d56Sopenharmony_ci     ProxyType,
197db96d56Sopenharmony_ci     ReferenceType,
207db96d56Sopenharmony_ci     _remove_dead_weakref)
217db96d56Sopenharmony_ci
227db96d56Sopenharmony_cifrom _weakrefset import WeakSet, _IterationGuard
237db96d56Sopenharmony_ci
247db96d56Sopenharmony_ciimport _collections_abc  # Import after _weakref to avoid circular import.
257db96d56Sopenharmony_ciimport sys
267db96d56Sopenharmony_ciimport itertools
277db96d56Sopenharmony_ci
287db96d56Sopenharmony_ciProxyTypes = (ProxyType, CallableProxyType)
297db96d56Sopenharmony_ci
307db96d56Sopenharmony_ci__all__ = ["ref", "proxy", "getweakrefcount", "getweakrefs",
317db96d56Sopenharmony_ci           "WeakKeyDictionary", "ReferenceType", "ProxyType",
327db96d56Sopenharmony_ci           "CallableProxyType", "ProxyTypes", "WeakValueDictionary",
337db96d56Sopenharmony_ci           "WeakSet", "WeakMethod", "finalize"]
347db96d56Sopenharmony_ci
357db96d56Sopenharmony_ci
367db96d56Sopenharmony_ci_collections_abc.MutableSet.register(WeakSet)
377db96d56Sopenharmony_ci
387db96d56Sopenharmony_ciclass WeakMethod(ref):
397db96d56Sopenharmony_ci    """
407db96d56Sopenharmony_ci    A custom `weakref.ref` subclass which simulates a weak reference to
417db96d56Sopenharmony_ci    a bound method, working around the lifetime problem of bound methods.
427db96d56Sopenharmony_ci    """
437db96d56Sopenharmony_ci
447db96d56Sopenharmony_ci    __slots__ = "_func_ref", "_meth_type", "_alive", "__weakref__"
457db96d56Sopenharmony_ci
467db96d56Sopenharmony_ci    def __new__(cls, meth, callback=None):
477db96d56Sopenharmony_ci        try:
487db96d56Sopenharmony_ci            obj = meth.__self__
497db96d56Sopenharmony_ci            func = meth.__func__
507db96d56Sopenharmony_ci        except AttributeError:
517db96d56Sopenharmony_ci            raise TypeError("argument should be a bound method, not {}"
527db96d56Sopenharmony_ci                            .format(type(meth))) from None
537db96d56Sopenharmony_ci        def _cb(arg):
547db96d56Sopenharmony_ci            # The self-weakref trick is needed to avoid creating a reference
557db96d56Sopenharmony_ci            # cycle.
567db96d56Sopenharmony_ci            self = self_wr()
577db96d56Sopenharmony_ci            if self._alive:
587db96d56Sopenharmony_ci                self._alive = False
597db96d56Sopenharmony_ci                if callback is not None:
607db96d56Sopenharmony_ci                    callback(self)
617db96d56Sopenharmony_ci        self = ref.__new__(cls, obj, _cb)
627db96d56Sopenharmony_ci        self._func_ref = ref(func, _cb)
637db96d56Sopenharmony_ci        self._meth_type = type(meth)
647db96d56Sopenharmony_ci        self._alive = True
657db96d56Sopenharmony_ci        self_wr = ref(self)
667db96d56Sopenharmony_ci        return self
677db96d56Sopenharmony_ci
687db96d56Sopenharmony_ci    def __call__(self):
697db96d56Sopenharmony_ci        obj = super().__call__()
707db96d56Sopenharmony_ci        func = self._func_ref()
717db96d56Sopenharmony_ci        if obj is None or func is None:
727db96d56Sopenharmony_ci            return None
737db96d56Sopenharmony_ci        return self._meth_type(func, obj)
747db96d56Sopenharmony_ci
757db96d56Sopenharmony_ci    def __eq__(self, other):
767db96d56Sopenharmony_ci        if isinstance(other, WeakMethod):
777db96d56Sopenharmony_ci            if not self._alive or not other._alive:
787db96d56Sopenharmony_ci                return self is other
797db96d56Sopenharmony_ci            return ref.__eq__(self, other) and self._func_ref == other._func_ref
807db96d56Sopenharmony_ci        return NotImplemented
817db96d56Sopenharmony_ci
827db96d56Sopenharmony_ci    def __ne__(self, other):
837db96d56Sopenharmony_ci        if isinstance(other, WeakMethod):
847db96d56Sopenharmony_ci            if not self._alive or not other._alive:
857db96d56Sopenharmony_ci                return self is not other
867db96d56Sopenharmony_ci            return ref.__ne__(self, other) or self._func_ref != other._func_ref
877db96d56Sopenharmony_ci        return NotImplemented
887db96d56Sopenharmony_ci
897db96d56Sopenharmony_ci    __hash__ = ref.__hash__
907db96d56Sopenharmony_ci
917db96d56Sopenharmony_ci
927db96d56Sopenharmony_ciclass WeakValueDictionary(_collections_abc.MutableMapping):
937db96d56Sopenharmony_ci    """Mapping class that references values weakly.
947db96d56Sopenharmony_ci
957db96d56Sopenharmony_ci    Entries in the dictionary will be discarded when no strong
967db96d56Sopenharmony_ci    reference to the value exists anymore
977db96d56Sopenharmony_ci    """
987db96d56Sopenharmony_ci    # We inherit the constructor without worrying about the input
997db96d56Sopenharmony_ci    # dictionary; since it uses our .update() method, we get the right
1007db96d56Sopenharmony_ci    # checks (if the other dictionary is a WeakValueDictionary,
1017db96d56Sopenharmony_ci    # objects are unwrapped on the way out, and we always wrap on the
1027db96d56Sopenharmony_ci    # way in).
1037db96d56Sopenharmony_ci
1047db96d56Sopenharmony_ci    def __init__(self, other=(), /, **kw):
1057db96d56Sopenharmony_ci        def remove(wr, selfref=ref(self), _atomic_removal=_remove_dead_weakref):
1067db96d56Sopenharmony_ci            self = selfref()
1077db96d56Sopenharmony_ci            if self is not None:
1087db96d56Sopenharmony_ci                if self._iterating:
1097db96d56Sopenharmony_ci                    self._pending_removals.append(wr.key)
1107db96d56Sopenharmony_ci                else:
1117db96d56Sopenharmony_ci                    # Atomic removal is necessary since this function
1127db96d56Sopenharmony_ci                    # can be called asynchronously by the GC
1137db96d56Sopenharmony_ci                    _atomic_removal(self.data, wr.key)
1147db96d56Sopenharmony_ci        self._remove = remove
1157db96d56Sopenharmony_ci        # A list of keys to be removed
1167db96d56Sopenharmony_ci        self._pending_removals = []
1177db96d56Sopenharmony_ci        self._iterating = set()
1187db96d56Sopenharmony_ci        self.data = {}
1197db96d56Sopenharmony_ci        self.update(other, **kw)
1207db96d56Sopenharmony_ci
1217db96d56Sopenharmony_ci    def _commit_removals(self, _atomic_removal=_remove_dead_weakref):
1227db96d56Sopenharmony_ci        pop = self._pending_removals.pop
1237db96d56Sopenharmony_ci        d = self.data
1247db96d56Sopenharmony_ci        # We shouldn't encounter any KeyError, because this method should
1257db96d56Sopenharmony_ci        # always be called *before* mutating the dict.
1267db96d56Sopenharmony_ci        while True:
1277db96d56Sopenharmony_ci            try:
1287db96d56Sopenharmony_ci                key = pop()
1297db96d56Sopenharmony_ci            except IndexError:
1307db96d56Sopenharmony_ci                return
1317db96d56Sopenharmony_ci            _atomic_removal(d, key)
1327db96d56Sopenharmony_ci
1337db96d56Sopenharmony_ci    def __getitem__(self, key):
1347db96d56Sopenharmony_ci        if self._pending_removals:
1357db96d56Sopenharmony_ci            self._commit_removals()
1367db96d56Sopenharmony_ci        o = self.data[key]()
1377db96d56Sopenharmony_ci        if o is None:
1387db96d56Sopenharmony_ci            raise KeyError(key)
1397db96d56Sopenharmony_ci        else:
1407db96d56Sopenharmony_ci            return o
1417db96d56Sopenharmony_ci
1427db96d56Sopenharmony_ci    def __delitem__(self, key):
1437db96d56Sopenharmony_ci        if self._pending_removals:
1447db96d56Sopenharmony_ci            self._commit_removals()
1457db96d56Sopenharmony_ci        del self.data[key]
1467db96d56Sopenharmony_ci
1477db96d56Sopenharmony_ci    def __len__(self):
1487db96d56Sopenharmony_ci        if self._pending_removals:
1497db96d56Sopenharmony_ci            self._commit_removals()
1507db96d56Sopenharmony_ci        return len(self.data)
1517db96d56Sopenharmony_ci
1527db96d56Sopenharmony_ci    def __contains__(self, key):
1537db96d56Sopenharmony_ci        if self._pending_removals:
1547db96d56Sopenharmony_ci            self._commit_removals()
1557db96d56Sopenharmony_ci        try:
1567db96d56Sopenharmony_ci            o = self.data[key]()
1577db96d56Sopenharmony_ci        except KeyError:
1587db96d56Sopenharmony_ci            return False
1597db96d56Sopenharmony_ci        return o is not None
1607db96d56Sopenharmony_ci
1617db96d56Sopenharmony_ci    def __repr__(self):
1627db96d56Sopenharmony_ci        return "<%s at %#x>" % (self.__class__.__name__, id(self))
1637db96d56Sopenharmony_ci
1647db96d56Sopenharmony_ci    def __setitem__(self, key, value):
1657db96d56Sopenharmony_ci        if self._pending_removals:
1667db96d56Sopenharmony_ci            self._commit_removals()
1677db96d56Sopenharmony_ci        self.data[key] = KeyedRef(value, self._remove, key)
1687db96d56Sopenharmony_ci
1697db96d56Sopenharmony_ci    def copy(self):
1707db96d56Sopenharmony_ci        if self._pending_removals:
1717db96d56Sopenharmony_ci            self._commit_removals()
1727db96d56Sopenharmony_ci        new = WeakValueDictionary()
1737db96d56Sopenharmony_ci        with _IterationGuard(self):
1747db96d56Sopenharmony_ci            for key, wr in self.data.items():
1757db96d56Sopenharmony_ci                o = wr()
1767db96d56Sopenharmony_ci                if o is not None:
1777db96d56Sopenharmony_ci                    new[key] = o
1787db96d56Sopenharmony_ci        return new
1797db96d56Sopenharmony_ci
1807db96d56Sopenharmony_ci    __copy__ = copy
1817db96d56Sopenharmony_ci
1827db96d56Sopenharmony_ci    def __deepcopy__(self, memo):
1837db96d56Sopenharmony_ci        from copy import deepcopy
1847db96d56Sopenharmony_ci        if self._pending_removals:
1857db96d56Sopenharmony_ci            self._commit_removals()
1867db96d56Sopenharmony_ci        new = self.__class__()
1877db96d56Sopenharmony_ci        with _IterationGuard(self):
1887db96d56Sopenharmony_ci            for key, wr in self.data.items():
1897db96d56Sopenharmony_ci                o = wr()
1907db96d56Sopenharmony_ci                if o is not None:
1917db96d56Sopenharmony_ci                    new[deepcopy(key, memo)] = o
1927db96d56Sopenharmony_ci        return new
1937db96d56Sopenharmony_ci
1947db96d56Sopenharmony_ci    def get(self, key, default=None):
1957db96d56Sopenharmony_ci        if self._pending_removals:
1967db96d56Sopenharmony_ci            self._commit_removals()
1977db96d56Sopenharmony_ci        try:
1987db96d56Sopenharmony_ci            wr = self.data[key]
1997db96d56Sopenharmony_ci        except KeyError:
2007db96d56Sopenharmony_ci            return default
2017db96d56Sopenharmony_ci        else:
2027db96d56Sopenharmony_ci            o = wr()
2037db96d56Sopenharmony_ci            if o is None:
2047db96d56Sopenharmony_ci                # This should only happen
2057db96d56Sopenharmony_ci                return default
2067db96d56Sopenharmony_ci            else:
2077db96d56Sopenharmony_ci                return o
2087db96d56Sopenharmony_ci
2097db96d56Sopenharmony_ci    def items(self):
2107db96d56Sopenharmony_ci        if self._pending_removals:
2117db96d56Sopenharmony_ci            self._commit_removals()
2127db96d56Sopenharmony_ci        with _IterationGuard(self):
2137db96d56Sopenharmony_ci            for k, wr in self.data.items():
2147db96d56Sopenharmony_ci                v = wr()
2157db96d56Sopenharmony_ci                if v is not None:
2167db96d56Sopenharmony_ci                    yield k, v
2177db96d56Sopenharmony_ci
2187db96d56Sopenharmony_ci    def keys(self):
2197db96d56Sopenharmony_ci        if self._pending_removals:
2207db96d56Sopenharmony_ci            self._commit_removals()
2217db96d56Sopenharmony_ci        with _IterationGuard(self):
2227db96d56Sopenharmony_ci            for k, wr in self.data.items():
2237db96d56Sopenharmony_ci                if wr() is not None:
2247db96d56Sopenharmony_ci                    yield k
2257db96d56Sopenharmony_ci
2267db96d56Sopenharmony_ci    __iter__ = keys
2277db96d56Sopenharmony_ci
2287db96d56Sopenharmony_ci    def itervaluerefs(self):
2297db96d56Sopenharmony_ci        """Return an iterator that yields the weak references to the values.
2307db96d56Sopenharmony_ci
2317db96d56Sopenharmony_ci        The references are not guaranteed to be 'live' at the time
2327db96d56Sopenharmony_ci        they are used, so the result of calling the references needs
2337db96d56Sopenharmony_ci        to be checked before being used.  This can be used to avoid
2347db96d56Sopenharmony_ci        creating references that will cause the garbage collector to
2357db96d56Sopenharmony_ci        keep the values around longer than needed.
2367db96d56Sopenharmony_ci
2377db96d56Sopenharmony_ci        """
2387db96d56Sopenharmony_ci        if self._pending_removals:
2397db96d56Sopenharmony_ci            self._commit_removals()
2407db96d56Sopenharmony_ci        with _IterationGuard(self):
2417db96d56Sopenharmony_ci            yield from self.data.values()
2427db96d56Sopenharmony_ci
2437db96d56Sopenharmony_ci    def values(self):
2447db96d56Sopenharmony_ci        if self._pending_removals:
2457db96d56Sopenharmony_ci            self._commit_removals()
2467db96d56Sopenharmony_ci        with _IterationGuard(self):
2477db96d56Sopenharmony_ci            for wr in self.data.values():
2487db96d56Sopenharmony_ci                obj = wr()
2497db96d56Sopenharmony_ci                if obj is not None:
2507db96d56Sopenharmony_ci                    yield obj
2517db96d56Sopenharmony_ci
2527db96d56Sopenharmony_ci    def popitem(self):
2537db96d56Sopenharmony_ci        if self._pending_removals:
2547db96d56Sopenharmony_ci            self._commit_removals()
2557db96d56Sopenharmony_ci        while True:
2567db96d56Sopenharmony_ci            key, wr = self.data.popitem()
2577db96d56Sopenharmony_ci            o = wr()
2587db96d56Sopenharmony_ci            if o is not None:
2597db96d56Sopenharmony_ci                return key, o
2607db96d56Sopenharmony_ci
2617db96d56Sopenharmony_ci    def pop(self, key, *args):
2627db96d56Sopenharmony_ci        if self._pending_removals:
2637db96d56Sopenharmony_ci            self._commit_removals()
2647db96d56Sopenharmony_ci        try:
2657db96d56Sopenharmony_ci            o = self.data.pop(key)()
2667db96d56Sopenharmony_ci        except KeyError:
2677db96d56Sopenharmony_ci            o = None
2687db96d56Sopenharmony_ci        if o is None:
2697db96d56Sopenharmony_ci            if args:
2707db96d56Sopenharmony_ci                return args[0]
2717db96d56Sopenharmony_ci            else:
2727db96d56Sopenharmony_ci                raise KeyError(key)
2737db96d56Sopenharmony_ci        else:
2747db96d56Sopenharmony_ci            return o
2757db96d56Sopenharmony_ci
2767db96d56Sopenharmony_ci    def setdefault(self, key, default=None):
2777db96d56Sopenharmony_ci        try:
2787db96d56Sopenharmony_ci            o = self.data[key]()
2797db96d56Sopenharmony_ci        except KeyError:
2807db96d56Sopenharmony_ci            o = None
2817db96d56Sopenharmony_ci        if o is None:
2827db96d56Sopenharmony_ci            if self._pending_removals:
2837db96d56Sopenharmony_ci                self._commit_removals()
2847db96d56Sopenharmony_ci            self.data[key] = KeyedRef(default, self._remove, key)
2857db96d56Sopenharmony_ci            return default
2867db96d56Sopenharmony_ci        else:
2877db96d56Sopenharmony_ci            return o
2887db96d56Sopenharmony_ci
2897db96d56Sopenharmony_ci    def update(self, other=None, /, **kwargs):
2907db96d56Sopenharmony_ci        if self._pending_removals:
2917db96d56Sopenharmony_ci            self._commit_removals()
2927db96d56Sopenharmony_ci        d = self.data
2937db96d56Sopenharmony_ci        if other is not None:
2947db96d56Sopenharmony_ci            if not hasattr(other, "items"):
2957db96d56Sopenharmony_ci                other = dict(other)
2967db96d56Sopenharmony_ci            for key, o in other.items():
2977db96d56Sopenharmony_ci                d[key] = KeyedRef(o, self._remove, key)
2987db96d56Sopenharmony_ci        for key, o in kwargs.items():
2997db96d56Sopenharmony_ci            d[key] = KeyedRef(o, self._remove, key)
3007db96d56Sopenharmony_ci
3017db96d56Sopenharmony_ci    def valuerefs(self):
3027db96d56Sopenharmony_ci        """Return a list of weak references to the values.
3037db96d56Sopenharmony_ci
3047db96d56Sopenharmony_ci        The references are not guaranteed to be 'live' at the time
3057db96d56Sopenharmony_ci        they are used, so the result of calling the references needs
3067db96d56Sopenharmony_ci        to be checked before being used.  This can be used to avoid
3077db96d56Sopenharmony_ci        creating references that will cause the garbage collector to
3087db96d56Sopenharmony_ci        keep the values around longer than needed.
3097db96d56Sopenharmony_ci
3107db96d56Sopenharmony_ci        """
3117db96d56Sopenharmony_ci        if self._pending_removals:
3127db96d56Sopenharmony_ci            self._commit_removals()
3137db96d56Sopenharmony_ci        return list(self.data.values())
3147db96d56Sopenharmony_ci
3157db96d56Sopenharmony_ci    def __ior__(self, other):
3167db96d56Sopenharmony_ci        self.update(other)
3177db96d56Sopenharmony_ci        return self
3187db96d56Sopenharmony_ci
3197db96d56Sopenharmony_ci    def __or__(self, other):
3207db96d56Sopenharmony_ci        if isinstance(other, _collections_abc.Mapping):
3217db96d56Sopenharmony_ci            c = self.copy()
3227db96d56Sopenharmony_ci            c.update(other)
3237db96d56Sopenharmony_ci            return c
3247db96d56Sopenharmony_ci        return NotImplemented
3257db96d56Sopenharmony_ci
3267db96d56Sopenharmony_ci    def __ror__(self, other):
3277db96d56Sopenharmony_ci        if isinstance(other, _collections_abc.Mapping):
3287db96d56Sopenharmony_ci            c = self.__class__()
3297db96d56Sopenharmony_ci            c.update(other)
3307db96d56Sopenharmony_ci            c.update(self)
3317db96d56Sopenharmony_ci            return c
3327db96d56Sopenharmony_ci        return NotImplemented
3337db96d56Sopenharmony_ci
3347db96d56Sopenharmony_ci
3357db96d56Sopenharmony_ciclass KeyedRef(ref):
3367db96d56Sopenharmony_ci    """Specialized reference that includes a key corresponding to the value.
3377db96d56Sopenharmony_ci
3387db96d56Sopenharmony_ci    This is used in the WeakValueDictionary to avoid having to create
3397db96d56Sopenharmony_ci    a function object for each key stored in the mapping.  A shared
3407db96d56Sopenharmony_ci    callback object can use the 'key' attribute of a KeyedRef instead
3417db96d56Sopenharmony_ci    of getting a reference to the key from an enclosing scope.
3427db96d56Sopenharmony_ci
3437db96d56Sopenharmony_ci    """
3447db96d56Sopenharmony_ci
3457db96d56Sopenharmony_ci    __slots__ = "key",
3467db96d56Sopenharmony_ci
3477db96d56Sopenharmony_ci    def __new__(type, ob, callback, key):
3487db96d56Sopenharmony_ci        self = ref.__new__(type, ob, callback)
3497db96d56Sopenharmony_ci        self.key = key
3507db96d56Sopenharmony_ci        return self
3517db96d56Sopenharmony_ci
3527db96d56Sopenharmony_ci    def __init__(self, ob, callback, key):
3537db96d56Sopenharmony_ci        super().__init__(ob, callback)
3547db96d56Sopenharmony_ci
3557db96d56Sopenharmony_ci
3567db96d56Sopenharmony_ciclass WeakKeyDictionary(_collections_abc.MutableMapping):
3577db96d56Sopenharmony_ci    """ Mapping class that references keys weakly.
3587db96d56Sopenharmony_ci
3597db96d56Sopenharmony_ci    Entries in the dictionary will be discarded when there is no
3607db96d56Sopenharmony_ci    longer a strong reference to the key. This can be used to
3617db96d56Sopenharmony_ci    associate additional data with an object owned by other parts of
3627db96d56Sopenharmony_ci    an application without adding attributes to those objects. This
3637db96d56Sopenharmony_ci    can be especially useful with objects that override attribute
3647db96d56Sopenharmony_ci    accesses.
3657db96d56Sopenharmony_ci    """
3667db96d56Sopenharmony_ci
3677db96d56Sopenharmony_ci    def __init__(self, dict=None):
3687db96d56Sopenharmony_ci        self.data = {}
3697db96d56Sopenharmony_ci        def remove(k, selfref=ref(self)):
3707db96d56Sopenharmony_ci            self = selfref()
3717db96d56Sopenharmony_ci            if self is not None:
3727db96d56Sopenharmony_ci                if self._iterating:
3737db96d56Sopenharmony_ci                    self._pending_removals.append(k)
3747db96d56Sopenharmony_ci                else:
3757db96d56Sopenharmony_ci                    try:
3767db96d56Sopenharmony_ci                        del self.data[k]
3777db96d56Sopenharmony_ci                    except KeyError:
3787db96d56Sopenharmony_ci                        pass
3797db96d56Sopenharmony_ci        self._remove = remove
3807db96d56Sopenharmony_ci        # A list of dead weakrefs (keys to be removed)
3817db96d56Sopenharmony_ci        self._pending_removals = []
3827db96d56Sopenharmony_ci        self._iterating = set()
3837db96d56Sopenharmony_ci        self._dirty_len = False
3847db96d56Sopenharmony_ci        if dict is not None:
3857db96d56Sopenharmony_ci            self.update(dict)
3867db96d56Sopenharmony_ci
3877db96d56Sopenharmony_ci    def _commit_removals(self):
3887db96d56Sopenharmony_ci        # NOTE: We don't need to call this method before mutating the dict,
3897db96d56Sopenharmony_ci        # because a dead weakref never compares equal to a live weakref,
3907db96d56Sopenharmony_ci        # even if they happened to refer to equal objects.
3917db96d56Sopenharmony_ci        # However, it means keys may already have been removed.
3927db96d56Sopenharmony_ci        pop = self._pending_removals.pop
3937db96d56Sopenharmony_ci        d = self.data
3947db96d56Sopenharmony_ci        while True:
3957db96d56Sopenharmony_ci            try:
3967db96d56Sopenharmony_ci                key = pop()
3977db96d56Sopenharmony_ci            except IndexError:
3987db96d56Sopenharmony_ci                return
3997db96d56Sopenharmony_ci
4007db96d56Sopenharmony_ci            try:
4017db96d56Sopenharmony_ci                del d[key]
4027db96d56Sopenharmony_ci            except KeyError:
4037db96d56Sopenharmony_ci                pass
4047db96d56Sopenharmony_ci
4057db96d56Sopenharmony_ci    def _scrub_removals(self):
4067db96d56Sopenharmony_ci        d = self.data
4077db96d56Sopenharmony_ci        self._pending_removals = [k for k in self._pending_removals if k in d]
4087db96d56Sopenharmony_ci        self._dirty_len = False
4097db96d56Sopenharmony_ci
4107db96d56Sopenharmony_ci    def __delitem__(self, key):
4117db96d56Sopenharmony_ci        self._dirty_len = True
4127db96d56Sopenharmony_ci        del self.data[ref(key)]
4137db96d56Sopenharmony_ci
4147db96d56Sopenharmony_ci    def __getitem__(self, key):
4157db96d56Sopenharmony_ci        return self.data[ref(key)]
4167db96d56Sopenharmony_ci
4177db96d56Sopenharmony_ci    def __len__(self):
4187db96d56Sopenharmony_ci        if self._dirty_len and self._pending_removals:
4197db96d56Sopenharmony_ci            # self._pending_removals may still contain keys which were
4207db96d56Sopenharmony_ci            # explicitly removed, we have to scrub them (see issue #21173).
4217db96d56Sopenharmony_ci            self._scrub_removals()
4227db96d56Sopenharmony_ci        return len(self.data) - len(self._pending_removals)
4237db96d56Sopenharmony_ci
4247db96d56Sopenharmony_ci    def __repr__(self):
4257db96d56Sopenharmony_ci        return "<%s at %#x>" % (self.__class__.__name__, id(self))
4267db96d56Sopenharmony_ci
4277db96d56Sopenharmony_ci    def __setitem__(self, key, value):
4287db96d56Sopenharmony_ci        self.data[ref(key, self._remove)] = value
4297db96d56Sopenharmony_ci
4307db96d56Sopenharmony_ci    def copy(self):
4317db96d56Sopenharmony_ci        new = WeakKeyDictionary()
4327db96d56Sopenharmony_ci        with _IterationGuard(self):
4337db96d56Sopenharmony_ci            for key, value in self.data.items():
4347db96d56Sopenharmony_ci                o = key()
4357db96d56Sopenharmony_ci                if o is not None:
4367db96d56Sopenharmony_ci                    new[o] = value
4377db96d56Sopenharmony_ci        return new
4387db96d56Sopenharmony_ci
4397db96d56Sopenharmony_ci    __copy__ = copy
4407db96d56Sopenharmony_ci
4417db96d56Sopenharmony_ci    def __deepcopy__(self, memo):
4427db96d56Sopenharmony_ci        from copy import deepcopy
4437db96d56Sopenharmony_ci        new = self.__class__()
4447db96d56Sopenharmony_ci        with _IterationGuard(self):
4457db96d56Sopenharmony_ci            for key, value in self.data.items():
4467db96d56Sopenharmony_ci                o = key()
4477db96d56Sopenharmony_ci                if o is not None:
4487db96d56Sopenharmony_ci                    new[o] = deepcopy(value, memo)
4497db96d56Sopenharmony_ci        return new
4507db96d56Sopenharmony_ci
4517db96d56Sopenharmony_ci    def get(self, key, default=None):
4527db96d56Sopenharmony_ci        return self.data.get(ref(key),default)
4537db96d56Sopenharmony_ci
4547db96d56Sopenharmony_ci    def __contains__(self, key):
4557db96d56Sopenharmony_ci        try:
4567db96d56Sopenharmony_ci            wr = ref(key)
4577db96d56Sopenharmony_ci        except TypeError:
4587db96d56Sopenharmony_ci            return False
4597db96d56Sopenharmony_ci        return wr in self.data
4607db96d56Sopenharmony_ci
4617db96d56Sopenharmony_ci    def items(self):
4627db96d56Sopenharmony_ci        with _IterationGuard(self):
4637db96d56Sopenharmony_ci            for wr, value in self.data.items():
4647db96d56Sopenharmony_ci                key = wr()
4657db96d56Sopenharmony_ci                if key is not None:
4667db96d56Sopenharmony_ci                    yield key, value
4677db96d56Sopenharmony_ci
4687db96d56Sopenharmony_ci    def keys(self):
4697db96d56Sopenharmony_ci        with _IterationGuard(self):
4707db96d56Sopenharmony_ci            for wr in self.data:
4717db96d56Sopenharmony_ci                obj = wr()
4727db96d56Sopenharmony_ci                if obj is not None:
4737db96d56Sopenharmony_ci                    yield obj
4747db96d56Sopenharmony_ci
4757db96d56Sopenharmony_ci    __iter__ = keys
4767db96d56Sopenharmony_ci
4777db96d56Sopenharmony_ci    def values(self):
4787db96d56Sopenharmony_ci        with _IterationGuard(self):
4797db96d56Sopenharmony_ci            for wr, value in self.data.items():
4807db96d56Sopenharmony_ci                if wr() is not None:
4817db96d56Sopenharmony_ci                    yield value
4827db96d56Sopenharmony_ci
4837db96d56Sopenharmony_ci    def keyrefs(self):
4847db96d56Sopenharmony_ci        """Return a list of weak references to the keys.
4857db96d56Sopenharmony_ci
4867db96d56Sopenharmony_ci        The references are not guaranteed to be 'live' at the time
4877db96d56Sopenharmony_ci        they are used, so the result of calling the references needs
4887db96d56Sopenharmony_ci        to be checked before being used.  This can be used to avoid
4897db96d56Sopenharmony_ci        creating references that will cause the garbage collector to
4907db96d56Sopenharmony_ci        keep the keys around longer than needed.
4917db96d56Sopenharmony_ci
4927db96d56Sopenharmony_ci        """
4937db96d56Sopenharmony_ci        return list(self.data)
4947db96d56Sopenharmony_ci
4957db96d56Sopenharmony_ci    def popitem(self):
4967db96d56Sopenharmony_ci        self._dirty_len = True
4977db96d56Sopenharmony_ci        while True:
4987db96d56Sopenharmony_ci            key, value = self.data.popitem()
4997db96d56Sopenharmony_ci            o = key()
5007db96d56Sopenharmony_ci            if o is not None:
5017db96d56Sopenharmony_ci                return o, value
5027db96d56Sopenharmony_ci
5037db96d56Sopenharmony_ci    def pop(self, key, *args):
5047db96d56Sopenharmony_ci        self._dirty_len = True
5057db96d56Sopenharmony_ci        return self.data.pop(ref(key), *args)
5067db96d56Sopenharmony_ci
5077db96d56Sopenharmony_ci    def setdefault(self, key, default=None):
5087db96d56Sopenharmony_ci        return self.data.setdefault(ref(key, self._remove),default)
5097db96d56Sopenharmony_ci
5107db96d56Sopenharmony_ci    def update(self, dict=None, /, **kwargs):
5117db96d56Sopenharmony_ci        d = self.data
5127db96d56Sopenharmony_ci        if dict is not None:
5137db96d56Sopenharmony_ci            if not hasattr(dict, "items"):
5147db96d56Sopenharmony_ci                dict = type({})(dict)
5157db96d56Sopenharmony_ci            for key, value in dict.items():
5167db96d56Sopenharmony_ci                d[ref(key, self._remove)] = value
5177db96d56Sopenharmony_ci        if len(kwargs):
5187db96d56Sopenharmony_ci            self.update(kwargs)
5197db96d56Sopenharmony_ci
5207db96d56Sopenharmony_ci    def __ior__(self, other):
5217db96d56Sopenharmony_ci        self.update(other)
5227db96d56Sopenharmony_ci        return self
5237db96d56Sopenharmony_ci
5247db96d56Sopenharmony_ci    def __or__(self, other):
5257db96d56Sopenharmony_ci        if isinstance(other, _collections_abc.Mapping):
5267db96d56Sopenharmony_ci            c = self.copy()
5277db96d56Sopenharmony_ci            c.update(other)
5287db96d56Sopenharmony_ci            return c
5297db96d56Sopenharmony_ci        return NotImplemented
5307db96d56Sopenharmony_ci
5317db96d56Sopenharmony_ci    def __ror__(self, other):
5327db96d56Sopenharmony_ci        if isinstance(other, _collections_abc.Mapping):
5337db96d56Sopenharmony_ci            c = self.__class__()
5347db96d56Sopenharmony_ci            c.update(other)
5357db96d56Sopenharmony_ci            c.update(self)
5367db96d56Sopenharmony_ci            return c
5377db96d56Sopenharmony_ci        return NotImplemented
5387db96d56Sopenharmony_ci
5397db96d56Sopenharmony_ci
5407db96d56Sopenharmony_ciclass finalize:
5417db96d56Sopenharmony_ci    """Class for finalization of weakrefable objects
5427db96d56Sopenharmony_ci
5437db96d56Sopenharmony_ci    finalize(obj, func, *args, **kwargs) returns a callable finalizer
5447db96d56Sopenharmony_ci    object which will be called when obj is garbage collected. The
5457db96d56Sopenharmony_ci    first time the finalizer is called it evaluates func(*arg, **kwargs)
5467db96d56Sopenharmony_ci    and returns the result. After this the finalizer is dead, and
5477db96d56Sopenharmony_ci    calling it just returns None.
5487db96d56Sopenharmony_ci
5497db96d56Sopenharmony_ci    When the program exits any remaining finalizers for which the
5507db96d56Sopenharmony_ci    atexit attribute is true will be run in reverse order of creation.
5517db96d56Sopenharmony_ci    By default atexit is true.
5527db96d56Sopenharmony_ci    """
5537db96d56Sopenharmony_ci
5547db96d56Sopenharmony_ci    # Finalizer objects don't have any state of their own.  They are
5557db96d56Sopenharmony_ci    # just used as keys to lookup _Info objects in the registry.  This
5567db96d56Sopenharmony_ci    # ensures that they cannot be part of a ref-cycle.
5577db96d56Sopenharmony_ci
5587db96d56Sopenharmony_ci    __slots__ = ()
5597db96d56Sopenharmony_ci    _registry = {}
5607db96d56Sopenharmony_ci    _shutdown = False
5617db96d56Sopenharmony_ci    _index_iter = itertools.count()
5627db96d56Sopenharmony_ci    _dirty = False
5637db96d56Sopenharmony_ci    _registered_with_atexit = False
5647db96d56Sopenharmony_ci
5657db96d56Sopenharmony_ci    class _Info:
5667db96d56Sopenharmony_ci        __slots__ = ("weakref", "func", "args", "kwargs", "atexit", "index")
5677db96d56Sopenharmony_ci
5687db96d56Sopenharmony_ci    def __init__(self, obj, func, /, *args, **kwargs):
5697db96d56Sopenharmony_ci        if not self._registered_with_atexit:
5707db96d56Sopenharmony_ci            # We may register the exit function more than once because
5717db96d56Sopenharmony_ci            # of a thread race, but that is harmless
5727db96d56Sopenharmony_ci            import atexit
5737db96d56Sopenharmony_ci            atexit.register(self._exitfunc)
5747db96d56Sopenharmony_ci            finalize._registered_with_atexit = True
5757db96d56Sopenharmony_ci        info = self._Info()
5767db96d56Sopenharmony_ci        info.weakref = ref(obj, self)
5777db96d56Sopenharmony_ci        info.func = func
5787db96d56Sopenharmony_ci        info.args = args
5797db96d56Sopenharmony_ci        info.kwargs = kwargs or None
5807db96d56Sopenharmony_ci        info.atexit = True
5817db96d56Sopenharmony_ci        info.index = next(self._index_iter)
5827db96d56Sopenharmony_ci        self._registry[self] = info
5837db96d56Sopenharmony_ci        finalize._dirty = True
5847db96d56Sopenharmony_ci
5857db96d56Sopenharmony_ci    def __call__(self, _=None):
5867db96d56Sopenharmony_ci        """If alive then mark as dead and return func(*args, **kwargs);
5877db96d56Sopenharmony_ci        otherwise return None"""
5887db96d56Sopenharmony_ci        info = self._registry.pop(self, None)
5897db96d56Sopenharmony_ci        if info and not self._shutdown:
5907db96d56Sopenharmony_ci            return info.func(*info.args, **(info.kwargs or {}))
5917db96d56Sopenharmony_ci
5927db96d56Sopenharmony_ci    def detach(self):
5937db96d56Sopenharmony_ci        """If alive then mark as dead and return (obj, func, args, kwargs);
5947db96d56Sopenharmony_ci        otherwise return None"""
5957db96d56Sopenharmony_ci        info = self._registry.get(self)
5967db96d56Sopenharmony_ci        obj = info and info.weakref()
5977db96d56Sopenharmony_ci        if obj is not None and self._registry.pop(self, None):
5987db96d56Sopenharmony_ci            return (obj, info.func, info.args, info.kwargs or {})
5997db96d56Sopenharmony_ci
6007db96d56Sopenharmony_ci    def peek(self):
6017db96d56Sopenharmony_ci        """If alive then return (obj, func, args, kwargs);
6027db96d56Sopenharmony_ci        otherwise return None"""
6037db96d56Sopenharmony_ci        info = self._registry.get(self)
6047db96d56Sopenharmony_ci        obj = info and info.weakref()
6057db96d56Sopenharmony_ci        if obj is not None:
6067db96d56Sopenharmony_ci            return (obj, info.func, info.args, info.kwargs or {})
6077db96d56Sopenharmony_ci
6087db96d56Sopenharmony_ci    @property
6097db96d56Sopenharmony_ci    def alive(self):
6107db96d56Sopenharmony_ci        """Whether finalizer is alive"""
6117db96d56Sopenharmony_ci        return self in self._registry
6127db96d56Sopenharmony_ci
6137db96d56Sopenharmony_ci    @property
6147db96d56Sopenharmony_ci    def atexit(self):
6157db96d56Sopenharmony_ci        """Whether finalizer should be called at exit"""
6167db96d56Sopenharmony_ci        info = self._registry.get(self)
6177db96d56Sopenharmony_ci        return bool(info) and info.atexit
6187db96d56Sopenharmony_ci
6197db96d56Sopenharmony_ci    @atexit.setter
6207db96d56Sopenharmony_ci    def atexit(self, value):
6217db96d56Sopenharmony_ci        info = self._registry.get(self)
6227db96d56Sopenharmony_ci        if info:
6237db96d56Sopenharmony_ci            info.atexit = bool(value)
6247db96d56Sopenharmony_ci
6257db96d56Sopenharmony_ci    def __repr__(self):
6267db96d56Sopenharmony_ci        info = self._registry.get(self)
6277db96d56Sopenharmony_ci        obj = info and info.weakref()
6287db96d56Sopenharmony_ci        if obj is None:
6297db96d56Sopenharmony_ci            return '<%s object at %#x; dead>' % (type(self).__name__, id(self))
6307db96d56Sopenharmony_ci        else:
6317db96d56Sopenharmony_ci            return '<%s object at %#x; for %r at %#x>' % \
6327db96d56Sopenharmony_ci                (type(self).__name__, id(self), type(obj).__name__, id(obj))
6337db96d56Sopenharmony_ci
6347db96d56Sopenharmony_ci    @classmethod
6357db96d56Sopenharmony_ci    def _select_for_exit(cls):
6367db96d56Sopenharmony_ci        # Return live finalizers marked for exit, oldest first
6377db96d56Sopenharmony_ci        L = [(f,i) for (f,i) in cls._registry.items() if i.atexit]
6387db96d56Sopenharmony_ci        L.sort(key=lambda item:item[1].index)
6397db96d56Sopenharmony_ci        return [f for (f,i) in L]
6407db96d56Sopenharmony_ci
6417db96d56Sopenharmony_ci    @classmethod
6427db96d56Sopenharmony_ci    def _exitfunc(cls):
6437db96d56Sopenharmony_ci        # At shutdown invoke finalizers for which atexit is true.
6447db96d56Sopenharmony_ci        # This is called once all other non-daemonic threads have been
6457db96d56Sopenharmony_ci        # joined.
6467db96d56Sopenharmony_ci        reenable_gc = False
6477db96d56Sopenharmony_ci        try:
6487db96d56Sopenharmony_ci            if cls._registry:
6497db96d56Sopenharmony_ci                import gc
6507db96d56Sopenharmony_ci                if gc.isenabled():
6517db96d56Sopenharmony_ci                    reenable_gc = True
6527db96d56Sopenharmony_ci                    gc.disable()
6537db96d56Sopenharmony_ci                pending = None
6547db96d56Sopenharmony_ci                while True:
6557db96d56Sopenharmony_ci                    if pending is None or finalize._dirty:
6567db96d56Sopenharmony_ci                        pending = cls._select_for_exit()
6577db96d56Sopenharmony_ci                        finalize._dirty = False
6587db96d56Sopenharmony_ci                    if not pending:
6597db96d56Sopenharmony_ci                        break
6607db96d56Sopenharmony_ci                    f = pending.pop()
6617db96d56Sopenharmony_ci                    try:
6627db96d56Sopenharmony_ci                        # gc is disabled, so (assuming no daemonic
6637db96d56Sopenharmony_ci                        # threads) the following is the only line in
6647db96d56Sopenharmony_ci                        # this function which might trigger creation
6657db96d56Sopenharmony_ci                        # of a new finalizer
6667db96d56Sopenharmony_ci                        f()
6677db96d56Sopenharmony_ci                    except Exception:
6687db96d56Sopenharmony_ci                        sys.excepthook(*sys.exc_info())
6697db96d56Sopenharmony_ci                    assert f not in cls._registry
6707db96d56Sopenharmony_ci        finally:
6717db96d56Sopenharmony_ci            # prevent any more finalizers from executing during shutdown
6727db96d56Sopenharmony_ci            finalize._shutdown = True
6737db96d56Sopenharmony_ci            if reenable_gc:
6747db96d56Sopenharmony_ci                gc.enable()
675