blob: 39ec33049d2c08785afdb62ec62b399ac6d74777 [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 = {}
147 if dict is not None: self.update(dict)
Fred Drake746fe0f2001-09-28 19:01:26 +0000148 def remove(k, selfref=ref(self)):
149 self = selfref()
150 if self is not None:
151 del self.data[k]
Martin v. Löwis5e163332001-02-27 18:36:56 +0000152 self._remove = remove
153
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):
182 return self.data.has_key(ref(key))
183
Martin v. Löwis5e163332001-02-27 18:36:56 +0000184 def items(self):
185 L = []
186 for key, value in self.data.items():
187 o = key()
188 if o is not None:
189 L.append((o, value))
190 return L
191
Fred Drake101209d2001-05-02 05:43:09 +0000192 def iteritems(self):
193 return WeakKeyedItemIterator(self)
194
195 def iterkeys(self):
196 return WeakKeyedKeyIterator(self)
197 __iter__ = iterkeys
198
199 def itervalues(self):
200 return self.data.itervalues()
201
Fred Drake1d9e4b72001-04-16 17:34:48 +0000202 def keys(self):
203 L = []
Fred Drakebd7f8182001-04-19 16:26:06 +0000204 for wr in self.data.keys():
205 o = wr()
Fred Drake1d9e4b72001-04-16 17:34:48 +0000206 if o is not None:
207 L.append(o)
208 return L
209
Martin v. Löwis5e163332001-02-27 18:36:56 +0000210 def popitem(self):
211 while 1:
212 key, value = self.data.popitem()
213 o = key()
214 if o is not None:
215 return o, value
216
217 def setdefault(self, key, default):
218 return self.data.setdefault(ref(key, self._remove),default)
219
220 def update(self, dict):
221 d = self.data
Martin v. Löwis5e163332001-02-27 18:36:56 +0000222 for key, value in dict.items():
Fred Drakebd7f8182001-04-19 16:26:06 +0000223 d[ref(key, self._remove)] = value
224
Martin v. Löwis5e163332001-02-27 18:36:56 +0000225
Fred Drake101209d2001-05-02 05:43:09 +0000226class BaseIter:
227 def __iter__(self):
228 return self
229
230
231class WeakKeyedKeyIterator(BaseIter):
232 def __init__(self, weakdict):
233 self._next = weakdict.data.iterkeys().next
234
235 def next(self):
236 while 1:
237 wr = self._next()
238 obj = wr()
239 if obj is not None:
240 return obj
241
242
243class WeakKeyedItemIterator(BaseIter):
244 def __init__(self, weakdict):
245 self._next = weakdict.data.iteritems().next
246
247 def next(self):
248 while 1:
249 wr, value = self._next()
250 key = wr()
251 if key is not None:
252 return key, value
253
254
255class WeakValuedValueIterator(BaseIter):
256 def __init__(self, weakdict):
257 self._next = weakdict.data.itervalues().next
258
259 def next(self):
260 while 1:
261 wr = self._next()
262 obj = wr()
263 if obj is not None:
264 return obj
265
266
267class WeakValuedItemIterator(BaseIter):
268 def __init__(self, weakdict):
269 self._next = weakdict.data.iteritems().next
270
271 def next(self):
272 while 1:
273 key, wr = self._next()
274 value = wr()
275 if value is not None:
276 return key, value
277
278
Fred Drake41deb1e2001-02-01 05:27:45 +0000279# no longer needed
280del UserDict