blob: 0cf6bf9cc32f4e2e7e2f1f6a04a2b02a58258b44 [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):
Fred Drake746fe0f2001-09-28 19:01:26 +000054 self.data[key] = ref(value, self.__makeremove(key))
Fred Drake41deb1e2001-02-01 05:27:45 +000055
56 def copy(self):
Fred Drake9d2c85d2001-03-01 03:06:03 +000057 new = WeakValueDictionary()
Fred Drakebd7f8182001-04-19 16:26:06 +000058 for key, wr in self.data.items():
59 o = wr()
Fred Drake41deb1e2001-02-01 05:27:45 +000060 if o is not None:
61 new[key] = o
Fred Drake9d2c85d2001-03-01 03:06:03 +000062 return new
Fred Drake41deb1e2001-02-01 05:27:45 +000063
Fred Drake1d9e4b72001-04-16 17:34:48 +000064 def get(self, key, default=None):
Fred Drake41deb1e2001-02-01 05:27:45 +000065 try:
Fred Drakebd7f8182001-04-19 16:26:06 +000066 wr = self.data[key]
Fred Drake41deb1e2001-02-01 05:27:45 +000067 except KeyError:
68 return default
69 else:
Fred Drakebd7f8182001-04-19 16:26:06 +000070 o = wr()
Fred Drake41deb1e2001-02-01 05:27:45 +000071 if o is None:
72 # This should only happen
73 return default
74 else:
75 return o
76
77 def items(self):
Fred Drake312a5dc2001-02-02 15:13:24 +000078 L = []
Fred Drakebd7f8182001-04-19 16:26:06 +000079 for key, wr in self.data.items():
80 o = wr()
Fred Drake41deb1e2001-02-01 05:27:45 +000081 if o is not None:
Fred Drake312a5dc2001-02-02 15:13:24 +000082 L.append((key, o))
Fred Drake41deb1e2001-02-01 05:27:45 +000083 return L
84
Fred Drake101209d2001-05-02 05:43:09 +000085 def iteritems(self):
86 return WeakValuedItemIterator(self)
87
88 def iterkeys(self):
89 return self.data.iterkeys()
90 __iter__ = iterkeys
91
92 def itervalues(self):
93 return WeakValuedValueIterator(self)
94
Fred Drake41deb1e2001-02-01 05:27:45 +000095 def popitem(self):
96 while 1:
Fred Drakebd7f8182001-04-19 16:26:06 +000097 key, wr = self.data.popitem()
98 o = wr()
Fred Drake41deb1e2001-02-01 05:27:45 +000099 if o is not None:
100 return key, o
101
102 def setdefault(self, key, default):
103 try:
Fred Drakebd7f8182001-04-19 16:26:06 +0000104 wr = self.data[key]
Fred Drake41deb1e2001-02-01 05:27:45 +0000105 except KeyError:
Fred Drake746fe0f2001-09-28 19:01:26 +0000106 self.data[key] = ref(default, self.__makeremove(key))
Fred Drake41deb1e2001-02-01 05:27:45 +0000107 return default
108 else:
Fred Drakebd7f8182001-04-19 16:26:06 +0000109 return wr()
Fred Drake41deb1e2001-02-01 05:27:45 +0000110
111 def update(self, dict):
112 d = self.data
Fred Drake41deb1e2001-02-01 05:27:45 +0000113 for key, o in dict.items():
Fred Drake746fe0f2001-09-28 19:01:26 +0000114 d[key] = ref(o, self.__makeremove(key))
Fred Drake41deb1e2001-02-01 05:27:45 +0000115
116 def values(self):
117 L = []
Fred Drakebd7f8182001-04-19 16:26:06 +0000118 for wr in self.data.values():
119 o = wr()
Fred Drake41deb1e2001-02-01 05:27:45 +0000120 if o is not None:
121 L.append(o)
122 return L
123
Fred Drake746fe0f2001-09-28 19:01:26 +0000124 def __makeremove(self, key):
125 def remove(o, selfref=ref(self), key=key):
126 self = selfref()
127 if self is not None:
128 del self.data[key]
129 return remove
130
Fred Drake41deb1e2001-02-01 05:27:45 +0000131
Martin v. Löwis5e163332001-02-27 18:36:56 +0000132class WeakKeyDictionary(UserDict.UserDict):
Fred Drakebd7f8182001-04-19 16:26:06 +0000133 """ Mapping class that references keys weakly.
134
135 Entries in the dictionary will be discarded when there is no
136 longer a strong reference to the key. This can be used to
137 associate additional data with an object owned by other parts of
138 an application without adding attributes to those objects. This
139 can be especially useful with objects that override attribute
140 accesses.
141 """
Martin v. Löwis5e163332001-02-27 18:36:56 +0000142
143 def __init__(self, dict=None):
144 self.data = {}
145 if dict is not None: self.update(dict)
Fred Drake746fe0f2001-09-28 19:01:26 +0000146 def remove(k, selfref=ref(self)):
147 self = selfref()
148 if self is not None:
149 del self.data[k]
Martin v. Löwis5e163332001-02-27 18:36:56 +0000150 self._remove = remove
151
Fred Drakeb663a2c2001-09-06 14:51:01 +0000152 def __delitem__(self, key):
153 for ref in self.data.iterkeys():
154 o = ref()
155 if o == key:
156 del self.data[ref]
157 return
158
Martin v. Löwis5e163332001-02-27 18:36:56 +0000159 def __getitem__(self, key):
160 return self.data[ref(key)]
161
162 def __repr__(self):
163 return "<WeakKeyDictionary at %s>" % id(self)
164
165 def __setitem__(self, key, value):
166 self.data[ref(key, self._remove)] = value
167
168 def copy(self):
169 new = WeakKeyDictionary()
170 for key, value in self.data.items():
171 o = key()
172 if o is not None:
173 new[o] = value
Fred Drake9d2c85d2001-03-01 03:06:03 +0000174 return new
Martin v. Löwis5e163332001-02-27 18:36:56 +0000175
Fred Drake1d9e4b72001-04-16 17:34:48 +0000176 def get(self, key, default=None):
Martin v. Löwis5e163332001-02-27 18:36:56 +0000177 return self.data.get(ref(key),default)
178
Fred Drake1d9e4b72001-04-16 17:34:48 +0000179 def has_key(self, key):
180 return self.data.has_key(ref(key))
181
Martin v. Löwis5e163332001-02-27 18:36:56 +0000182 def items(self):
183 L = []
184 for key, value in self.data.items():
185 o = key()
186 if o is not None:
187 L.append((o, value))
188 return L
189
Fred Drake101209d2001-05-02 05:43:09 +0000190 def iteritems(self):
191 return WeakKeyedItemIterator(self)
192
193 def iterkeys(self):
194 return WeakKeyedKeyIterator(self)
195 __iter__ = iterkeys
196
197 def itervalues(self):
198 return self.data.itervalues()
199
Fred Drake1d9e4b72001-04-16 17:34:48 +0000200 def keys(self):
201 L = []
Fred Drakebd7f8182001-04-19 16:26:06 +0000202 for wr in self.data.keys():
203 o = wr()
Fred Drake1d9e4b72001-04-16 17:34:48 +0000204 if o is not None:
205 L.append(o)
206 return L
207
Martin v. Löwis5e163332001-02-27 18:36:56 +0000208 def popitem(self):
209 while 1:
210 key, value = self.data.popitem()
211 o = key()
212 if o is not None:
213 return o, value
214
215 def setdefault(self, key, default):
216 return self.data.setdefault(ref(key, self._remove),default)
217
218 def update(self, dict):
219 d = self.data
Martin v. Löwis5e163332001-02-27 18:36:56 +0000220 for key, value in dict.items():
Fred Drakebd7f8182001-04-19 16:26:06 +0000221 d[ref(key, self._remove)] = value
222
Martin v. Löwis5e163332001-02-27 18:36:56 +0000223
Fred Drake101209d2001-05-02 05:43:09 +0000224class BaseIter:
225 def __iter__(self):
226 return self
227
228
229class WeakKeyedKeyIterator(BaseIter):
230 def __init__(self, weakdict):
231 self._next = weakdict.data.iterkeys().next
232
233 def next(self):
234 while 1:
235 wr = self._next()
236 obj = wr()
237 if obj is not None:
238 return obj
239
240
241class WeakKeyedItemIterator(BaseIter):
242 def __init__(self, weakdict):
243 self._next = weakdict.data.iteritems().next
244
245 def next(self):
246 while 1:
247 wr, value = self._next()
248 key = wr()
249 if key is not None:
250 return key, value
251
252
253class WeakValuedValueIterator(BaseIter):
254 def __init__(self, weakdict):
255 self._next = weakdict.data.itervalues().next
256
257 def next(self):
258 while 1:
259 wr = self._next()
260 obj = wr()
261 if obj is not None:
262 return obj
263
264
265class WeakValuedItemIterator(BaseIter):
266 def __init__(self, weakdict):
267 self._next = weakdict.data.iteritems().next
268
269 def next(self):
270 while 1:
271 key, wr = self._next()
272 value = wr()
273 if value is not None:
274 return key, value
275
276
Fred Drake41deb1e2001-02-01 05:27:45 +0000277# no longer needed
278del UserDict