blob: 6153bd966d6bfc244b3a96a12f1149b9b1da8bd3 [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
104 def setdefault(self, key, default):
105 try:
Fred Drakebd7f8182001-04-19 16:26:06 +0000106 wr = self.data[key]
Fred Drake41deb1e2001-02-01 05:27:45 +0000107 except KeyError:
Fred Drake746fe0f2001-09-28 19:01:26 +0000108 self.data[key] = ref(default, self.__makeremove(key))
Fred Drake41deb1e2001-02-01 05:27:45 +0000109 return default
110 else:
Fred Drakebd7f8182001-04-19 16:26:06 +0000111 return wr()
Fred Drake41deb1e2001-02-01 05:27:45 +0000112
113 def update(self, dict):
114 d = self.data
Fred Drake41deb1e2001-02-01 05:27:45 +0000115 for key, o in dict.items():
Fred Drake746fe0f2001-09-28 19:01:26 +0000116 d[key] = ref(o, self.__makeremove(key))
Fred Drake41deb1e2001-02-01 05:27:45 +0000117
118 def values(self):
119 L = []
Fred Drakebd7f8182001-04-19 16:26:06 +0000120 for wr in self.data.values():
121 o = wr()
Fred Drake41deb1e2001-02-01 05:27:45 +0000122 if o is not None:
123 L.append(o)
124 return L
125
Fred Drake746fe0f2001-09-28 19:01:26 +0000126 def __makeremove(self, key):
127 def remove(o, selfref=ref(self), key=key):
128 self = selfref()
129 if self is not None:
130 del self.data[key]
131 return remove
132
Fred Drake41deb1e2001-02-01 05:27:45 +0000133
Martin v. Löwis5e163332001-02-27 18:36:56 +0000134class WeakKeyDictionary(UserDict.UserDict):
Fred Drakebd7f8182001-04-19 16:26:06 +0000135 """ Mapping class that references keys weakly.
136
137 Entries in the dictionary will be discarded when there is no
138 longer a strong reference to the key. This can be used to
139 associate additional data with an object owned by other parts of
140 an application without adding attributes to those objects. This
141 can be especially useful with objects that override attribute
142 accesses.
143 """
Martin v. Löwis5e163332001-02-27 18:36:56 +0000144
145 def __init__(self, dict=None):
146 self.data = {}
Fred Drake746fe0f2001-09-28 19:01:26 +0000147 def remove(k, selfref=ref(self)):
148 self = selfref()
149 if self is not None:
150 del self.data[k]
Martin v. Löwis5e163332001-02-27 18:36:56 +0000151 self._remove = remove
Guido van Rossum009afb72002-06-10 20:00:52 +0000152 if dict is not None: self.update(dict)
Martin v. Löwis5e163332001-02-27 18:36:56 +0000153
Fred Drakeb663a2c2001-09-06 14:51:01 +0000154 def __delitem__(self, key):
155 for ref in self.data.iterkeys():
156 o = ref()
157 if o == key:
158 del self.data[ref]
159 return
160
Martin v. Löwis5e163332001-02-27 18:36:56 +0000161 def __getitem__(self, key):
162 return self.data[ref(key)]
163
164 def __repr__(self):
165 return "<WeakKeyDictionary at %s>" % id(self)
166
167 def __setitem__(self, key, value):
168 self.data[ref(key, self._remove)] = value
169
170 def copy(self):
171 new = WeakKeyDictionary()
172 for key, value in self.data.items():
173 o = key()
174 if o is not None:
175 new[o] = value
Fred Drake9d2c85d2001-03-01 03:06:03 +0000176 return new
Martin v. Löwis5e163332001-02-27 18:36:56 +0000177
Fred Drake1d9e4b72001-04-16 17:34:48 +0000178 def get(self, key, default=None):
Martin v. Löwis5e163332001-02-27 18:36:56 +0000179 return self.data.get(ref(key),default)
180
Fred Drake1d9e4b72001-04-16 17:34:48 +0000181 def has_key(self, key):
Fred Drake3bae7dd2001-11-06 16:36:53 +0000182 try:
183 wr = ref(key)
184 except TypeError:
185 return 0
Raymond Hettinger54f02222002-06-01 14:18:47 +0000186 return wr in self.data
Fred Drake1d9e4b72001-04-16 17:34:48 +0000187
Raymond Hettinger54f02222002-06-01 14:18:47 +0000188 def __contains__(self, key):
189 try:
190 wr = ref(key)
191 except TypeError:
192 return 0
193 return wr in self.data
Tim Petersc411dba2002-07-16 21:35:23 +0000194
Martin v. Löwis5e163332001-02-27 18:36:56 +0000195 def items(self):
196 L = []
197 for key, value in self.data.items():
198 o = key()
199 if o is not None:
200 L.append((o, value))
201 return L
202
Fred Drake101209d2001-05-02 05:43:09 +0000203 def iteritems(self):
204 return WeakKeyedItemIterator(self)
205
206 def iterkeys(self):
207 return WeakKeyedKeyIterator(self)
208 __iter__ = iterkeys
209
210 def itervalues(self):
211 return self.data.itervalues()
212
Fred Drake1d9e4b72001-04-16 17:34:48 +0000213 def keys(self):
214 L = []
Fred Drakebd7f8182001-04-19 16:26:06 +0000215 for wr in self.data.keys():
216 o = wr()
Fred Drake1d9e4b72001-04-16 17:34:48 +0000217 if o is not None:
218 L.append(o)
219 return L
220
Martin v. Löwis5e163332001-02-27 18:36:56 +0000221 def popitem(self):
222 while 1:
223 key, value = self.data.popitem()
224 o = key()
225 if o is not None:
226 return o, value
227
228 def setdefault(self, key, default):
229 return self.data.setdefault(ref(key, self._remove),default)
230
231 def update(self, dict):
232 d = self.data
Martin v. Löwis5e163332001-02-27 18:36:56 +0000233 for key, value in dict.items():
Fred Drakebd7f8182001-04-19 16:26:06 +0000234 d[ref(key, self._remove)] = value
235
Martin v. Löwis5e163332001-02-27 18:36:56 +0000236
Fred Drake101209d2001-05-02 05:43:09 +0000237class BaseIter:
238 def __iter__(self):
239 return self
240
241
242class WeakKeyedKeyIterator(BaseIter):
243 def __init__(self, weakdict):
244 self._next = weakdict.data.iterkeys().next
245
246 def next(self):
247 while 1:
248 wr = self._next()
249 obj = wr()
250 if obj is not None:
251 return obj
252
253
254class WeakKeyedItemIterator(BaseIter):
255 def __init__(self, weakdict):
256 self._next = weakdict.data.iteritems().next
257
258 def next(self):
259 while 1:
260 wr, value = self._next()
261 key = wr()
262 if key is not None:
263 return key, value
264
265
266class WeakValuedValueIterator(BaseIter):
267 def __init__(self, weakdict):
268 self._next = weakdict.data.itervalues().next
269
270 def next(self):
271 while 1:
272 wr = self._next()
273 obj = wr()
274 if obj is not None:
275 return obj
276
277
278class WeakValuedItemIterator(BaseIter):
279 def __init__(self, weakdict):
280 self._next = weakdict.data.iteritems().next
281
282 def next(self):
283 while 1:
284 key, wr = self._next()
285 value = wr()
286 if value is not None:
287 return key, value
288
289
Fred Drake41deb1e2001-02-01 05:27:45 +0000290# no longer needed
291del UserDict