blob: ca37f8752875991233ddafb9da5a262a23138a74 [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
Alexandre Vassalottiba08f072008-04-27 00:52:24 +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
Fred Drake41deb1e2001-02-01 05:27:45 +000012import UserDict
13
Andrew M. Kuchling33ad28b2004-08-31 11:38:12 +000014from _weakref import (
15 getweakrefcount,
16 getweakrefs,
17 ref,
18 proxy,
19 CallableProxyType,
20 ProxyType,
21 ReferenceType)
Fred Drake41deb1e2001-02-01 05:27:45 +000022
Kristján Valur Jónsson222b2842013-12-05 10:03:45 +000023from _weakrefset import WeakSet, _IterationGuard
Michael Foorde6410c52010-03-29 20:04:23 +000024
Fred Drakee0292422001-10-05 21:54:09 +000025from exceptions import ReferenceError
26
27
Fred Drake41deb1e2001-02-01 05:27:45 +000028ProxyTypes = (ProxyType, CallableProxyType)
29
Fred Drake9a9d2192001-04-10 19:11:23 +000030__all__ = ["ref", "proxy", "getweakrefcount", "getweakrefs",
Brett Cannon88f801d2008-08-18 00:46:22 +000031 "WeakKeyDictionary", "ReferenceError", "ReferenceType", "ProxyType",
Michael Foorde6410c52010-03-29 20:04:23 +000032 "CallableProxyType", "ProxyTypes", "WeakValueDictionary", 'WeakSet']
Fred Drake41deb1e2001-02-01 05:27:45 +000033
Fred Drake41deb1e2001-02-01 05:27:45 +000034
Fred Drakebd7f8182001-04-19 16:26:06 +000035class WeakValueDictionary(UserDict.UserDict):
36 """Mapping class that references values weakly.
37
38 Entries in the dictionary will be discarded when no strong
39 reference to the value exists anymore
40 """
Fred Drake41deb1e2001-02-01 05:27:45 +000041 # We inherit the constructor without worrying about the input
42 # dictionary; since it uses our .update() method, we get the right
Fred Drake9d2c85d2001-03-01 03:06:03 +000043 # checks (if the other dictionary is a WeakValueDictionary,
44 # objects are unwrapped on the way out, and we always wrap on the
45 # way in).
Fred Drake41deb1e2001-02-01 05:27:45 +000046
Serhiy Storchakaf522bbc2015-09-29 23:51:27 +030047 def __init__(*args, **kw):
48 if not args:
49 raise TypeError("descriptor '__init__' of 'WeakValueDictionary' "
50 "object needs an argument")
51 self = args[0]
52 args = args[1:]
53 if len(args) > 1:
54 raise TypeError('expected at most 1 arguments, got %d' % len(args))
Fred Drake0a4dd392004-07-02 18:57:45 +000055 def remove(wr, selfref=ref(self)):
56 self = selfref()
57 if self is not None:
Kristján Valur Jónsson222b2842013-12-05 10:03:45 +000058 if self._iterating:
59 self._pending_removals.append(wr.key)
60 else:
61 del self.data[wr.key]
Fred Drake0a4dd392004-07-02 18:57:45 +000062 self._remove = remove
Kristján Valur Jónsson222b2842013-12-05 10:03:45 +000063 # A list of keys to be removed
64 self._pending_removals = []
65 self._iterating = set()
Georg Brandl9166e1a2005-06-04 09:20:03 +000066 UserDict.UserDict.__init__(self, *args, **kw)
Fred Drake0a4dd392004-07-02 18:57:45 +000067
Kristján Valur Jónsson222b2842013-12-05 10:03:45 +000068 def _commit_removals(self):
69 l = self._pending_removals
70 d = self.data
71 # We shouldn't encounter any KeyError, because this method should
72 # always be called *before* mutating the dict.
73 while l:
74 del d[l.pop()]
75
Fred Drake41deb1e2001-02-01 05:27:45 +000076 def __getitem__(self, key):
Fred Drake4fd06e02001-08-03 04:11:27 +000077 o = self.data[key]()
Fred Drake41deb1e2001-02-01 05:27:45 +000078 if o is None:
79 raise KeyError, key
80 else:
81 return o
82
Kristján Valur Jónsson222b2842013-12-05 10:03:45 +000083 def __delitem__(self, key):
84 if self._pending_removals:
85 self._commit_removals()
86 del self.data[key]
87
Raymond Hettinger61146792004-08-19 21:32:06 +000088 def __contains__(self, key):
89 try:
90 o = self.data[key]()
91 except KeyError:
92 return False
93 return o is not None
94
95 def has_key(self, key):
96 try:
97 o = self.data[key]()
98 except KeyError:
99 return False
100 return o is not None
101
Fred Drake41deb1e2001-02-01 05:27:45 +0000102 def __repr__(self):
Fred Drake9d2c85d2001-03-01 03:06:03 +0000103 return "<WeakValueDictionary at %s>" % id(self)
Fred Drake41deb1e2001-02-01 05:27:45 +0000104
105 def __setitem__(self, key, value):
Kristján Valur Jónsson222b2842013-12-05 10:03:45 +0000106 if self._pending_removals:
107 self._commit_removals()
Fred Drake0a4dd392004-07-02 18:57:45 +0000108 self.data[key] = KeyedRef(value, self._remove, key)
Fred Drake41deb1e2001-02-01 05:27:45 +0000109
Kristján Valur Jónsson222b2842013-12-05 10:03:45 +0000110 def clear(self):
111 if self._pending_removals:
112 self._commit_removals()
113 self.data.clear()
114
Fred Drake41deb1e2001-02-01 05:27:45 +0000115 def copy(self):
Fred Drake9d2c85d2001-03-01 03:06:03 +0000116 new = WeakValueDictionary()
Fred Drakebd7f8182001-04-19 16:26:06 +0000117 for key, wr in self.data.items():
118 o = wr()
Fred Drake41deb1e2001-02-01 05:27:45 +0000119 if o is not None:
120 new[key] = o
Fred Drake9d2c85d2001-03-01 03:06:03 +0000121 return new
Fred Drake41deb1e2001-02-01 05:27:45 +0000122
Antoine Pitrou775fd662009-05-15 16:54:52 +0000123 __copy__ = copy
124
125 def __deepcopy__(self, memo):
126 from copy import deepcopy
127 new = self.__class__()
128 for key, wr in self.data.items():
129 o = wr()
130 if o is not None:
131 new[deepcopy(key, memo)] = o
132 return new
133
Fred Drake1d9e4b72001-04-16 17:34:48 +0000134 def get(self, key, default=None):
Fred Drake41deb1e2001-02-01 05:27:45 +0000135 try:
Fred Drakebd7f8182001-04-19 16:26:06 +0000136 wr = self.data[key]
Fred Drake41deb1e2001-02-01 05:27:45 +0000137 except KeyError:
138 return default
139 else:
Fred Drakebd7f8182001-04-19 16:26:06 +0000140 o = wr()
Fred Drake41deb1e2001-02-01 05:27:45 +0000141 if o is None:
142 # This should only happen
143 return default
144 else:
145 return o
146
147 def items(self):
Fred Drake312a5dc2001-02-02 15:13:24 +0000148 L = []
Fred Drakebd7f8182001-04-19 16:26:06 +0000149 for key, wr in self.data.items():
150 o = wr()
Fred Drake41deb1e2001-02-01 05:27:45 +0000151 if o is not None:
Fred Drake312a5dc2001-02-02 15:13:24 +0000152 L.append((key, o))
Fred Drake41deb1e2001-02-01 05:27:45 +0000153 return L
154
Fred Drake101209d2001-05-02 05:43:09 +0000155 def iteritems(self):
Kristján Valur Jónsson222b2842013-12-05 10:03:45 +0000156 with _IterationGuard(self):
157 for wr in self.data.itervalues():
158 value = wr()
159 if value is not None:
160 yield wr.key, value
Fred Drake101209d2001-05-02 05:43:09 +0000161
162 def iterkeys(self):
Kristján Valur Jónsson222b2842013-12-05 10:03:45 +0000163 with _IterationGuard(self):
164 for k in self.data.iterkeys():
165 yield k
Raymond Hettinger61146792004-08-19 21:32:06 +0000166
Kristján Valur Jónsson222b2842013-12-05 10:03:45 +0000167 __iter__ = iterkeys
Fred Drake101209d2001-05-02 05:43:09 +0000168
Fred Drake017e68c2006-05-02 06:53:59 +0000169 def itervaluerefs(self):
170 """Return an iterator that yields the weak references to the values.
171
172 The references are not guaranteed to be 'live' at the time
173 they are used, so the result of calling the references needs
174 to be checked before being used. This can be used to avoid
175 creating references that will cause the garbage collector to
176 keep the values around longer than needed.
177
178 """
Kristján Valur Jónsson222b2842013-12-05 10:03:45 +0000179 with _IterationGuard(self):
180 for wr in self.data.itervalues():
181 yield wr
Fred Drake017e68c2006-05-02 06:53:59 +0000182
Fred Drake101209d2001-05-02 05:43:09 +0000183 def itervalues(self):
Kristján Valur Jónsson222b2842013-12-05 10:03:45 +0000184 with _IterationGuard(self):
185 for wr in self.data.itervalues():
186 obj = wr()
187 if obj is not None:
188 yield obj
Fred Drake101209d2001-05-02 05:43:09 +0000189
Fred Drake41deb1e2001-02-01 05:27:45 +0000190 def popitem(self):
Kristján Valur Jónsson222b2842013-12-05 10:03:45 +0000191 if self._pending_removals:
192 self._commit_removals()
Fred Drake41deb1e2001-02-01 05:27:45 +0000193 while 1:
Fred Drakebd7f8182001-04-19 16:26:06 +0000194 key, wr = self.data.popitem()
195 o = wr()
Fred Drake41deb1e2001-02-01 05:27:45 +0000196 if o is not None:
197 return key, o
198
Raymond Hettinger2c2d3222003-03-09 07:05:43 +0000199 def pop(self, key, *args):
Kristján Valur Jónsson222b2842013-12-05 10:03:45 +0000200 if self._pending_removals:
201 self._commit_removals()
Raymond Hettinger2c2d3222003-03-09 07:05:43 +0000202 try:
203 o = self.data.pop(key)()
204 except KeyError:
205 if args:
206 return args[0]
207 raise
208 if o is None:
209 raise KeyError, key
210 else:
211 return o
212
Walter Dörwald80ce6dd2004-05-27 18:16:25 +0000213 def setdefault(self, key, default=None):
Fred Drake41deb1e2001-02-01 05:27:45 +0000214 try:
Fred Drakebd7f8182001-04-19 16:26:06 +0000215 wr = self.data[key]
Fred Drake41deb1e2001-02-01 05:27:45 +0000216 except KeyError:
Kristján Valur Jónsson222b2842013-12-05 10:03:45 +0000217 if self._pending_removals:
218 self._commit_removals()
Fred Drake0a4dd392004-07-02 18:57:45 +0000219 self.data[key] = KeyedRef(default, self._remove, key)
Fred Drake41deb1e2001-02-01 05:27:45 +0000220 return default
221 else:
Fred Drakebd7f8182001-04-19 16:26:06 +0000222 return wr()
Fred Drake41deb1e2001-02-01 05:27:45 +0000223
Serhiy Storchakaf522bbc2015-09-29 23:51:27 +0300224 def update(*args, **kwargs):
225 if not args:
226 raise TypeError("descriptor 'update' of 'WeakValueDictionary' "
227 "object needs an argument")
228 self = args[0]
229 args = args[1:]
230 if len(args) > 1:
231 raise TypeError('expected at most 1 arguments, got %d' % len(args))
232 dict = args[0] if args else None
Kristján Valur Jónsson222b2842013-12-05 10:03:45 +0000233 if self._pending_removals:
234 self._commit_removals()
Fred Drake41deb1e2001-02-01 05:27:45 +0000235 d = self.data
Raymond Hettinger31017ae2004-03-04 08:25:44 +0000236 if dict is not None:
237 if not hasattr(dict, "items"):
238 dict = type({})(dict)
239 for key, o in dict.items():
Fred Drake0a4dd392004-07-02 18:57:45 +0000240 d[key] = KeyedRef(o, self._remove, key)
Raymond Hettinger31017ae2004-03-04 08:25:44 +0000241 if len(kwargs):
242 self.update(kwargs)
Fred Drake41deb1e2001-02-01 05:27:45 +0000243
Fred Drake017e68c2006-05-02 06:53:59 +0000244 def valuerefs(self):
245 """Return a list of weak references to the values.
246
247 The references are not guaranteed to be 'live' at the time
248 they are used, so the result of calling the references needs
249 to be checked before being used. This can be used to avoid
250 creating references that will cause the garbage collector to
251 keep the values around longer than needed.
252
253 """
254 return self.data.values()
255
Fred Drake41deb1e2001-02-01 05:27:45 +0000256 def values(self):
257 L = []
Fred Drakebd7f8182001-04-19 16:26:06 +0000258 for wr in self.data.values():
259 o = wr()
Fred Drake41deb1e2001-02-01 05:27:45 +0000260 if o is not None:
261 L.append(o)
262 return L
263
Fred Drake0a4dd392004-07-02 18:57:45 +0000264
265class KeyedRef(ref):
266 """Specialized reference that includes a key corresponding to the value.
267
268 This is used in the WeakValueDictionary to avoid having to create
269 a function object for each key stored in the mapping. A shared
270 callback object can use the 'key' attribute of a KeyedRef instead
271 of getting a reference to the key from an enclosing scope.
272
273 """
274
275 __slots__ = "key",
276
277 def __new__(type, ob, callback, key):
278 self = ref.__new__(type, ob, callback)
279 self.key = key
280 return self
281
282 def __init__(self, ob, callback, key):
283 super(KeyedRef, self).__init__(ob, callback)
Fred Drake746fe0f2001-09-28 19:01:26 +0000284
Fred Drake41deb1e2001-02-01 05:27:45 +0000285
Martin v. Löwis5e163332001-02-27 18:36:56 +0000286class WeakKeyDictionary(UserDict.UserDict):
Fred Drakebd7f8182001-04-19 16:26:06 +0000287 """ Mapping class that references keys weakly.
288
289 Entries in the dictionary will be discarded when there is no
290 longer a strong reference to the key. This can be used to
291 associate additional data with an object owned by other parts of
292 an application without adding attributes to those objects. This
293 can be especially useful with objects that override attribute
294 accesses.
295 """
Martin v. Löwis5e163332001-02-27 18:36:56 +0000296
297 def __init__(self, dict=None):
298 self.data = {}
Fred Drake746fe0f2001-09-28 19:01:26 +0000299 def remove(k, selfref=ref(self)):
300 self = selfref()
301 if self is not None:
Kristján Valur Jónsson222b2842013-12-05 10:03:45 +0000302 if self._iterating:
303 self._pending_removals.append(k)
304 else:
305 del self.data[k]
Martin v. Löwis5e163332001-02-27 18:36:56 +0000306 self._remove = remove
Kristján Valur Jónsson222b2842013-12-05 10:03:45 +0000307 # A list of dead weakrefs (keys to be removed)
308 self._pending_removals = []
309 self._iterating = set()
310 if dict is not None:
311 self.update(dict)
312
313 def _commit_removals(self):
314 # NOTE: We don't need to call this method before mutating the dict,
315 # because a dead weakref never compares equal to a live weakref,
316 # even if they happened to refer to equal objects.
317 # However, it means keys may already have been removed.
318 l = self._pending_removals
319 d = self.data
320 while l:
321 try:
322 del d[l.pop()]
323 except KeyError:
324 pass
Martin v. Löwis5e163332001-02-27 18:36:56 +0000325
Fred Drakeb663a2c2001-09-06 14:51:01 +0000326 def __delitem__(self, key):
Tim Peters886128f2003-05-25 01:45:11 +0000327 del self.data[ref(key)]
Fred Drakeb663a2c2001-09-06 14:51:01 +0000328
Martin v. Löwis5e163332001-02-27 18:36:56 +0000329 def __getitem__(self, key):
330 return self.data[ref(key)]
331
332 def __repr__(self):
333 return "<WeakKeyDictionary at %s>" % id(self)
334
335 def __setitem__(self, key, value):
336 self.data[ref(key, self._remove)] = value
337
338 def copy(self):
339 new = WeakKeyDictionary()
340 for key, value in self.data.items():
341 o = key()
342 if o is not None:
343 new[o] = value
Fred Drake9d2c85d2001-03-01 03:06:03 +0000344 return new
Martin v. Löwis5e163332001-02-27 18:36:56 +0000345
Antoine Pitrou775fd662009-05-15 16:54:52 +0000346 __copy__ = copy
347
348 def __deepcopy__(self, memo):
349 from copy import deepcopy
350 new = self.__class__()
351 for key, value in self.data.items():
352 o = key()
353 if o is not None:
354 new[o] = deepcopy(value, memo)
355 return new
356
Fred Drake1d9e4b72001-04-16 17:34:48 +0000357 def get(self, key, default=None):
Martin v. Löwis5e163332001-02-27 18:36:56 +0000358 return self.data.get(ref(key),default)
359
Fred Drake1d9e4b72001-04-16 17:34:48 +0000360 def has_key(self, key):
Fred Drake3bae7dd2001-11-06 16:36:53 +0000361 try:
362 wr = ref(key)
363 except TypeError:
364 return 0
Raymond Hettinger54f02222002-06-01 14:18:47 +0000365 return wr in self.data
Fred Drake1d9e4b72001-04-16 17:34:48 +0000366
Raymond Hettinger54f02222002-06-01 14:18:47 +0000367 def __contains__(self, key):
368 try:
369 wr = ref(key)
370 except TypeError:
371 return 0
372 return wr in self.data
Tim Petersc411dba2002-07-16 21:35:23 +0000373
Martin v. Löwis5e163332001-02-27 18:36:56 +0000374 def items(self):
375 L = []
376 for key, value in self.data.items():
377 o = key()
378 if o is not None:
379 L.append((o, value))
380 return L
381
Fred Drake101209d2001-05-02 05:43:09 +0000382 def iteritems(self):
Kristján Valur Jónsson222b2842013-12-05 10:03:45 +0000383 with _IterationGuard(self):
384 for wr, value in self.data.iteritems():
385 key = wr()
386 if key is not None:
387 yield key, value
Fred Drake101209d2001-05-02 05:43:09 +0000388
Fred Drake017e68c2006-05-02 06:53:59 +0000389 def iterkeyrefs(self):
390 """Return an iterator that yields the weak references to the keys.
391
392 The references are not guaranteed to be 'live' at the time
393 they are used, so the result of calling the references needs
394 to be checked before being used. This can be used to avoid
395 creating references that will cause the garbage collector to
396 keep the keys around longer than needed.
397
398 """
Kristján Valur Jónsson222b2842013-12-05 10:03:45 +0000399 with _IterationGuard(self):
400 for wr in self.data.iterkeys():
401 yield wr
Fred Drake017e68c2006-05-02 06:53:59 +0000402
Fred Drake101209d2001-05-02 05:43:09 +0000403 def iterkeys(self):
Kristján Valur Jónsson222b2842013-12-05 10:03:45 +0000404 with _IterationGuard(self):
405 for wr in self.data.iterkeys():
406 obj = wr()
407 if obj is not None:
408 yield obj
Raymond Hettinger61146792004-08-19 21:32:06 +0000409
Kristján Valur Jónsson222b2842013-12-05 10:03:45 +0000410 __iter__ = iterkeys
Fred Drake101209d2001-05-02 05:43:09 +0000411
412 def itervalues(self):
Kristján Valur Jónsson222b2842013-12-05 10:03:45 +0000413 with _IterationGuard(self):
414 for value in self.data.itervalues():
415 yield value
Fred Drake101209d2001-05-02 05:43:09 +0000416
Fred Drake017e68c2006-05-02 06:53:59 +0000417 def keyrefs(self):
418 """Return a list of weak references to the keys.
419
420 The references are not guaranteed to be 'live' at the time
421 they are used, so the result of calling the references needs
422 to be checked before being used. This can be used to avoid
423 creating references that will cause the garbage collector to
424 keep the keys around longer than needed.
425
426 """
427 return self.data.keys()
428
Fred Drake1d9e4b72001-04-16 17:34:48 +0000429 def keys(self):
430 L = []
Fred Drakebd7f8182001-04-19 16:26:06 +0000431 for wr in self.data.keys():
432 o = wr()
Fred Drake1d9e4b72001-04-16 17:34:48 +0000433 if o is not None:
434 L.append(o)
435 return L
436
Martin v. Löwis5e163332001-02-27 18:36:56 +0000437 def popitem(self):
438 while 1:
439 key, value = self.data.popitem()
440 o = key()
441 if o is not None:
442 return o, value
443
Raymond Hettinger2c2d3222003-03-09 07:05:43 +0000444 def pop(self, key, *args):
445 return self.data.pop(ref(key), *args)
446
Walter Dörwald80ce6dd2004-05-27 18:16:25 +0000447 def setdefault(self, key, default=None):
Martin v. Löwis5e163332001-02-27 18:36:56 +0000448 return self.data.setdefault(ref(key, self._remove),default)
449
Raymond Hettinger31017ae2004-03-04 08:25:44 +0000450 def update(self, dict=None, **kwargs):
Martin v. Löwis5e163332001-02-27 18:36:56 +0000451 d = self.data
Raymond Hettinger31017ae2004-03-04 08:25:44 +0000452 if dict is not None:
453 if not hasattr(dict, "items"):
454 dict = type({})(dict)
455 for key, value in dict.items():
456 d[ref(key, self._remove)] = value
457 if len(kwargs):
458 self.update(kwargs)