blob: 9d7008947f06d40b48a7d736f8231f41af3db409 [file] [log] [blame]
Fred Drake41deb1e2001-02-01 05:27:45 +00001"""Weak reference support for Python.
2
3This module is an implementation of PEP 205:
4
Christian Heimes81ee3ef2008-05-04 22:42:01 +00005http://www.python.org/dev/peps/pep-0205/
Fred Drake41deb1e2001-02-01 05:27:45 +00006"""
7
Fred Drakebd7f8182001-04-19 16:26:06 +00008# Naming convention: Variables named "wr" are weak reference objects;
9# they are called this instead of "ref" to avoid name collisions with
10# the module-global ref() function imported from _weakref.
11
Andrew M. Kuchling33ad28b2004-08-31 11:38:12 +000012from _weakref import (
13 getweakrefcount,
14 getweakrefs,
15 ref,
16 proxy,
17 CallableProxyType,
18 ProxyType,
Antoine Pitroue10ca3a2016-12-27 14:19:20 +010019 ReferenceType,
20 _remove_dead_weakref)
Fred Drake41deb1e2001-02-01 05:27:45 +000021
Antoine Pitrouc1baa602010-01-08 17:54:23 +000022from _weakrefset import WeakSet, _IterationGuard
Fred Drakee0292422001-10-05 21:54:09 +000023
Serhiy Storchaka81108372017-09-26 00:55:55 +030024import _collections_abc # Import after _weakref to avoid circular import.
Richard Oudkerk7a3dae02013-05-05 23:05:00 +010025import sys
26import itertools
Brett Cannon663fffa2009-03-25 23:31:22 +000027
Fred Drake41deb1e2001-02-01 05:27:45 +000028ProxyTypes = (ProxyType, CallableProxyType)
29
Fred Drake9a9d2192001-04-10 19:11:23 +000030__all__ = ["ref", "proxy", "getweakrefcount", "getweakrefs",
Gregory P. Smith7d10c2b2008-08-18 03:41:46 +000031 "WeakKeyDictionary", "ReferenceType", "ProxyType",
Raymond Hettinger93fa6082008-02-05 00:20:01 +000032 "CallableProxyType", "ProxyTypes", "WeakValueDictionary",
Richard Oudkerk7a3dae02013-05-05 23:05:00 +010033 "WeakSet", "WeakMethod", "finalize"]
Antoine Pitrouc3afba12012-11-17 18:57:38 +010034
35
36class WeakMethod(ref):
37 """
38 A custom `weakref.ref` subclass which simulates a weak reference to
39 a bound method, working around the lifetime problem of bound methods.
40 """
41
42 __slots__ = "_func_ref", "_meth_type", "_alive", "__weakref__"
43
44 def __new__(cls, meth, callback=None):
45 try:
46 obj = meth.__self__
47 func = meth.__func__
48 except AttributeError:
49 raise TypeError("argument should be a bound method, not {}"
50 .format(type(meth))) from None
51 def _cb(arg):
52 # The self-weakref trick is needed to avoid creating a reference
53 # cycle.
54 self = self_wr()
55 if self._alive:
56 self._alive = False
57 if callback is not None:
58 callback(self)
59 self = ref.__new__(cls, obj, _cb)
60 self._func_ref = ref(func, _cb)
61 self._meth_type = type(meth)
62 self._alive = True
63 self_wr = ref(self)
64 return self
65
66 def __call__(self):
67 obj = super().__call__()
68 func = self._func_ref()
69 if obj is None or func is None:
70 return None
71 return self._meth_type(func, obj)
72
73 def __eq__(self, other):
74 if isinstance(other, WeakMethod):
75 if not self._alive or not other._alive:
76 return self is other
77 return ref.__eq__(self, other) and self._func_ref == other._func_ref
78 return False
79
80 def __ne__(self, other):
81 if isinstance(other, WeakMethod):
82 if not self._alive or not other._alive:
83 return self is not other
84 return ref.__ne__(self, other) or self._func_ref != other._func_ref
85 return True
86
87 __hash__ = ref.__hash__
Fred Drake41deb1e2001-02-01 05:27:45 +000088
Fred Drake41deb1e2001-02-01 05:27:45 +000089
Serhiy Storchaka81108372017-09-26 00:55:55 +030090class WeakValueDictionary(_collections_abc.MutableMapping):
Fred Drakebd7f8182001-04-19 16:26:06 +000091 """Mapping class that references values weakly.
92
93 Entries in the dictionary will be discarded when no strong
94 reference to the value exists anymore
95 """
Fred Drake41deb1e2001-02-01 05:27:45 +000096 # We inherit the constructor without worrying about the input
97 # dictionary; since it uses our .update() method, we get the right
Fred Drake9d2c85d2001-03-01 03:06:03 +000098 # checks (if the other dictionary is a WeakValueDictionary,
99 # objects are unwrapped on the way out, and we always wrap on the
100 # way in).
Fred Drake41deb1e2001-02-01 05:27:45 +0000101
Serhiy Storchaka2085bd02019-06-01 11:00:15 +0300102 def __init__(self, other=(), /, **kw):
Ɓukasz Langa9cd7e172017-02-10 00:14:55 -0800103 def remove(wr, selfref=ref(self), _atomic_removal=_remove_dead_weakref):
Fred Drake0a4dd392004-07-02 18:57:45 +0000104 self = selfref()
105 if self is not None:
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000106 if self._iterating:
107 self._pending_removals.append(wr.key)
108 else:
Antoine Pitroue10ca3a2016-12-27 14:19:20 +0100109 # Atomic removal is necessary since this function
110 # can be called asynchronously by the GC
Miss Islington (bot)78d15fa2019-09-09 09:24:16 -0700111 _atomic_removal(self.data, wr.key)
Fred Drake0a4dd392004-07-02 18:57:45 +0000112 self._remove = remove
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000113 # A list of keys to be removed
114 self._pending_removals = []
115 self._iterating = set()
Miss Islington (bot)78d15fa2019-09-09 09:24:16 -0700116 self.data = {}
Serhiy Storchaka2085bd02019-06-01 11:00:15 +0300117 self.update(other, **kw)
Fred Drake0a4dd392004-07-02 18:57:45 +0000118
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000119 def _commit_removals(self):
120 l = self._pending_removals
121 d = self.data
122 # We shouldn't encounter any KeyError, because this method should
123 # always be called *before* mutating the dict.
124 while l:
Antoine Pitroue10ca3a2016-12-27 14:19:20 +0100125 key = l.pop()
126 _remove_dead_weakref(d, key)
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000127
Fred Drake41deb1e2001-02-01 05:27:45 +0000128 def __getitem__(self, key):
Antoine Pitroue10ca3a2016-12-27 14:19:20 +0100129 if self._pending_removals:
130 self._commit_removals()
Fred Drake4fd06e02001-08-03 04:11:27 +0000131 o = self.data[key]()
Fred Drake41deb1e2001-02-01 05:27:45 +0000132 if o is None:
Collin Winterce36ad82007-08-30 01:19:48 +0000133 raise KeyError(key)
Fred Drake41deb1e2001-02-01 05:27:45 +0000134 else:
135 return o
136
Raymond Hettinger7ac60952008-02-05 01:15:57 +0000137 def __delitem__(self, key):
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000138 if self._pending_removals:
139 self._commit_removals()
Raymond Hettinger7ac60952008-02-05 01:15:57 +0000140 del self.data[key]
141
142 def __len__(self):
Antoine Pitroue10ca3a2016-12-27 14:19:20 +0100143 if self._pending_removals:
144 self._commit_removals()
145 return len(self.data)
Raymond Hettinger7ac60952008-02-05 01:15:57 +0000146
Raymond Hettinger61146792004-08-19 21:32:06 +0000147 def __contains__(self, key):
Antoine Pitroue10ca3a2016-12-27 14:19:20 +0100148 if self._pending_removals:
149 self._commit_removals()
Raymond Hettinger61146792004-08-19 21:32:06 +0000150 try:
151 o = self.data[key]()
152 except KeyError:
153 return False
154 return o is not None
155
Fred Drake41deb1e2001-02-01 05:27:45 +0000156 def __repr__(self):
Serhiy Storchaka465e60e2014-07-25 23:36:00 +0300157 return "<%s at %#x>" % (self.__class__.__name__, id(self))
Fred Drake41deb1e2001-02-01 05:27:45 +0000158
159 def __setitem__(self, key, value):
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000160 if self._pending_removals:
161 self._commit_removals()
Fred Drake0a4dd392004-07-02 18:57:45 +0000162 self.data[key] = KeyedRef(value, self._remove, key)
Fred Drake41deb1e2001-02-01 05:27:45 +0000163
164 def copy(self):
Antoine Pitroue10ca3a2016-12-27 14:19:20 +0100165 if self._pending_removals:
166 self._commit_removals()
Fred Drake9d2c85d2001-03-01 03:06:03 +0000167 new = WeakValueDictionary()
Fish96d37db2019-02-07 14:51:59 -0500168 with _IterationGuard(self):
169 for key, wr in self.data.items():
170 o = wr()
171 if o is not None:
172 new[key] = o
Fred Drake9d2c85d2001-03-01 03:06:03 +0000173 return new
Fred Drake41deb1e2001-02-01 05:27:45 +0000174
Antoine Pitrou6e610062009-05-15 17:04:50 +0000175 __copy__ = copy
176
177 def __deepcopy__(self, memo):
178 from copy import deepcopy
Antoine Pitroue10ca3a2016-12-27 14:19:20 +0100179 if self._pending_removals:
180 self._commit_removals()
Antoine Pitrou6e610062009-05-15 17:04:50 +0000181 new = self.__class__()
Fish96d37db2019-02-07 14:51:59 -0500182 with _IterationGuard(self):
183 for key, wr in self.data.items():
184 o = wr()
185 if o is not None:
186 new[deepcopy(key, memo)] = o
Antoine Pitrou6e610062009-05-15 17:04:50 +0000187 return new
188
Fred Drake1d9e4b72001-04-16 17:34:48 +0000189 def get(self, key, default=None):
Antoine Pitroue10ca3a2016-12-27 14:19:20 +0100190 if self._pending_removals:
191 self._commit_removals()
Fred Drake41deb1e2001-02-01 05:27:45 +0000192 try:
Fred Drakebd7f8182001-04-19 16:26:06 +0000193 wr = self.data[key]
Fred Drake41deb1e2001-02-01 05:27:45 +0000194 except KeyError:
195 return default
196 else:
Fred Drakebd7f8182001-04-19 16:26:06 +0000197 o = wr()
Fred Drake41deb1e2001-02-01 05:27:45 +0000198 if o is None:
199 # This should only happen
200 return default
201 else:
202 return o
203
204 def items(self):
Antoine Pitroue10ca3a2016-12-27 14:19:20 +0100205 if self._pending_removals:
206 self._commit_removals()
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000207 with _IterationGuard(self):
208 for k, wr in self.data.items():
209 v = wr()
210 if v is not None:
211 yield k, v
Fred Drake101209d2001-05-02 05:43:09 +0000212
Barry Warsawecaab832008-09-04 01:42:51 +0000213 def keys(self):
Antoine Pitroue10ca3a2016-12-27 14:19:20 +0100214 if self._pending_removals:
215 self._commit_removals()
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000216 with _IterationGuard(self):
217 for k, wr in self.data.items():
218 if wr() is not None:
219 yield k
Raymond Hettinger61146792004-08-19 21:32:06 +0000220
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000221 __iter__ = keys
Fred Drake101209d2001-05-02 05:43:09 +0000222
Thomas Wouters477c8d52006-05-27 19:21:47 +0000223 def itervaluerefs(self):
224 """Return an iterator that yields the weak references to the values.
225
226 The references are not guaranteed to be 'live' at the time
227 they are used, so the result of calling the references needs
228 to be checked before being used. This can be used to avoid
229 creating references that will cause the garbage collector to
230 keep the values around longer than needed.
231
232 """
Antoine Pitroue10ca3a2016-12-27 14:19:20 +0100233 if self._pending_removals:
234 self._commit_removals()
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000235 with _IterationGuard(self):
Philip Jenvey4993cc02012-10-01 12:53:43 -0700236 yield from self.data.values()
Thomas Wouters477c8d52006-05-27 19:21:47 +0000237
Barry Warsawecaab832008-09-04 01:42:51 +0000238 def values(self):
Antoine Pitroue10ca3a2016-12-27 14:19:20 +0100239 if self._pending_removals:
240 self._commit_removals()
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000241 with _IterationGuard(self):
242 for wr in self.data.values():
243 obj = wr()
244 if obj is not None:
245 yield obj
Fred Drake101209d2001-05-02 05:43:09 +0000246
Fred Drake41deb1e2001-02-01 05:27:45 +0000247 def popitem(self):
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000248 if self._pending_removals:
249 self._commit_removals()
Georg Brandlbd87d082010-12-03 07:49:09 +0000250 while True:
Fred Drakebd7f8182001-04-19 16:26:06 +0000251 key, wr = self.data.popitem()
252 o = wr()
Fred Drake41deb1e2001-02-01 05:27:45 +0000253 if o is not None:
254 return key, o
255
Raymond Hettinger2c2d3222003-03-09 07:05:43 +0000256 def pop(self, key, *args):
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000257 if self._pending_removals:
258 self._commit_removals()
Raymond Hettinger2c2d3222003-03-09 07:05:43 +0000259 try:
260 o = self.data.pop(key)()
261 except KeyError:
Antoine Pitrouc1ee4882016-12-19 10:56:40 +0100262 o = None
263 if o is None:
Raymond Hettinger2c2d3222003-03-09 07:05:43 +0000264 if args:
265 return args[0]
Antoine Pitrouc1ee4882016-12-19 10:56:40 +0100266 else:
267 raise KeyError(key)
Raymond Hettinger2c2d3222003-03-09 07:05:43 +0000268 else:
269 return o
270
Walter Dörwald80ce6dd2004-05-27 18:16:25 +0000271 def setdefault(self, key, default=None):
Fred Drake41deb1e2001-02-01 05:27:45 +0000272 try:
Antoine Pitrouc1ee4882016-12-19 10:56:40 +0100273 o = self.data[key]()
Fred Drake41deb1e2001-02-01 05:27:45 +0000274 except KeyError:
Antoine Pitrouc1ee4882016-12-19 10:56:40 +0100275 o = None
276 if o is None:
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000277 if self._pending_removals:
278 self._commit_removals()
Fred Drake0a4dd392004-07-02 18:57:45 +0000279 self.data[key] = KeyedRef(default, self._remove, key)
Fred Drake41deb1e2001-02-01 05:27:45 +0000280 return default
281 else:
Antoine Pitrouc1ee4882016-12-19 10:56:40 +0100282 return o
Fred Drake41deb1e2001-02-01 05:27:45 +0000283
Serhiy Storchaka2085bd02019-06-01 11:00:15 +0300284 def update(self, other=None, /, **kwargs):
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000285 if self._pending_removals:
286 self._commit_removals()
Fred Drake41deb1e2001-02-01 05:27:45 +0000287 d = self.data
Serhiy Storchaka2085bd02019-06-01 11:00:15 +0300288 if other is not None:
289 if not hasattr(other, "items"):
290 other = dict(other)
291 for key, o in other.items():
Fred Drake0a4dd392004-07-02 18:57:45 +0000292 d[key] = KeyedRef(o, self._remove, key)
Serhiy Storchaka2085bd02019-06-01 11:00:15 +0300293 for key, o in kwargs.items():
294 d[key] = KeyedRef(o, self._remove, key)
Fred Drake41deb1e2001-02-01 05:27:45 +0000295
Thomas Wouters477c8d52006-05-27 19:21:47 +0000296 def valuerefs(self):
297 """Return a list of weak references to the values.
298
299 The references are not guaranteed to be 'live' at the time
300 they are used, so the result of calling the references needs
301 to be checked before being used. This can be used to avoid
302 creating references that will cause the garbage collector to
303 keep the values around longer than needed.
304
305 """
Antoine Pitroue10ca3a2016-12-27 14:19:20 +0100306 if self._pending_removals:
307 self._commit_removals()
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000308 return list(self.data.values())
Thomas Wouters477c8d52006-05-27 19:21:47 +0000309
Fred Drake0a4dd392004-07-02 18:57:45 +0000310
311class KeyedRef(ref):
312 """Specialized reference that includes a key corresponding to the value.
313
314 This is used in the WeakValueDictionary to avoid having to create
315 a function object for each key stored in the mapping. A shared
316 callback object can use the 'key' attribute of a KeyedRef instead
317 of getting a reference to the key from an enclosing scope.
318
319 """
320
321 __slots__ = "key",
322
323 def __new__(type, ob, callback, key):
324 self = ref.__new__(type, ob, callback)
325 self.key = key
326 return self
327
328 def __init__(self, ob, callback, key):
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000329 super().__init__(ob, callback)
Fred Drake746fe0f2001-09-28 19:01:26 +0000330
Fred Drake41deb1e2001-02-01 05:27:45 +0000331
Serhiy Storchaka81108372017-09-26 00:55:55 +0300332class WeakKeyDictionary(_collections_abc.MutableMapping):
Fred Drakebd7f8182001-04-19 16:26:06 +0000333 """ Mapping class that references keys weakly.
334
335 Entries in the dictionary will be discarded when there is no
336 longer a strong reference to the key. This can be used to
337 associate additional data with an object owned by other parts of
338 an application without adding attributes to those objects. This
339 can be especially useful with objects that override attribute
340 accesses.
341 """
Martin v. Löwis5e163332001-02-27 18:36:56 +0000342
343 def __init__(self, dict=None):
344 self.data = {}
Fred Drake746fe0f2001-09-28 19:01:26 +0000345 def remove(k, selfref=ref(self)):
346 self = selfref()
347 if self is not None:
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000348 if self._iterating:
349 self._pending_removals.append(k)
350 else:
351 del self.data[k]
Martin v. Löwis5e163332001-02-27 18:36:56 +0000352 self._remove = remove
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000353 # A list of dead weakrefs (keys to be removed)
354 self._pending_removals = []
355 self._iterating = set()
Antoine Pitrou1bf974d2014-10-05 20:02:28 +0200356 self._dirty_len = False
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000357 if dict is not None:
358 self.update(dict)
359
360 def _commit_removals(self):
361 # NOTE: We don't need to call this method before mutating the dict,
362 # because a dead weakref never compares equal to a live weakref,
363 # even if they happened to refer to equal objects.
364 # However, it means keys may already have been removed.
365 l = self._pending_removals
366 d = self.data
367 while l:
368 try:
369 del d[l.pop()]
370 except KeyError:
371 pass
Martin v. Löwis5e163332001-02-27 18:36:56 +0000372
Antoine Pitrou1bf974d2014-10-05 20:02:28 +0200373 def _scrub_removals(self):
374 d = self.data
375 self._pending_removals = [k for k in self._pending_removals if k in d]
376 self._dirty_len = False
377
Fred Drakeb663a2c2001-09-06 14:51:01 +0000378 def __delitem__(self, key):
Antoine Pitrou1bf974d2014-10-05 20:02:28 +0200379 self._dirty_len = True
Tim Peters886128f2003-05-25 01:45:11 +0000380 del self.data[ref(key)]
Fred Drakeb663a2c2001-09-06 14:51:01 +0000381
Martin v. Löwis5e163332001-02-27 18:36:56 +0000382 def __getitem__(self, key):
383 return self.data[ref(key)]
384
Raymond Hettinger7ac60952008-02-05 01:15:57 +0000385 def __len__(self):
Antoine Pitrou1bf974d2014-10-05 20:02:28 +0200386 if self._dirty_len and self._pending_removals:
387 # self._pending_removals may still contain keys which were
388 # explicitly removed, we have to scrub them (see issue #21173).
389 self._scrub_removals()
Antoine Pitroubbe2f602012-03-01 16:26:35 +0100390 return len(self.data) - len(self._pending_removals)
Raymond Hettinger7ac60952008-02-05 01:15:57 +0000391
Martin v. Löwis5e163332001-02-27 18:36:56 +0000392 def __repr__(self):
Serhiy Storchaka465e60e2014-07-25 23:36:00 +0300393 return "<%s at %#x>" % (self.__class__.__name__, id(self))
Martin v. Löwis5e163332001-02-27 18:36:56 +0000394
395 def __setitem__(self, key, value):
396 self.data[ref(key, self._remove)] = value
397
398 def copy(self):
399 new = WeakKeyDictionary()
Fish96d37db2019-02-07 14:51:59 -0500400 with _IterationGuard(self):
401 for key, value in self.data.items():
402 o = key()
403 if o is not None:
404 new[o] = value
Fred Drake9d2c85d2001-03-01 03:06:03 +0000405 return new
Martin v. Löwis5e163332001-02-27 18:36:56 +0000406
Antoine Pitrou6e610062009-05-15 17:04:50 +0000407 __copy__ = copy
408
409 def __deepcopy__(self, memo):
410 from copy import deepcopy
411 new = self.__class__()
Fish96d37db2019-02-07 14:51:59 -0500412 with _IterationGuard(self):
413 for key, value in self.data.items():
414 o = key()
415 if o is not None:
416 new[o] = deepcopy(value, memo)
Antoine Pitrou6e610062009-05-15 17:04:50 +0000417 return new
418
Fred Drake1d9e4b72001-04-16 17:34:48 +0000419 def get(self, key, default=None):
Martin v. Löwis5e163332001-02-27 18:36:56 +0000420 return self.data.get(ref(key),default)
421
Raymond Hettinger54f02222002-06-01 14:18:47 +0000422 def __contains__(self, key):
423 try:
424 wr = ref(key)
425 except TypeError:
Georg Brandlbd87d082010-12-03 07:49:09 +0000426 return False
Raymond Hettinger54f02222002-06-01 14:18:47 +0000427 return wr in self.data
Tim Petersc411dba2002-07-16 21:35:23 +0000428
Martin v. Löwis5e163332001-02-27 18:36:56 +0000429 def items(self):
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000430 with _IterationGuard(self):
431 for wr, value in self.data.items():
432 key = wr()
433 if key is not None:
434 yield key, value
Thomas Wouters477c8d52006-05-27 19:21:47 +0000435
Barry Warsawecaab832008-09-04 01:42:51 +0000436 def keys(self):
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000437 with _IterationGuard(self):
438 for wr in self.data:
439 obj = wr()
440 if obj is not None:
441 yield obj
Raymond Hettinger61146792004-08-19 21:32:06 +0000442
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000443 __iter__ = keys
Fred Drake101209d2001-05-02 05:43:09 +0000444
Barry Warsawecaab832008-09-04 01:42:51 +0000445 def values(self):
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000446 with _IterationGuard(self):
447 for wr, value in self.data.items():
448 if wr() is not None:
449 yield value
Fred Drake101209d2001-05-02 05:43:09 +0000450
Thomas Wouters477c8d52006-05-27 19:21:47 +0000451 def keyrefs(self):
452 """Return a list of weak references to the keys.
453
454 The references are not guaranteed to be 'live' at the time
455 they are used, so the result of calling the references needs
456 to be checked before being used. This can be used to avoid
457 creating references that will cause the garbage collector to
458 keep the keys around longer than needed.
459
460 """
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000461 return list(self.data)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000462
Martin v. Löwis5e163332001-02-27 18:36:56 +0000463 def popitem(self):
Antoine Pitrou1bf974d2014-10-05 20:02:28 +0200464 self._dirty_len = True
Georg Brandlbd87d082010-12-03 07:49:09 +0000465 while True:
Martin v. Löwis5e163332001-02-27 18:36:56 +0000466 key, value = self.data.popitem()
467 o = key()
468 if o is not None:
469 return o, value
470
Raymond Hettinger2c2d3222003-03-09 07:05:43 +0000471 def pop(self, key, *args):
Antoine Pitrou1bf974d2014-10-05 20:02:28 +0200472 self._dirty_len = True
Raymond Hettinger2c2d3222003-03-09 07:05:43 +0000473 return self.data.pop(ref(key), *args)
474
Walter Dörwald80ce6dd2004-05-27 18:16:25 +0000475 def setdefault(self, key, default=None):
Martin v. Löwis5e163332001-02-27 18:36:56 +0000476 return self.data.setdefault(ref(key, self._remove),default)
477
Serhiy Storchaka2085bd02019-06-01 11:00:15 +0300478 def update(self, dict=None, /, **kwargs):
Martin v. Löwis5e163332001-02-27 18:36:56 +0000479 d = self.data
Raymond Hettinger31017ae2004-03-04 08:25:44 +0000480 if dict is not None:
481 if not hasattr(dict, "items"):
482 dict = type({})(dict)
483 for key, value in dict.items():
484 d[ref(key, self._remove)] = value
485 if len(kwargs):
486 self.update(kwargs)
Richard Oudkerk7a3dae02013-05-05 23:05:00 +0100487
488
489class finalize:
490 """Class for finalization of weakrefable objects
491
492 finalize(obj, func, *args, **kwargs) returns a callable finalizer
493 object which will be called when obj is garbage collected. The
494 first time the finalizer is called it evaluates func(*arg, **kwargs)
495 and returns the result. After this the finalizer is dead, and
496 calling it just returns None.
497
498 When the program exits any remaining finalizers for which the
499 atexit attribute is true will be run in reverse order of creation.
500 By default atexit is true.
501 """
502
503 # Finalizer objects don't have any state of their own. They are
504 # just used as keys to lookup _Info objects in the registry. This
505 # ensures that they cannot be part of a ref-cycle.
506
507 __slots__ = ()
508 _registry = {}
509 _shutdown = False
510 _index_iter = itertools.count()
511 _dirty = False
Richard Oudkerka81dd652013-06-08 16:52:29 +0100512 _registered_with_atexit = False
Richard Oudkerk7a3dae02013-05-05 23:05:00 +0100513
514 class _Info:
515 __slots__ = ("weakref", "func", "args", "kwargs", "atexit", "index")
516
Serhiy Storchaka42a139e2019-04-01 09:16:35 +0300517 def __init__(*args, **kwargs):
518 if len(args) >= 3:
519 self, obj, func, *args = args
520 elif not args:
521 raise TypeError("descriptor '__init__' of 'finalize' object "
522 "needs an argument")
523 else:
524 if 'func' not in kwargs:
525 raise TypeError('finalize expected at least 2 positional '
526 'arguments, got %d' % (len(args)-1))
527 func = kwargs.pop('func')
528 if len(args) >= 2:
529 self, obj, *args = args
530 import warnings
531 warnings.warn("Passing 'func' as keyword argument is deprecated",
532 DeprecationWarning, stacklevel=2)
533 else:
534 if 'obj' not in kwargs:
535 raise TypeError('finalize expected at least 2 positional '
536 'arguments, got %d' % (len(args)-1))
537 obj = kwargs.pop('obj')
538 self, *args = args
539 import warnings
540 warnings.warn("Passing 'obj' as keyword argument is deprecated",
541 DeprecationWarning, stacklevel=2)
542 args = tuple(args)
543
Richard Oudkerka81dd652013-06-08 16:52:29 +0100544 if not self._registered_with_atexit:
545 # We may register the exit function more than once because
546 # of a thread race, but that is harmless
547 import atexit
548 atexit.register(self._exitfunc)
549 finalize._registered_with_atexit = True
Richard Oudkerk7a3dae02013-05-05 23:05:00 +0100550 info = self._Info()
551 info.weakref = ref(obj, self)
552 info.func = func
553 info.args = args
554 info.kwargs = kwargs or None
555 info.atexit = True
556 info.index = next(self._index_iter)
557 self._registry[self] = info
558 finalize._dirty = True
Serhiy Storchakad53cf992019-05-06 22:40:27 +0300559 __init__.__text_signature__ = '($self, obj, func, /, *args, **kwargs)'
Richard Oudkerk7a3dae02013-05-05 23:05:00 +0100560
561 def __call__(self, _=None):
562 """If alive then mark as dead and return func(*args, **kwargs);
563 otherwise return None"""
564 info = self._registry.pop(self, None)
565 if info and not self._shutdown:
566 return info.func(*info.args, **(info.kwargs or {}))
567
568 def detach(self):
569 """If alive then mark as dead and return (obj, func, args, kwargs);
570 otherwise return None"""
571 info = self._registry.get(self)
572 obj = info and info.weakref()
573 if obj is not None and self._registry.pop(self, None):
574 return (obj, info.func, info.args, info.kwargs or {})
575
576 def peek(self):
577 """If alive then return (obj, func, args, kwargs);
578 otherwise return None"""
579 info = self._registry.get(self)
580 obj = info and info.weakref()
581 if obj is not None:
582 return (obj, info.func, info.args, info.kwargs or {})
583
584 @property
585 def alive(self):
586 """Whether finalizer is alive"""
587 return self in self._registry
588
589 @property
590 def atexit(self):
591 """Whether finalizer should be called at exit"""
592 info = self._registry.get(self)
593 return bool(info) and info.atexit
594
595 @atexit.setter
596 def atexit(self, value):
597 info = self._registry.get(self)
598 if info:
599 info.atexit = bool(value)
600
601 def __repr__(self):
602 info = self._registry.get(self)
603 obj = info and info.weakref()
604 if obj is None:
605 return '<%s object at %#x; dead>' % (type(self).__name__, id(self))
606 else:
607 return '<%s object at %#x; for %r at %#x>' % \
608 (type(self).__name__, id(self), type(obj).__name__, id(obj))
609
610 @classmethod
611 def _select_for_exit(cls):
612 # Return live finalizers marked for exit, oldest first
613 L = [(f,i) for (f,i) in cls._registry.items() if i.atexit]
614 L.sort(key=lambda item:item[1].index)
615 return [f for (f,i) in L]
616
617 @classmethod
618 def _exitfunc(cls):
619 # At shutdown invoke finalizers for which atexit is true.
620 # This is called once all other non-daemonic threads have been
621 # joined.
622 reenable_gc = False
623 try:
624 if cls._registry:
625 import gc
626 if gc.isenabled():
627 reenable_gc = True
628 gc.disable()
629 pending = None
630 while True:
631 if pending is None or finalize._dirty:
632 pending = cls._select_for_exit()
633 finalize._dirty = False
634 if not pending:
635 break
636 f = pending.pop()
637 try:
638 # gc is disabled, so (assuming no daemonic
639 # threads) the following is the only line in
640 # this function which might trigger creation
641 # of a new finalizer
642 f()
643 except Exception:
644 sys.excepthook(*sys.exc_info())
645 assert f not in cls._registry
646 finally:
647 # prevent any more finalizers from executing during shutdown
648 finalize._shutdown = True
649 if reenable_gc:
650 gc.enable()