blob: c71d04b85358205d2ea717cb62df4a065cf25417 [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, \
19 ReferenceError, \
20 CallableProxyType, \
21 ProxyType, \
22 ReferenceType
23
24ProxyTypes = (ProxyType, CallableProxyType)
25
Fred Drake9a9d2192001-04-10 19:11:23 +000026__all__ = ["ref", "proxy", "getweakrefcount", "getweakrefs",
Skip Montanaro40fc1602001-03-01 04:27:19 +000027 "WeakKeyDictionary", "ReferenceType", "ProxyType",
28 "CallableProxyType", "ProxyTypes", "WeakValueDictionary"]
Fred Drake41deb1e2001-02-01 05:27:45 +000029
Fred Drake41deb1e2001-02-01 05:27:45 +000030
Fred Drakebd7f8182001-04-19 16:26:06 +000031class WeakValueDictionary(UserDict.UserDict):
32 """Mapping class that references values weakly.
33
34 Entries in the dictionary will be discarded when no strong
35 reference to the value exists anymore
36 """
Fred Drake41deb1e2001-02-01 05:27:45 +000037 # We inherit the constructor without worrying about the input
38 # dictionary; since it uses our .update() method, we get the right
Fred Drake9d2c85d2001-03-01 03:06:03 +000039 # checks (if the other dictionary is a WeakValueDictionary,
40 # objects are unwrapped on the way out, and we always wrap on the
41 # way in).
Fred Drake41deb1e2001-02-01 05:27:45 +000042
43 def __getitem__(self, key):
Fred Drake4fd06e02001-08-03 04:11:27 +000044 o = self.data[key]()
Fred Drake41deb1e2001-02-01 05:27:45 +000045 if o is None:
46 raise KeyError, key
47 else:
48 return o
49
50 def __repr__(self):
Fred Drake9d2c85d2001-03-01 03:06:03 +000051 return "<WeakValueDictionary at %s>" % id(self)
Fred Drake41deb1e2001-02-01 05:27:45 +000052
53 def __setitem__(self, key, value):
54 def remove(o, data=self.data, key=key):
55 del data[key]
56 self.data[key] = ref(value, remove)
57
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:
108 def remove(o, data=self.data, key=key):
109 del data[key]
Fred Drakebd7f8182001-04-19 16:26:06 +0000110 self.data[key] = ref(default, remove)
Fred Drake41deb1e2001-02-01 05:27:45 +0000111 return default
112 else:
Fred Drakebd7f8182001-04-19 16:26:06 +0000113 return wr()
Fred Drake41deb1e2001-02-01 05:27:45 +0000114
115 def update(self, dict):
116 d = self.data
Fred Drake41deb1e2001-02-01 05:27:45 +0000117 for key, o in dict.items():
118 def remove(o, data=d, key=key):
119 del data[key]
Fred Drakebd7f8182001-04-19 16:26:06 +0000120 d[key] = ref(o, remove)
Fred Drake41deb1e2001-02-01 05:27:45 +0000121
122 def values(self):
123 L = []
Fred Drakebd7f8182001-04-19 16:26:06 +0000124 for wr in self.data.values():
125 o = wr()
Fred Drake41deb1e2001-02-01 05:27:45 +0000126 if o is not None:
127 L.append(o)
128 return L
129
130
Martin v. Löwis5e163332001-02-27 18:36:56 +0000131class WeakKeyDictionary(UserDict.UserDict):
Fred Drakebd7f8182001-04-19 16:26:06 +0000132 """ Mapping class that references keys weakly.
133
134 Entries in the dictionary will be discarded when there is no
135 longer a strong reference to the key. This can be used to
136 associate additional data with an object owned by other parts of
137 an application without adding attributes to those objects. This
138 can be especially useful with objects that override attribute
139 accesses.
140 """
Martin v. Löwis5e163332001-02-27 18:36:56 +0000141
142 def __init__(self, dict=None):
143 self.data = {}
144 if dict is not None: self.update(dict)
145 def remove(k, data=self.data):
146 del data[k]
147 self._remove = remove
148
Fred Drakeb663a2c2001-09-06 14:51:01 +0000149 def __delitem__(self, key):
150 for ref in self.data.iterkeys():
151 o = ref()
152 if o == key:
153 del self.data[ref]
154 return
155
Martin v. Löwis5e163332001-02-27 18:36:56 +0000156 def __getitem__(self, key):
157 return self.data[ref(key)]
158
159 def __repr__(self):
160 return "<WeakKeyDictionary at %s>" % id(self)
161
162 def __setitem__(self, key, value):
163 self.data[ref(key, self._remove)] = value
164
165 def copy(self):
166 new = WeakKeyDictionary()
167 for key, value in self.data.items():
168 o = key()
169 if o is not None:
170 new[o] = value
Fred Drake9d2c85d2001-03-01 03:06:03 +0000171 return new
Martin v. Löwis5e163332001-02-27 18:36:56 +0000172
Fred Drake1d9e4b72001-04-16 17:34:48 +0000173 def get(self, key, default=None):
Martin v. Löwis5e163332001-02-27 18:36:56 +0000174 return self.data.get(ref(key),default)
175
Fred Drake1d9e4b72001-04-16 17:34:48 +0000176 def has_key(self, key):
177 return self.data.has_key(ref(key))
178
Martin v. Löwis5e163332001-02-27 18:36:56 +0000179 def items(self):
180 L = []
181 for key, value in self.data.items():
182 o = key()
183 if o is not None:
184 L.append((o, value))
185 return L
186
Fred Drake101209d2001-05-02 05:43:09 +0000187 def iteritems(self):
188 return WeakKeyedItemIterator(self)
189
190 def iterkeys(self):
191 return WeakKeyedKeyIterator(self)
192 __iter__ = iterkeys
193
194 def itervalues(self):
195 return self.data.itervalues()
196
Fred Drake1d9e4b72001-04-16 17:34:48 +0000197 def keys(self):
198 L = []
Fred Drakebd7f8182001-04-19 16:26:06 +0000199 for wr in self.data.keys():
200 o = wr()
Fred Drake1d9e4b72001-04-16 17:34:48 +0000201 if o is not None:
202 L.append(o)
203 return L
204
Martin v. Löwis5e163332001-02-27 18:36:56 +0000205 def popitem(self):
206 while 1:
207 key, value = self.data.popitem()
208 o = key()
209 if o is not None:
210 return o, value
211
212 def setdefault(self, key, default):
213 return self.data.setdefault(ref(key, self._remove),default)
214
215 def update(self, dict):
216 d = self.data
Martin v. Löwis5e163332001-02-27 18:36:56 +0000217 for key, value in dict.items():
Fred Drakebd7f8182001-04-19 16:26:06 +0000218 d[ref(key, self._remove)] = value
219
Martin v. Löwis5e163332001-02-27 18:36:56 +0000220
Fred Drake101209d2001-05-02 05:43:09 +0000221class BaseIter:
222 def __iter__(self):
223 return self
224
225
226class WeakKeyedKeyIterator(BaseIter):
227 def __init__(self, weakdict):
228 self._next = weakdict.data.iterkeys().next
229
230 def next(self):
231 while 1:
232 wr = self._next()
233 obj = wr()
234 if obj is not None:
235 return obj
236
237
238class WeakKeyedItemIterator(BaseIter):
239 def __init__(self, weakdict):
240 self._next = weakdict.data.iteritems().next
241
242 def next(self):
243 while 1:
244 wr, value = self._next()
245 key = wr()
246 if key is not None:
247 return key, value
248
249
250class WeakValuedValueIterator(BaseIter):
251 def __init__(self, weakdict):
252 self._next = weakdict.data.itervalues().next
253
254 def next(self):
255 while 1:
256 wr = self._next()
257 obj = wr()
258 if obj is not None:
259 return obj
260
261
262class WeakValuedItemIterator(BaseIter):
263 def __init__(self, weakdict):
264 self._next = weakdict.data.iteritems().next
265
266 def next(self):
267 while 1:
268 key, wr = self._next()
269 value = wr()
270 if value is not None:
271 return key, value
272
273
Fred Drake41deb1e2001-02-01 05:27:45 +0000274# no longer needed
275del UserDict