blob: cf950baef72e160444c999184098a85175d89530 [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):
44 o = self.data.get(key)()
45 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
149 def __getitem__(self, key):
150 return self.data[ref(key)]
151
152 def __repr__(self):
153 return "<WeakKeyDictionary at %s>" % id(self)
154
155 def __setitem__(self, key, value):
156 self.data[ref(key, self._remove)] = value
157
158 def copy(self):
159 new = WeakKeyDictionary()
160 for key, value in self.data.items():
161 o = key()
162 if o is not None:
163 new[o] = value
Fred Drake9d2c85d2001-03-01 03:06:03 +0000164 return new
Martin v. Löwis5e163332001-02-27 18:36:56 +0000165
Fred Drake1d9e4b72001-04-16 17:34:48 +0000166 def get(self, key, default=None):
Martin v. Löwis5e163332001-02-27 18:36:56 +0000167 return self.data.get(ref(key),default)
168
Fred Drake1d9e4b72001-04-16 17:34:48 +0000169 def has_key(self, key):
170 return self.data.has_key(ref(key))
171
Martin v. Löwis5e163332001-02-27 18:36:56 +0000172 def items(self):
173 L = []
174 for key, value in self.data.items():
175 o = key()
176 if o is not None:
177 L.append((o, value))
178 return L
179
Fred Drake101209d2001-05-02 05:43:09 +0000180 def iteritems(self):
181 return WeakKeyedItemIterator(self)
182
183 def iterkeys(self):
184 return WeakKeyedKeyIterator(self)
185 __iter__ = iterkeys
186
187 def itervalues(self):
188 return self.data.itervalues()
189
Fred Drake1d9e4b72001-04-16 17:34:48 +0000190 def keys(self):
191 L = []
Fred Drakebd7f8182001-04-19 16:26:06 +0000192 for wr in self.data.keys():
193 o = wr()
Fred Drake1d9e4b72001-04-16 17:34:48 +0000194 if o is not None:
195 L.append(o)
196 return L
197
Martin v. Löwis5e163332001-02-27 18:36:56 +0000198 def popitem(self):
199 while 1:
200 key, value = self.data.popitem()
201 o = key()
202 if o is not None:
203 return o, value
204
205 def setdefault(self, key, default):
206 return self.data.setdefault(ref(key, self._remove),default)
207
208 def update(self, dict):
209 d = self.data
Martin v. Löwis5e163332001-02-27 18:36:56 +0000210 for key, value in dict.items():
Fred Drakebd7f8182001-04-19 16:26:06 +0000211 d[ref(key, self._remove)] = value
212
Martin v. Löwis5e163332001-02-27 18:36:56 +0000213
Fred Drake101209d2001-05-02 05:43:09 +0000214class BaseIter:
215 def __iter__(self):
216 return self
217
218
219class WeakKeyedKeyIterator(BaseIter):
220 def __init__(self, weakdict):
221 self._next = weakdict.data.iterkeys().next
222
223 def next(self):
224 while 1:
225 wr = self._next()
226 obj = wr()
227 if obj is not None:
228 return obj
229
230
231class WeakKeyedItemIterator(BaseIter):
232 def __init__(self, weakdict):
233 self._next = weakdict.data.iteritems().next
234
235 def next(self):
236 while 1:
237 wr, value = self._next()
238 key = wr()
239 if key is not None:
240 return key, value
241
242
243class WeakValuedValueIterator(BaseIter):
244 def __init__(self, weakdict):
245 self._next = weakdict.data.itervalues().next
246
247 def next(self):
248 while 1:
249 wr = self._next()
250 obj = wr()
251 if obj is not None:
252 return obj
253
254
255class WeakValuedItemIterator(BaseIter):
256 def __init__(self, weakdict):
257 self._next = weakdict.data.iteritems().next
258
259 def next(self):
260 while 1:
261 key, wr = self._next()
262 value = wr()
263 if value is not None:
264 return key, value
265
266
Fred Drake41deb1e2001-02-01 05:27:45 +0000267# no longer needed
268del UserDict