blob: c0669b03173e5ec46f3e318ca23431c40308d703 [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
5http://python.sourceforge.net/peps/pep-0205.html
6"""
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
Fred Drakee0292422001-10-05 21:54:09 +000023from exceptions import ReferenceError
24
25
Fred Drake41deb1e2001-02-01 05:27:45 +000026ProxyTypes = (ProxyType, CallableProxyType)
27
Fred Drake9a9d2192001-04-10 19:11:23 +000028__all__ = ["ref", "proxy", "getweakrefcount", "getweakrefs",
Skip Montanaro40fc1602001-03-01 04:27:19 +000029 "WeakKeyDictionary", "ReferenceType", "ProxyType",
30 "CallableProxyType", "ProxyTypes", "WeakValueDictionary"]
Fred Drake41deb1e2001-02-01 05:27:45 +000031
Fred Drake41deb1e2001-02-01 05:27:45 +000032
Fred Drakebd7f8182001-04-19 16:26:06 +000033class 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 """
Fred Drake41deb1e2001-02-01 05:27:45 +000039 # We inherit the constructor without worrying about the input
40 # dictionary; since it uses our .update() method, we get the right
Fred Drake9d2c85d2001-03-01 03:06:03 +000041 # 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).
Fred Drake41deb1e2001-02-01 05:27:45 +000044
Fred Drake0a4dd392004-07-02 18:57:45 +000045 def __init__(self, *args, **kw):
46 UserDict.UserDict.__init__(self, *args, **kw)
47 def remove(wr, selfref=ref(self)):
48 self = selfref()
49 if self is not None:
50 del self.data[wr.key]
51 self._remove = remove
52
Fred Drake41deb1e2001-02-01 05:27:45 +000053 def __getitem__(self, key):
Fred Drake4fd06e02001-08-03 04:11:27 +000054 o = self.data[key]()
Fred Drake41deb1e2001-02-01 05:27:45 +000055 if o is None:
56 raise KeyError, key
57 else:
58 return o
59
Raymond Hettinger61146792004-08-19 21:32:06 +000060 def __contains__(self, key):
61 try:
62 o = self.data[key]()
63 except KeyError:
64 return False
65 return o is not None
66
67 def has_key(self, key):
68 try:
69 o = self.data[key]()
70 except KeyError:
71 return False
72 return o is not None
73
Fred Drake41deb1e2001-02-01 05:27:45 +000074 def __repr__(self):
Fred Drake9d2c85d2001-03-01 03:06:03 +000075 return "<WeakValueDictionary at %s>" % id(self)
Fred Drake41deb1e2001-02-01 05:27:45 +000076
77 def __setitem__(self, key, value):
Fred Drake0a4dd392004-07-02 18:57:45 +000078 self.data[key] = KeyedRef(value, self._remove, key)
Fred Drake41deb1e2001-02-01 05:27:45 +000079
80 def copy(self):
Fred Drake9d2c85d2001-03-01 03:06:03 +000081 new = WeakValueDictionary()
Fred Drakebd7f8182001-04-19 16:26:06 +000082 for key, wr in self.data.items():
83 o = wr()
Fred Drake41deb1e2001-02-01 05:27:45 +000084 if o is not None:
85 new[key] = o
Fred Drake9d2c85d2001-03-01 03:06:03 +000086 return new
Fred Drake41deb1e2001-02-01 05:27:45 +000087
Fred Drake1d9e4b72001-04-16 17:34:48 +000088 def get(self, key, default=None):
Fred Drake41deb1e2001-02-01 05:27:45 +000089 try:
Fred Drakebd7f8182001-04-19 16:26:06 +000090 wr = self.data[key]
Fred Drake41deb1e2001-02-01 05:27:45 +000091 except KeyError:
92 return default
93 else:
Fred Drakebd7f8182001-04-19 16:26:06 +000094 o = wr()
Fred Drake41deb1e2001-02-01 05:27:45 +000095 if o is None:
96 # This should only happen
97 return default
98 else:
99 return o
100
101 def items(self):
Fred Drake312a5dc2001-02-02 15:13:24 +0000102 L = []
Fred Drakebd7f8182001-04-19 16:26:06 +0000103 for key, wr in self.data.items():
104 o = wr()
Fred Drake41deb1e2001-02-01 05:27:45 +0000105 if o is not None:
Fred Drake312a5dc2001-02-02 15:13:24 +0000106 L.append((key, o))
Fred Drake41deb1e2001-02-01 05:27:45 +0000107 return L
108
Fred Drake101209d2001-05-02 05:43:09 +0000109 def iteritems(self):
Raymond Hettinger61146792004-08-19 21:32:06 +0000110 for wr in self.data.itervalues():
111 value = wr()
112 if value is not None:
113 yield wr.key, value
Fred Drake101209d2001-05-02 05:43:09 +0000114
115 def iterkeys(self):
116 return self.data.iterkeys()
Raymond Hettinger61146792004-08-19 21:32:06 +0000117
118 def __iter__(self):
119 return self.data.iterkeys()
Fred Drake101209d2001-05-02 05:43:09 +0000120
121 def itervalues(self):
Raymond Hettinger61146792004-08-19 21:32:06 +0000122 for wr in self.data.itervalues():
123 obj = wr()
124 if obj is not None:
125 yield obj
Fred Drake101209d2001-05-02 05:43:09 +0000126
Fred Drake41deb1e2001-02-01 05:27:45 +0000127 def popitem(self):
128 while 1:
Fred Drakebd7f8182001-04-19 16:26:06 +0000129 key, wr = self.data.popitem()
130 o = wr()
Fred Drake41deb1e2001-02-01 05:27:45 +0000131 if o is not None:
132 return key, o
133
Raymond Hettinger2c2d3222003-03-09 07:05:43 +0000134 def pop(self, key, *args):
135 try:
136 o = self.data.pop(key)()
137 except KeyError:
138 if args:
139 return args[0]
140 raise
141 if o is None:
142 raise KeyError, key
143 else:
144 return o
145
Walter Dörwald80ce6dd2004-05-27 18:16:25 +0000146 def setdefault(self, key, default=None):
Fred Drake41deb1e2001-02-01 05:27:45 +0000147 try:
Fred Drakebd7f8182001-04-19 16:26:06 +0000148 wr = self.data[key]
Fred Drake41deb1e2001-02-01 05:27:45 +0000149 except KeyError:
Fred Drake0a4dd392004-07-02 18:57:45 +0000150 self.data[key] = KeyedRef(default, self._remove, key)
Fred Drake41deb1e2001-02-01 05:27:45 +0000151 return default
152 else:
Fred Drakebd7f8182001-04-19 16:26:06 +0000153 return wr()
Fred Drake41deb1e2001-02-01 05:27:45 +0000154
Raymond Hettinger31017ae2004-03-04 08:25:44 +0000155 def update(self, dict=None, **kwargs):
Fred Drake41deb1e2001-02-01 05:27:45 +0000156 d = self.data
Raymond Hettinger31017ae2004-03-04 08:25:44 +0000157 if dict is not None:
158 if not hasattr(dict, "items"):
159 dict = type({})(dict)
160 for key, o in dict.items():
Fred Drake0a4dd392004-07-02 18:57:45 +0000161 d[key] = KeyedRef(o, self._remove, key)
Raymond Hettinger31017ae2004-03-04 08:25:44 +0000162 if len(kwargs):
163 self.update(kwargs)
Fred Drake41deb1e2001-02-01 05:27:45 +0000164
165 def values(self):
166 L = []
Fred Drakebd7f8182001-04-19 16:26:06 +0000167 for wr in self.data.values():
168 o = wr()
Fred Drake41deb1e2001-02-01 05:27:45 +0000169 if o is not None:
170 L.append(o)
171 return L
172
Fred Drake0a4dd392004-07-02 18:57:45 +0000173
174class KeyedRef(ref):
175 """Specialized reference that includes a key corresponding to the value.
176
177 This is used in the WeakValueDictionary to avoid having to create
178 a function object for each key stored in the mapping. A shared
179 callback object can use the 'key' attribute of a KeyedRef instead
180 of getting a reference to the key from an enclosing scope.
181
182 """
183
184 __slots__ = "key",
185
186 def __new__(type, ob, callback, key):
187 self = ref.__new__(type, ob, callback)
188 self.key = key
189 return self
190
191 def __init__(self, ob, callback, key):
192 super(KeyedRef, self).__init__(ob, callback)
Fred Drake746fe0f2001-09-28 19:01:26 +0000193
Fred Drake41deb1e2001-02-01 05:27:45 +0000194
Martin v. Löwis5e163332001-02-27 18:36:56 +0000195class WeakKeyDictionary(UserDict.UserDict):
Fred Drakebd7f8182001-04-19 16:26:06 +0000196 """ Mapping class that references keys weakly.
197
198 Entries in the dictionary will be discarded when there is no
199 longer a strong reference to the key. This can be used to
200 associate additional data with an object owned by other parts of
201 an application without adding attributes to those objects. This
202 can be especially useful with objects that override attribute
203 accesses.
204 """
Martin v. Löwis5e163332001-02-27 18:36:56 +0000205
206 def __init__(self, dict=None):
207 self.data = {}
Fred Drake746fe0f2001-09-28 19:01:26 +0000208 def remove(k, selfref=ref(self)):
209 self = selfref()
210 if self is not None:
211 del self.data[k]
Martin v. Löwis5e163332001-02-27 18:36:56 +0000212 self._remove = remove
Guido van Rossum009afb72002-06-10 20:00:52 +0000213 if dict is not None: self.update(dict)
Martin v. Löwis5e163332001-02-27 18:36:56 +0000214
Fred Drakeb663a2c2001-09-06 14:51:01 +0000215 def __delitem__(self, key):
Tim Peters886128f2003-05-25 01:45:11 +0000216 del self.data[ref(key)]
Fred Drakeb663a2c2001-09-06 14:51:01 +0000217
Martin v. Löwis5e163332001-02-27 18:36:56 +0000218 def __getitem__(self, key):
219 return self.data[ref(key)]
220
221 def __repr__(self):
222 return "<WeakKeyDictionary at %s>" % id(self)
223
224 def __setitem__(self, key, value):
225 self.data[ref(key, self._remove)] = value
226
227 def copy(self):
228 new = WeakKeyDictionary()
229 for key, value in self.data.items():
230 o = key()
231 if o is not None:
232 new[o] = value
Fred Drake9d2c85d2001-03-01 03:06:03 +0000233 return new
Martin v. Löwis5e163332001-02-27 18:36:56 +0000234
Fred Drake1d9e4b72001-04-16 17:34:48 +0000235 def get(self, key, default=None):
Martin v. Löwis5e163332001-02-27 18:36:56 +0000236 return self.data.get(ref(key),default)
237
Fred Drake1d9e4b72001-04-16 17:34:48 +0000238 def has_key(self, key):
Fred Drake3bae7dd2001-11-06 16:36:53 +0000239 try:
240 wr = ref(key)
241 except TypeError:
242 return 0
Raymond Hettinger54f02222002-06-01 14:18:47 +0000243 return wr in self.data
Fred Drake1d9e4b72001-04-16 17:34:48 +0000244
Raymond Hettinger54f02222002-06-01 14:18:47 +0000245 def __contains__(self, key):
246 try:
247 wr = ref(key)
248 except TypeError:
249 return 0
250 return wr in self.data
Tim Petersc411dba2002-07-16 21:35:23 +0000251
Martin v. Löwis5e163332001-02-27 18:36:56 +0000252 def items(self):
253 L = []
254 for key, value in self.data.items():
255 o = key()
256 if o is not None:
257 L.append((o, value))
258 return L
259
Fred Drake101209d2001-05-02 05:43:09 +0000260 def iteritems(self):
Raymond Hettinger61146792004-08-19 21:32:06 +0000261 for wr, value in self.data.iteritems():
262 key = wr()
263 if key is not None:
264 yield key, value
Fred Drake101209d2001-05-02 05:43:09 +0000265
266 def iterkeys(self):
Raymond Hettinger61146792004-08-19 21:32:06 +0000267 for wr in self.data.iterkeys():
268 obj = wr()
269 if obj is not None:
270 yield obj
271
272 def __iter__(self):
273 return self.iterkeys()
Fred Drake101209d2001-05-02 05:43:09 +0000274
275 def itervalues(self):
276 return self.data.itervalues()
277
Fred Drake1d9e4b72001-04-16 17:34:48 +0000278 def keys(self):
279 L = []
Fred Drakebd7f8182001-04-19 16:26:06 +0000280 for wr in self.data.keys():
281 o = wr()
Fred Drake1d9e4b72001-04-16 17:34:48 +0000282 if o is not None:
283 L.append(o)
284 return L
285
Martin v. Löwis5e163332001-02-27 18:36:56 +0000286 def popitem(self):
287 while 1:
288 key, value = self.data.popitem()
289 o = key()
290 if o is not None:
291 return o, value
292
Raymond Hettinger2c2d3222003-03-09 07:05:43 +0000293 def pop(self, key, *args):
294 return self.data.pop(ref(key), *args)
295
Walter Dörwald80ce6dd2004-05-27 18:16:25 +0000296 def setdefault(self, key, default=None):
Martin v. Löwis5e163332001-02-27 18:36:56 +0000297 return self.data.setdefault(ref(key, self._remove),default)
298
Raymond Hettinger31017ae2004-03-04 08:25:44 +0000299 def update(self, dict=None, **kwargs):
Martin v. Löwis5e163332001-02-27 18:36:56 +0000300 d = self.data
Raymond Hettinger31017ae2004-03-04 08:25:44 +0000301 if dict is not None:
302 if not hasattr(dict, "items"):
303 dict = type({})(dict)
304 for key, value in dict.items():
305 d[ref(key, self._remove)] = value
306 if len(kwargs):
307 self.update(kwargs)