blob: 838ff5ef7a5bbaff88b0fd8927a6be09146f31a4 [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):
167 for ref in self.data.iterkeys():
168 o = ref()
169 if o == key:
170 del self.data[ref]
171 return
172
Martin v. Löwis5e163332001-02-27 18:36:56 +0000173 def __getitem__(self, key):
174 return self.data[ref(key)]
175
176 def __repr__(self):
177 return "<WeakKeyDictionary at %s>" % id(self)
178
179 def __setitem__(self, key, value):
180 self.data[ref(key, self._remove)] = value
181
182 def copy(self):
183 new = WeakKeyDictionary()
184 for key, value in self.data.items():
185 o = key()
186 if o is not None:
187 new[o] = value
Fred Drake9d2c85d2001-03-01 03:06:03 +0000188 return new
Martin v. Löwis5e163332001-02-27 18:36:56 +0000189
Fred Drake1d9e4b72001-04-16 17:34:48 +0000190 def get(self, key, default=None):
Martin v. Löwis5e163332001-02-27 18:36:56 +0000191 return self.data.get(ref(key),default)
192
Fred Drake1d9e4b72001-04-16 17:34:48 +0000193 def has_key(self, key):
Fred Drake3bae7dd2001-11-06 16:36:53 +0000194 try:
195 wr = ref(key)
196 except TypeError:
197 return 0
Raymond Hettinger54f02222002-06-01 14:18:47 +0000198 return wr in self.data
Fred Drake1d9e4b72001-04-16 17:34:48 +0000199
Raymond Hettinger54f02222002-06-01 14:18:47 +0000200 def __contains__(self, key):
201 try:
202 wr = ref(key)
203 except TypeError:
204 return 0
205 return wr in self.data
Tim Petersc411dba2002-07-16 21:35:23 +0000206
Martin v. Löwis5e163332001-02-27 18:36:56 +0000207 def items(self):
208 L = []
209 for key, value in self.data.items():
210 o = key()
211 if o is not None:
212 L.append((o, value))
213 return L
214
Fred Drake101209d2001-05-02 05:43:09 +0000215 def iteritems(self):
216 return WeakKeyedItemIterator(self)
217
218 def iterkeys(self):
219 return WeakKeyedKeyIterator(self)
220 __iter__ = iterkeys
221
222 def itervalues(self):
223 return self.data.itervalues()
224
Fred Drake1d9e4b72001-04-16 17:34:48 +0000225 def keys(self):
226 L = []
Fred Drakebd7f8182001-04-19 16:26:06 +0000227 for wr in self.data.keys():
228 o = wr()
Fred Drake1d9e4b72001-04-16 17:34:48 +0000229 if o is not None:
230 L.append(o)
231 return L
232
Martin v. Löwis5e163332001-02-27 18:36:56 +0000233 def popitem(self):
234 while 1:
235 key, value = self.data.popitem()
236 o = key()
237 if o is not None:
238 return o, value
239
Raymond Hettinger2c2d3222003-03-09 07:05:43 +0000240 def pop(self, key, *args):
241 return self.data.pop(ref(key), *args)
242
Martin v. Löwis5e163332001-02-27 18:36:56 +0000243 def setdefault(self, key, default):
244 return self.data.setdefault(ref(key, self._remove),default)
245
246 def update(self, dict):
247 d = self.data
Martin v. Löwis5e163332001-02-27 18:36:56 +0000248 for key, value in dict.items():
Fred Drakebd7f8182001-04-19 16:26:06 +0000249 d[ref(key, self._remove)] = value
250
Martin v. Löwis5e163332001-02-27 18:36:56 +0000251
Fred Drake101209d2001-05-02 05:43:09 +0000252class BaseIter:
253 def __iter__(self):
254 return self
255
256
257class WeakKeyedKeyIterator(BaseIter):
258 def __init__(self, weakdict):
259 self._next = weakdict.data.iterkeys().next
260
261 def next(self):
262 while 1:
263 wr = self._next()
264 obj = wr()
265 if obj is not None:
266 return obj
267
268
269class WeakKeyedItemIterator(BaseIter):
270 def __init__(self, weakdict):
271 self._next = weakdict.data.iteritems().next
272
273 def next(self):
274 while 1:
275 wr, value = self._next()
276 key = wr()
277 if key is not None:
278 return key, value
279
280
281class WeakValuedValueIterator(BaseIter):
282 def __init__(self, weakdict):
283 self._next = weakdict.data.itervalues().next
284
285 def next(self):
286 while 1:
287 wr = self._next()
288 obj = wr()
289 if obj is not None:
290 return obj
291
292
293class WeakValuedItemIterator(BaseIter):
294 def __init__(self, weakdict):
295 self._next = weakdict.data.iteritems().next
296
297 def next(self):
298 while 1:
299 key, wr = self._next()
300 value = wr()
301 if value is not None:
302 return key, value
303
304
Fred Drake41deb1e2001-02-01 05:27:45 +0000305# no longer needed
306del UserDict