blob: 5c661861b034c0e4b26c74f1987d52dc786608e5 [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
14from _weakref import \
15 getweakrefcount, \
16 getweakrefs, \
17 ref, \
18 proxy, \
Fred Drake41deb1e2001-02-01 05:27:45 +000019 CallableProxyType, \
20 ProxyType, \
21 ReferenceType
22
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
45 def __getitem__(self, key):
Fred Drake4fd06e02001-08-03 04:11:27 +000046 o = self.data[key]()
Fred Drake41deb1e2001-02-01 05:27:45 +000047 if o is None:
48 raise KeyError, key
49 else:
50 return o
51
52 def __repr__(self):
Fred Drake9d2c85d2001-03-01 03:06:03 +000053 return "<WeakValueDictionary at %s>" % id(self)
Fred Drake41deb1e2001-02-01 05:27:45 +000054
55 def __setitem__(self, key, value):
Fred Drake746fe0f2001-09-28 19:01:26 +000056 self.data[key] = ref(value, self.__makeremove(key))
Fred Drake41deb1e2001-02-01 05:27:45 +000057
58 def copy(self):
Fred Drake9d2c85d2001-03-01 03:06:03 +000059 new = WeakValueDictionary()
Fred Drakebd7f8182001-04-19 16:26:06 +000060 for key, wr in self.data.items():
61 o = wr()
Fred Drake41deb1e2001-02-01 05:27:45 +000062 if o is not None:
63 new[key] = o
Fred Drake9d2c85d2001-03-01 03:06:03 +000064 return new
Fred Drake41deb1e2001-02-01 05:27:45 +000065
Fred Drake1d9e4b72001-04-16 17:34:48 +000066 def get(self, key, default=None):
Fred Drake41deb1e2001-02-01 05:27:45 +000067 try:
Fred Drakebd7f8182001-04-19 16:26:06 +000068 wr = self.data[key]
Fred Drake41deb1e2001-02-01 05:27:45 +000069 except KeyError:
70 return default
71 else:
Fred Drakebd7f8182001-04-19 16:26:06 +000072 o = wr()
Fred Drake41deb1e2001-02-01 05:27:45 +000073 if o is None:
74 # This should only happen
75 return default
76 else:
77 return o
78
79 def items(self):
Fred Drake312a5dc2001-02-02 15:13:24 +000080 L = []
Fred Drakebd7f8182001-04-19 16:26:06 +000081 for key, wr in self.data.items():
82 o = wr()
Fred Drake41deb1e2001-02-01 05:27:45 +000083 if o is not None:
Fred Drake312a5dc2001-02-02 15:13:24 +000084 L.append((key, o))
Fred Drake41deb1e2001-02-01 05:27:45 +000085 return L
86
Fred Drake101209d2001-05-02 05:43:09 +000087 def iteritems(self):
88 return WeakValuedItemIterator(self)
89
90 def iterkeys(self):
91 return self.data.iterkeys()
92 __iter__ = iterkeys
93
94 def itervalues(self):
95 return WeakValuedValueIterator(self)
96
Fred Drake41deb1e2001-02-01 05:27:45 +000097 def popitem(self):
98 while 1:
Fred Drakebd7f8182001-04-19 16:26:06 +000099 key, wr = self.data.popitem()
100 o = wr()
Fred Drake41deb1e2001-02-01 05:27:45 +0000101 if o is not None:
102 return key, o
103
Raymond Hettinger2c2d3222003-03-09 07:05:43 +0000104 def pop(self, key, *args):
105 try:
106 o = self.data.pop(key)()
107 except KeyError:
108 if args:
109 return args[0]
110 raise
111 if o is None:
112 raise KeyError, key
113 else:
114 return o
115
Fred Drake41deb1e2001-02-01 05:27:45 +0000116 def setdefault(self, key, default):
117 try:
Fred Drakebd7f8182001-04-19 16:26:06 +0000118 wr = self.data[key]
Fred Drake41deb1e2001-02-01 05:27:45 +0000119 except KeyError:
Fred Drake746fe0f2001-09-28 19:01:26 +0000120 self.data[key] = ref(default, self.__makeremove(key))
Fred Drake41deb1e2001-02-01 05:27:45 +0000121 return default
122 else:
Fred Drakebd7f8182001-04-19 16:26:06 +0000123 return wr()
Fred Drake41deb1e2001-02-01 05:27:45 +0000124
Raymond Hettinger31017ae2004-03-04 08:25:44 +0000125 def update(self, dict=None, **kwargs):
Fred Drake41deb1e2001-02-01 05:27:45 +0000126 d = self.data
Raymond Hettinger31017ae2004-03-04 08:25:44 +0000127 if dict is not None:
128 if not hasattr(dict, "items"):
129 dict = type({})(dict)
130 for key, o in dict.items():
131 d[key] = ref(o, self.__makeremove(key))
132 if len(kwargs):
133 self.update(kwargs)
Fred Drake41deb1e2001-02-01 05:27:45 +0000134
135 def values(self):
136 L = []
Fred Drakebd7f8182001-04-19 16:26:06 +0000137 for wr in self.data.values():
138 o = wr()
Fred Drake41deb1e2001-02-01 05:27:45 +0000139 if o is not None:
140 L.append(o)
141 return L
142
Fred Drake746fe0f2001-09-28 19:01:26 +0000143 def __makeremove(self, key):
144 def remove(o, selfref=ref(self), key=key):
145 self = selfref()
146 if self is not None:
147 del self.data[key]
148 return remove
149
Fred Drake41deb1e2001-02-01 05:27:45 +0000150
Martin v. Löwis5e163332001-02-27 18:36:56 +0000151class WeakKeyDictionary(UserDict.UserDict):
Fred Drakebd7f8182001-04-19 16:26:06 +0000152 """ Mapping class that references keys weakly.
153
154 Entries in the dictionary will be discarded when there is no
155 longer a strong reference to the key. This can be used to
156 associate additional data with an object owned by other parts of
157 an application without adding attributes to those objects. This
158 can be especially useful with objects that override attribute
159 accesses.
160 """
Martin v. Löwis5e163332001-02-27 18:36:56 +0000161
162 def __init__(self, dict=None):
163 self.data = {}
Fred Drake746fe0f2001-09-28 19:01:26 +0000164 def remove(k, selfref=ref(self)):
165 self = selfref()
166 if self is not None:
167 del self.data[k]
Martin v. Löwis5e163332001-02-27 18:36:56 +0000168 self._remove = remove
Guido van Rossum009afb72002-06-10 20:00:52 +0000169 if dict is not None: self.update(dict)
Martin v. Löwis5e163332001-02-27 18:36:56 +0000170
Fred Drakeb663a2c2001-09-06 14:51:01 +0000171 def __delitem__(self, key):
Tim Peters886128f2003-05-25 01:45:11 +0000172 del self.data[ref(key)]
Fred Drakeb663a2c2001-09-06 14:51:01 +0000173
Martin v. Löwis5e163332001-02-27 18:36:56 +0000174 def __getitem__(self, key):
175 return self.data[ref(key)]
176
177 def __repr__(self):
178 return "<WeakKeyDictionary at %s>" % id(self)
179
180 def __setitem__(self, key, value):
181 self.data[ref(key, self._remove)] = value
182
183 def copy(self):
184 new = WeakKeyDictionary()
185 for key, value in self.data.items():
186 o = key()
187 if o is not None:
188 new[o] = value
Fred Drake9d2c85d2001-03-01 03:06:03 +0000189 return new
Martin v. Löwis5e163332001-02-27 18:36:56 +0000190
Fred Drake1d9e4b72001-04-16 17:34:48 +0000191 def get(self, key, default=None):
Martin v. Löwis5e163332001-02-27 18:36:56 +0000192 return self.data.get(ref(key),default)
193
Fred Drake1d9e4b72001-04-16 17:34:48 +0000194 def has_key(self, key):
Fred Drake3bae7dd2001-11-06 16:36:53 +0000195 try:
196 wr = ref(key)
197 except TypeError:
198 return 0
Raymond Hettinger54f02222002-06-01 14:18:47 +0000199 return wr in self.data
Fred Drake1d9e4b72001-04-16 17:34:48 +0000200
Raymond Hettinger54f02222002-06-01 14:18:47 +0000201 def __contains__(self, key):
202 try:
203 wr = ref(key)
204 except TypeError:
205 return 0
206 return wr in self.data
Tim Petersc411dba2002-07-16 21:35:23 +0000207
Martin v. Löwis5e163332001-02-27 18:36:56 +0000208 def items(self):
209 L = []
210 for key, value in self.data.items():
211 o = key()
212 if o is not None:
213 L.append((o, value))
214 return L
215
Fred Drake101209d2001-05-02 05:43:09 +0000216 def iteritems(self):
217 return WeakKeyedItemIterator(self)
218
219 def iterkeys(self):
220 return WeakKeyedKeyIterator(self)
221 __iter__ = iterkeys
222
223 def itervalues(self):
224 return self.data.itervalues()
225
Fred Drake1d9e4b72001-04-16 17:34:48 +0000226 def keys(self):
227 L = []
Fred Drakebd7f8182001-04-19 16:26:06 +0000228 for wr in self.data.keys():
229 o = wr()
Fred Drake1d9e4b72001-04-16 17:34:48 +0000230 if o is not None:
231 L.append(o)
232 return L
233
Martin v. Löwis5e163332001-02-27 18:36:56 +0000234 def popitem(self):
235 while 1:
236 key, value = self.data.popitem()
237 o = key()
238 if o is not None:
239 return o, value
240
Raymond Hettinger2c2d3222003-03-09 07:05:43 +0000241 def pop(self, key, *args):
242 return self.data.pop(ref(key), *args)
243
Martin v. Löwis5e163332001-02-27 18:36:56 +0000244 def setdefault(self, key, default):
245 return self.data.setdefault(ref(key, self._remove),default)
246
Raymond Hettinger31017ae2004-03-04 08:25:44 +0000247 def update(self, dict=None, **kwargs):
Martin v. Löwis5e163332001-02-27 18:36:56 +0000248 d = self.data
Raymond Hettinger31017ae2004-03-04 08:25:44 +0000249 if dict is not None:
250 if not hasattr(dict, "items"):
251 dict = type({})(dict)
252 for key, value in dict.items():
253 d[ref(key, self._remove)] = value
254 if len(kwargs):
255 self.update(kwargs)
Fred Drakebd7f8182001-04-19 16:26:06 +0000256
Martin v. Löwis5e163332001-02-27 18:36:56 +0000257
Fred Drake101209d2001-05-02 05:43:09 +0000258class BaseIter:
259 def __iter__(self):
260 return self
261
262
263class WeakKeyedKeyIterator(BaseIter):
264 def __init__(self, weakdict):
265 self._next = weakdict.data.iterkeys().next
266
267 def next(self):
268 while 1:
269 wr = self._next()
270 obj = wr()
271 if obj is not None:
272 return obj
273
274
275class WeakKeyedItemIterator(BaseIter):
276 def __init__(self, weakdict):
277 self._next = weakdict.data.iteritems().next
278
279 def next(self):
280 while 1:
281 wr, value = self._next()
282 key = wr()
283 if key is not None:
284 return key, value
285
286
287class WeakValuedValueIterator(BaseIter):
288 def __init__(self, weakdict):
289 self._next = weakdict.data.itervalues().next
290
291 def next(self):
292 while 1:
293 wr = self._next()
294 obj = wr()
295 if obj is not None:
296 return obj
297
298
299class WeakValuedItemIterator(BaseIter):
300 def __init__(self, weakdict):
301 self._next = weakdict.data.iteritems().next
302
303 def next(self):
304 while 1:
305 key, wr = self._next()
306 value = wr()
307 if value is not None:
308 return key, value
309
310
Fred Drake41deb1e2001-02-01 05:27:45 +0000311# no longer needed
312del UserDict