blob: 8f9c107aa6f12f97030a7121a1e186119e4721ad [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.
24
Fred Drake41deb1e2001-02-01 05:27:45 +000025ProxyTypes = (ProxyType, CallableProxyType)
26
Fred Drake9a9d2192001-04-10 19:11:23 +000027__all__ = ["ref", "proxy", "getweakrefcount", "getweakrefs",
Gregory P. Smith7d10c2b2008-08-18 03:41:46 +000028 "WeakKeyDictionary", "ReferenceType", "ProxyType",
Raymond Hettinger93fa6082008-02-05 00:20:01 +000029 "CallableProxyType", "ProxyTypes", "WeakValueDictionary",
Antoine Pitrouc3afba12012-11-17 18:57:38 +010030 "WeakSet", "WeakMethod"]
31
32
33class WeakMethod(ref):
34 """
35 A custom `weakref.ref` subclass which simulates a weak reference to
36 a bound method, working around the lifetime problem of bound methods.
37 """
38
39 __slots__ = "_func_ref", "_meth_type", "_alive", "__weakref__"
40
41 def __new__(cls, meth, callback=None):
42 try:
43 obj = meth.__self__
44 func = meth.__func__
45 except AttributeError:
46 raise TypeError("argument should be a bound method, not {}"
47 .format(type(meth))) from None
48 def _cb(arg):
49 # The self-weakref trick is needed to avoid creating a reference
50 # cycle.
51 self = self_wr()
52 if self._alive:
53 self._alive = False
54 if callback is not None:
55 callback(self)
56 self = ref.__new__(cls, obj, _cb)
57 self._func_ref = ref(func, _cb)
58 self._meth_type = type(meth)
59 self._alive = True
60 self_wr = ref(self)
61 return self
62
63 def __call__(self):
64 obj = super().__call__()
65 func = self._func_ref()
66 if obj is None or func is None:
67 return None
68 return self._meth_type(func, obj)
69
70 def __eq__(self, other):
71 if isinstance(other, WeakMethod):
72 if not self._alive or not other._alive:
73 return self is other
74 return ref.__eq__(self, other) and self._func_ref == other._func_ref
75 return False
76
77 def __ne__(self, other):
78 if isinstance(other, WeakMethod):
79 if not self._alive or not other._alive:
80 return self is not other
81 return ref.__ne__(self, other) or self._func_ref != other._func_ref
82 return True
83
84 __hash__ = ref.__hash__
Fred Drake41deb1e2001-02-01 05:27:45 +000085
Fred Drake41deb1e2001-02-01 05:27:45 +000086
Raymond Hettinger7ac60952008-02-05 01:15:57 +000087class WeakValueDictionary(collections.MutableMapping):
Fred Drakebd7f8182001-04-19 16:26:06 +000088 """Mapping class that references values weakly.
89
90 Entries in the dictionary will be discarded when no strong
91 reference to the value exists anymore
92 """
Fred Drake41deb1e2001-02-01 05:27:45 +000093 # We inherit the constructor without worrying about the input
94 # dictionary; since it uses our .update() method, we get the right
Fred Drake9d2c85d2001-03-01 03:06:03 +000095 # checks (if the other dictionary is a WeakValueDictionary,
96 # objects are unwrapped on the way out, and we always wrap on the
97 # way in).
Fred Drake41deb1e2001-02-01 05:27:45 +000098
Fred Drake0a4dd392004-07-02 18:57:45 +000099 def __init__(self, *args, **kw):
Fred Drake0a4dd392004-07-02 18:57:45 +0000100 def remove(wr, selfref=ref(self)):
101 self = selfref()
102 if self is not None:
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000103 if self._iterating:
104 self._pending_removals.append(wr.key)
105 else:
106 del self.data[wr.key]
Fred Drake0a4dd392004-07-02 18:57:45 +0000107 self._remove = remove
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000108 # A list of keys to be removed
109 self._pending_removals = []
110 self._iterating = set()
Raymond Hettinger7ac60952008-02-05 01:15:57 +0000111 self.data = d = {}
Antoine Pitrouc06de472009-05-30 21:04:26 +0000112 self.update(*args, **kw)
Fred Drake0a4dd392004-07-02 18:57:45 +0000113
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000114 def _commit_removals(self):
115 l = self._pending_removals
116 d = self.data
117 # We shouldn't encounter any KeyError, because this method should
118 # always be called *before* mutating the dict.
119 while l:
120 del d[l.pop()]
121
Fred Drake41deb1e2001-02-01 05:27:45 +0000122 def __getitem__(self, key):
Fred Drake4fd06e02001-08-03 04:11:27 +0000123 o = self.data[key]()
Fred Drake41deb1e2001-02-01 05:27:45 +0000124 if o is None:
Collin Winterce36ad82007-08-30 01:19:48 +0000125 raise KeyError(key)
Fred Drake41deb1e2001-02-01 05:27:45 +0000126 else:
127 return o
128
Raymond Hettinger7ac60952008-02-05 01:15:57 +0000129 def __delitem__(self, key):
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000130 if self._pending_removals:
131 self._commit_removals()
Raymond Hettinger7ac60952008-02-05 01:15:57 +0000132 del self.data[key]
133
134 def __len__(self):
Antoine Pitroubbe2f602012-03-01 16:26:35 +0100135 return len(self.data) - len(self._pending_removals)
Raymond Hettinger7ac60952008-02-05 01:15:57 +0000136
Raymond Hettinger61146792004-08-19 21:32:06 +0000137 def __contains__(self, key):
138 try:
139 o = self.data[key]()
140 except KeyError:
141 return False
142 return o is not None
143
Fred Drake41deb1e2001-02-01 05:27:45 +0000144 def __repr__(self):
Fred Drake9d2c85d2001-03-01 03:06:03 +0000145 return "<WeakValueDictionary at %s>" % id(self)
Fred Drake41deb1e2001-02-01 05:27:45 +0000146
147 def __setitem__(self, key, value):
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000148 if self._pending_removals:
149 self._commit_removals()
Fred Drake0a4dd392004-07-02 18:57:45 +0000150 self.data[key] = KeyedRef(value, self._remove, key)
Fred Drake41deb1e2001-02-01 05:27:45 +0000151
152 def copy(self):
Fred Drake9d2c85d2001-03-01 03:06:03 +0000153 new = WeakValueDictionary()
Fred Drakebd7f8182001-04-19 16:26:06 +0000154 for key, wr in self.data.items():
155 o = wr()
Fred Drake41deb1e2001-02-01 05:27:45 +0000156 if o is not None:
157 new[key] = o
Fred Drake9d2c85d2001-03-01 03:06:03 +0000158 return new
Fred Drake41deb1e2001-02-01 05:27:45 +0000159
Antoine Pitrou6e610062009-05-15 17:04:50 +0000160 __copy__ = copy
161
162 def __deepcopy__(self, memo):
163 from copy import deepcopy
164 new = self.__class__()
165 for key, wr in self.data.items():
166 o = wr()
167 if o is not None:
168 new[deepcopy(key, memo)] = o
169 return new
170
Fred Drake1d9e4b72001-04-16 17:34:48 +0000171 def get(self, key, default=None):
Fred Drake41deb1e2001-02-01 05:27:45 +0000172 try:
Fred Drakebd7f8182001-04-19 16:26:06 +0000173 wr = self.data[key]
Fred Drake41deb1e2001-02-01 05:27:45 +0000174 except KeyError:
175 return default
176 else:
Fred Drakebd7f8182001-04-19 16:26:06 +0000177 o = wr()
Fred Drake41deb1e2001-02-01 05:27:45 +0000178 if o is None:
179 # This should only happen
180 return default
181 else:
182 return o
183
184 def items(self):
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000185 with _IterationGuard(self):
186 for k, wr in self.data.items():
187 v = wr()
188 if v is not None:
189 yield k, v
Fred Drake101209d2001-05-02 05:43:09 +0000190
Barry Warsawecaab832008-09-04 01:42:51 +0000191 def keys(self):
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000192 with _IterationGuard(self):
193 for k, wr in self.data.items():
194 if wr() is not None:
195 yield k
Raymond Hettinger61146792004-08-19 21:32:06 +0000196
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000197 __iter__ = keys
Fred Drake101209d2001-05-02 05:43:09 +0000198
Thomas Wouters477c8d52006-05-27 19:21:47 +0000199 def itervaluerefs(self):
200 """Return an iterator that yields the weak references to the values.
201
202 The references are not guaranteed to be 'live' at the time
203 they are used, so the result of calling the references needs
204 to be checked before being used. This can be used to avoid
205 creating references that will cause the garbage collector to
206 keep the values around longer than needed.
207
208 """
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000209 with _IterationGuard(self):
Philip Jenvey4993cc02012-10-01 12:53:43 -0700210 yield from self.data.values()
Thomas Wouters477c8d52006-05-27 19:21:47 +0000211
Barry Warsawecaab832008-09-04 01:42:51 +0000212 def values(self):
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000213 with _IterationGuard(self):
214 for wr in self.data.values():
215 obj = wr()
216 if obj is not None:
217 yield obj
Fred Drake101209d2001-05-02 05:43:09 +0000218
Fred Drake41deb1e2001-02-01 05:27:45 +0000219 def popitem(self):
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000220 if self._pending_removals:
221 self._commit_removals()
Georg Brandlbd87d082010-12-03 07:49:09 +0000222 while True:
Fred Drakebd7f8182001-04-19 16:26:06 +0000223 key, wr = self.data.popitem()
224 o = wr()
Fred Drake41deb1e2001-02-01 05:27:45 +0000225 if o is not None:
226 return key, o
227
Raymond Hettinger2c2d3222003-03-09 07:05:43 +0000228 def pop(self, key, *args):
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000229 if self._pending_removals:
230 self._commit_removals()
Raymond Hettinger2c2d3222003-03-09 07:05:43 +0000231 try:
232 o = self.data.pop(key)()
233 except KeyError:
234 if args:
235 return args[0]
236 raise
237 if o is None:
Collin Winterce36ad82007-08-30 01:19:48 +0000238 raise KeyError(key)
Raymond Hettinger2c2d3222003-03-09 07:05:43 +0000239 else:
240 return o
241
Walter Dörwald80ce6dd2004-05-27 18:16:25 +0000242 def setdefault(self, key, default=None):
Fred Drake41deb1e2001-02-01 05:27:45 +0000243 try:
Fred Drakebd7f8182001-04-19 16:26:06 +0000244 wr = self.data[key]
Fred Drake41deb1e2001-02-01 05:27:45 +0000245 except KeyError:
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000246 if self._pending_removals:
247 self._commit_removals()
Fred Drake0a4dd392004-07-02 18:57:45 +0000248 self.data[key] = KeyedRef(default, self._remove, key)
Fred Drake41deb1e2001-02-01 05:27:45 +0000249 return default
250 else:
Fred Drakebd7f8182001-04-19 16:26:06 +0000251 return wr()
Fred Drake41deb1e2001-02-01 05:27:45 +0000252
Raymond Hettinger31017ae2004-03-04 08:25:44 +0000253 def update(self, dict=None, **kwargs):
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000254 if self._pending_removals:
255 self._commit_removals()
Fred Drake41deb1e2001-02-01 05:27:45 +0000256 d = self.data
Raymond Hettinger31017ae2004-03-04 08:25:44 +0000257 if dict is not None:
258 if not hasattr(dict, "items"):
259 dict = type({})(dict)
260 for key, o in dict.items():
Fred Drake0a4dd392004-07-02 18:57:45 +0000261 d[key] = KeyedRef(o, self._remove, key)
Raymond Hettinger31017ae2004-03-04 08:25:44 +0000262 if len(kwargs):
263 self.update(kwargs)
Fred Drake41deb1e2001-02-01 05:27:45 +0000264
Thomas Wouters477c8d52006-05-27 19:21:47 +0000265 def valuerefs(self):
266 """Return a list of weak references to the values.
267
268 The references are not guaranteed to be 'live' at the time
269 they are used, so the result of calling the references needs
270 to be checked before being used. This can be used to avoid
271 creating references that will cause the garbage collector to
272 keep the values around longer than needed.
273
274 """
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000275 return list(self.data.values())
Thomas Wouters477c8d52006-05-27 19:21:47 +0000276
Fred Drake0a4dd392004-07-02 18:57:45 +0000277
278class KeyedRef(ref):
279 """Specialized reference that includes a key corresponding to the value.
280
281 This is used in the WeakValueDictionary to avoid having to create
282 a function object for each key stored in the mapping. A shared
283 callback object can use the 'key' attribute of a KeyedRef instead
284 of getting a reference to the key from an enclosing scope.
285
286 """
287
288 __slots__ = "key",
289
290 def __new__(type, ob, callback, key):
291 self = ref.__new__(type, ob, callback)
292 self.key = key
293 return self
294
295 def __init__(self, ob, callback, key):
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000296 super().__init__(ob, callback)
Fred Drake746fe0f2001-09-28 19:01:26 +0000297
Fred Drake41deb1e2001-02-01 05:27:45 +0000298
Raymond Hettinger7ac60952008-02-05 01:15:57 +0000299class WeakKeyDictionary(collections.MutableMapping):
Fred Drakebd7f8182001-04-19 16:26:06 +0000300 """ Mapping class that references keys weakly.
301
302 Entries in the dictionary will be discarded when there is no
303 longer a strong reference to the key. This can be used to
304 associate additional data with an object owned by other parts of
305 an application without adding attributes to those objects. This
306 can be especially useful with objects that override attribute
307 accesses.
308 """
Martin v. Löwis5e163332001-02-27 18:36:56 +0000309
310 def __init__(self, dict=None):
311 self.data = {}
Fred Drake746fe0f2001-09-28 19:01:26 +0000312 def remove(k, selfref=ref(self)):
313 self = selfref()
314 if self is not None:
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000315 if self._iterating:
316 self._pending_removals.append(k)
317 else:
318 del self.data[k]
Martin v. Löwis5e163332001-02-27 18:36:56 +0000319 self._remove = remove
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000320 # A list of dead weakrefs (keys to be removed)
321 self._pending_removals = []
322 self._iterating = set()
323 if dict is not None:
324 self.update(dict)
325
326 def _commit_removals(self):
327 # NOTE: We don't need to call this method before mutating the dict,
328 # because a dead weakref never compares equal to a live weakref,
329 # even if they happened to refer to equal objects.
330 # However, it means keys may already have been removed.
331 l = self._pending_removals
332 d = self.data
333 while l:
334 try:
335 del d[l.pop()]
336 except KeyError:
337 pass
Martin v. Löwis5e163332001-02-27 18:36:56 +0000338
Fred Drakeb663a2c2001-09-06 14:51:01 +0000339 def __delitem__(self, key):
Tim Peters886128f2003-05-25 01:45:11 +0000340 del self.data[ref(key)]
Fred Drakeb663a2c2001-09-06 14:51:01 +0000341
Martin v. Löwis5e163332001-02-27 18:36:56 +0000342 def __getitem__(self, key):
343 return self.data[ref(key)]
344
Raymond Hettinger7ac60952008-02-05 01:15:57 +0000345 def __len__(self):
Antoine Pitroubbe2f602012-03-01 16:26:35 +0100346 return len(self.data) - len(self._pending_removals)
Raymond Hettinger7ac60952008-02-05 01:15:57 +0000347
Martin v. Löwis5e163332001-02-27 18:36:56 +0000348 def __repr__(self):
349 return "<WeakKeyDictionary at %s>" % id(self)
350
351 def __setitem__(self, key, value):
352 self.data[ref(key, self._remove)] = value
353
354 def copy(self):
355 new = WeakKeyDictionary()
356 for key, value in self.data.items():
357 o = key()
358 if o is not None:
359 new[o] = value
Fred Drake9d2c85d2001-03-01 03:06:03 +0000360 return new
Martin v. Löwis5e163332001-02-27 18:36:56 +0000361
Antoine Pitrou6e610062009-05-15 17:04:50 +0000362 __copy__ = copy
363
364 def __deepcopy__(self, memo):
365 from copy import deepcopy
366 new = self.__class__()
367 for key, value in self.data.items():
368 o = key()
369 if o is not None:
370 new[o] = deepcopy(value, memo)
371 return new
372
Fred Drake1d9e4b72001-04-16 17:34:48 +0000373 def get(self, key, default=None):
Martin v. Löwis5e163332001-02-27 18:36:56 +0000374 return self.data.get(ref(key),default)
375
Raymond Hettinger54f02222002-06-01 14:18:47 +0000376 def __contains__(self, key):
377 try:
378 wr = ref(key)
379 except TypeError:
Georg Brandlbd87d082010-12-03 07:49:09 +0000380 return False
Raymond Hettinger54f02222002-06-01 14:18:47 +0000381 return wr in self.data
Tim Petersc411dba2002-07-16 21:35:23 +0000382
Martin v. Löwis5e163332001-02-27 18:36:56 +0000383 def items(self):
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000384 with _IterationGuard(self):
385 for wr, value in self.data.items():
386 key = wr()
387 if key is not None:
388 yield key, value
Thomas Wouters477c8d52006-05-27 19:21:47 +0000389
Barry Warsawecaab832008-09-04 01:42:51 +0000390 def keys(self):
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000391 with _IterationGuard(self):
392 for wr in self.data:
393 obj = wr()
394 if obj is not None:
395 yield obj
Raymond Hettinger61146792004-08-19 21:32:06 +0000396
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000397 __iter__ = keys
Fred Drake101209d2001-05-02 05:43:09 +0000398
Barry Warsawecaab832008-09-04 01:42:51 +0000399 def values(self):
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000400 with _IterationGuard(self):
401 for wr, value in self.data.items():
402 if wr() is not None:
403 yield value
Fred Drake101209d2001-05-02 05:43:09 +0000404
Thomas Wouters477c8d52006-05-27 19:21:47 +0000405 def keyrefs(self):
406 """Return a list of weak references to the keys.
407
408 The references are not guaranteed to be 'live' at the time
409 they are used, so the result of calling the references needs
410 to be checked before being used. This can be used to avoid
411 creating references that will cause the garbage collector to
412 keep the keys around longer than needed.
413
414 """
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000415 return list(self.data)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000416
Martin v. Löwis5e163332001-02-27 18:36:56 +0000417 def popitem(self):
Georg Brandlbd87d082010-12-03 07:49:09 +0000418 while True:
Martin v. Löwis5e163332001-02-27 18:36:56 +0000419 key, value = self.data.popitem()
420 o = key()
421 if o is not None:
422 return o, value
423
Raymond Hettinger2c2d3222003-03-09 07:05:43 +0000424 def pop(self, key, *args):
425 return self.data.pop(ref(key), *args)
426
Walter Dörwald80ce6dd2004-05-27 18:16:25 +0000427 def setdefault(self, key, default=None):
Martin v. Löwis5e163332001-02-27 18:36:56 +0000428 return self.data.setdefault(ref(key, self._remove),default)
429
Raymond Hettinger31017ae2004-03-04 08:25:44 +0000430 def update(self, dict=None, **kwargs):
Martin v. Löwis5e163332001-02-27 18:36:56 +0000431 d = self.data
Raymond Hettinger31017ae2004-03-04 08:25:44 +0000432 if dict is not None:
433 if not hasattr(dict, "items"):
434 dict = type({})(dict)
435 for key, value in dict.items():
436 d[ref(key, self._remove)] = value
437 if len(kwargs):
438 self.update(kwargs)