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