blob: 09bed6560e6034ba23d5adc5df73d1b5f2e6a6ea [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
125 def update(self, dict):
126 d = self.data
Fred Drake41deb1e2001-02-01 05:27:45 +0000127 for key, o in dict.items():
Fred Drake746fe0f2001-09-28 19:01:26 +0000128 d[key] = ref(o, self.__makeremove(key))
Fred Drake41deb1e2001-02-01 05:27:45 +0000129
130 def values(self):
131 L = []
Fred Drakebd7f8182001-04-19 16:26:06 +0000132 for wr in self.data.values():
133 o = wr()
Fred Drake41deb1e2001-02-01 05:27:45 +0000134 if o is not None:
135 L.append(o)
136 return L
137
Fred Drake746fe0f2001-09-28 19:01:26 +0000138 def __makeremove(self, key):
139 def remove(o, selfref=ref(self), key=key):
140 self = selfref()
141 if self is not None:
142 del self.data[key]
143 return remove
144
Fred Drake41deb1e2001-02-01 05:27:45 +0000145
Martin v. Löwis5e163332001-02-27 18:36:56 +0000146class WeakKeyDictionary(UserDict.UserDict):
Fred Drakebd7f8182001-04-19 16:26:06 +0000147 """ Mapping class that references keys weakly.
148
149 Entries in the dictionary will be discarded when there is no
150 longer a strong reference to the key. This can be used to
151 associate additional data with an object owned by other parts of
152 an application without adding attributes to those objects. This
153 can be especially useful with objects that override attribute
154 accesses.
155 """
Martin v. Löwis5e163332001-02-27 18:36:56 +0000156
157 def __init__(self, dict=None):
158 self.data = {}
Fred Drake746fe0f2001-09-28 19:01:26 +0000159 def remove(k, selfref=ref(self)):
160 self = selfref()
161 if self is not None:
162 del self.data[k]
Martin v. Löwis5e163332001-02-27 18:36:56 +0000163 self._remove = remove
Guido van Rossum009afb72002-06-10 20:00:52 +0000164 if dict is not None: self.update(dict)
Martin v. Löwis5e163332001-02-27 18:36:56 +0000165
Fred Drakeb663a2c2001-09-06 14:51:01 +0000166 def __delitem__(self, key):
Tim Peters886128f2003-05-25 01:45:11 +0000167 del self.data[ref(key)]
Fred Drakeb663a2c2001-09-06 14:51:01 +0000168
Martin v. Löwis5e163332001-02-27 18:36:56 +0000169 def __getitem__(self, key):
170 return self.data[ref(key)]
171
172 def __repr__(self):
173 return "<WeakKeyDictionary at %s>" % id(self)
174
175 def __setitem__(self, key, value):
176 self.data[ref(key, self._remove)] = value
177
178 def copy(self):
179 new = WeakKeyDictionary()
180 for key, value in self.data.items():
181 o = key()
182 if o is not None:
183 new[o] = value
Fred Drake9d2c85d2001-03-01 03:06:03 +0000184 return new
Martin v. Löwis5e163332001-02-27 18:36:56 +0000185
Fred Drake1d9e4b72001-04-16 17:34:48 +0000186 def get(self, key, default=None):
Martin v. Löwis5e163332001-02-27 18:36:56 +0000187 return self.data.get(ref(key),default)
188
Fred Drake1d9e4b72001-04-16 17:34:48 +0000189 def has_key(self, key):
Fred Drake3bae7dd2001-11-06 16:36:53 +0000190 try:
191 wr = ref(key)
192 except TypeError:
193 return 0
Raymond Hettinger54f02222002-06-01 14:18:47 +0000194 return wr in self.data
Fred Drake1d9e4b72001-04-16 17:34:48 +0000195
Raymond Hettinger54f02222002-06-01 14:18:47 +0000196 def __contains__(self, key):
197 try:
198 wr = ref(key)
199 except TypeError:
200 return 0
201 return wr in self.data
Tim Petersc411dba2002-07-16 21:35:23 +0000202
Martin v. Löwis5e163332001-02-27 18:36:56 +0000203 def items(self):
204 L = []
205 for key, value in self.data.items():
206 o = key()
207 if o is not None:
208 L.append((o, value))
209 return L
210
Fred Drake101209d2001-05-02 05:43:09 +0000211 def iteritems(self):
212 return WeakKeyedItemIterator(self)
213
214 def iterkeys(self):
215 return WeakKeyedKeyIterator(self)
216 __iter__ = iterkeys
217
218 def itervalues(self):
219 return self.data.itervalues()
220
Fred Drake1d9e4b72001-04-16 17:34:48 +0000221 def keys(self):
222 L = []
Fred Drakebd7f8182001-04-19 16:26:06 +0000223 for wr in self.data.keys():
224 o = wr()
Fred Drake1d9e4b72001-04-16 17:34:48 +0000225 if o is not None:
226 L.append(o)
227 return L
228
Martin v. Löwis5e163332001-02-27 18:36:56 +0000229 def popitem(self):
230 while 1:
231 key, value = self.data.popitem()
232 o = key()
233 if o is not None:
234 return o, value
235
Raymond Hettinger2c2d3222003-03-09 07:05:43 +0000236 def pop(self, key, *args):
237 return self.data.pop(ref(key), *args)
238
Martin v. Löwis5e163332001-02-27 18:36:56 +0000239 def setdefault(self, key, default):
240 return self.data.setdefault(ref(key, self._remove),default)
241
242 def update(self, dict):
243 d = self.data
Martin v. Löwis5e163332001-02-27 18:36:56 +0000244 for key, value in dict.items():
Fred Drakebd7f8182001-04-19 16:26:06 +0000245 d[ref(key, self._remove)] = value
246
Martin v. Löwis5e163332001-02-27 18:36:56 +0000247
Fred Drake101209d2001-05-02 05:43:09 +0000248class BaseIter:
249 def __iter__(self):
250 return self
251
252
253class WeakKeyedKeyIterator(BaseIter):
254 def __init__(self, weakdict):
255 self._next = weakdict.data.iterkeys().next
256
257 def next(self):
258 while 1:
259 wr = self._next()
260 obj = wr()
261 if obj is not None:
262 return obj
263
264
265class WeakKeyedItemIterator(BaseIter):
266 def __init__(self, weakdict):
267 self._next = weakdict.data.iteritems().next
268
269 def next(self):
270 while 1:
271 wr, value = self._next()
272 key = wr()
273 if key is not None:
274 return key, value
275
276
277class WeakValuedValueIterator(BaseIter):
278 def __init__(self, weakdict):
279 self._next = weakdict.data.itervalues().next
280
281 def next(self):
282 while 1:
283 wr = self._next()
284 obj = wr()
285 if obj is not None:
286 return obj
287
288
289class WeakValuedItemIterator(BaseIter):
290 def __init__(self, weakdict):
291 self._next = weakdict.data.iteritems().next
292
293 def next(self):
294 while 1:
295 key, wr = self._next()
296 value = wr()
297 if value is not None:
298 return key, value
299
300
Fred Drake41deb1e2001-02-01 05:27:45 +0000301# no longer needed
302del UserDict