xref: /aosp_15_r20/prebuilts/build-tools/common/py3-stdlib/weakref.py (revision cda5da8d549138a6648c5ee6d7a49cf8f4a657be)
1*cda5da8dSAndroid Build Coastguard Worker"""Weak reference support for Python.
2*cda5da8dSAndroid Build Coastguard Worker
3*cda5da8dSAndroid Build Coastguard WorkerThis module is an implementation of PEP 205:
4*cda5da8dSAndroid Build Coastguard Worker
5*cda5da8dSAndroid Build Coastguard Workerhttps://peps.python.org/pep-0205/
6*cda5da8dSAndroid Build Coastguard Worker"""
7*cda5da8dSAndroid Build Coastguard Worker
8*cda5da8dSAndroid Build Coastguard Worker# Naming convention: Variables named "wr" are weak reference objects;
9*cda5da8dSAndroid Build Coastguard Worker# they are called this instead of "ref" to avoid name collisions with
10*cda5da8dSAndroid Build Coastguard Worker# the module-global ref() function imported from _weakref.
11*cda5da8dSAndroid Build Coastguard Worker
12*cda5da8dSAndroid Build Coastguard Workerfrom _weakref import (
13*cda5da8dSAndroid Build Coastguard Worker     getweakrefcount,
14*cda5da8dSAndroid Build Coastguard Worker     getweakrefs,
15*cda5da8dSAndroid Build Coastguard Worker     ref,
16*cda5da8dSAndroid Build Coastguard Worker     proxy,
17*cda5da8dSAndroid Build Coastguard Worker     CallableProxyType,
18*cda5da8dSAndroid Build Coastguard Worker     ProxyType,
19*cda5da8dSAndroid Build Coastguard Worker     ReferenceType,
20*cda5da8dSAndroid Build Coastguard Worker     _remove_dead_weakref)
21*cda5da8dSAndroid Build Coastguard Worker
22*cda5da8dSAndroid Build Coastguard Workerfrom _weakrefset import WeakSet, _IterationGuard
23*cda5da8dSAndroid Build Coastguard Worker
24*cda5da8dSAndroid Build Coastguard Workerimport _collections_abc  # Import after _weakref to avoid circular import.
25*cda5da8dSAndroid Build Coastguard Workerimport sys
26*cda5da8dSAndroid Build Coastguard Workerimport itertools
27*cda5da8dSAndroid Build Coastguard Worker
28*cda5da8dSAndroid Build Coastguard WorkerProxyTypes = (ProxyType, CallableProxyType)
29*cda5da8dSAndroid Build Coastguard Worker
30*cda5da8dSAndroid Build Coastguard Worker__all__ = ["ref", "proxy", "getweakrefcount", "getweakrefs",
31*cda5da8dSAndroid Build Coastguard Worker           "WeakKeyDictionary", "ReferenceType", "ProxyType",
32*cda5da8dSAndroid Build Coastguard Worker           "CallableProxyType", "ProxyTypes", "WeakValueDictionary",
33*cda5da8dSAndroid Build Coastguard Worker           "WeakSet", "WeakMethod", "finalize"]
34*cda5da8dSAndroid Build Coastguard Worker
35*cda5da8dSAndroid Build Coastguard Worker
36*cda5da8dSAndroid Build Coastguard Worker_collections_abc.MutableSet.register(WeakSet)
37*cda5da8dSAndroid Build Coastguard Worker
38*cda5da8dSAndroid Build Coastguard Workerclass WeakMethod(ref):
39*cda5da8dSAndroid Build Coastguard Worker    """
40*cda5da8dSAndroid Build Coastguard Worker    A custom `weakref.ref` subclass which simulates a weak reference to
41*cda5da8dSAndroid Build Coastguard Worker    a bound method, working around the lifetime problem of bound methods.
42*cda5da8dSAndroid Build Coastguard Worker    """
43*cda5da8dSAndroid Build Coastguard Worker
44*cda5da8dSAndroid Build Coastguard Worker    __slots__ = "_func_ref", "_meth_type", "_alive", "__weakref__"
45*cda5da8dSAndroid Build Coastguard Worker
46*cda5da8dSAndroid Build Coastguard Worker    def __new__(cls, meth, callback=None):
47*cda5da8dSAndroid Build Coastguard Worker        try:
48*cda5da8dSAndroid Build Coastguard Worker            obj = meth.__self__
49*cda5da8dSAndroid Build Coastguard Worker            func = meth.__func__
50*cda5da8dSAndroid Build Coastguard Worker        except AttributeError:
51*cda5da8dSAndroid Build Coastguard Worker            raise TypeError("argument should be a bound method, not {}"
52*cda5da8dSAndroid Build Coastguard Worker                            .format(type(meth))) from None
53*cda5da8dSAndroid Build Coastguard Worker        def _cb(arg):
54*cda5da8dSAndroid Build Coastguard Worker            # The self-weakref trick is needed to avoid creating a reference
55*cda5da8dSAndroid Build Coastguard Worker            # cycle.
56*cda5da8dSAndroid Build Coastguard Worker            self = self_wr()
57*cda5da8dSAndroid Build Coastguard Worker            if self._alive:
58*cda5da8dSAndroid Build Coastguard Worker                self._alive = False
59*cda5da8dSAndroid Build Coastguard Worker                if callback is not None:
60*cda5da8dSAndroid Build Coastguard Worker                    callback(self)
61*cda5da8dSAndroid Build Coastguard Worker        self = ref.__new__(cls, obj, _cb)
62*cda5da8dSAndroid Build Coastguard Worker        self._func_ref = ref(func, _cb)
63*cda5da8dSAndroid Build Coastguard Worker        self._meth_type = type(meth)
64*cda5da8dSAndroid Build Coastguard Worker        self._alive = True
65*cda5da8dSAndroid Build Coastguard Worker        self_wr = ref(self)
66*cda5da8dSAndroid Build Coastguard Worker        return self
67*cda5da8dSAndroid Build Coastguard Worker
68*cda5da8dSAndroid Build Coastguard Worker    def __call__(self):
69*cda5da8dSAndroid Build Coastguard Worker        obj = super().__call__()
70*cda5da8dSAndroid Build Coastguard Worker        func = self._func_ref()
71*cda5da8dSAndroid Build Coastguard Worker        if obj is None or func is None:
72*cda5da8dSAndroid Build Coastguard Worker            return None
73*cda5da8dSAndroid Build Coastguard Worker        return self._meth_type(func, obj)
74*cda5da8dSAndroid Build Coastguard Worker
75*cda5da8dSAndroid Build Coastguard Worker    def __eq__(self, other):
76*cda5da8dSAndroid Build Coastguard Worker        if isinstance(other, WeakMethod):
77*cda5da8dSAndroid Build Coastguard Worker            if not self._alive or not other._alive:
78*cda5da8dSAndroid Build Coastguard Worker                return self is other
79*cda5da8dSAndroid Build Coastguard Worker            return ref.__eq__(self, other) and self._func_ref == other._func_ref
80*cda5da8dSAndroid Build Coastguard Worker        return NotImplemented
81*cda5da8dSAndroid Build Coastguard Worker
82*cda5da8dSAndroid Build Coastguard Worker    def __ne__(self, other):
83*cda5da8dSAndroid Build Coastguard Worker        if isinstance(other, WeakMethod):
84*cda5da8dSAndroid Build Coastguard Worker            if not self._alive or not other._alive:
85*cda5da8dSAndroid Build Coastguard Worker                return self is not other
86*cda5da8dSAndroid Build Coastguard Worker            return ref.__ne__(self, other) or self._func_ref != other._func_ref
87*cda5da8dSAndroid Build Coastguard Worker        return NotImplemented
88*cda5da8dSAndroid Build Coastguard Worker
89*cda5da8dSAndroid Build Coastguard Worker    __hash__ = ref.__hash__
90*cda5da8dSAndroid Build Coastguard Worker
91*cda5da8dSAndroid Build Coastguard Worker
92*cda5da8dSAndroid Build Coastguard Workerclass WeakValueDictionary(_collections_abc.MutableMapping):
93*cda5da8dSAndroid Build Coastguard Worker    """Mapping class that references values weakly.
94*cda5da8dSAndroid Build Coastguard Worker
95*cda5da8dSAndroid Build Coastguard Worker    Entries in the dictionary will be discarded when no strong
96*cda5da8dSAndroid Build Coastguard Worker    reference to the value exists anymore
97*cda5da8dSAndroid Build Coastguard Worker    """
98*cda5da8dSAndroid Build Coastguard Worker    # We inherit the constructor without worrying about the input
99*cda5da8dSAndroid Build Coastguard Worker    # dictionary; since it uses our .update() method, we get the right
100*cda5da8dSAndroid Build Coastguard Worker    # checks (if the other dictionary is a WeakValueDictionary,
101*cda5da8dSAndroid Build Coastguard Worker    # objects are unwrapped on the way out, and we always wrap on the
102*cda5da8dSAndroid Build Coastguard Worker    # way in).
103*cda5da8dSAndroid Build Coastguard Worker
104*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, other=(), /, **kw):
105*cda5da8dSAndroid Build Coastguard Worker        def remove(wr, selfref=ref(self), _atomic_removal=_remove_dead_weakref):
106*cda5da8dSAndroid Build Coastguard Worker            self = selfref()
107*cda5da8dSAndroid Build Coastguard Worker            if self is not None:
108*cda5da8dSAndroid Build Coastguard Worker                if self._iterating:
109*cda5da8dSAndroid Build Coastguard Worker                    self._pending_removals.append(wr.key)
110*cda5da8dSAndroid Build Coastguard Worker                else:
111*cda5da8dSAndroid Build Coastguard Worker                    # Atomic removal is necessary since this function
112*cda5da8dSAndroid Build Coastguard Worker                    # can be called asynchronously by the GC
113*cda5da8dSAndroid Build Coastguard Worker                    _atomic_removal(self.data, wr.key)
114*cda5da8dSAndroid Build Coastguard Worker        self._remove = remove
115*cda5da8dSAndroid Build Coastguard Worker        # A list of keys to be removed
116*cda5da8dSAndroid Build Coastguard Worker        self._pending_removals = []
117*cda5da8dSAndroid Build Coastguard Worker        self._iterating = set()
118*cda5da8dSAndroid Build Coastguard Worker        self.data = {}
119*cda5da8dSAndroid Build Coastguard Worker        self.update(other, **kw)
120*cda5da8dSAndroid Build Coastguard Worker
121*cda5da8dSAndroid Build Coastguard Worker    def _commit_removals(self, _atomic_removal=_remove_dead_weakref):
122*cda5da8dSAndroid Build Coastguard Worker        pop = self._pending_removals.pop
123*cda5da8dSAndroid Build Coastguard Worker        d = self.data
124*cda5da8dSAndroid Build Coastguard Worker        # We shouldn't encounter any KeyError, because this method should
125*cda5da8dSAndroid Build Coastguard Worker        # always be called *before* mutating the dict.
126*cda5da8dSAndroid Build Coastguard Worker        while True:
127*cda5da8dSAndroid Build Coastguard Worker            try:
128*cda5da8dSAndroid Build Coastguard Worker                key = pop()
129*cda5da8dSAndroid Build Coastguard Worker            except IndexError:
130*cda5da8dSAndroid Build Coastguard Worker                return
131*cda5da8dSAndroid Build Coastguard Worker            _atomic_removal(d, key)
132*cda5da8dSAndroid Build Coastguard Worker
133*cda5da8dSAndroid Build Coastguard Worker    def __getitem__(self, key):
134*cda5da8dSAndroid Build Coastguard Worker        if self._pending_removals:
135*cda5da8dSAndroid Build Coastguard Worker            self._commit_removals()
136*cda5da8dSAndroid Build Coastguard Worker        o = self.data[key]()
137*cda5da8dSAndroid Build Coastguard Worker        if o is None:
138*cda5da8dSAndroid Build Coastguard Worker            raise KeyError(key)
139*cda5da8dSAndroid Build Coastguard Worker        else:
140*cda5da8dSAndroid Build Coastguard Worker            return o
141*cda5da8dSAndroid Build Coastguard Worker
142*cda5da8dSAndroid Build Coastguard Worker    def __delitem__(self, key):
143*cda5da8dSAndroid Build Coastguard Worker        if self._pending_removals:
144*cda5da8dSAndroid Build Coastguard Worker            self._commit_removals()
145*cda5da8dSAndroid Build Coastguard Worker        del self.data[key]
146*cda5da8dSAndroid Build Coastguard Worker
147*cda5da8dSAndroid Build Coastguard Worker    def __len__(self):
148*cda5da8dSAndroid Build Coastguard Worker        if self._pending_removals:
149*cda5da8dSAndroid Build Coastguard Worker            self._commit_removals()
150*cda5da8dSAndroid Build Coastguard Worker        return len(self.data)
151*cda5da8dSAndroid Build Coastguard Worker
152*cda5da8dSAndroid Build Coastguard Worker    def __contains__(self, key):
153*cda5da8dSAndroid Build Coastguard Worker        if self._pending_removals:
154*cda5da8dSAndroid Build Coastguard Worker            self._commit_removals()
155*cda5da8dSAndroid Build Coastguard Worker        try:
156*cda5da8dSAndroid Build Coastguard Worker            o = self.data[key]()
157*cda5da8dSAndroid Build Coastguard Worker        except KeyError:
158*cda5da8dSAndroid Build Coastguard Worker            return False
159*cda5da8dSAndroid Build Coastguard Worker        return o is not None
160*cda5da8dSAndroid Build Coastguard Worker
161*cda5da8dSAndroid Build Coastguard Worker    def __repr__(self):
162*cda5da8dSAndroid Build Coastguard Worker        return "<%s at %#x>" % (self.__class__.__name__, id(self))
163*cda5da8dSAndroid Build Coastguard Worker
164*cda5da8dSAndroid Build Coastguard Worker    def __setitem__(self, key, value):
165*cda5da8dSAndroid Build Coastguard Worker        if self._pending_removals:
166*cda5da8dSAndroid Build Coastguard Worker            self._commit_removals()
167*cda5da8dSAndroid Build Coastguard Worker        self.data[key] = KeyedRef(value, self._remove, key)
168*cda5da8dSAndroid Build Coastguard Worker
169*cda5da8dSAndroid Build Coastguard Worker    def copy(self):
170*cda5da8dSAndroid Build Coastguard Worker        if self._pending_removals:
171*cda5da8dSAndroid Build Coastguard Worker            self._commit_removals()
172*cda5da8dSAndroid Build Coastguard Worker        new = WeakValueDictionary()
173*cda5da8dSAndroid Build Coastguard Worker        with _IterationGuard(self):
174*cda5da8dSAndroid Build Coastguard Worker            for key, wr in self.data.items():
175*cda5da8dSAndroid Build Coastguard Worker                o = wr()
176*cda5da8dSAndroid Build Coastguard Worker                if o is not None:
177*cda5da8dSAndroid Build Coastguard Worker                    new[key] = o
178*cda5da8dSAndroid Build Coastguard Worker        return new
179*cda5da8dSAndroid Build Coastguard Worker
180*cda5da8dSAndroid Build Coastguard Worker    __copy__ = copy
181*cda5da8dSAndroid Build Coastguard Worker
182*cda5da8dSAndroid Build Coastguard Worker    def __deepcopy__(self, memo):
183*cda5da8dSAndroid Build Coastguard Worker        from copy import deepcopy
184*cda5da8dSAndroid Build Coastguard Worker        if self._pending_removals:
185*cda5da8dSAndroid Build Coastguard Worker            self._commit_removals()
186*cda5da8dSAndroid Build Coastguard Worker        new = self.__class__()
187*cda5da8dSAndroid Build Coastguard Worker        with _IterationGuard(self):
188*cda5da8dSAndroid Build Coastguard Worker            for key, wr in self.data.items():
189*cda5da8dSAndroid Build Coastguard Worker                o = wr()
190*cda5da8dSAndroid Build Coastguard Worker                if o is not None:
191*cda5da8dSAndroid Build Coastguard Worker                    new[deepcopy(key, memo)] = o
192*cda5da8dSAndroid Build Coastguard Worker        return new
193*cda5da8dSAndroid Build Coastguard Worker
194*cda5da8dSAndroid Build Coastguard Worker    def get(self, key, default=None):
195*cda5da8dSAndroid Build Coastguard Worker        if self._pending_removals:
196*cda5da8dSAndroid Build Coastguard Worker            self._commit_removals()
197*cda5da8dSAndroid Build Coastguard Worker        try:
198*cda5da8dSAndroid Build Coastguard Worker            wr = self.data[key]
199*cda5da8dSAndroid Build Coastguard Worker        except KeyError:
200*cda5da8dSAndroid Build Coastguard Worker            return default
201*cda5da8dSAndroid Build Coastguard Worker        else:
202*cda5da8dSAndroid Build Coastguard Worker            o = wr()
203*cda5da8dSAndroid Build Coastguard Worker            if o is None:
204*cda5da8dSAndroid Build Coastguard Worker                # This should only happen
205*cda5da8dSAndroid Build Coastguard Worker                return default
206*cda5da8dSAndroid Build Coastguard Worker            else:
207*cda5da8dSAndroid Build Coastguard Worker                return o
208*cda5da8dSAndroid Build Coastguard Worker
209*cda5da8dSAndroid Build Coastguard Worker    def items(self):
210*cda5da8dSAndroid Build Coastguard Worker        if self._pending_removals:
211*cda5da8dSAndroid Build Coastguard Worker            self._commit_removals()
212*cda5da8dSAndroid Build Coastguard Worker        with _IterationGuard(self):
213*cda5da8dSAndroid Build Coastguard Worker            for k, wr in self.data.items():
214*cda5da8dSAndroid Build Coastguard Worker                v = wr()
215*cda5da8dSAndroid Build Coastguard Worker                if v is not None:
216*cda5da8dSAndroid Build Coastguard Worker                    yield k, v
217*cda5da8dSAndroid Build Coastguard Worker
218*cda5da8dSAndroid Build Coastguard Worker    def keys(self):
219*cda5da8dSAndroid Build Coastguard Worker        if self._pending_removals:
220*cda5da8dSAndroid Build Coastguard Worker            self._commit_removals()
221*cda5da8dSAndroid Build Coastguard Worker        with _IterationGuard(self):
222*cda5da8dSAndroid Build Coastguard Worker            for k, wr in self.data.items():
223*cda5da8dSAndroid Build Coastguard Worker                if wr() is not None:
224*cda5da8dSAndroid Build Coastguard Worker                    yield k
225*cda5da8dSAndroid Build Coastguard Worker
226*cda5da8dSAndroid Build Coastguard Worker    __iter__ = keys
227*cda5da8dSAndroid Build Coastguard Worker
228*cda5da8dSAndroid Build Coastguard Worker    def itervaluerefs(self):
229*cda5da8dSAndroid Build Coastguard Worker        """Return an iterator that yields the weak references to the values.
230*cda5da8dSAndroid Build Coastguard Worker
231*cda5da8dSAndroid Build Coastguard Worker        The references are not guaranteed to be 'live' at the time
232*cda5da8dSAndroid Build Coastguard Worker        they are used, so the result of calling the references needs
233*cda5da8dSAndroid Build Coastguard Worker        to be checked before being used.  This can be used to avoid
234*cda5da8dSAndroid Build Coastguard Worker        creating references that will cause the garbage collector to
235*cda5da8dSAndroid Build Coastguard Worker        keep the values around longer than needed.
236*cda5da8dSAndroid Build Coastguard Worker
237*cda5da8dSAndroid Build Coastguard Worker        """
238*cda5da8dSAndroid Build Coastguard Worker        if self._pending_removals:
239*cda5da8dSAndroid Build Coastguard Worker            self._commit_removals()
240*cda5da8dSAndroid Build Coastguard Worker        with _IterationGuard(self):
241*cda5da8dSAndroid Build Coastguard Worker            yield from self.data.values()
242*cda5da8dSAndroid Build Coastguard Worker
243*cda5da8dSAndroid Build Coastguard Worker    def values(self):
244*cda5da8dSAndroid Build Coastguard Worker        if self._pending_removals:
245*cda5da8dSAndroid Build Coastguard Worker            self._commit_removals()
246*cda5da8dSAndroid Build Coastguard Worker        with _IterationGuard(self):
247*cda5da8dSAndroid Build Coastguard Worker            for wr in self.data.values():
248*cda5da8dSAndroid Build Coastguard Worker                obj = wr()
249*cda5da8dSAndroid Build Coastguard Worker                if obj is not None:
250*cda5da8dSAndroid Build Coastguard Worker                    yield obj
251*cda5da8dSAndroid Build Coastguard Worker
252*cda5da8dSAndroid Build Coastguard Worker    def popitem(self):
253*cda5da8dSAndroid Build Coastguard Worker        if self._pending_removals:
254*cda5da8dSAndroid Build Coastguard Worker            self._commit_removals()
255*cda5da8dSAndroid Build Coastguard Worker        while True:
256*cda5da8dSAndroid Build Coastguard Worker            key, wr = self.data.popitem()
257*cda5da8dSAndroid Build Coastguard Worker            o = wr()
258*cda5da8dSAndroid Build Coastguard Worker            if o is not None:
259*cda5da8dSAndroid Build Coastguard Worker                return key, o
260*cda5da8dSAndroid Build Coastguard Worker
261*cda5da8dSAndroid Build Coastguard Worker    def pop(self, key, *args):
262*cda5da8dSAndroid Build Coastguard Worker        if self._pending_removals:
263*cda5da8dSAndroid Build Coastguard Worker            self._commit_removals()
264*cda5da8dSAndroid Build Coastguard Worker        try:
265*cda5da8dSAndroid Build Coastguard Worker            o = self.data.pop(key)()
266*cda5da8dSAndroid Build Coastguard Worker        except KeyError:
267*cda5da8dSAndroid Build Coastguard Worker            o = None
268*cda5da8dSAndroid Build Coastguard Worker        if o is None:
269*cda5da8dSAndroid Build Coastguard Worker            if args:
270*cda5da8dSAndroid Build Coastguard Worker                return args[0]
271*cda5da8dSAndroid Build Coastguard Worker            else:
272*cda5da8dSAndroid Build Coastguard Worker                raise KeyError(key)
273*cda5da8dSAndroid Build Coastguard Worker        else:
274*cda5da8dSAndroid Build Coastguard Worker            return o
275*cda5da8dSAndroid Build Coastguard Worker
276*cda5da8dSAndroid Build Coastguard Worker    def setdefault(self, key, default=None):
277*cda5da8dSAndroid Build Coastguard Worker        try:
278*cda5da8dSAndroid Build Coastguard Worker            o = self.data[key]()
279*cda5da8dSAndroid Build Coastguard Worker        except KeyError:
280*cda5da8dSAndroid Build Coastguard Worker            o = None
281*cda5da8dSAndroid Build Coastguard Worker        if o is None:
282*cda5da8dSAndroid Build Coastguard Worker            if self._pending_removals:
283*cda5da8dSAndroid Build Coastguard Worker                self._commit_removals()
284*cda5da8dSAndroid Build Coastguard Worker            self.data[key] = KeyedRef(default, self._remove, key)
285*cda5da8dSAndroid Build Coastguard Worker            return default
286*cda5da8dSAndroid Build Coastguard Worker        else:
287*cda5da8dSAndroid Build Coastguard Worker            return o
288*cda5da8dSAndroid Build Coastguard Worker
289*cda5da8dSAndroid Build Coastguard Worker    def update(self, other=None, /, **kwargs):
290*cda5da8dSAndroid Build Coastguard Worker        if self._pending_removals:
291*cda5da8dSAndroid Build Coastguard Worker            self._commit_removals()
292*cda5da8dSAndroid Build Coastguard Worker        d = self.data
293*cda5da8dSAndroid Build Coastguard Worker        if other is not None:
294*cda5da8dSAndroid Build Coastguard Worker            if not hasattr(other, "items"):
295*cda5da8dSAndroid Build Coastguard Worker                other = dict(other)
296*cda5da8dSAndroid Build Coastguard Worker            for key, o in other.items():
297*cda5da8dSAndroid Build Coastguard Worker                d[key] = KeyedRef(o, self._remove, key)
298*cda5da8dSAndroid Build Coastguard Worker        for key, o in kwargs.items():
299*cda5da8dSAndroid Build Coastguard Worker            d[key] = KeyedRef(o, self._remove, key)
300*cda5da8dSAndroid Build Coastguard Worker
301*cda5da8dSAndroid Build Coastguard Worker    def valuerefs(self):
302*cda5da8dSAndroid Build Coastguard Worker        """Return a list of weak references to the values.
303*cda5da8dSAndroid Build Coastguard Worker
304*cda5da8dSAndroid Build Coastguard Worker        The references are not guaranteed to be 'live' at the time
305*cda5da8dSAndroid Build Coastguard Worker        they are used, so the result of calling the references needs
306*cda5da8dSAndroid Build Coastguard Worker        to be checked before being used.  This can be used to avoid
307*cda5da8dSAndroid Build Coastguard Worker        creating references that will cause the garbage collector to
308*cda5da8dSAndroid Build Coastguard Worker        keep the values around longer than needed.
309*cda5da8dSAndroid Build Coastguard Worker
310*cda5da8dSAndroid Build Coastguard Worker        """
311*cda5da8dSAndroid Build Coastguard Worker        if self._pending_removals:
312*cda5da8dSAndroid Build Coastguard Worker            self._commit_removals()
313*cda5da8dSAndroid Build Coastguard Worker        return list(self.data.values())
314*cda5da8dSAndroid Build Coastguard Worker
315*cda5da8dSAndroid Build Coastguard Worker    def __ior__(self, other):
316*cda5da8dSAndroid Build Coastguard Worker        self.update(other)
317*cda5da8dSAndroid Build Coastguard Worker        return self
318*cda5da8dSAndroid Build Coastguard Worker
319*cda5da8dSAndroid Build Coastguard Worker    def __or__(self, other):
320*cda5da8dSAndroid Build Coastguard Worker        if isinstance(other, _collections_abc.Mapping):
321*cda5da8dSAndroid Build Coastguard Worker            c = self.copy()
322*cda5da8dSAndroid Build Coastguard Worker            c.update(other)
323*cda5da8dSAndroid Build Coastguard Worker            return c
324*cda5da8dSAndroid Build Coastguard Worker        return NotImplemented
325*cda5da8dSAndroid Build Coastguard Worker
326*cda5da8dSAndroid Build Coastguard Worker    def __ror__(self, other):
327*cda5da8dSAndroid Build Coastguard Worker        if isinstance(other, _collections_abc.Mapping):
328*cda5da8dSAndroid Build Coastguard Worker            c = self.__class__()
329*cda5da8dSAndroid Build Coastguard Worker            c.update(other)
330*cda5da8dSAndroid Build Coastguard Worker            c.update(self)
331*cda5da8dSAndroid Build Coastguard Worker            return c
332*cda5da8dSAndroid Build Coastguard Worker        return NotImplemented
333*cda5da8dSAndroid Build Coastguard Worker
334*cda5da8dSAndroid Build Coastguard Worker
335*cda5da8dSAndroid Build Coastguard Workerclass KeyedRef(ref):
336*cda5da8dSAndroid Build Coastguard Worker    """Specialized reference that includes a key corresponding to the value.
337*cda5da8dSAndroid Build Coastguard Worker
338*cda5da8dSAndroid Build Coastguard Worker    This is used in the WeakValueDictionary to avoid having to create
339*cda5da8dSAndroid Build Coastguard Worker    a function object for each key stored in the mapping.  A shared
340*cda5da8dSAndroid Build Coastguard Worker    callback object can use the 'key' attribute of a KeyedRef instead
341*cda5da8dSAndroid Build Coastguard Worker    of getting a reference to the key from an enclosing scope.
342*cda5da8dSAndroid Build Coastguard Worker
343*cda5da8dSAndroid Build Coastguard Worker    """
344*cda5da8dSAndroid Build Coastguard Worker
345*cda5da8dSAndroid Build Coastguard Worker    __slots__ = "key",
346*cda5da8dSAndroid Build Coastguard Worker
347*cda5da8dSAndroid Build Coastguard Worker    def __new__(type, ob, callback, key):
348*cda5da8dSAndroid Build Coastguard Worker        self = ref.__new__(type, ob, callback)
349*cda5da8dSAndroid Build Coastguard Worker        self.key = key
350*cda5da8dSAndroid Build Coastguard Worker        return self
351*cda5da8dSAndroid Build Coastguard Worker
352*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, ob, callback, key):
353*cda5da8dSAndroid Build Coastguard Worker        super().__init__(ob, callback)
354*cda5da8dSAndroid Build Coastguard Worker
355*cda5da8dSAndroid Build Coastguard Worker
356*cda5da8dSAndroid Build Coastguard Workerclass WeakKeyDictionary(_collections_abc.MutableMapping):
357*cda5da8dSAndroid Build Coastguard Worker    """ Mapping class that references keys weakly.
358*cda5da8dSAndroid Build Coastguard Worker
359*cda5da8dSAndroid Build Coastguard Worker    Entries in the dictionary will be discarded when there is no
360*cda5da8dSAndroid Build Coastguard Worker    longer a strong reference to the key. This can be used to
361*cda5da8dSAndroid Build Coastguard Worker    associate additional data with an object owned by other parts of
362*cda5da8dSAndroid Build Coastguard Worker    an application without adding attributes to those objects. This
363*cda5da8dSAndroid Build Coastguard Worker    can be especially useful with objects that override attribute
364*cda5da8dSAndroid Build Coastguard Worker    accesses.
365*cda5da8dSAndroid Build Coastguard Worker    """
366*cda5da8dSAndroid Build Coastguard Worker
367*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, dict=None):
368*cda5da8dSAndroid Build Coastguard Worker        self.data = {}
369*cda5da8dSAndroid Build Coastguard Worker        def remove(k, selfref=ref(self)):
370*cda5da8dSAndroid Build Coastguard Worker            self = selfref()
371*cda5da8dSAndroid Build Coastguard Worker            if self is not None:
372*cda5da8dSAndroid Build Coastguard Worker                if self._iterating:
373*cda5da8dSAndroid Build Coastguard Worker                    self._pending_removals.append(k)
374*cda5da8dSAndroid Build Coastguard Worker                else:
375*cda5da8dSAndroid Build Coastguard Worker                    try:
376*cda5da8dSAndroid Build Coastguard Worker                        del self.data[k]
377*cda5da8dSAndroid Build Coastguard Worker                    except KeyError:
378*cda5da8dSAndroid Build Coastguard Worker                        pass
379*cda5da8dSAndroid Build Coastguard Worker        self._remove = remove
380*cda5da8dSAndroid Build Coastguard Worker        # A list of dead weakrefs (keys to be removed)
381*cda5da8dSAndroid Build Coastguard Worker        self._pending_removals = []
382*cda5da8dSAndroid Build Coastguard Worker        self._iterating = set()
383*cda5da8dSAndroid Build Coastguard Worker        self._dirty_len = False
384*cda5da8dSAndroid Build Coastguard Worker        if dict is not None:
385*cda5da8dSAndroid Build Coastguard Worker            self.update(dict)
386*cda5da8dSAndroid Build Coastguard Worker
387*cda5da8dSAndroid Build Coastguard Worker    def _commit_removals(self):
388*cda5da8dSAndroid Build Coastguard Worker        # NOTE: We don't need to call this method before mutating the dict,
389*cda5da8dSAndroid Build Coastguard Worker        # because a dead weakref never compares equal to a live weakref,
390*cda5da8dSAndroid Build Coastguard Worker        # even if they happened to refer to equal objects.
391*cda5da8dSAndroid Build Coastguard Worker        # However, it means keys may already have been removed.
392*cda5da8dSAndroid Build Coastguard Worker        pop = self._pending_removals.pop
393*cda5da8dSAndroid Build Coastguard Worker        d = self.data
394*cda5da8dSAndroid Build Coastguard Worker        while True:
395*cda5da8dSAndroid Build Coastguard Worker            try:
396*cda5da8dSAndroid Build Coastguard Worker                key = pop()
397*cda5da8dSAndroid Build Coastguard Worker            except IndexError:
398*cda5da8dSAndroid Build Coastguard Worker                return
399*cda5da8dSAndroid Build Coastguard Worker
400*cda5da8dSAndroid Build Coastguard Worker            try:
401*cda5da8dSAndroid Build Coastguard Worker                del d[key]
402*cda5da8dSAndroid Build Coastguard Worker            except KeyError:
403*cda5da8dSAndroid Build Coastguard Worker                pass
404*cda5da8dSAndroid Build Coastguard Worker
405*cda5da8dSAndroid Build Coastguard Worker    def _scrub_removals(self):
406*cda5da8dSAndroid Build Coastguard Worker        d = self.data
407*cda5da8dSAndroid Build Coastguard Worker        self._pending_removals = [k for k in self._pending_removals if k in d]
408*cda5da8dSAndroid Build Coastguard Worker        self._dirty_len = False
409*cda5da8dSAndroid Build Coastguard Worker
410*cda5da8dSAndroid Build Coastguard Worker    def __delitem__(self, key):
411*cda5da8dSAndroid Build Coastguard Worker        self._dirty_len = True
412*cda5da8dSAndroid Build Coastguard Worker        del self.data[ref(key)]
413*cda5da8dSAndroid Build Coastguard Worker
414*cda5da8dSAndroid Build Coastguard Worker    def __getitem__(self, key):
415*cda5da8dSAndroid Build Coastguard Worker        return self.data[ref(key)]
416*cda5da8dSAndroid Build Coastguard Worker
417*cda5da8dSAndroid Build Coastguard Worker    def __len__(self):
418*cda5da8dSAndroid Build Coastguard Worker        if self._dirty_len and self._pending_removals:
419*cda5da8dSAndroid Build Coastguard Worker            # self._pending_removals may still contain keys which were
420*cda5da8dSAndroid Build Coastguard Worker            # explicitly removed, we have to scrub them (see issue #21173).
421*cda5da8dSAndroid Build Coastguard Worker            self._scrub_removals()
422*cda5da8dSAndroid Build Coastguard Worker        return len(self.data) - len(self._pending_removals)
423*cda5da8dSAndroid Build Coastguard Worker
424*cda5da8dSAndroid Build Coastguard Worker    def __repr__(self):
425*cda5da8dSAndroid Build Coastguard Worker        return "<%s at %#x>" % (self.__class__.__name__, id(self))
426*cda5da8dSAndroid Build Coastguard Worker
427*cda5da8dSAndroid Build Coastguard Worker    def __setitem__(self, key, value):
428*cda5da8dSAndroid Build Coastguard Worker        self.data[ref(key, self._remove)] = value
429*cda5da8dSAndroid Build Coastguard Worker
430*cda5da8dSAndroid Build Coastguard Worker    def copy(self):
431*cda5da8dSAndroid Build Coastguard Worker        new = WeakKeyDictionary()
432*cda5da8dSAndroid Build Coastguard Worker        with _IterationGuard(self):
433*cda5da8dSAndroid Build Coastguard Worker            for key, value in self.data.items():
434*cda5da8dSAndroid Build Coastguard Worker                o = key()
435*cda5da8dSAndroid Build Coastguard Worker                if o is not None:
436*cda5da8dSAndroid Build Coastguard Worker                    new[o] = value
437*cda5da8dSAndroid Build Coastguard Worker        return new
438*cda5da8dSAndroid Build Coastguard Worker
439*cda5da8dSAndroid Build Coastguard Worker    __copy__ = copy
440*cda5da8dSAndroid Build Coastguard Worker
441*cda5da8dSAndroid Build Coastguard Worker    def __deepcopy__(self, memo):
442*cda5da8dSAndroid Build Coastguard Worker        from copy import deepcopy
443*cda5da8dSAndroid Build Coastguard Worker        new = self.__class__()
444*cda5da8dSAndroid Build Coastguard Worker        with _IterationGuard(self):
445*cda5da8dSAndroid Build Coastguard Worker            for key, value in self.data.items():
446*cda5da8dSAndroid Build Coastguard Worker                o = key()
447*cda5da8dSAndroid Build Coastguard Worker                if o is not None:
448*cda5da8dSAndroid Build Coastguard Worker                    new[o] = deepcopy(value, memo)
449*cda5da8dSAndroid Build Coastguard Worker        return new
450*cda5da8dSAndroid Build Coastguard Worker
451*cda5da8dSAndroid Build Coastguard Worker    def get(self, key, default=None):
452*cda5da8dSAndroid Build Coastguard Worker        return self.data.get(ref(key),default)
453*cda5da8dSAndroid Build Coastguard Worker
454*cda5da8dSAndroid Build Coastguard Worker    def __contains__(self, key):
455*cda5da8dSAndroid Build Coastguard Worker        try:
456*cda5da8dSAndroid Build Coastguard Worker            wr = ref(key)
457*cda5da8dSAndroid Build Coastguard Worker        except TypeError:
458*cda5da8dSAndroid Build Coastguard Worker            return False
459*cda5da8dSAndroid Build Coastguard Worker        return wr in self.data
460*cda5da8dSAndroid Build Coastguard Worker
461*cda5da8dSAndroid Build Coastguard Worker    def items(self):
462*cda5da8dSAndroid Build Coastguard Worker        with _IterationGuard(self):
463*cda5da8dSAndroid Build Coastguard Worker            for wr, value in self.data.items():
464*cda5da8dSAndroid Build Coastguard Worker                key = wr()
465*cda5da8dSAndroid Build Coastguard Worker                if key is not None:
466*cda5da8dSAndroid Build Coastguard Worker                    yield key, value
467*cda5da8dSAndroid Build Coastguard Worker
468*cda5da8dSAndroid Build Coastguard Worker    def keys(self):
469*cda5da8dSAndroid Build Coastguard Worker        with _IterationGuard(self):
470*cda5da8dSAndroid Build Coastguard Worker            for wr in self.data:
471*cda5da8dSAndroid Build Coastguard Worker                obj = wr()
472*cda5da8dSAndroid Build Coastguard Worker                if obj is not None:
473*cda5da8dSAndroid Build Coastguard Worker                    yield obj
474*cda5da8dSAndroid Build Coastguard Worker
475*cda5da8dSAndroid Build Coastguard Worker    __iter__ = keys
476*cda5da8dSAndroid Build Coastguard Worker
477*cda5da8dSAndroid Build Coastguard Worker    def values(self):
478*cda5da8dSAndroid Build Coastguard Worker        with _IterationGuard(self):
479*cda5da8dSAndroid Build Coastguard Worker            for wr, value in self.data.items():
480*cda5da8dSAndroid Build Coastguard Worker                if wr() is not None:
481*cda5da8dSAndroid Build Coastguard Worker                    yield value
482*cda5da8dSAndroid Build Coastguard Worker
483*cda5da8dSAndroid Build Coastguard Worker    def keyrefs(self):
484*cda5da8dSAndroid Build Coastguard Worker        """Return a list of weak references to the keys.
485*cda5da8dSAndroid Build Coastguard Worker
486*cda5da8dSAndroid Build Coastguard Worker        The references are not guaranteed to be 'live' at the time
487*cda5da8dSAndroid Build Coastguard Worker        they are used, so the result of calling the references needs
488*cda5da8dSAndroid Build Coastguard Worker        to be checked before being used.  This can be used to avoid
489*cda5da8dSAndroid Build Coastguard Worker        creating references that will cause the garbage collector to
490*cda5da8dSAndroid Build Coastguard Worker        keep the keys around longer than needed.
491*cda5da8dSAndroid Build Coastguard Worker
492*cda5da8dSAndroid Build Coastguard Worker        """
493*cda5da8dSAndroid Build Coastguard Worker        return list(self.data)
494*cda5da8dSAndroid Build Coastguard Worker
495*cda5da8dSAndroid Build Coastguard Worker    def popitem(self):
496*cda5da8dSAndroid Build Coastguard Worker        self._dirty_len = True
497*cda5da8dSAndroid Build Coastguard Worker        while True:
498*cda5da8dSAndroid Build Coastguard Worker            key, value = self.data.popitem()
499*cda5da8dSAndroid Build Coastguard Worker            o = key()
500*cda5da8dSAndroid Build Coastguard Worker            if o is not None:
501*cda5da8dSAndroid Build Coastguard Worker                return o, value
502*cda5da8dSAndroid Build Coastguard Worker
503*cda5da8dSAndroid Build Coastguard Worker    def pop(self, key, *args):
504*cda5da8dSAndroid Build Coastguard Worker        self._dirty_len = True
505*cda5da8dSAndroid Build Coastguard Worker        return self.data.pop(ref(key), *args)
506*cda5da8dSAndroid Build Coastguard Worker
507*cda5da8dSAndroid Build Coastguard Worker    def setdefault(self, key, default=None):
508*cda5da8dSAndroid Build Coastguard Worker        return self.data.setdefault(ref(key, self._remove),default)
509*cda5da8dSAndroid Build Coastguard Worker
510*cda5da8dSAndroid Build Coastguard Worker    def update(self, dict=None, /, **kwargs):
511*cda5da8dSAndroid Build Coastguard Worker        d = self.data
512*cda5da8dSAndroid Build Coastguard Worker        if dict is not None:
513*cda5da8dSAndroid Build Coastguard Worker            if not hasattr(dict, "items"):
514*cda5da8dSAndroid Build Coastguard Worker                dict = type({})(dict)
515*cda5da8dSAndroid Build Coastguard Worker            for key, value in dict.items():
516*cda5da8dSAndroid Build Coastguard Worker                d[ref(key, self._remove)] = value
517*cda5da8dSAndroid Build Coastguard Worker        if len(kwargs):
518*cda5da8dSAndroid Build Coastguard Worker            self.update(kwargs)
519*cda5da8dSAndroid Build Coastguard Worker
520*cda5da8dSAndroid Build Coastguard Worker    def __ior__(self, other):
521*cda5da8dSAndroid Build Coastguard Worker        self.update(other)
522*cda5da8dSAndroid Build Coastguard Worker        return self
523*cda5da8dSAndroid Build Coastguard Worker
524*cda5da8dSAndroid Build Coastguard Worker    def __or__(self, other):
525*cda5da8dSAndroid Build Coastguard Worker        if isinstance(other, _collections_abc.Mapping):
526*cda5da8dSAndroid Build Coastguard Worker            c = self.copy()
527*cda5da8dSAndroid Build Coastguard Worker            c.update(other)
528*cda5da8dSAndroid Build Coastguard Worker            return c
529*cda5da8dSAndroid Build Coastguard Worker        return NotImplemented
530*cda5da8dSAndroid Build Coastguard Worker
531*cda5da8dSAndroid Build Coastguard Worker    def __ror__(self, other):
532*cda5da8dSAndroid Build Coastguard Worker        if isinstance(other, _collections_abc.Mapping):
533*cda5da8dSAndroid Build Coastguard Worker            c = self.__class__()
534*cda5da8dSAndroid Build Coastguard Worker            c.update(other)
535*cda5da8dSAndroid Build Coastguard Worker            c.update(self)
536*cda5da8dSAndroid Build Coastguard Worker            return c
537*cda5da8dSAndroid Build Coastguard Worker        return NotImplemented
538*cda5da8dSAndroid Build Coastguard Worker
539*cda5da8dSAndroid Build Coastguard Worker
540*cda5da8dSAndroid Build Coastguard Workerclass finalize:
541*cda5da8dSAndroid Build Coastguard Worker    """Class for finalization of weakrefable objects
542*cda5da8dSAndroid Build Coastguard Worker
543*cda5da8dSAndroid Build Coastguard Worker    finalize(obj, func, *args, **kwargs) returns a callable finalizer
544*cda5da8dSAndroid Build Coastguard Worker    object which will be called when obj is garbage collected. The
545*cda5da8dSAndroid Build Coastguard Worker    first time the finalizer is called it evaluates func(*arg, **kwargs)
546*cda5da8dSAndroid Build Coastguard Worker    and returns the result. After this the finalizer is dead, and
547*cda5da8dSAndroid Build Coastguard Worker    calling it just returns None.
548*cda5da8dSAndroid Build Coastguard Worker
549*cda5da8dSAndroid Build Coastguard Worker    When the program exits any remaining finalizers for which the
550*cda5da8dSAndroid Build Coastguard Worker    atexit attribute is true will be run in reverse order of creation.
551*cda5da8dSAndroid Build Coastguard Worker    By default atexit is true.
552*cda5da8dSAndroid Build Coastguard Worker    """
553*cda5da8dSAndroid Build Coastguard Worker
554*cda5da8dSAndroid Build Coastguard Worker    # Finalizer objects don't have any state of their own.  They are
555*cda5da8dSAndroid Build Coastguard Worker    # just used as keys to lookup _Info objects in the registry.  This
556*cda5da8dSAndroid Build Coastguard Worker    # ensures that they cannot be part of a ref-cycle.
557*cda5da8dSAndroid Build Coastguard Worker
558*cda5da8dSAndroid Build Coastguard Worker    __slots__ = ()
559*cda5da8dSAndroid Build Coastguard Worker    _registry = {}
560*cda5da8dSAndroid Build Coastguard Worker    _shutdown = False
561*cda5da8dSAndroid Build Coastguard Worker    _index_iter = itertools.count()
562*cda5da8dSAndroid Build Coastguard Worker    _dirty = False
563*cda5da8dSAndroid Build Coastguard Worker    _registered_with_atexit = False
564*cda5da8dSAndroid Build Coastguard Worker
565*cda5da8dSAndroid Build Coastguard Worker    class _Info:
566*cda5da8dSAndroid Build Coastguard Worker        __slots__ = ("weakref", "func", "args", "kwargs", "atexit", "index")
567*cda5da8dSAndroid Build Coastguard Worker
568*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, obj, func, /, *args, **kwargs):
569*cda5da8dSAndroid Build Coastguard Worker        if not self._registered_with_atexit:
570*cda5da8dSAndroid Build Coastguard Worker            # We may register the exit function more than once because
571*cda5da8dSAndroid Build Coastguard Worker            # of a thread race, but that is harmless
572*cda5da8dSAndroid Build Coastguard Worker            import atexit
573*cda5da8dSAndroid Build Coastguard Worker            atexit.register(self._exitfunc)
574*cda5da8dSAndroid Build Coastguard Worker            finalize._registered_with_atexit = True
575*cda5da8dSAndroid Build Coastguard Worker        info = self._Info()
576*cda5da8dSAndroid Build Coastguard Worker        info.weakref = ref(obj, self)
577*cda5da8dSAndroid Build Coastguard Worker        info.func = func
578*cda5da8dSAndroid Build Coastguard Worker        info.args = args
579*cda5da8dSAndroid Build Coastguard Worker        info.kwargs = kwargs or None
580*cda5da8dSAndroid Build Coastguard Worker        info.atexit = True
581*cda5da8dSAndroid Build Coastguard Worker        info.index = next(self._index_iter)
582*cda5da8dSAndroid Build Coastguard Worker        self._registry[self] = info
583*cda5da8dSAndroid Build Coastguard Worker        finalize._dirty = True
584*cda5da8dSAndroid Build Coastguard Worker
585*cda5da8dSAndroid Build Coastguard Worker    def __call__(self, _=None):
586*cda5da8dSAndroid Build Coastguard Worker        """If alive then mark as dead and return func(*args, **kwargs);
587*cda5da8dSAndroid Build Coastguard Worker        otherwise return None"""
588*cda5da8dSAndroid Build Coastguard Worker        info = self._registry.pop(self, None)
589*cda5da8dSAndroid Build Coastguard Worker        if info and not self._shutdown:
590*cda5da8dSAndroid Build Coastguard Worker            return info.func(*info.args, **(info.kwargs or {}))
591*cda5da8dSAndroid Build Coastguard Worker
592*cda5da8dSAndroid Build Coastguard Worker    def detach(self):
593*cda5da8dSAndroid Build Coastguard Worker        """If alive then mark as dead and return (obj, func, args, kwargs);
594*cda5da8dSAndroid Build Coastguard Worker        otherwise return None"""
595*cda5da8dSAndroid Build Coastguard Worker        info = self._registry.get(self)
596*cda5da8dSAndroid Build Coastguard Worker        obj = info and info.weakref()
597*cda5da8dSAndroid Build Coastguard Worker        if obj is not None and self._registry.pop(self, None):
598*cda5da8dSAndroid Build Coastguard Worker            return (obj, info.func, info.args, info.kwargs or {})
599*cda5da8dSAndroid Build Coastguard Worker
600*cda5da8dSAndroid Build Coastguard Worker    def peek(self):
601*cda5da8dSAndroid Build Coastguard Worker        """If alive then return (obj, func, args, kwargs);
602*cda5da8dSAndroid Build Coastguard Worker        otherwise return None"""
603*cda5da8dSAndroid Build Coastguard Worker        info = self._registry.get(self)
604*cda5da8dSAndroid Build Coastguard Worker        obj = info and info.weakref()
605*cda5da8dSAndroid Build Coastguard Worker        if obj is not None:
606*cda5da8dSAndroid Build Coastguard Worker            return (obj, info.func, info.args, info.kwargs or {})
607*cda5da8dSAndroid Build Coastguard Worker
608*cda5da8dSAndroid Build Coastguard Worker    @property
609*cda5da8dSAndroid Build Coastguard Worker    def alive(self):
610*cda5da8dSAndroid Build Coastguard Worker        """Whether finalizer is alive"""
611*cda5da8dSAndroid Build Coastguard Worker        return self in self._registry
612*cda5da8dSAndroid Build Coastguard Worker
613*cda5da8dSAndroid Build Coastguard Worker    @property
614*cda5da8dSAndroid Build Coastguard Worker    def atexit(self):
615*cda5da8dSAndroid Build Coastguard Worker        """Whether finalizer should be called at exit"""
616*cda5da8dSAndroid Build Coastguard Worker        info = self._registry.get(self)
617*cda5da8dSAndroid Build Coastguard Worker        return bool(info) and info.atexit
618*cda5da8dSAndroid Build Coastguard Worker
619*cda5da8dSAndroid Build Coastguard Worker    @atexit.setter
620*cda5da8dSAndroid Build Coastguard Worker    def atexit(self, value):
621*cda5da8dSAndroid Build Coastguard Worker        info = self._registry.get(self)
622*cda5da8dSAndroid Build Coastguard Worker        if info:
623*cda5da8dSAndroid Build Coastguard Worker            info.atexit = bool(value)
624*cda5da8dSAndroid Build Coastguard Worker
625*cda5da8dSAndroid Build Coastguard Worker    def __repr__(self):
626*cda5da8dSAndroid Build Coastguard Worker        info = self._registry.get(self)
627*cda5da8dSAndroid Build Coastguard Worker        obj = info and info.weakref()
628*cda5da8dSAndroid Build Coastguard Worker        if obj is None:
629*cda5da8dSAndroid Build Coastguard Worker            return '<%s object at %#x; dead>' % (type(self).__name__, id(self))
630*cda5da8dSAndroid Build Coastguard Worker        else:
631*cda5da8dSAndroid Build Coastguard Worker            return '<%s object at %#x; for %r at %#x>' % \
632*cda5da8dSAndroid Build Coastguard Worker                (type(self).__name__, id(self), type(obj).__name__, id(obj))
633*cda5da8dSAndroid Build Coastguard Worker
634*cda5da8dSAndroid Build Coastguard Worker    @classmethod
635*cda5da8dSAndroid Build Coastguard Worker    def _select_for_exit(cls):
636*cda5da8dSAndroid Build Coastguard Worker        # Return live finalizers marked for exit, oldest first
637*cda5da8dSAndroid Build Coastguard Worker        L = [(f,i) for (f,i) in cls._registry.items() if i.atexit]
638*cda5da8dSAndroid Build Coastguard Worker        L.sort(key=lambda item:item[1].index)
639*cda5da8dSAndroid Build Coastguard Worker        return [f for (f,i) in L]
640*cda5da8dSAndroid Build Coastguard Worker
641*cda5da8dSAndroid Build Coastguard Worker    @classmethod
642*cda5da8dSAndroid Build Coastguard Worker    def _exitfunc(cls):
643*cda5da8dSAndroid Build Coastguard Worker        # At shutdown invoke finalizers for which atexit is true.
644*cda5da8dSAndroid Build Coastguard Worker        # This is called once all other non-daemonic threads have been
645*cda5da8dSAndroid Build Coastguard Worker        # joined.
646*cda5da8dSAndroid Build Coastguard Worker        reenable_gc = False
647*cda5da8dSAndroid Build Coastguard Worker        try:
648*cda5da8dSAndroid Build Coastguard Worker            if cls._registry:
649*cda5da8dSAndroid Build Coastguard Worker                import gc
650*cda5da8dSAndroid Build Coastguard Worker                if gc.isenabled():
651*cda5da8dSAndroid Build Coastguard Worker                    reenable_gc = True
652*cda5da8dSAndroid Build Coastguard Worker                    gc.disable()
653*cda5da8dSAndroid Build Coastguard Worker                pending = None
654*cda5da8dSAndroid Build Coastguard Worker                while True:
655*cda5da8dSAndroid Build Coastguard Worker                    if pending is None or finalize._dirty:
656*cda5da8dSAndroid Build Coastguard Worker                        pending = cls._select_for_exit()
657*cda5da8dSAndroid Build Coastguard Worker                        finalize._dirty = False
658*cda5da8dSAndroid Build Coastguard Worker                    if not pending:
659*cda5da8dSAndroid Build Coastguard Worker                        break
660*cda5da8dSAndroid Build Coastguard Worker                    f = pending.pop()
661*cda5da8dSAndroid Build Coastguard Worker                    try:
662*cda5da8dSAndroid Build Coastguard Worker                        # gc is disabled, so (assuming no daemonic
663*cda5da8dSAndroid Build Coastguard Worker                        # threads) the following is the only line in
664*cda5da8dSAndroid Build Coastguard Worker                        # this function which might trigger creation
665*cda5da8dSAndroid Build Coastguard Worker                        # of a new finalizer
666*cda5da8dSAndroid Build Coastguard Worker                        f()
667*cda5da8dSAndroid Build Coastguard Worker                    except Exception:
668*cda5da8dSAndroid Build Coastguard Worker                        sys.excepthook(*sys.exc_info())
669*cda5da8dSAndroid Build Coastguard Worker                    assert f not in cls._registry
670*cda5da8dSAndroid Build Coastguard Worker        finally:
671*cda5da8dSAndroid Build Coastguard Worker            # prevent any more finalizers from executing during shutdown
672*cda5da8dSAndroid Build Coastguard Worker            finalize._shutdown = True
673*cda5da8dSAndroid Build Coastguard Worker            if reenable_gc:
674*cda5da8dSAndroid Build Coastguard Worker                gc.enable()
675