blob: 2968fb9f726e69bae7b83213cbe04163d2844275 [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:
242 if args:
243 return args[0]
244 raise
245 if o is None:
Collin Winterce36ad82007-08-30 01:19:48 +0000246 raise KeyError(key)
Raymond Hettinger2c2d3222003-03-09 07:05:43 +0000247 else:
248 return o
249
Walter Dörwald80ce6dd2004-05-27 18:16:25 +0000250 def setdefault(self, key, default=None):
Fred Drake41deb1e2001-02-01 05:27:45 +0000251 try:
Fred Drakebd7f8182001-04-19 16:26:06 +0000252 wr = self.data[key]
Fred Drake41deb1e2001-02-01 05:27:45 +0000253 except KeyError:
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000254 if self._pending_removals:
255 self._commit_removals()
Fred Drake0a4dd392004-07-02 18:57:45 +0000256 self.data[key] = KeyedRef(default, self._remove, key)
Fred Drake41deb1e2001-02-01 05:27:45 +0000257 return default
258 else:
Fred Drakebd7f8182001-04-19 16:26:06 +0000259 return wr()
Fred Drake41deb1e2001-02-01 05:27:45 +0000260
Serhiy Storchakab5102e32015-09-29 23:52:09 +0300261 def update(*args, **kwargs):
262 if not args:
263 raise TypeError("descriptor 'update' of 'WeakValueDictionary' "
264 "object needs an argument")
265 self, *args = args
266 if len(args) > 1:
267 raise TypeError('expected at most 1 arguments, got %d' % len(args))
268 dict = args[0] if args else None
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000269 if self._pending_removals:
270 self._commit_removals()
Fred Drake41deb1e2001-02-01 05:27:45 +0000271 d = self.data
Raymond Hettinger31017ae2004-03-04 08:25:44 +0000272 if dict is not None:
273 if not hasattr(dict, "items"):
274 dict = type({})(dict)
275 for key, o in dict.items():
Fred Drake0a4dd392004-07-02 18:57:45 +0000276 d[key] = KeyedRef(o, self._remove, key)
Raymond Hettinger31017ae2004-03-04 08:25:44 +0000277 if len(kwargs):
278 self.update(kwargs)
Fred Drake41deb1e2001-02-01 05:27:45 +0000279
Thomas Wouters477c8d52006-05-27 19:21:47 +0000280 def valuerefs(self):
281 """Return a list of weak references to the values.
282
283 The references are not guaranteed to be 'live' at the time
284 they are used, so the result of calling the references needs
285 to be checked before being used. This can be used to avoid
286 creating references that will cause the garbage collector to
287 keep the values around longer than needed.
288
289 """
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000290 return list(self.data.values())
Thomas Wouters477c8d52006-05-27 19:21:47 +0000291
Fred Drake0a4dd392004-07-02 18:57:45 +0000292
293class KeyedRef(ref):
294 """Specialized reference that includes a key corresponding to the value.
295
296 This is used in the WeakValueDictionary to avoid having to create
297 a function object for each key stored in the mapping. A shared
298 callback object can use the 'key' attribute of a KeyedRef instead
299 of getting a reference to the key from an enclosing scope.
300
301 """
302
303 __slots__ = "key",
304
305 def __new__(type, ob, callback, key):
306 self = ref.__new__(type, ob, callback)
307 self.key = key
308 return self
309
310 def __init__(self, ob, callback, key):
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000311 super().__init__(ob, callback)
Fred Drake746fe0f2001-09-28 19:01:26 +0000312
Fred Drake41deb1e2001-02-01 05:27:45 +0000313
Raymond Hettinger7ac60952008-02-05 01:15:57 +0000314class WeakKeyDictionary(collections.MutableMapping):
Fred Drakebd7f8182001-04-19 16:26:06 +0000315 """ Mapping class that references keys weakly.
316
317 Entries in the dictionary will be discarded when there is no
318 longer a strong reference to the key. This can be used to
319 associate additional data with an object owned by other parts of
320 an application without adding attributes to those objects. This
321 can be especially useful with objects that override attribute
322 accesses.
323 """
Martin v. Löwis5e163332001-02-27 18:36:56 +0000324
325 def __init__(self, dict=None):
326 self.data = {}
Fred Drake746fe0f2001-09-28 19:01:26 +0000327 def remove(k, selfref=ref(self)):
328 self = selfref()
329 if self is not None:
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000330 if self._iterating:
331 self._pending_removals.append(k)
332 else:
333 del self.data[k]
Martin v. Löwis5e163332001-02-27 18:36:56 +0000334 self._remove = remove
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000335 # A list of dead weakrefs (keys to be removed)
336 self._pending_removals = []
337 self._iterating = set()
Antoine Pitrou1bf974d2014-10-05 20:02:28 +0200338 self._dirty_len = False
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000339 if dict is not None:
340 self.update(dict)
341
342 def _commit_removals(self):
343 # NOTE: We don't need to call this method before mutating the dict,
344 # because a dead weakref never compares equal to a live weakref,
345 # even if they happened to refer to equal objects.
346 # However, it means keys may already have been removed.
347 l = self._pending_removals
348 d = self.data
349 while l:
350 try:
351 del d[l.pop()]
352 except KeyError:
353 pass
Martin v. Löwis5e163332001-02-27 18:36:56 +0000354
Antoine Pitrou1bf974d2014-10-05 20:02:28 +0200355 def _scrub_removals(self):
356 d = self.data
357 self._pending_removals = [k for k in self._pending_removals if k in d]
358 self._dirty_len = False
359
Fred Drakeb663a2c2001-09-06 14:51:01 +0000360 def __delitem__(self, key):
Antoine Pitrou1bf974d2014-10-05 20:02:28 +0200361 self._dirty_len = True
Tim Peters886128f2003-05-25 01:45:11 +0000362 del self.data[ref(key)]
Fred Drakeb663a2c2001-09-06 14:51:01 +0000363
Martin v. Löwis5e163332001-02-27 18:36:56 +0000364 def __getitem__(self, key):
365 return self.data[ref(key)]
366
Raymond Hettinger7ac60952008-02-05 01:15:57 +0000367 def __len__(self):
Antoine Pitrou1bf974d2014-10-05 20:02:28 +0200368 if self._dirty_len and self._pending_removals:
369 # self._pending_removals may still contain keys which were
370 # explicitly removed, we have to scrub them (see issue #21173).
371 self._scrub_removals()
Antoine Pitroubbe2f602012-03-01 16:26:35 +0100372 return len(self.data) - len(self._pending_removals)
Raymond Hettinger7ac60952008-02-05 01:15:57 +0000373
Martin v. Löwis5e163332001-02-27 18:36:56 +0000374 def __repr__(self):
Serhiy Storchaka465e60e2014-07-25 23:36:00 +0300375 return "<%s at %#x>" % (self.__class__.__name__, id(self))
Martin v. Löwis5e163332001-02-27 18:36:56 +0000376
377 def __setitem__(self, key, value):
378 self.data[ref(key, self._remove)] = value
379
380 def copy(self):
381 new = WeakKeyDictionary()
382 for key, value in self.data.items():
383 o = key()
384 if o is not None:
385 new[o] = value
Fred Drake9d2c85d2001-03-01 03:06:03 +0000386 return new
Martin v. Löwis5e163332001-02-27 18:36:56 +0000387
Antoine Pitrou6e610062009-05-15 17:04:50 +0000388 __copy__ = copy
389
390 def __deepcopy__(self, memo):
391 from copy import deepcopy
392 new = self.__class__()
393 for key, value in self.data.items():
394 o = key()
395 if o is not None:
396 new[o] = deepcopy(value, memo)
397 return new
398
Fred Drake1d9e4b72001-04-16 17:34:48 +0000399 def get(self, key, default=None):
Martin v. Löwis5e163332001-02-27 18:36:56 +0000400 return self.data.get(ref(key),default)
401
Raymond Hettinger54f02222002-06-01 14:18:47 +0000402 def __contains__(self, key):
403 try:
404 wr = ref(key)
405 except TypeError:
Georg Brandlbd87d082010-12-03 07:49:09 +0000406 return False
Raymond Hettinger54f02222002-06-01 14:18:47 +0000407 return wr in self.data
Tim Petersc411dba2002-07-16 21:35:23 +0000408
Martin v. Löwis5e163332001-02-27 18:36:56 +0000409 def items(self):
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000410 with _IterationGuard(self):
411 for wr, value in self.data.items():
412 key = wr()
413 if key is not None:
414 yield key, value
Thomas Wouters477c8d52006-05-27 19:21:47 +0000415
Barry Warsawecaab832008-09-04 01:42:51 +0000416 def keys(self):
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000417 with _IterationGuard(self):
418 for wr in self.data:
419 obj = wr()
420 if obj is not None:
421 yield obj
Raymond Hettinger61146792004-08-19 21:32:06 +0000422
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000423 __iter__ = keys
Fred Drake101209d2001-05-02 05:43:09 +0000424
Barry Warsawecaab832008-09-04 01:42:51 +0000425 def values(self):
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000426 with _IterationGuard(self):
427 for wr, value in self.data.items():
428 if wr() is not None:
429 yield value
Fred Drake101209d2001-05-02 05:43:09 +0000430
Thomas Wouters477c8d52006-05-27 19:21:47 +0000431 def keyrefs(self):
432 """Return a list of weak references to the keys.
433
434 The references are not guaranteed to be 'live' at the time
435 they are used, so the result of calling the references needs
436 to be checked before being used. This can be used to avoid
437 creating references that will cause the garbage collector to
438 keep the keys around longer than needed.
439
440 """
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000441 return list(self.data)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000442
Martin v. Löwis5e163332001-02-27 18:36:56 +0000443 def popitem(self):
Antoine Pitrou1bf974d2014-10-05 20:02:28 +0200444 self._dirty_len = True
Georg Brandlbd87d082010-12-03 07:49:09 +0000445 while True:
Martin v. Löwis5e163332001-02-27 18:36:56 +0000446 key, value = self.data.popitem()
447 o = key()
448 if o is not None:
449 return o, value
450
Raymond Hettinger2c2d3222003-03-09 07:05:43 +0000451 def pop(self, key, *args):
Antoine Pitrou1bf974d2014-10-05 20:02:28 +0200452 self._dirty_len = True
Raymond Hettinger2c2d3222003-03-09 07:05:43 +0000453 return self.data.pop(ref(key), *args)
454
Walter Dörwald80ce6dd2004-05-27 18:16:25 +0000455 def setdefault(self, key, default=None):
Martin v. Löwis5e163332001-02-27 18:36:56 +0000456 return self.data.setdefault(ref(key, self._remove),default)
457
Raymond Hettinger31017ae2004-03-04 08:25:44 +0000458 def update(self, dict=None, **kwargs):
Martin v. Löwis5e163332001-02-27 18:36:56 +0000459 d = self.data
Raymond Hettinger31017ae2004-03-04 08:25:44 +0000460 if dict is not None:
461 if not hasattr(dict, "items"):
462 dict = type({})(dict)
463 for key, value in dict.items():
464 d[ref(key, self._remove)] = value
465 if len(kwargs):
466 self.update(kwargs)
Richard Oudkerk7a3dae02013-05-05 23:05:00 +0100467
468
469class finalize:
470 """Class for finalization of weakrefable objects
471
472 finalize(obj, func, *args, **kwargs) returns a callable finalizer
473 object which will be called when obj is garbage collected. The
474 first time the finalizer is called it evaluates func(*arg, **kwargs)
475 and returns the result. After this the finalizer is dead, and
476 calling it just returns None.
477
478 When the program exits any remaining finalizers for which the
479 atexit attribute is true will be run in reverse order of creation.
480 By default atexit is true.
481 """
482
483 # Finalizer objects don't have any state of their own. They are
484 # just used as keys to lookup _Info objects in the registry. This
485 # ensures that they cannot be part of a ref-cycle.
486
487 __slots__ = ()
488 _registry = {}
489 _shutdown = False
490 _index_iter = itertools.count()
491 _dirty = False
Richard Oudkerka81dd652013-06-08 16:52:29 +0100492 _registered_with_atexit = False
Richard Oudkerk7a3dae02013-05-05 23:05:00 +0100493
494 class _Info:
495 __slots__ = ("weakref", "func", "args", "kwargs", "atexit", "index")
496
497 def __init__(self, obj, func, *args, **kwargs):
Richard Oudkerka81dd652013-06-08 16:52:29 +0100498 if not self._registered_with_atexit:
499 # We may register the exit function more than once because
500 # of a thread race, but that is harmless
501 import atexit
502 atexit.register(self._exitfunc)
503 finalize._registered_with_atexit = True
Richard Oudkerk7a3dae02013-05-05 23:05:00 +0100504 info = self._Info()
505 info.weakref = ref(obj, self)
506 info.func = func
507 info.args = args
508 info.kwargs = kwargs or None
509 info.atexit = True
510 info.index = next(self._index_iter)
511 self._registry[self] = info
512 finalize._dirty = True
513
514 def __call__(self, _=None):
515 """If alive then mark as dead and return func(*args, **kwargs);
516 otherwise return None"""
517 info = self._registry.pop(self, None)
518 if info and not self._shutdown:
519 return info.func(*info.args, **(info.kwargs or {}))
520
521 def detach(self):
522 """If alive then mark as dead and return (obj, func, args, kwargs);
523 otherwise return None"""
524 info = self._registry.get(self)
525 obj = info and info.weakref()
526 if obj is not None and self._registry.pop(self, None):
527 return (obj, info.func, info.args, info.kwargs or {})
528
529 def peek(self):
530 """If alive then return (obj, func, args, kwargs);
531 otherwise return None"""
532 info = self._registry.get(self)
533 obj = info and info.weakref()
534 if obj is not None:
535 return (obj, info.func, info.args, info.kwargs or {})
536
537 @property
538 def alive(self):
539 """Whether finalizer is alive"""
540 return self in self._registry
541
542 @property
543 def atexit(self):
544 """Whether finalizer should be called at exit"""
545 info = self._registry.get(self)
546 return bool(info) and info.atexit
547
548 @atexit.setter
549 def atexit(self, value):
550 info = self._registry.get(self)
551 if info:
552 info.atexit = bool(value)
553
554 def __repr__(self):
555 info = self._registry.get(self)
556 obj = info and info.weakref()
557 if obj is None:
558 return '<%s object at %#x; dead>' % (type(self).__name__, id(self))
559 else:
560 return '<%s object at %#x; for %r at %#x>' % \
561 (type(self).__name__, id(self), type(obj).__name__, id(obj))
562
563 @classmethod
564 def _select_for_exit(cls):
565 # Return live finalizers marked for exit, oldest first
566 L = [(f,i) for (f,i) in cls._registry.items() if i.atexit]
567 L.sort(key=lambda item:item[1].index)
568 return [f for (f,i) in L]
569
570 @classmethod
571 def _exitfunc(cls):
572 # At shutdown invoke finalizers for which atexit is true.
573 # This is called once all other non-daemonic threads have been
574 # joined.
575 reenable_gc = False
576 try:
577 if cls._registry:
578 import gc
579 if gc.isenabled():
580 reenable_gc = True
581 gc.disable()
582 pending = None
583 while True:
584 if pending is None or finalize._dirty:
585 pending = cls._select_for_exit()
586 finalize._dirty = False
587 if not pending:
588 break
589 f = pending.pop()
590 try:
591 # gc is disabled, so (assuming no daemonic
592 # threads) the following is the only line in
593 # this function which might trigger creation
594 # of a new finalizer
595 f()
596 except Exception:
597 sys.excepthook(*sys.exc_info())
598 assert f not in cls._registry
599 finally:
600 # prevent any more finalizers from executing during shutdown
601 finalize._shutdown = True
602 if reenable_gc:
603 gc.enable()