blob: 9f8ef3eb8c6510b0856d3b1605d6298307921512 [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,
19 ReferenceType)
Fred Drake41deb1e2001-02-01 05:27:45 +000020
Antoine Pitrouc1baa602010-01-08 17:54:23 +000021from _weakrefset import WeakSet, _IterationGuard
Fred Drakee0292422001-10-05 21:54:09 +000022
Brett Cannon663fffa2009-03-25 23:31:22 +000023import collections # Import after _weakref to avoid circular import.
Richard Oudkerk7a3dae02013-05-05 23:05:00 +010024import sys
25import itertools
Brett Cannon663fffa2009-03-25 23:31:22 +000026
Fred Drake41deb1e2001-02-01 05:27:45 +000027ProxyTypes = (ProxyType, CallableProxyType)
28
Fred Drake9a9d2192001-04-10 19:11:23 +000029__all__ = ["ref", "proxy", "getweakrefcount", "getweakrefs",
Gregory P. Smith7d10c2b2008-08-18 03:41:46 +000030 "WeakKeyDictionary", "ReferenceType", "ProxyType",
Raymond Hettinger93fa6082008-02-05 00:20:01 +000031 "CallableProxyType", "ProxyTypes", "WeakValueDictionary",
Richard Oudkerk7a3dae02013-05-05 23:05:00 +010032 "WeakSet", "WeakMethod", "finalize"]
Antoine Pitrouc3afba12012-11-17 18:57:38 +010033
34
35class WeakMethod(ref):
36 """
37 A custom `weakref.ref` subclass which simulates a weak reference to
38 a bound method, working around the lifetime problem of bound methods.
39 """
40
41 __slots__ = "_func_ref", "_meth_type", "_alive", "__weakref__"
42
43 def __new__(cls, meth, callback=None):
44 try:
45 obj = meth.__self__
46 func = meth.__func__
47 except AttributeError:
48 raise TypeError("argument should be a bound method, not {}"
49 .format(type(meth))) from None
50 def _cb(arg):
51 # The self-weakref trick is needed to avoid creating a reference
52 # cycle.
53 self = self_wr()
54 if self._alive:
55 self._alive = False
56 if callback is not None:
57 callback(self)
58 self = ref.__new__(cls, obj, _cb)
59 self._func_ref = ref(func, _cb)
60 self._meth_type = type(meth)
61 self._alive = True
62 self_wr = ref(self)
63 return self
64
65 def __call__(self):
66 obj = super().__call__()
67 func = self._func_ref()
68 if obj is None or func is None:
69 return None
70 return self._meth_type(func, obj)
71
72 def __eq__(self, other):
73 if isinstance(other, WeakMethod):
74 if not self._alive or not other._alive:
75 return self is other
76 return ref.__eq__(self, other) and self._func_ref == other._func_ref
77 return False
78
79 def __ne__(self, other):
80 if isinstance(other, WeakMethod):
81 if not self._alive or not other._alive:
82 return self is not other
83 return ref.__ne__(self, other) or self._func_ref != other._func_ref
84 return True
85
86 __hash__ = ref.__hash__
Fred Drake41deb1e2001-02-01 05:27:45 +000087
Fred Drake41deb1e2001-02-01 05:27:45 +000088
Raymond Hettinger7ac60952008-02-05 01:15:57 +000089class WeakValueDictionary(collections.MutableMapping):
Fred Drakebd7f8182001-04-19 16:26:06 +000090 """Mapping class that references values weakly.
91
92 Entries in the dictionary will be discarded when no strong
93 reference to the value exists anymore
94 """
Fred Drake41deb1e2001-02-01 05:27:45 +000095 # We inherit the constructor without worrying about the input
96 # dictionary; since it uses our .update() method, we get the right
Fred Drake9d2c85d2001-03-01 03:06:03 +000097 # checks (if the other dictionary is a WeakValueDictionary,
98 # objects are unwrapped on the way out, and we always wrap on the
99 # way in).
Fred Drake41deb1e2001-02-01 05:27:45 +0000100
Serhiy Storchakab5102e32015-09-29 23:52:09 +0300101 def __init__(*args, **kw):
102 if not args:
103 raise TypeError("descriptor '__init__' of 'WeakValueDictionary' "
104 "object needs an argument")
105 self, *args = args
106 if len(args) > 1:
107 raise TypeError('expected at most 1 arguments, got %d' % len(args))
Fred Drake0a4dd392004-07-02 18:57:45 +0000108 def remove(wr, selfref=ref(self)):
109 self = selfref()
110 if self is not None:
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000111 if self._iterating:
112 self._pending_removals.append(wr.key)
113 else:
114 del 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()
Raymond Hettinger7ac60952008-02-05 01:15:57 +0000119 self.data = d = {}
Antoine Pitrouc06de472009-05-30 21:04:26 +0000120 self.update(*args, **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:
128 del d[l.pop()]
129
Fred Drake41deb1e2001-02-01 05:27:45 +0000130 def __getitem__(self, key):
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 Pitroubbe2f602012-03-01 16:26:35 +0100143 return len(self.data) - len(self._pending_removals)
Raymond Hettinger7ac60952008-02-05 01:15:57 +0000144
Raymond Hettinger61146792004-08-19 21:32:06 +0000145 def __contains__(self, key):
146 try:
147 o = self.data[key]()
148 except KeyError:
149 return False
150 return o is not None
151
Fred Drake41deb1e2001-02-01 05:27:45 +0000152 def __repr__(self):
Serhiy Storchaka465e60e2014-07-25 23:36:00 +0300153 return "<%s at %#x>" % (self.__class__.__name__, id(self))
Fred Drake41deb1e2001-02-01 05:27:45 +0000154
155 def __setitem__(self, key, value):
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000156 if self._pending_removals:
157 self._commit_removals()
Fred Drake0a4dd392004-07-02 18:57:45 +0000158 self.data[key] = KeyedRef(value, self._remove, key)
Fred Drake41deb1e2001-02-01 05:27:45 +0000159
160 def copy(self):
Fred Drake9d2c85d2001-03-01 03:06:03 +0000161 new = WeakValueDictionary()
Fred Drakebd7f8182001-04-19 16:26:06 +0000162 for key, wr in self.data.items():
163 o = wr()
Fred Drake41deb1e2001-02-01 05:27:45 +0000164 if o is not None:
165 new[key] = o
Fred Drake9d2c85d2001-03-01 03:06:03 +0000166 return new
Fred Drake41deb1e2001-02-01 05:27:45 +0000167
Antoine Pitrou6e610062009-05-15 17:04:50 +0000168 __copy__ = copy
169
170 def __deepcopy__(self, memo):
171 from copy import deepcopy
172 new = self.__class__()
173 for key, wr in self.data.items():
174 o = wr()
175 if o is not None:
176 new[deepcopy(key, memo)] = o
177 return new
178
Fred Drake1d9e4b72001-04-16 17:34:48 +0000179 def get(self, key, default=None):
Fred Drake41deb1e2001-02-01 05:27:45 +0000180 try:
Fred Drakebd7f8182001-04-19 16:26:06 +0000181 wr = self.data[key]
Fred Drake41deb1e2001-02-01 05:27:45 +0000182 except KeyError:
183 return default
184 else:
Fred Drakebd7f8182001-04-19 16:26:06 +0000185 o = wr()
Fred Drake41deb1e2001-02-01 05:27:45 +0000186 if o is None:
187 # This should only happen
188 return default
189 else:
190 return o
191
192 def items(self):
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000193 with _IterationGuard(self):
194 for k, wr in self.data.items():
195 v = wr()
196 if v is not None:
197 yield k, v
Fred Drake101209d2001-05-02 05:43:09 +0000198
Barry Warsawecaab832008-09-04 01:42:51 +0000199 def keys(self):
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000200 with _IterationGuard(self):
201 for k, wr in self.data.items():
202 if wr() is not None:
203 yield k
Raymond Hettinger61146792004-08-19 21:32:06 +0000204
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000205 __iter__ = keys
Fred Drake101209d2001-05-02 05:43:09 +0000206
Thomas Wouters477c8d52006-05-27 19:21:47 +0000207 def itervaluerefs(self):
208 """Return an iterator that yields the weak references to the values.
209
210 The references are not guaranteed to be 'live' at the time
211 they are used, so the result of calling the references needs
212 to be checked before being used. This can be used to avoid
213 creating references that will cause the garbage collector to
214 keep the values around longer than needed.
215
216 """
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000217 with _IterationGuard(self):
Philip Jenvey4993cc02012-10-01 12:53:43 -0700218 yield from self.data.values()
Thomas Wouters477c8d52006-05-27 19:21:47 +0000219
Barry Warsawecaab832008-09-04 01:42:51 +0000220 def values(self):
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000221 with _IterationGuard(self):
222 for wr in self.data.values():
223 obj = wr()
224 if obj is not None:
225 yield obj
Fred Drake101209d2001-05-02 05:43:09 +0000226
Fred Drake41deb1e2001-02-01 05:27:45 +0000227 def popitem(self):
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000228 if self._pending_removals:
229 self._commit_removals()
Georg Brandlbd87d082010-12-03 07:49:09 +0000230 while True:
Fred Drakebd7f8182001-04-19 16:26:06 +0000231 key, wr = self.data.popitem()
232 o = wr()
Fred Drake41deb1e2001-02-01 05:27:45 +0000233 if o is not None:
234 return key, o
235
Raymond Hettinger2c2d3222003-03-09 07:05:43 +0000236 def pop(self, key, *args):
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000237 if self._pending_removals:
238 self._commit_removals()
Raymond Hettinger2c2d3222003-03-09 07:05:43 +0000239 try:
240 o = self.data.pop(key)()
241 except KeyError:
Antoine Pitrouc1ee4882016-12-19 10:56:40 +0100242 o = None
243 if o is None:
Raymond Hettinger2c2d3222003-03-09 07:05:43 +0000244 if args:
245 return args[0]
Antoine Pitrouc1ee4882016-12-19 10:56:40 +0100246 else:
247 raise KeyError(key)
Raymond Hettinger2c2d3222003-03-09 07:05:43 +0000248 else:
249 return o
250
Walter Dörwald80ce6dd2004-05-27 18:16:25 +0000251 def setdefault(self, key, default=None):
Fred Drake41deb1e2001-02-01 05:27:45 +0000252 try:
Antoine Pitrouc1ee4882016-12-19 10:56:40 +0100253 o = self.data[key]()
Fred Drake41deb1e2001-02-01 05:27:45 +0000254 except KeyError:
Antoine Pitrouc1ee4882016-12-19 10:56:40 +0100255 o = None
256 if o is None:
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000257 if self._pending_removals:
258 self._commit_removals()
Fred Drake0a4dd392004-07-02 18:57:45 +0000259 self.data[key] = KeyedRef(default, self._remove, key)
Fred Drake41deb1e2001-02-01 05:27:45 +0000260 return default
261 else:
Antoine Pitrouc1ee4882016-12-19 10:56:40 +0100262 return o
Fred Drake41deb1e2001-02-01 05:27:45 +0000263
Serhiy Storchakab5102e32015-09-29 23:52:09 +0300264 def update(*args, **kwargs):
265 if not args:
266 raise TypeError("descriptor 'update' of 'WeakValueDictionary' "
267 "object needs an argument")
268 self, *args = args
269 if len(args) > 1:
270 raise TypeError('expected at most 1 arguments, got %d' % len(args))
271 dict = args[0] if args else None
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000272 if self._pending_removals:
273 self._commit_removals()
Fred Drake41deb1e2001-02-01 05:27:45 +0000274 d = self.data
Raymond Hettinger31017ae2004-03-04 08:25:44 +0000275 if dict is not None:
276 if not hasattr(dict, "items"):
277 dict = type({})(dict)
278 for key, o in dict.items():
Fred Drake0a4dd392004-07-02 18:57:45 +0000279 d[key] = KeyedRef(o, self._remove, key)
Raymond Hettinger31017ae2004-03-04 08:25:44 +0000280 if len(kwargs):
281 self.update(kwargs)
Fred Drake41deb1e2001-02-01 05:27:45 +0000282
Thomas Wouters477c8d52006-05-27 19:21:47 +0000283 def valuerefs(self):
284 """Return a list of weak references to the values.
285
286 The references are not guaranteed to be 'live' at the time
287 they are used, so the result of calling the references needs
288 to be checked before being used. This can be used to avoid
289 creating references that will cause the garbage collector to
290 keep the values around longer than needed.
291
292 """
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000293 return list(self.data.values())
Thomas Wouters477c8d52006-05-27 19:21:47 +0000294
Fred Drake0a4dd392004-07-02 18:57:45 +0000295
296class KeyedRef(ref):
297 """Specialized reference that includes a key corresponding to the value.
298
299 This is used in the WeakValueDictionary to avoid having to create
300 a function object for each key stored in the mapping. A shared
301 callback object can use the 'key' attribute of a KeyedRef instead
302 of getting a reference to the key from an enclosing scope.
303
304 """
305
306 __slots__ = "key",
307
308 def __new__(type, ob, callback, key):
309 self = ref.__new__(type, ob, callback)
310 self.key = key
311 return self
312
313 def __init__(self, ob, callback, key):
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000314 super().__init__(ob, callback)
Fred Drake746fe0f2001-09-28 19:01:26 +0000315
Fred Drake41deb1e2001-02-01 05:27:45 +0000316
Raymond Hettinger7ac60952008-02-05 01:15:57 +0000317class WeakKeyDictionary(collections.MutableMapping):
Fred Drakebd7f8182001-04-19 16:26:06 +0000318 """ Mapping class that references keys weakly.
319
320 Entries in the dictionary will be discarded when there is no
321 longer a strong reference to the key. This can be used to
322 associate additional data with an object owned by other parts of
323 an application without adding attributes to those objects. This
324 can be especially useful with objects that override attribute
325 accesses.
326 """
Martin v. Löwis5e163332001-02-27 18:36:56 +0000327
328 def __init__(self, dict=None):
329 self.data = {}
Fred Drake746fe0f2001-09-28 19:01:26 +0000330 def remove(k, selfref=ref(self)):
331 self = selfref()
332 if self is not None:
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000333 if self._iterating:
334 self._pending_removals.append(k)
335 else:
336 del self.data[k]
Martin v. Löwis5e163332001-02-27 18:36:56 +0000337 self._remove = remove
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000338 # A list of dead weakrefs (keys to be removed)
339 self._pending_removals = []
340 self._iterating = set()
Antoine Pitrou1bf974d2014-10-05 20:02:28 +0200341 self._dirty_len = False
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000342 if dict is not None:
343 self.update(dict)
344
345 def _commit_removals(self):
346 # NOTE: We don't need to call this method before mutating the dict,
347 # because a dead weakref never compares equal to a live weakref,
348 # even if they happened to refer to equal objects.
349 # However, it means keys may already have been removed.
350 l = self._pending_removals
351 d = self.data
352 while l:
353 try:
354 del d[l.pop()]
355 except KeyError:
356 pass
Martin v. Löwis5e163332001-02-27 18:36:56 +0000357
Antoine Pitrou1bf974d2014-10-05 20:02:28 +0200358 def _scrub_removals(self):
359 d = self.data
360 self._pending_removals = [k for k in self._pending_removals if k in d]
361 self._dirty_len = False
362
Fred Drakeb663a2c2001-09-06 14:51:01 +0000363 def __delitem__(self, key):
Antoine Pitrou1bf974d2014-10-05 20:02:28 +0200364 self._dirty_len = True
Tim Peters886128f2003-05-25 01:45:11 +0000365 del self.data[ref(key)]
Fred Drakeb663a2c2001-09-06 14:51:01 +0000366
Martin v. Löwis5e163332001-02-27 18:36:56 +0000367 def __getitem__(self, key):
368 return self.data[ref(key)]
369
Raymond Hettinger7ac60952008-02-05 01:15:57 +0000370 def __len__(self):
Antoine Pitrou1bf974d2014-10-05 20:02:28 +0200371 if self._dirty_len and self._pending_removals:
372 # self._pending_removals may still contain keys which were
373 # explicitly removed, we have to scrub them (see issue #21173).
374 self._scrub_removals()
Antoine Pitroubbe2f602012-03-01 16:26:35 +0100375 return len(self.data) - len(self._pending_removals)
Raymond Hettinger7ac60952008-02-05 01:15:57 +0000376
Martin v. Löwis5e163332001-02-27 18:36:56 +0000377 def __repr__(self):
Serhiy Storchaka465e60e2014-07-25 23:36:00 +0300378 return "<%s at %#x>" % (self.__class__.__name__, id(self))
Martin v. Löwis5e163332001-02-27 18:36:56 +0000379
380 def __setitem__(self, key, value):
381 self.data[ref(key, self._remove)] = value
382
383 def copy(self):
384 new = WeakKeyDictionary()
385 for key, value in self.data.items():
386 o = key()
387 if o is not None:
388 new[o] = value
Fred Drake9d2c85d2001-03-01 03:06:03 +0000389 return new
Martin v. Löwis5e163332001-02-27 18:36:56 +0000390
Antoine Pitrou6e610062009-05-15 17:04:50 +0000391 __copy__ = copy
392
393 def __deepcopy__(self, memo):
394 from copy import deepcopy
395 new = self.__class__()
396 for key, value in self.data.items():
397 o = key()
398 if o is not None:
399 new[o] = deepcopy(value, memo)
400 return new
401
Fred Drake1d9e4b72001-04-16 17:34:48 +0000402 def get(self, key, default=None):
Martin v. Löwis5e163332001-02-27 18:36:56 +0000403 return self.data.get(ref(key),default)
404
Raymond Hettinger54f02222002-06-01 14:18:47 +0000405 def __contains__(self, key):
406 try:
407 wr = ref(key)
408 except TypeError:
Georg Brandlbd87d082010-12-03 07:49:09 +0000409 return False
Raymond Hettinger54f02222002-06-01 14:18:47 +0000410 return wr in self.data
Tim Petersc411dba2002-07-16 21:35:23 +0000411
Martin v. Löwis5e163332001-02-27 18:36:56 +0000412 def items(self):
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000413 with _IterationGuard(self):
414 for wr, value in self.data.items():
415 key = wr()
416 if key is not None:
417 yield key, value
Thomas Wouters477c8d52006-05-27 19:21:47 +0000418
Barry Warsawecaab832008-09-04 01:42:51 +0000419 def keys(self):
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000420 with _IterationGuard(self):
421 for wr in self.data:
422 obj = wr()
423 if obj is not None:
424 yield obj
Raymond Hettinger61146792004-08-19 21:32:06 +0000425
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000426 __iter__ = keys
Fred Drake101209d2001-05-02 05:43:09 +0000427
Barry Warsawecaab832008-09-04 01:42:51 +0000428 def values(self):
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000429 with _IterationGuard(self):
430 for wr, value in self.data.items():
431 if wr() is not None:
432 yield value
Fred Drake101209d2001-05-02 05:43:09 +0000433
Thomas Wouters477c8d52006-05-27 19:21:47 +0000434 def keyrefs(self):
435 """Return a list of weak references to the keys.
436
437 The references are not guaranteed to be 'live' at the time
438 they are used, so the result of calling the references needs
439 to be checked before being used. This can be used to avoid
440 creating references that will cause the garbage collector to
441 keep the keys around longer than needed.
442
443 """
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000444 return list(self.data)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000445
Martin v. Löwis5e163332001-02-27 18:36:56 +0000446 def popitem(self):
Antoine Pitrou1bf974d2014-10-05 20:02:28 +0200447 self._dirty_len = True
Georg Brandlbd87d082010-12-03 07:49:09 +0000448 while True:
Martin v. Löwis5e163332001-02-27 18:36:56 +0000449 key, value = self.data.popitem()
450 o = key()
451 if o is not None:
452 return o, value
453
Raymond Hettinger2c2d3222003-03-09 07:05:43 +0000454 def pop(self, key, *args):
Antoine Pitrou1bf974d2014-10-05 20:02:28 +0200455 self._dirty_len = True
Raymond Hettinger2c2d3222003-03-09 07:05:43 +0000456 return self.data.pop(ref(key), *args)
457
Walter Dörwald80ce6dd2004-05-27 18:16:25 +0000458 def setdefault(self, key, default=None):
Martin v. Löwis5e163332001-02-27 18:36:56 +0000459 return self.data.setdefault(ref(key, self._remove),default)
460
Raymond Hettinger31017ae2004-03-04 08:25:44 +0000461 def update(self, dict=None, **kwargs):
Martin v. Löwis5e163332001-02-27 18:36:56 +0000462 d = self.data
Raymond Hettinger31017ae2004-03-04 08:25:44 +0000463 if dict is not None:
464 if not hasattr(dict, "items"):
465 dict = type({})(dict)
466 for key, value in dict.items():
467 d[ref(key, self._remove)] = value
468 if len(kwargs):
469 self.update(kwargs)
Richard Oudkerk7a3dae02013-05-05 23:05:00 +0100470
471
472class finalize:
473 """Class for finalization of weakrefable objects
474
475 finalize(obj, func, *args, **kwargs) returns a callable finalizer
476 object which will be called when obj is garbage collected. The
477 first time the finalizer is called it evaluates func(*arg, **kwargs)
478 and returns the result. After this the finalizer is dead, and
479 calling it just returns None.
480
481 When the program exits any remaining finalizers for which the
482 atexit attribute is true will be run in reverse order of creation.
483 By default atexit is true.
484 """
485
486 # Finalizer objects don't have any state of their own. They are
487 # just used as keys to lookup _Info objects in the registry. This
488 # ensures that they cannot be part of a ref-cycle.
489
490 __slots__ = ()
491 _registry = {}
492 _shutdown = False
493 _index_iter = itertools.count()
494 _dirty = False
Richard Oudkerka81dd652013-06-08 16:52:29 +0100495 _registered_with_atexit = False
Richard Oudkerk7a3dae02013-05-05 23:05:00 +0100496
497 class _Info:
498 __slots__ = ("weakref", "func", "args", "kwargs", "atexit", "index")
499
500 def __init__(self, obj, func, *args, **kwargs):
Richard Oudkerka81dd652013-06-08 16:52:29 +0100501 if not self._registered_with_atexit:
502 # We may register the exit function more than once because
503 # of a thread race, but that is harmless
504 import atexit
505 atexit.register(self._exitfunc)
506 finalize._registered_with_atexit = True
Richard Oudkerk7a3dae02013-05-05 23:05:00 +0100507 info = self._Info()
508 info.weakref = ref(obj, self)
509 info.func = func
510 info.args = args
511 info.kwargs = kwargs or None
512 info.atexit = True
513 info.index = next(self._index_iter)
514 self._registry[self] = info
515 finalize._dirty = True
516
517 def __call__(self, _=None):
518 """If alive then mark as dead and return func(*args, **kwargs);
519 otherwise return None"""
520 info = self._registry.pop(self, None)
521 if info and not self._shutdown:
522 return info.func(*info.args, **(info.kwargs or {}))
523
524 def detach(self):
525 """If alive then mark as dead and return (obj, func, args, kwargs);
526 otherwise return None"""
527 info = self._registry.get(self)
528 obj = info and info.weakref()
529 if obj is not None and self._registry.pop(self, None):
530 return (obj, info.func, info.args, info.kwargs or {})
531
532 def peek(self):
533 """If alive then return (obj, func, args, kwargs);
534 otherwise return None"""
535 info = self._registry.get(self)
536 obj = info and info.weakref()
537 if obj is not None:
538 return (obj, info.func, info.args, info.kwargs or {})
539
540 @property
541 def alive(self):
542 """Whether finalizer is alive"""
543 return self in self._registry
544
545 @property
546 def atexit(self):
547 """Whether finalizer should be called at exit"""
548 info = self._registry.get(self)
549 return bool(info) and info.atexit
550
551 @atexit.setter
552 def atexit(self, value):
553 info = self._registry.get(self)
554 if info:
555 info.atexit = bool(value)
556
557 def __repr__(self):
558 info = self._registry.get(self)
559 obj = info and info.weakref()
560 if obj is None:
561 return '<%s object at %#x; dead>' % (type(self).__name__, id(self))
562 else:
563 return '<%s object at %#x; for %r at %#x>' % \
564 (type(self).__name__, id(self), type(obj).__name__, id(obj))
565
566 @classmethod
567 def _select_for_exit(cls):
568 # Return live finalizers marked for exit, oldest first
569 L = [(f,i) for (f,i) in cls._registry.items() if i.atexit]
570 L.sort(key=lambda item:item[1].index)
571 return [f for (f,i) in L]
572
573 @classmethod
574 def _exitfunc(cls):
575 # At shutdown invoke finalizers for which atexit is true.
576 # This is called once all other non-daemonic threads have been
577 # joined.
578 reenable_gc = False
579 try:
580 if cls._registry:
581 import gc
582 if gc.isenabled():
583 reenable_gc = True
584 gc.disable()
585 pending = None
586 while True:
587 if pending is None or finalize._dirty:
588 pending = cls._select_for_exit()
589 finalize._dirty = False
590 if not pending:
591 break
592 f = pending.pop()
593 try:
594 # gc is disabled, so (assuming no daemonic
595 # threads) the following is the only line in
596 # this function which might trigger creation
597 # of a new finalizer
598 f()
599 except Exception:
600 sys.excepthook(*sys.exc_info())
601 assert f not in cls._registry
602 finally:
603 # prevent any more finalizers from executing during shutdown
604 finalize._shutdown = True
605 if reenable_gc:
606 gc.enable()