blob: 39af9b821e768cc549e1817fa5263f31d19e9c97 [file] [log] [blame]
Tor Norbye3a2425a52013-11-04 10:16:08 -08001"""Weak reference support for Python.
2
3This module is an implementation of PEP 205:
4
5http://python.sourceforge.net/peps/pep-0205.html
6"""
7
8# 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
12import UserDict
13
14from _weakref import (
15 getweakrefcount,
16 getweakrefs,
17 ref,
18 proxy,
19 CallableProxyType,
20 ProxyType,
21 ReferenceType)
22
23from exceptions import ReferenceError
24
25
26ProxyTypes = (ProxyType, CallableProxyType)
27
28__all__ = ["ref", "proxy", "getweakrefcount", "getweakrefs",
29 "WeakKeyDictionary", "ReferenceType", "ProxyType",
30 "CallableProxyType", "ProxyTypes", "WeakValueDictionary"]
31
32
33class WeakValueDictionary(UserDict.UserDict):
34 """Mapping class that references values weakly.
35
36 Entries in the dictionary will be discarded when no strong
37 reference to the value exists anymore
38 """
39 # We inherit the constructor without worrying about the input
40 # dictionary; since it uses our .update() method, we get the right
41 # checks (if the other dictionary is a WeakValueDictionary,
42 # objects are unwrapped on the way out, and we always wrap on the
43 # way in).
44
45 def __init__(self, *args, **kw):
46 def remove(wr, selfref=ref(self)):
47 self = selfref()
48 if self is not None:
49 try:
50 del self.data[wr.key]
51 except KeyError:
52 pass
53 self._remove = remove
54 UserDict.UserDict.__init__(self, *args, **kw)
55
56 def __getitem__(self, key):
57 o = self.data[key]()
58 if o is None:
59 raise KeyError, key
60 else:
61 return o
62
63 def __contains__(self, key):
64 try:
65 o = self.data[key]()
66 except KeyError:
67 return False
68 return o is not None
69
70 def has_key(self, key):
71 try:
72 o = self.data[key]()
73 except KeyError:
74 return False
75 return o is not None
76
77 def __repr__(self):
78 return "<WeakValueDictionary at %s>" % id(self)
79
80 def __setitem__(self, key, value):
81 self.data[key] = KeyedRef(value, self._remove, key)
82
83 def copy(self):
84 new = WeakValueDictionary()
85 for key, wr in self.data.items():
86 o = wr()
87 if o is not None:
88 new[key] = o
89 return new
90
91 def get(self, key, default=None):
92 try:
93 wr = self.data[key]
94 except KeyError:
95 return default
96 else:
97 o = wr()
98 if o is None:
99 # This should only happen
100 return default
101 else:
102 return o
103
104 def items(self):
105 L = []
106 for key, wr in self.data.items():
107 o = wr()
108 if o is not None:
109 L.append((key, o))
110 return L
111
112 def iteritems(self):
113 for wr in self.data.itervalues():
114 value = wr()
115 if value is not None:
116 yield wr.key, value
117
118 def iterkeys(self):
119 return self.data.iterkeys()
120
121 def __iter__(self):
122 return self.data.iterkeys()
123
124 def itervaluerefs(self):
125 """Return an iterator that yields the weak references to the values.
126
127 The references are not guaranteed to be 'live' at the time
128 they are used, so the result of calling the references needs
129 to be checked before being used. This can be used to avoid
130 creating references that will cause the garbage collector to
131 keep the values around longer than needed.
132
133 """
134 return self.data.itervalues()
135
136 def itervalues(self):
137 for wr in self.data.itervalues():
138 obj = wr()
139 if obj is not None:
140 yield obj
141
142 def popitem(self):
143 while 1:
144 key, wr = self.data.popitem()
145 o = wr()
146 if o is not None:
147 return key, o
148
149 def pop(self, key, *args):
150 try:
151 o = self.data.pop(key)()
152 except KeyError:
153 if args:
154 return args[0]
155 raise
156 if o is None:
157 raise KeyError, key
158 else:
159 return o
160
161 def setdefault(self, key, default=None):
162 try:
163 wr = self.data[key]
164 except KeyError:
165 self.data[key] = KeyedRef(default, self._remove, key)
166 return default
167 else:
168 return wr()
169
170 def update(self, dict=None, **kwargs):
171 d = self.data
172 if dict is not None:
173 if not hasattr(dict, "items"):
174 dict = type({})(dict)
175 for key, o in dict.items():
176 d[key] = KeyedRef(o, self._remove, key)
177 if len(kwargs):
178 self.update(kwargs)
179
180 def valuerefs(self):
181 """Return a list of weak references to the values.
182
183 The references are not guaranteed to be 'live' at the time
184 they are used, so the result of calling the references needs
185 to be checked before being used. This can be used to avoid
186 creating references that will cause the garbage collector to
187 keep the values around longer than needed.
188
189 """
190 return self.data.values()
191
192 def values(self):
193 L = []
194 for wr in self.data.values():
195 o = wr()
196 if o is not None:
197 L.append(o)
198 return L
199
200
201class KeyedRef(ref):
202 """Specialized reference that includes a key corresponding to the value.
203
204 This is used in the WeakValueDictionary to avoid having to create
205 a function object for each key stored in the mapping. A shared
206 callback object can use the 'key' attribute of a KeyedRef instead
207 of getting a reference to the key from an enclosing scope.
208
209 """
210
211 __slots__ = "key",
212
213 def __new__(type, ob, callback, key):
214 self = ref.__new__(type, ob, callback)
215 self.key = key
216 return self
217
218 def __init__(self, ob, callback, key):
219 super(KeyedRef, self).__init__(ob, callback)
220
221
222class WeakKeyDictionary(UserDict.UserDict):
223 """ Mapping class that references keys weakly.
224
225 Entries in the dictionary will be discarded when there is no
226 longer a strong reference to the key. This can be used to
227 associate additional data with an object owned by other parts of
228 an application without adding attributes to those objects. This
229 can be especially useful with objects that override attribute
230 accesses.
231 """
232
233 def __init__(self, dict=None):
234 self.data = {}
235 def remove(k, selfref=ref(self)):
236 self = selfref()
237 if self is not None:
238 try:
239 del self.data[k]
240 except KeyError:
241 pass
242 self._remove = remove
243 if dict is not None: self.update(dict)
244
245 def __delitem__(self, key):
246 del self.data[ref(key)]
247
248 def __getitem__(self, key):
249 return self.data[ref(key)]
250
251 def __repr__(self):
252 return "<WeakKeyDictionary at %s>" % id(self)
253
254 def __setitem__(self, key, value):
255 self.data[ref(key, self._remove)] = value
256
257 def copy(self):
258 new = WeakKeyDictionary()
259 for key, value in self.data.items():
260 o = key()
261 if o is not None:
262 new[o] = value
263 return new
264
265 def get(self, key, default=None):
266 return self.data.get(ref(key),default)
267
268 def has_key(self, key):
269 try:
270 wr = ref(key)
271 except TypeError:
272 return 0
273 return wr in self.data
274
275 def __contains__(self, key):
276 try:
277 wr = ref(key)
278 except TypeError:
279 return 0
280 return wr in self.data
281
282 def items(self):
283 L = []
284 for key, value in self.data.items():
285 o = key()
286 if o is not None:
287 L.append((o, value))
288 return L
289
290 def iteritems(self):
291 for wr, value in self.data.iteritems():
292 key = wr()
293 if key is not None:
294 yield key, value
295
296 def iterkeyrefs(self):
297 """Return an iterator that yields the weak references to the keys.
298
299 The references are not guaranteed to be 'live' at the time
300 they are used, so the result of calling the references needs
301 to be checked before being used. This can be used to avoid
302 creating references that will cause the garbage collector to
303 keep the keys around longer than needed.
304
305 """
306 return self.data.iterkeys()
307
308 def iterkeys(self):
309 for wr in self.data.iterkeys():
310 obj = wr()
311 if obj is not None:
312 yield obj
313
314 def __iter__(self):
315 return self.iterkeys()
316
317 def itervalues(self):
318 return self.data.itervalues()
319
320 def keyrefs(self):
321 """Return a list of weak references to the keys.
322
323 The references are not guaranteed to be 'live' at the time
324 they are used, so the result of calling the references needs
325 to be checked before being used. This can be used to avoid
326 creating references that will cause the garbage collector to
327 keep the keys around longer than needed.
328
329 """
330 return self.data.keys()
331
332 def keys(self):
333 L = []
334 for wr in self.data.keys():
335 o = wr()
336 if o is not None:
337 L.append(o)
338 return L
339
340 def popitem(self):
341 while 1:
342 key, value = self.data.popitem()
343 o = key()
344 if o is not None:
345 return o, value
346
347 def pop(self, key, *args):
348 return self.data.pop(ref(key), *args)
349
350 def setdefault(self, key, default=None):
351 return self.data.setdefault(ref(key, self._remove),default)
352
353 def update(self, dict=None, **kwargs):
354 d = self.data
355 if dict is not None:
356 if not hasattr(dict, "items"):
357 dict = type({})(dict)
358 for key, value in dict.items():
359 d[ref(key, self._remove)] = value
360 if len(kwargs):
361 self.update(kwargs)