blob: 994ea8aa37de583809b01f82d16ca47dbb1cec8a [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
Miss Islington (bot)f7f1c262021-07-30 07:25:28 -07005https://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 Oudkerk7a3dae052013-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 Oudkerk7a3dae052013-05-05 23:05:00 +010033 "WeakSet", "WeakMethod", "finalize"]
Antoine Pitrouc3afba12012-11-17 18:57:38 +010034
35
Raymond Hettinger84ac4372019-11-10 20:12:04 -080036_collections_abc.Set.register(WeakSet)
37_collections_abc.MutableSet.register(WeakSet)
38
Antoine Pitrouc3afba12012-11-17 18:57:38 +010039class WeakMethod(ref):
40 """
41 A custom `weakref.ref` subclass which simulates a weak reference to
42 a bound method, working around the lifetime problem of bound methods.
43 """
44
45 __slots__ = "_func_ref", "_meth_type", "_alive", "__weakref__"
46
47 def __new__(cls, meth, callback=None):
48 try:
49 obj = meth.__self__
50 func = meth.__func__
51 except AttributeError:
52 raise TypeError("argument should be a bound method, not {}"
53 .format(type(meth))) from None
54 def _cb(arg):
55 # The self-weakref trick is needed to avoid creating a reference
56 # cycle.
57 self = self_wr()
58 if self._alive:
59 self._alive = False
60 if callback is not None:
61 callback(self)
62 self = ref.__new__(cls, obj, _cb)
63 self._func_ref = ref(func, _cb)
64 self._meth_type = type(meth)
65 self._alive = True
66 self_wr = ref(self)
67 return self
68
69 def __call__(self):
70 obj = super().__call__()
71 func = self._func_ref()
72 if obj is None or func is None:
73 return None
74 return self._meth_type(func, obj)
75
76 def __eq__(self, other):
77 if isinstance(other, WeakMethod):
78 if not self._alive or not other._alive:
79 return self is other
80 return ref.__eq__(self, other) and self._func_ref == other._func_ref
Serhiy Storchaka662db122019-08-08 08:42:54 +030081 return NotImplemented
Antoine Pitrouc3afba12012-11-17 18:57:38 +010082
83 def __ne__(self, other):
84 if isinstance(other, WeakMethod):
85 if not self._alive or not other._alive:
86 return self is not other
87 return ref.__ne__(self, other) or self._func_ref != other._func_ref
Serhiy Storchaka662db122019-08-08 08:42:54 +030088 return NotImplemented
Antoine Pitrouc3afba12012-11-17 18:57:38 +010089
90 __hash__ = ref.__hash__
Fred Drake41deb1e2001-02-01 05:27:45 +000091
Fred Drake41deb1e2001-02-01 05:27:45 +000092
Serhiy Storchaka81108372017-09-26 00:55:55 +030093class WeakValueDictionary(_collections_abc.MutableMapping):
Fred Drakebd7f8182001-04-19 16:26:06 +000094 """Mapping class that references values weakly.
95
96 Entries in the dictionary will be discarded when no strong
97 reference to the value exists anymore
98 """
Fred Drake41deb1e2001-02-01 05:27:45 +000099 # We inherit the constructor without worrying about the input
100 # dictionary; since it uses our .update() method, we get the right
Fred Drake9d2c85d2001-03-01 03:06:03 +0000101 # checks (if the other dictionary is a WeakValueDictionary,
102 # objects are unwrapped on the way out, and we always wrap on the
103 # way in).
Fred Drake41deb1e2001-02-01 05:27:45 +0000104
Serhiy Storchaka2085bd02019-06-01 11:00:15 +0300105 def __init__(self, other=(), /, **kw):
Ɓukasz Langa9cd7e172017-02-10 00:14:55 -0800106 def remove(wr, selfref=ref(self), _atomic_removal=_remove_dead_weakref):
Fred Drake0a4dd392004-07-02 18:57:45 +0000107 self = selfref()
108 if self is not None:
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000109 if self._iterating:
110 self._pending_removals.append(wr.key)
111 else:
Antoine Pitroue10ca3a2016-12-27 14:19:20 +0100112 # Atomic removal is necessary since this function
113 # can be called asynchronously by the GC
Victor Stinnera2af05a2019-09-09 16:55:58 +0200114 _atomic_removal(self.data, wr.key)
Fred Drake0a4dd392004-07-02 18:57:45 +0000115 self._remove = remove
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000116 # A list of keys to be removed
117 self._pending_removals = []
118 self._iterating = set()
Victor Stinnera2af05a2019-09-09 16:55:58 +0200119 self.data = {}
Serhiy Storchaka2085bd02019-06-01 11:00:15 +0300120 self.update(other, **kw)
Fred Drake0a4dd392004-07-02 18:57:45 +0000121
Miss Islington (bot)8aa64cc2021-08-28 11:09:21 -0700122 def _commit_removals(self, _atomic_removal=_remove_dead_weakref):
123 pop = self._pending_removals.pop
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000124 d = self.data
125 # We shouldn't encounter any KeyError, because this method should
126 # always be called *before* mutating the dict.
Miss Islington (bot)8aa64cc2021-08-28 11:09:21 -0700127 while True:
128 try:
129 key = pop()
130 except IndexError:
131 return
132 _atomic_removal(d, key)
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000133
Fred Drake41deb1e2001-02-01 05:27:45 +0000134 def __getitem__(self, key):
Antoine Pitroue10ca3a2016-12-27 14:19:20 +0100135 if self._pending_removals:
136 self._commit_removals()
Fred Drake4fd06e02001-08-03 04:11:27 +0000137 o = self.data[key]()
Fred Drake41deb1e2001-02-01 05:27:45 +0000138 if o is None:
Collin Winterce36ad82007-08-30 01:19:48 +0000139 raise KeyError(key)
Fred Drake41deb1e2001-02-01 05:27:45 +0000140 else:
141 return o
142
Raymond Hettinger7ac60952008-02-05 01:15:57 +0000143 def __delitem__(self, key):
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000144 if self._pending_removals:
145 self._commit_removals()
Raymond Hettinger7ac60952008-02-05 01:15:57 +0000146 del self.data[key]
147
148 def __len__(self):
Antoine Pitroue10ca3a2016-12-27 14:19:20 +0100149 if self._pending_removals:
150 self._commit_removals()
151 return len(self.data)
Raymond Hettinger7ac60952008-02-05 01:15:57 +0000152
Raymond Hettinger61146792004-08-19 21:32:06 +0000153 def __contains__(self, key):
Antoine Pitroue10ca3a2016-12-27 14:19:20 +0100154 if self._pending_removals:
155 self._commit_removals()
Raymond Hettinger61146792004-08-19 21:32:06 +0000156 try:
157 o = self.data[key]()
158 except KeyError:
159 return False
160 return o is not None
161
Fred Drake41deb1e2001-02-01 05:27:45 +0000162 def __repr__(self):
Serhiy Storchaka465e60e2014-07-25 23:36:00 +0300163 return "<%s at %#x>" % (self.__class__.__name__, id(self))
Fred Drake41deb1e2001-02-01 05:27:45 +0000164
165 def __setitem__(self, key, value):
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000166 if self._pending_removals:
167 self._commit_removals()
Fred Drake0a4dd392004-07-02 18:57:45 +0000168 self.data[key] = KeyedRef(value, self._remove, key)
Fred Drake41deb1e2001-02-01 05:27:45 +0000169
170 def copy(self):
Antoine Pitroue10ca3a2016-12-27 14:19:20 +0100171 if self._pending_removals:
172 self._commit_removals()
Fred Drake9d2c85d2001-03-01 03:06:03 +0000173 new = WeakValueDictionary()
Fish96d37db2019-02-07 14:51:59 -0500174 with _IterationGuard(self):
175 for key, wr in self.data.items():
176 o = wr()
177 if o is not None:
178 new[key] = o
Fred Drake9d2c85d2001-03-01 03:06:03 +0000179 return new
Fred Drake41deb1e2001-02-01 05:27:45 +0000180
Antoine Pitrou6e610062009-05-15 17:04:50 +0000181 __copy__ = copy
182
183 def __deepcopy__(self, memo):
184 from copy import deepcopy
Antoine Pitroue10ca3a2016-12-27 14:19:20 +0100185 if self._pending_removals:
186 self._commit_removals()
Antoine Pitrou6e610062009-05-15 17:04:50 +0000187 new = self.__class__()
Fish96d37db2019-02-07 14:51:59 -0500188 with _IterationGuard(self):
189 for key, wr in self.data.items():
190 o = wr()
191 if o is not None:
192 new[deepcopy(key, memo)] = o
Antoine Pitrou6e610062009-05-15 17:04:50 +0000193 return new
194
Fred Drake1d9e4b72001-04-16 17:34:48 +0000195 def get(self, key, default=None):
Antoine Pitroue10ca3a2016-12-27 14:19:20 +0100196 if self._pending_removals:
197 self._commit_removals()
Fred Drake41deb1e2001-02-01 05:27:45 +0000198 try:
Fred Drakebd7f8182001-04-19 16:26:06 +0000199 wr = self.data[key]
Fred Drake41deb1e2001-02-01 05:27:45 +0000200 except KeyError:
201 return default
202 else:
Fred Drakebd7f8182001-04-19 16:26:06 +0000203 o = wr()
Fred Drake41deb1e2001-02-01 05:27:45 +0000204 if o is None:
205 # This should only happen
206 return default
207 else:
208 return o
209
210 def items(self):
Antoine Pitroue10ca3a2016-12-27 14:19:20 +0100211 if self._pending_removals:
212 self._commit_removals()
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000213 with _IterationGuard(self):
214 for k, wr in self.data.items():
215 v = wr()
216 if v is not None:
217 yield k, v
Fred Drake101209d2001-05-02 05:43:09 +0000218
Barry Warsawecaab832008-09-04 01:42:51 +0000219 def keys(self):
Antoine Pitroue10ca3a2016-12-27 14:19:20 +0100220 if self._pending_removals:
221 self._commit_removals()
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000222 with _IterationGuard(self):
223 for k, wr in self.data.items():
224 if wr() is not None:
225 yield k
Raymond Hettinger61146792004-08-19 21:32:06 +0000226
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000227 __iter__ = keys
Fred Drake101209d2001-05-02 05:43:09 +0000228
Thomas Wouters477c8d52006-05-27 19:21:47 +0000229 def itervaluerefs(self):
230 """Return an iterator that yields the weak references to the values.
231
232 The references are not guaranteed to be 'live' at the time
233 they are used, so the result of calling the references needs
234 to be checked before being used. This can be used to avoid
235 creating references that will cause the garbage collector to
236 keep the values around longer than needed.
237
238 """
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):
Philip Jenvey4993cc02012-10-01 12:53:43 -0700242 yield from self.data.values()
Thomas Wouters477c8d52006-05-27 19:21:47 +0000243
Barry Warsawecaab832008-09-04 01:42:51 +0000244 def values(self):
Antoine Pitroue10ca3a2016-12-27 14:19:20 +0100245 if self._pending_removals:
246 self._commit_removals()
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000247 with _IterationGuard(self):
248 for wr in self.data.values():
249 obj = wr()
250 if obj is not None:
251 yield obj
Fred Drake101209d2001-05-02 05:43:09 +0000252
Fred Drake41deb1e2001-02-01 05:27:45 +0000253 def popitem(self):
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000254 if self._pending_removals:
255 self._commit_removals()
Georg Brandlbd87d082010-12-03 07:49:09 +0000256 while True:
Fred Drakebd7f8182001-04-19 16:26:06 +0000257 key, wr = self.data.popitem()
258 o = wr()
Fred Drake41deb1e2001-02-01 05:27:45 +0000259 if o is not None:
260 return key, o
261
Raymond Hettinger2c2d3222003-03-09 07:05:43 +0000262 def pop(self, key, *args):
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000263 if self._pending_removals:
264 self._commit_removals()
Raymond Hettinger2c2d3222003-03-09 07:05:43 +0000265 try:
266 o = self.data.pop(key)()
267 except KeyError:
Antoine Pitrouc1ee4882016-12-19 10:56:40 +0100268 o = None
269 if o is None:
Raymond Hettinger2c2d3222003-03-09 07:05:43 +0000270 if args:
271 return args[0]
Antoine Pitrouc1ee4882016-12-19 10:56:40 +0100272 else:
273 raise KeyError(key)
Raymond Hettinger2c2d3222003-03-09 07:05:43 +0000274 else:
275 return o
276
Walter Dörwald80ce6dd2004-05-27 18:16:25 +0000277 def setdefault(self, key, default=None):
Fred Drake41deb1e2001-02-01 05:27:45 +0000278 try:
Antoine Pitrouc1ee4882016-12-19 10:56:40 +0100279 o = self.data[key]()
Fred Drake41deb1e2001-02-01 05:27:45 +0000280 except KeyError:
Antoine Pitrouc1ee4882016-12-19 10:56:40 +0100281 o = None
282 if o is None:
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000283 if self._pending_removals:
284 self._commit_removals()
Fred Drake0a4dd392004-07-02 18:57:45 +0000285 self.data[key] = KeyedRef(default, self._remove, key)
Fred Drake41deb1e2001-02-01 05:27:45 +0000286 return default
287 else:
Antoine Pitrouc1ee4882016-12-19 10:56:40 +0100288 return o
Fred Drake41deb1e2001-02-01 05:27:45 +0000289
Serhiy Storchaka2085bd02019-06-01 11:00:15 +0300290 def update(self, other=None, /, **kwargs):
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000291 if self._pending_removals:
292 self._commit_removals()
Fred Drake41deb1e2001-02-01 05:27:45 +0000293 d = self.data
Serhiy Storchaka2085bd02019-06-01 11:00:15 +0300294 if other is not None:
295 if not hasattr(other, "items"):
296 other = dict(other)
297 for key, o in other.items():
Fred Drake0a4dd392004-07-02 18:57:45 +0000298 d[key] = KeyedRef(o, self._remove, key)
Serhiy Storchaka2085bd02019-06-01 11:00:15 +0300299 for key, o in kwargs.items():
300 d[key] = KeyedRef(o, self._remove, key)
Fred Drake41deb1e2001-02-01 05:27:45 +0000301
Thomas Wouters477c8d52006-05-27 19:21:47 +0000302 def valuerefs(self):
303 """Return a list of weak references to the values.
304
305 The references are not guaranteed to be 'live' at the time
306 they are used, so the result of calling the references needs
307 to be checked before being used. This can be used to avoid
308 creating references that will cause the garbage collector to
309 keep the values around longer than needed.
310
311 """
Antoine Pitroue10ca3a2016-12-27 14:19:20 +0100312 if self._pending_removals:
313 self._commit_removals()
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000314 return list(self.data.values())
Thomas Wouters477c8d52006-05-27 19:21:47 +0000315
Curtis Bucher8f1ed212020-03-24 18:51:29 -0700316 def __ior__(self, other):
317 self.update(other)
318 return self
319
320 def __or__(self, other):
321 if isinstance(other, _collections_abc.Mapping):
322 c = self.copy()
323 c.update(other)
324 return c
325 return NotImplemented
326
327 def __ror__(self, other):
328 if isinstance(other, _collections_abc.Mapping):
329 c = self.__class__()
330 c.update(other)
331 c.update(self)
332 return c
333 return NotImplemented
334
Fred Drake0a4dd392004-07-02 18:57:45 +0000335
336class KeyedRef(ref):
337 """Specialized reference that includes a key corresponding to the value.
338
339 This is used in the WeakValueDictionary to avoid having to create
340 a function object for each key stored in the mapping. A shared
341 callback object can use the 'key' attribute of a KeyedRef instead
342 of getting a reference to the key from an enclosing scope.
343
344 """
345
346 __slots__ = "key",
347
348 def __new__(type, ob, callback, key):
349 self = ref.__new__(type, ob, callback)
350 self.key = key
351 return self
352
353 def __init__(self, ob, callback, key):
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000354 super().__init__(ob, callback)
Fred Drake746fe0f2001-09-28 19:01:26 +0000355
Fred Drake41deb1e2001-02-01 05:27:45 +0000356
Serhiy Storchaka81108372017-09-26 00:55:55 +0300357class WeakKeyDictionary(_collections_abc.MutableMapping):
Fred Drakebd7f8182001-04-19 16:26:06 +0000358 """ Mapping class that references keys weakly.
359
360 Entries in the dictionary will be discarded when there is no
361 longer a strong reference to the key. This can be used to
362 associate additional data with an object owned by other parts of
363 an application without adding attributes to those objects. This
364 can be especially useful with objects that override attribute
365 accesses.
366 """
Martin v. Löwis5e163332001-02-27 18:36:56 +0000367
368 def __init__(self, dict=None):
369 self.data = {}
Fred Drake746fe0f2001-09-28 19:01:26 +0000370 def remove(k, selfref=ref(self)):
371 self = selfref()
372 if self is not None:
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000373 if self._iterating:
374 self._pending_removals.append(k)
375 else:
Miss Islington (bot)8aa64cc2021-08-28 11:09:21 -0700376 try:
377 del self.data[k]
378 except KeyError:
379 pass
Martin v. Löwis5e163332001-02-27 18:36:56 +0000380 self._remove = remove
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000381 # A list of dead weakrefs (keys to be removed)
382 self._pending_removals = []
383 self._iterating = set()
Antoine Pitrou1bf974d2014-10-05 20:02:28 +0200384 self._dirty_len = False
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000385 if dict is not None:
386 self.update(dict)
387
388 def _commit_removals(self):
389 # NOTE: We don't need to call this method before mutating the dict,
390 # because a dead weakref never compares equal to a live weakref,
391 # even if they happened to refer to equal objects.
392 # However, it means keys may already have been removed.
Miss Islington (bot)8aa64cc2021-08-28 11:09:21 -0700393 pop = self._pending_removals.pop
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000394 d = self.data
Miss Islington (bot)8aa64cc2021-08-28 11:09:21 -0700395 while True:
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000396 try:
Miss Islington (bot)8aa64cc2021-08-28 11:09:21 -0700397 key = pop()
398 except IndexError:
399 return
400
401 try:
402 del d[key]
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000403 except KeyError:
404 pass
Martin v. Löwis5e163332001-02-27 18:36:56 +0000405
Antoine Pitrou1bf974d2014-10-05 20:02:28 +0200406 def _scrub_removals(self):
407 d = self.data
408 self._pending_removals = [k for k in self._pending_removals if k in d]
409 self._dirty_len = False
410
Fred Drakeb663a2c2001-09-06 14:51:01 +0000411 def __delitem__(self, key):
Antoine Pitrou1bf974d2014-10-05 20:02:28 +0200412 self._dirty_len = True
Tim Peters886128f2003-05-25 01:45:11 +0000413 del self.data[ref(key)]
Fred Drakeb663a2c2001-09-06 14:51:01 +0000414
Martin v. Löwis5e163332001-02-27 18:36:56 +0000415 def __getitem__(self, key):
416 return self.data[ref(key)]
417
Raymond Hettinger7ac60952008-02-05 01:15:57 +0000418 def __len__(self):
Antoine Pitrou1bf974d2014-10-05 20:02:28 +0200419 if self._dirty_len and self._pending_removals:
420 # self._pending_removals may still contain keys which were
421 # explicitly removed, we have to scrub them (see issue #21173).
422 self._scrub_removals()
Antoine Pitroubbe2f602012-03-01 16:26:35 +0100423 return len(self.data) - len(self._pending_removals)
Raymond Hettinger7ac60952008-02-05 01:15:57 +0000424
Martin v. Löwis5e163332001-02-27 18:36:56 +0000425 def __repr__(self):
Serhiy Storchaka465e60e2014-07-25 23:36:00 +0300426 return "<%s at %#x>" % (self.__class__.__name__, id(self))
Martin v. Löwis5e163332001-02-27 18:36:56 +0000427
428 def __setitem__(self, key, value):
429 self.data[ref(key, self._remove)] = value
430
431 def copy(self):
432 new = WeakKeyDictionary()
Fish96d37db2019-02-07 14:51:59 -0500433 with _IterationGuard(self):
434 for key, value in self.data.items():
435 o = key()
436 if o is not None:
437 new[o] = value
Fred Drake9d2c85d2001-03-01 03:06:03 +0000438 return new
Martin v. Löwis5e163332001-02-27 18:36:56 +0000439
Antoine Pitrou6e610062009-05-15 17:04:50 +0000440 __copy__ = copy
441
442 def __deepcopy__(self, memo):
443 from copy import deepcopy
444 new = self.__class__()
Fish96d37db2019-02-07 14:51:59 -0500445 with _IterationGuard(self):
446 for key, value in self.data.items():
447 o = key()
448 if o is not None:
449 new[o] = deepcopy(value, memo)
Antoine Pitrou6e610062009-05-15 17:04:50 +0000450 return new
451
Fred Drake1d9e4b72001-04-16 17:34:48 +0000452 def get(self, key, default=None):
Martin v. Löwis5e163332001-02-27 18:36:56 +0000453 return self.data.get(ref(key),default)
454
Raymond Hettinger54f02222002-06-01 14:18:47 +0000455 def __contains__(self, key):
456 try:
457 wr = ref(key)
458 except TypeError:
Georg Brandlbd87d082010-12-03 07:49:09 +0000459 return False
Raymond Hettinger54f02222002-06-01 14:18:47 +0000460 return wr in self.data
Tim Petersc411dba2002-07-16 21:35:23 +0000461
Martin v. Löwis5e163332001-02-27 18:36:56 +0000462 def items(self):
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000463 with _IterationGuard(self):
464 for wr, value in self.data.items():
465 key = wr()
466 if key is not None:
467 yield key, value
Thomas Wouters477c8d52006-05-27 19:21:47 +0000468
Barry Warsawecaab832008-09-04 01:42:51 +0000469 def keys(self):
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000470 with _IterationGuard(self):
471 for wr in self.data:
472 obj = wr()
473 if obj is not None:
474 yield obj
Raymond Hettinger61146792004-08-19 21:32:06 +0000475
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000476 __iter__ = keys
Fred Drake101209d2001-05-02 05:43:09 +0000477
Barry Warsawecaab832008-09-04 01:42:51 +0000478 def values(self):
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000479 with _IterationGuard(self):
480 for wr, value in self.data.items():
481 if wr() is not None:
482 yield value
Fred Drake101209d2001-05-02 05:43:09 +0000483
Thomas Wouters477c8d52006-05-27 19:21:47 +0000484 def keyrefs(self):
485 """Return a list of weak references to the keys.
486
487 The references are not guaranteed to be 'live' at the time
488 they are used, so the result of calling the references needs
489 to be checked before being used. This can be used to avoid
490 creating references that will cause the garbage collector to
491 keep the keys around longer than needed.
492
493 """
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000494 return list(self.data)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000495
Martin v. Löwis5e163332001-02-27 18:36:56 +0000496 def popitem(self):
Antoine Pitrou1bf974d2014-10-05 20:02:28 +0200497 self._dirty_len = True
Georg Brandlbd87d082010-12-03 07:49:09 +0000498 while True:
Martin v. Löwis5e163332001-02-27 18:36:56 +0000499 key, value = self.data.popitem()
500 o = key()
501 if o is not None:
502 return o, value
503
Raymond Hettinger2c2d3222003-03-09 07:05:43 +0000504 def pop(self, key, *args):
Antoine Pitrou1bf974d2014-10-05 20:02:28 +0200505 self._dirty_len = True
Raymond Hettinger2c2d3222003-03-09 07:05:43 +0000506 return self.data.pop(ref(key), *args)
507
Walter Dörwald80ce6dd2004-05-27 18:16:25 +0000508 def setdefault(self, key, default=None):
Martin v. Löwis5e163332001-02-27 18:36:56 +0000509 return self.data.setdefault(ref(key, self._remove),default)
510
Serhiy Storchaka2085bd02019-06-01 11:00:15 +0300511 def update(self, dict=None, /, **kwargs):
Martin v. Löwis5e163332001-02-27 18:36:56 +0000512 d = self.data
Raymond Hettinger31017ae2004-03-04 08:25:44 +0000513 if dict is not None:
514 if not hasattr(dict, "items"):
515 dict = type({})(dict)
516 for key, value in dict.items():
517 d[ref(key, self._remove)] = value
518 if len(kwargs):
519 self.update(kwargs)
Richard Oudkerk7a3dae052013-05-05 23:05:00 +0100520
Curtis Bucher25e580a2020-03-23 13:49:46 -0700521 def __ior__(self, other):
522 self.update(other)
523 return self
524
525 def __or__(self, other):
526 if isinstance(other, _collections_abc.Mapping):
527 c = self.copy()
528 c.update(other)
529 return c
530 return NotImplemented
531
532 def __ror__(self, other):
533 if isinstance(other, _collections_abc.Mapping):
534 c = self.__class__()
535 c.update(other)
536 c.update(self)
537 return c
538 return NotImplemented
539
Richard Oudkerk7a3dae052013-05-05 23:05:00 +0100540
541class finalize:
542 """Class for finalization of weakrefable objects
543
544 finalize(obj, func, *args, **kwargs) returns a callable finalizer
545 object which will be called when obj is garbage collected. The
546 first time the finalizer is called it evaluates func(*arg, **kwargs)
547 and returns the result. After this the finalizer is dead, and
548 calling it just returns None.
549
550 When the program exits any remaining finalizers for which the
551 atexit attribute is true will be run in reverse order of creation.
552 By default atexit is true.
553 """
554
555 # Finalizer objects don't have any state of their own. They are
556 # just used as keys to lookup _Info objects in the registry. This
557 # ensures that they cannot be part of a ref-cycle.
558
559 __slots__ = ()
560 _registry = {}
561 _shutdown = False
562 _index_iter = itertools.count()
563 _dirty = False
Richard Oudkerka81dd652013-06-08 16:52:29 +0100564 _registered_with_atexit = False
Richard Oudkerk7a3dae052013-05-05 23:05:00 +0100565
566 class _Info:
567 __slots__ = ("weakref", "func", "args", "kwargs", "atexit", "index")
568
Serhiy Storchaka142566c2019-06-05 18:22:31 +0300569 def __init__(self, obj, func, /, *args, **kwargs):
Richard Oudkerka81dd652013-06-08 16:52:29 +0100570 if not self._registered_with_atexit:
571 # We may register the exit function more than once because
572 # of a thread race, but that is harmless
573 import atexit
574 atexit.register(self._exitfunc)
575 finalize._registered_with_atexit = True
Richard Oudkerk7a3dae052013-05-05 23:05:00 +0100576 info = self._Info()
577 info.weakref = ref(obj, self)
578 info.func = func
579 info.args = args
580 info.kwargs = kwargs or None
581 info.atexit = True
582 info.index = next(self._index_iter)
583 self._registry[self] = info
584 finalize._dirty = True
585
586 def __call__(self, _=None):
587 """If alive then mark as dead and return func(*args, **kwargs);
588 otherwise return None"""
589 info = self._registry.pop(self, None)
590 if info and not self._shutdown:
591 return info.func(*info.args, **(info.kwargs or {}))
592
593 def detach(self):
594 """If alive then mark as dead and return (obj, func, args, kwargs);
595 otherwise return None"""
596 info = self._registry.get(self)
597 obj = info and info.weakref()
598 if obj is not None and self._registry.pop(self, None):
599 return (obj, info.func, info.args, info.kwargs or {})
600
601 def peek(self):
602 """If alive then return (obj, func, args, kwargs);
603 otherwise return None"""
604 info = self._registry.get(self)
605 obj = info and info.weakref()
606 if obj is not None:
607 return (obj, info.func, info.args, info.kwargs or {})
608
609 @property
610 def alive(self):
611 """Whether finalizer is alive"""
612 return self in self._registry
613
614 @property
615 def atexit(self):
616 """Whether finalizer should be called at exit"""
617 info = self._registry.get(self)
618 return bool(info) and info.atexit
619
620 @atexit.setter
621 def atexit(self, value):
622 info = self._registry.get(self)
623 if info:
624 info.atexit = bool(value)
625
626 def __repr__(self):
627 info = self._registry.get(self)
628 obj = info and info.weakref()
629 if obj is None:
630 return '<%s object at %#x; dead>' % (type(self).__name__, id(self))
631 else:
632 return '<%s object at %#x; for %r at %#x>' % \
633 (type(self).__name__, id(self), type(obj).__name__, id(obj))
634
635 @classmethod
636 def _select_for_exit(cls):
637 # Return live finalizers marked for exit, oldest first
638 L = [(f,i) for (f,i) in cls._registry.items() if i.atexit]
639 L.sort(key=lambda item:item[1].index)
640 return [f for (f,i) in L]
641
642 @classmethod
643 def _exitfunc(cls):
644 # At shutdown invoke finalizers for which atexit is true.
645 # This is called once all other non-daemonic threads have been
646 # joined.
647 reenable_gc = False
648 try:
649 if cls._registry:
650 import gc
651 if gc.isenabled():
652 reenable_gc = True
653 gc.disable()
654 pending = None
655 while True:
656 if pending is None or finalize._dirty:
657 pending = cls._select_for_exit()
658 finalize._dirty = False
659 if not pending:
660 break
661 f = pending.pop()
662 try:
663 # gc is disabled, so (assuming no daemonic
664 # threads) the following is the only line in
665 # this function which might trigger creation
666 # of a new finalizer
667 f()
668 except Exception:
669 sys.excepthook(*sys.exc_info())
670 assert f not in cls._registry
671 finally:
672 # prevent any more finalizers from executing during shutdown
673 finalize._shutdown = True
674 if reenable_gc:
675 gc.enable()