blob: e3c2ce2d9b8b865d9e3a8183c4fcd42f49571fba [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
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
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000122 def _commit_removals(self):
123 l = self._pending_removals
124 d = self.data
125 # We shouldn't encounter any KeyError, because this method should
126 # always be called *before* mutating the dict.
127 while l:
Antoine Pitroue10ca3a2016-12-27 14:19:20 +0100128 key = l.pop()
129 _remove_dead_weakref(d, key)
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000130
Fred Drake41deb1e2001-02-01 05:27:45 +0000131 def __getitem__(self, key):
Antoine Pitroue10ca3a2016-12-27 14:19:20 +0100132 if self._pending_removals:
133 self._commit_removals()
Fred Drake4fd06e02001-08-03 04:11:27 +0000134 o = self.data[key]()
Fred Drake41deb1e2001-02-01 05:27:45 +0000135 if o is None:
Collin Winterce36ad82007-08-30 01:19:48 +0000136 raise KeyError(key)
Fred Drake41deb1e2001-02-01 05:27:45 +0000137 else:
138 return o
139
Raymond Hettinger7ac60952008-02-05 01:15:57 +0000140 def __delitem__(self, key):
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000141 if self._pending_removals:
142 self._commit_removals()
Raymond Hettinger7ac60952008-02-05 01:15:57 +0000143 del self.data[key]
144
145 def __len__(self):
Antoine Pitroue10ca3a2016-12-27 14:19:20 +0100146 if self._pending_removals:
147 self._commit_removals()
148 return len(self.data)
Raymond Hettinger7ac60952008-02-05 01:15:57 +0000149
Raymond Hettinger61146792004-08-19 21:32:06 +0000150 def __contains__(self, key):
Antoine Pitroue10ca3a2016-12-27 14:19:20 +0100151 if self._pending_removals:
152 self._commit_removals()
Raymond Hettinger61146792004-08-19 21:32:06 +0000153 try:
154 o = self.data[key]()
155 except KeyError:
156 return False
157 return o is not None
158
Fred Drake41deb1e2001-02-01 05:27:45 +0000159 def __repr__(self):
Serhiy Storchaka465e60e2014-07-25 23:36:00 +0300160 return "<%s at %#x>" % (self.__class__.__name__, id(self))
Fred Drake41deb1e2001-02-01 05:27:45 +0000161
162 def __setitem__(self, key, value):
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000163 if self._pending_removals:
164 self._commit_removals()
Fred Drake0a4dd392004-07-02 18:57:45 +0000165 self.data[key] = KeyedRef(value, self._remove, key)
Fred Drake41deb1e2001-02-01 05:27:45 +0000166
167 def copy(self):
Antoine Pitroue10ca3a2016-12-27 14:19:20 +0100168 if self._pending_removals:
169 self._commit_removals()
Fred Drake9d2c85d2001-03-01 03:06:03 +0000170 new = WeakValueDictionary()
Fish96d37db2019-02-07 14:51:59 -0500171 with _IterationGuard(self):
172 for key, wr in self.data.items():
173 o = wr()
174 if o is not None:
175 new[key] = o
Fred Drake9d2c85d2001-03-01 03:06:03 +0000176 return new
Fred Drake41deb1e2001-02-01 05:27:45 +0000177
Antoine Pitrou6e610062009-05-15 17:04:50 +0000178 __copy__ = copy
179
180 def __deepcopy__(self, memo):
181 from copy import deepcopy
Antoine Pitroue10ca3a2016-12-27 14:19:20 +0100182 if self._pending_removals:
183 self._commit_removals()
Antoine Pitrou6e610062009-05-15 17:04:50 +0000184 new = self.__class__()
Fish96d37db2019-02-07 14:51:59 -0500185 with _IterationGuard(self):
186 for key, wr in self.data.items():
187 o = wr()
188 if o is not None:
189 new[deepcopy(key, memo)] = o
Antoine Pitrou6e610062009-05-15 17:04:50 +0000190 return new
191
Fred Drake1d9e4b72001-04-16 17:34:48 +0000192 def get(self, key, default=None):
Antoine Pitroue10ca3a2016-12-27 14:19:20 +0100193 if self._pending_removals:
194 self._commit_removals()
Fred Drake41deb1e2001-02-01 05:27:45 +0000195 try:
Fred Drakebd7f8182001-04-19 16:26:06 +0000196 wr = self.data[key]
Fred Drake41deb1e2001-02-01 05:27:45 +0000197 except KeyError:
198 return default
199 else:
Fred Drakebd7f8182001-04-19 16:26:06 +0000200 o = wr()
Fred Drake41deb1e2001-02-01 05:27:45 +0000201 if o is None:
202 # This should only happen
203 return default
204 else:
205 return o
206
207 def items(self):
Antoine Pitroue10ca3a2016-12-27 14:19:20 +0100208 if self._pending_removals:
209 self._commit_removals()
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000210 with _IterationGuard(self):
211 for k, wr in self.data.items():
212 v = wr()
213 if v is not None:
214 yield k, v
Fred Drake101209d2001-05-02 05:43:09 +0000215
Barry Warsawecaab832008-09-04 01:42:51 +0000216 def keys(self):
Antoine Pitroue10ca3a2016-12-27 14:19:20 +0100217 if self._pending_removals:
218 self._commit_removals()
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000219 with _IterationGuard(self):
220 for k, wr in self.data.items():
221 if wr() is not None:
222 yield k
Raymond Hettinger61146792004-08-19 21:32:06 +0000223
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000224 __iter__ = keys
Fred Drake101209d2001-05-02 05:43:09 +0000225
Thomas Wouters477c8d52006-05-27 19:21:47 +0000226 def itervaluerefs(self):
227 """Return an iterator that yields the weak references to the values.
228
229 The references are not guaranteed to be 'live' at the time
230 they are used, so the result of calling the references needs
231 to be checked before being used. This can be used to avoid
232 creating references that will cause the garbage collector to
233 keep the values around longer than needed.
234
235 """
Antoine Pitroue10ca3a2016-12-27 14:19:20 +0100236 if self._pending_removals:
237 self._commit_removals()
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000238 with _IterationGuard(self):
Philip Jenvey4993cc02012-10-01 12:53:43 -0700239 yield from self.data.values()
Thomas Wouters477c8d52006-05-27 19:21:47 +0000240
Barry Warsawecaab832008-09-04 01:42:51 +0000241 def values(self):
Antoine Pitroue10ca3a2016-12-27 14:19:20 +0100242 if self._pending_removals:
243 self._commit_removals()
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000244 with _IterationGuard(self):
245 for wr in self.data.values():
246 obj = wr()
247 if obj is not None:
248 yield obj
Fred Drake101209d2001-05-02 05:43:09 +0000249
Fred Drake41deb1e2001-02-01 05:27:45 +0000250 def popitem(self):
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000251 if self._pending_removals:
252 self._commit_removals()
Georg Brandlbd87d082010-12-03 07:49:09 +0000253 while True:
Fred Drakebd7f8182001-04-19 16:26:06 +0000254 key, wr = self.data.popitem()
255 o = wr()
Fred Drake41deb1e2001-02-01 05:27:45 +0000256 if o is not None:
257 return key, o
258
Raymond Hettinger2c2d3222003-03-09 07:05:43 +0000259 def pop(self, key, *args):
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000260 if self._pending_removals:
261 self._commit_removals()
Raymond Hettinger2c2d3222003-03-09 07:05:43 +0000262 try:
263 o = self.data.pop(key)()
264 except KeyError:
Antoine Pitrouc1ee4882016-12-19 10:56:40 +0100265 o = None
266 if o is None:
Raymond Hettinger2c2d3222003-03-09 07:05:43 +0000267 if args:
268 return args[0]
Antoine Pitrouc1ee4882016-12-19 10:56:40 +0100269 else:
270 raise KeyError(key)
Raymond Hettinger2c2d3222003-03-09 07:05:43 +0000271 else:
272 return o
273
Walter Dörwald80ce6dd2004-05-27 18:16:25 +0000274 def setdefault(self, key, default=None):
Fred Drake41deb1e2001-02-01 05:27:45 +0000275 try:
Antoine Pitrouc1ee4882016-12-19 10:56:40 +0100276 o = self.data[key]()
Fred Drake41deb1e2001-02-01 05:27:45 +0000277 except KeyError:
Antoine Pitrouc1ee4882016-12-19 10:56:40 +0100278 o = None
279 if o is None:
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000280 if self._pending_removals:
281 self._commit_removals()
Fred Drake0a4dd392004-07-02 18:57:45 +0000282 self.data[key] = KeyedRef(default, self._remove, key)
Fred Drake41deb1e2001-02-01 05:27:45 +0000283 return default
284 else:
Antoine Pitrouc1ee4882016-12-19 10:56:40 +0100285 return o
Fred Drake41deb1e2001-02-01 05:27:45 +0000286
Serhiy Storchaka2085bd02019-06-01 11:00:15 +0300287 def update(self, other=None, /, **kwargs):
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000288 if self._pending_removals:
289 self._commit_removals()
Fred Drake41deb1e2001-02-01 05:27:45 +0000290 d = self.data
Serhiy Storchaka2085bd02019-06-01 11:00:15 +0300291 if other is not None:
292 if not hasattr(other, "items"):
293 other = dict(other)
294 for key, o in other.items():
Fred Drake0a4dd392004-07-02 18:57:45 +0000295 d[key] = KeyedRef(o, self._remove, key)
Serhiy Storchaka2085bd02019-06-01 11:00:15 +0300296 for key, o in kwargs.items():
297 d[key] = KeyedRef(o, self._remove, key)
Fred Drake41deb1e2001-02-01 05:27:45 +0000298
Thomas Wouters477c8d52006-05-27 19:21:47 +0000299 def valuerefs(self):
300 """Return a list of weak references to the values.
301
302 The references are not guaranteed to be 'live' at the time
303 they are used, so the result of calling the references needs
304 to be checked before being used. This can be used to avoid
305 creating references that will cause the garbage collector to
306 keep the values around longer than needed.
307
308 """
Antoine Pitroue10ca3a2016-12-27 14:19:20 +0100309 if self._pending_removals:
310 self._commit_removals()
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000311 return list(self.data.values())
Thomas Wouters477c8d52006-05-27 19:21:47 +0000312
Fred Drake0a4dd392004-07-02 18:57:45 +0000313
314class KeyedRef(ref):
315 """Specialized reference that includes a key corresponding to the value.
316
317 This is used in the WeakValueDictionary to avoid having to create
318 a function object for each key stored in the mapping. A shared
319 callback object can use the 'key' attribute of a KeyedRef instead
320 of getting a reference to the key from an enclosing scope.
321
322 """
323
324 __slots__ = "key",
325
326 def __new__(type, ob, callback, key):
327 self = ref.__new__(type, ob, callback)
328 self.key = key
329 return self
330
331 def __init__(self, ob, callback, key):
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000332 super().__init__(ob, callback)
Fred Drake746fe0f2001-09-28 19:01:26 +0000333
Fred Drake41deb1e2001-02-01 05:27:45 +0000334
Serhiy Storchaka81108372017-09-26 00:55:55 +0300335class WeakKeyDictionary(_collections_abc.MutableMapping):
Fred Drakebd7f8182001-04-19 16:26:06 +0000336 """ Mapping class that references keys weakly.
337
338 Entries in the dictionary will be discarded when there is no
339 longer a strong reference to the key. This can be used to
340 associate additional data with an object owned by other parts of
341 an application without adding attributes to those objects. This
342 can be especially useful with objects that override attribute
343 accesses.
344 """
Martin v. Löwis5e163332001-02-27 18:36:56 +0000345
346 def __init__(self, dict=None):
347 self.data = {}
Fred Drake746fe0f2001-09-28 19:01:26 +0000348 def remove(k, selfref=ref(self)):
349 self = selfref()
350 if self is not None:
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000351 if self._iterating:
352 self._pending_removals.append(k)
353 else:
354 del self.data[k]
Martin v. Löwis5e163332001-02-27 18:36:56 +0000355 self._remove = remove
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000356 # A list of dead weakrefs (keys to be removed)
357 self._pending_removals = []
358 self._iterating = set()
Antoine Pitrou1bf974d2014-10-05 20:02:28 +0200359 self._dirty_len = False
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000360 if dict is not None:
361 self.update(dict)
362
363 def _commit_removals(self):
364 # NOTE: We don't need to call this method before mutating the dict,
365 # because a dead weakref never compares equal to a live weakref,
366 # even if they happened to refer to equal objects.
367 # However, it means keys may already have been removed.
368 l = self._pending_removals
369 d = self.data
370 while l:
371 try:
372 del d[l.pop()]
373 except KeyError:
374 pass
Martin v. Löwis5e163332001-02-27 18:36:56 +0000375
Antoine Pitrou1bf974d2014-10-05 20:02:28 +0200376 def _scrub_removals(self):
377 d = self.data
378 self._pending_removals = [k for k in self._pending_removals if k in d]
379 self._dirty_len = False
380
Fred Drakeb663a2c2001-09-06 14:51:01 +0000381 def __delitem__(self, key):
Antoine Pitrou1bf974d2014-10-05 20:02:28 +0200382 self._dirty_len = True
Tim Peters886128f2003-05-25 01:45:11 +0000383 del self.data[ref(key)]
Fred Drakeb663a2c2001-09-06 14:51:01 +0000384
Martin v. Löwis5e163332001-02-27 18:36:56 +0000385 def __getitem__(self, key):
386 return self.data[ref(key)]
387
Raymond Hettinger7ac60952008-02-05 01:15:57 +0000388 def __len__(self):
Antoine Pitrou1bf974d2014-10-05 20:02:28 +0200389 if self._dirty_len and self._pending_removals:
390 # self._pending_removals may still contain keys which were
391 # explicitly removed, we have to scrub them (see issue #21173).
392 self._scrub_removals()
Antoine Pitroubbe2f602012-03-01 16:26:35 +0100393 return len(self.data) - len(self._pending_removals)
Raymond Hettinger7ac60952008-02-05 01:15:57 +0000394
Martin v. Löwis5e163332001-02-27 18:36:56 +0000395 def __repr__(self):
Serhiy Storchaka465e60e2014-07-25 23:36:00 +0300396 return "<%s at %#x>" % (self.__class__.__name__, id(self))
Martin v. Löwis5e163332001-02-27 18:36:56 +0000397
398 def __setitem__(self, key, value):
399 self.data[ref(key, self._remove)] = value
400
401 def copy(self):
402 new = WeakKeyDictionary()
Fish96d37db2019-02-07 14:51:59 -0500403 with _IterationGuard(self):
404 for key, value in self.data.items():
405 o = key()
406 if o is not None:
407 new[o] = value
Fred Drake9d2c85d2001-03-01 03:06:03 +0000408 return new
Martin v. Löwis5e163332001-02-27 18:36:56 +0000409
Antoine Pitrou6e610062009-05-15 17:04:50 +0000410 __copy__ = copy
411
412 def __deepcopy__(self, memo):
413 from copy import deepcopy
414 new = self.__class__()
Fish96d37db2019-02-07 14:51:59 -0500415 with _IterationGuard(self):
416 for key, value in self.data.items():
417 o = key()
418 if o is not None:
419 new[o] = deepcopy(value, memo)
Antoine Pitrou6e610062009-05-15 17:04:50 +0000420 return new
421
Fred Drake1d9e4b72001-04-16 17:34:48 +0000422 def get(self, key, default=None):
Martin v. Löwis5e163332001-02-27 18:36:56 +0000423 return self.data.get(ref(key),default)
424
Raymond Hettinger54f02222002-06-01 14:18:47 +0000425 def __contains__(self, key):
426 try:
427 wr = ref(key)
428 except TypeError:
Georg Brandlbd87d082010-12-03 07:49:09 +0000429 return False
Raymond Hettinger54f02222002-06-01 14:18:47 +0000430 return wr in self.data
Tim Petersc411dba2002-07-16 21:35:23 +0000431
Martin v. Löwis5e163332001-02-27 18:36:56 +0000432 def items(self):
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000433 with _IterationGuard(self):
434 for wr, value in self.data.items():
435 key = wr()
436 if key is not None:
437 yield key, value
Thomas Wouters477c8d52006-05-27 19:21:47 +0000438
Barry Warsawecaab832008-09-04 01:42:51 +0000439 def keys(self):
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000440 with _IterationGuard(self):
441 for wr in self.data:
442 obj = wr()
443 if obj is not None:
444 yield obj
Raymond Hettinger61146792004-08-19 21:32:06 +0000445
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000446 __iter__ = keys
Fred Drake101209d2001-05-02 05:43:09 +0000447
Barry Warsawecaab832008-09-04 01:42:51 +0000448 def values(self):
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000449 with _IterationGuard(self):
450 for wr, value in self.data.items():
451 if wr() is not None:
452 yield value
Fred Drake101209d2001-05-02 05:43:09 +0000453
Thomas Wouters477c8d52006-05-27 19:21:47 +0000454 def keyrefs(self):
455 """Return a list of weak references to the keys.
456
457 The references are not guaranteed to be 'live' at the time
458 they are used, so the result of calling the references needs
459 to be checked before being used. This can be used to avoid
460 creating references that will cause the garbage collector to
461 keep the keys around longer than needed.
462
463 """
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000464 return list(self.data)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000465
Martin v. Löwis5e163332001-02-27 18:36:56 +0000466 def popitem(self):
Antoine Pitrou1bf974d2014-10-05 20:02:28 +0200467 self._dirty_len = True
Georg Brandlbd87d082010-12-03 07:49:09 +0000468 while True:
Martin v. Löwis5e163332001-02-27 18:36:56 +0000469 key, value = self.data.popitem()
470 o = key()
471 if o is not None:
472 return o, value
473
Raymond Hettinger2c2d3222003-03-09 07:05:43 +0000474 def pop(self, key, *args):
Antoine Pitrou1bf974d2014-10-05 20:02:28 +0200475 self._dirty_len = True
Raymond Hettinger2c2d3222003-03-09 07:05:43 +0000476 return self.data.pop(ref(key), *args)
477
Walter Dörwald80ce6dd2004-05-27 18:16:25 +0000478 def setdefault(self, key, default=None):
Martin v. Löwis5e163332001-02-27 18:36:56 +0000479 return self.data.setdefault(ref(key, self._remove),default)
480
Serhiy Storchaka2085bd02019-06-01 11:00:15 +0300481 def update(self, dict=None, /, **kwargs):
Martin v. Löwis5e163332001-02-27 18:36:56 +0000482 d = self.data
Raymond Hettinger31017ae2004-03-04 08:25:44 +0000483 if dict is not None:
484 if not hasattr(dict, "items"):
485 dict = type({})(dict)
486 for key, value in dict.items():
487 d[ref(key, self._remove)] = value
488 if len(kwargs):
489 self.update(kwargs)
Richard Oudkerk7a3dae02013-05-05 23:05:00 +0100490
491
492class finalize:
493 """Class for finalization of weakrefable objects
494
495 finalize(obj, func, *args, **kwargs) returns a callable finalizer
496 object which will be called when obj is garbage collected. The
497 first time the finalizer is called it evaluates func(*arg, **kwargs)
498 and returns the result. After this the finalizer is dead, and
499 calling it just returns None.
500
501 When the program exits any remaining finalizers for which the
502 atexit attribute is true will be run in reverse order of creation.
503 By default atexit is true.
504 """
505
506 # Finalizer objects don't have any state of their own. They are
507 # just used as keys to lookup _Info objects in the registry. This
508 # ensures that they cannot be part of a ref-cycle.
509
510 __slots__ = ()
511 _registry = {}
512 _shutdown = False
513 _index_iter = itertools.count()
514 _dirty = False
Richard Oudkerka81dd652013-06-08 16:52:29 +0100515 _registered_with_atexit = False
Richard Oudkerk7a3dae02013-05-05 23:05:00 +0100516
517 class _Info:
518 __slots__ = ("weakref", "func", "args", "kwargs", "atexit", "index")
519
Serhiy Storchaka142566c2019-06-05 18:22:31 +0300520 def __init__(self, obj, func, /, *args, **kwargs):
Richard Oudkerka81dd652013-06-08 16:52:29 +0100521 if not self._registered_with_atexit:
522 # We may register the exit function more than once because
523 # of a thread race, but that is harmless
524 import atexit
525 atexit.register(self._exitfunc)
526 finalize._registered_with_atexit = True
Richard Oudkerk7a3dae02013-05-05 23:05:00 +0100527 info = self._Info()
528 info.weakref = ref(obj, self)
529 info.func = func
530 info.args = args
531 info.kwargs = kwargs or None
532 info.atexit = True
533 info.index = next(self._index_iter)
534 self._registry[self] = info
535 finalize._dirty = True
536
537 def __call__(self, _=None):
538 """If alive then mark as dead and return func(*args, **kwargs);
539 otherwise return None"""
540 info = self._registry.pop(self, None)
541 if info and not self._shutdown:
542 return info.func(*info.args, **(info.kwargs or {}))
543
544 def detach(self):
545 """If alive then mark as dead and return (obj, func, args, kwargs);
546 otherwise return None"""
547 info = self._registry.get(self)
548 obj = info and info.weakref()
549 if obj is not None and self._registry.pop(self, None):
550 return (obj, info.func, info.args, info.kwargs or {})
551
552 def peek(self):
553 """If alive then return (obj, func, args, kwargs);
554 otherwise return None"""
555 info = self._registry.get(self)
556 obj = info and info.weakref()
557 if obj is not None:
558 return (obj, info.func, info.args, info.kwargs or {})
559
560 @property
561 def alive(self):
562 """Whether finalizer is alive"""
563 return self in self._registry
564
565 @property
566 def atexit(self):
567 """Whether finalizer should be called at exit"""
568 info = self._registry.get(self)
569 return bool(info) and info.atexit
570
571 @atexit.setter
572 def atexit(self, value):
573 info = self._registry.get(self)
574 if info:
575 info.atexit = bool(value)
576
577 def __repr__(self):
578 info = self._registry.get(self)
579 obj = info and info.weakref()
580 if obj is None:
581 return '<%s object at %#x; dead>' % (type(self).__name__, id(self))
582 else:
583 return '<%s object at %#x; for %r at %#x>' % \
584 (type(self).__name__, id(self), type(obj).__name__, id(obj))
585
586 @classmethod
587 def _select_for_exit(cls):
588 # Return live finalizers marked for exit, oldest first
589 L = [(f,i) for (f,i) in cls._registry.items() if i.atexit]
590 L.sort(key=lambda item:item[1].index)
591 return [f for (f,i) in L]
592
593 @classmethod
594 def _exitfunc(cls):
595 # At shutdown invoke finalizers for which atexit is true.
596 # This is called once all other non-daemonic threads have been
597 # joined.
598 reenable_gc = False
599 try:
600 if cls._registry:
601 import gc
602 if gc.isenabled():
603 reenable_gc = True
604 gc.disable()
605 pending = None
606 while True:
607 if pending is None or finalize._dirty:
608 pending = cls._select_for_exit()
609 finalize._dirty = False
610 if not pending:
611 break
612 f = pending.pop()
613 try:
614 # gc is disabled, so (assuming no daemonic
615 # threads) the following is the only line in
616 # this function which might trigger creation
617 # of a new finalizer
618 f()
619 except Exception:
620 sys.excepthook(*sys.exc_info())
621 assert f not in cls._registry
622 finally:
623 # prevent any more finalizers from executing during shutdown
624 finalize._shutdown = True
625 if reenable_gc:
626 gc.enable()