blob: 7f4870e187649ccb502cc257861e5049029a50d4 [file] [log] [blame]
Fred Drake41deb1e2001-02-01 05:27:45 +00001import sys
Fred Drakeb0fefc52001-03-23 04:22:45 +00002import unittest
Fred Drake41deb1e2001-02-01 05:27:45 +00003import weakref
4
Fred Drake2e2be372001-09-20 21:33:42 +00005import test_support
Fred Drake41deb1e2001-02-01 05:27:45 +00006
7
8class C:
Fred Drakeb0fefc52001-03-23 04:22:45 +00009 def method(self):
10 pass
Fred Drake41deb1e2001-02-01 05:27:45 +000011
12
Fred Drakeb0fefc52001-03-23 04:22:45 +000013class Callable:
14 bar = None
Fred Drake41deb1e2001-02-01 05:27:45 +000015
Fred Drakeb0fefc52001-03-23 04:22:45 +000016 def __call__(self, x):
17 self.bar = x
Fred Drake41deb1e2001-02-01 05:27:45 +000018
19
Fred Drakeb0fefc52001-03-23 04:22:45 +000020def create_function():
21 def f(): pass
22 return f
23
24def create_bound_method():
25 return C().method
26
27def create_unbound_method():
28 return C.method
Fred Drake41deb1e2001-02-01 05:27:45 +000029
30
Fred Drakeb0fefc52001-03-23 04:22:45 +000031class TestBase(unittest.TestCase):
32
33 def setUp(self):
34 self.cbcalled = 0
35
36 def callback(self, ref):
37 self.cbcalled += 1
Fred Drake41deb1e2001-02-01 05:27:45 +000038
39
Fred Drakeb0fefc52001-03-23 04:22:45 +000040class ReferencesTestCase(TestBase):
Fred Drake41deb1e2001-02-01 05:27:45 +000041
Fred Drakeb0fefc52001-03-23 04:22:45 +000042 def test_basic_ref(self):
43 self.check_basic_ref(C)
44 self.check_basic_ref(create_function)
45 self.check_basic_ref(create_bound_method)
46 self.check_basic_ref(create_unbound_method)
Fred Drake41deb1e2001-02-01 05:27:45 +000047
Fred Drakeb0fefc52001-03-23 04:22:45 +000048 def test_basic_callback(self):
49 self.check_basic_callback(C)
50 self.check_basic_callback(create_function)
51 self.check_basic_callback(create_bound_method)
52 self.check_basic_callback(create_unbound_method)
Fred Drake41deb1e2001-02-01 05:27:45 +000053
Fred Drakeb0fefc52001-03-23 04:22:45 +000054 def test_multiple_callbacks(self):
55 o = C()
56 ref1 = weakref.ref(o, self.callback)
57 ref2 = weakref.ref(o, self.callback)
58 del o
59 self.assert_(ref1() is None,
60 "expected reference to be invalidated")
61 self.assert_(ref2() is None,
62 "expected reference to be invalidated")
63 self.assert_(self.cbcalled == 2,
64 "callback not called the right number of times")
Fred Drake41deb1e2001-02-01 05:27:45 +000065
Fred Drake705088e2001-04-13 17:18:15 +000066 def test_multiple_selfref_callbacks(self):
67 """Make sure all references are invalidated before callbacks
68 are called."""
69 #
70 # What's important here is that we're using the first
71 # reference in the callback invoked on the second reference
72 # (the most recently created ref is cleaned up first). This
73 # tests that all references to the object are invalidated
74 # before any of the callbacks are invoked, so that we only
75 # have one invocation of _weakref.c:cleanup_helper() active
76 # for a particular object at a time.
77 #
78 def callback(object, self=self):
79 self.ref()
80 c = C()
81 self.ref = weakref.ref(c, callback)
82 ref1 = weakref.ref(c, callback)
83 del c
84
Fred Drakeb0fefc52001-03-23 04:22:45 +000085 def test_proxy_ref(self):
86 o = C()
87 o.bar = 1
88 ref1 = weakref.proxy(o, self.callback)
89 ref2 = weakref.proxy(o, self.callback)
90 del o
Fred Drake41deb1e2001-02-01 05:27:45 +000091
Fred Drakeb0fefc52001-03-23 04:22:45 +000092 def check(proxy):
93 proxy.bar
Fred Drake41deb1e2001-02-01 05:27:45 +000094
Fred Drakeb0fefc52001-03-23 04:22:45 +000095 self.assertRaises(weakref.ReferenceError, check, ref1)
96 self.assertRaises(weakref.ReferenceError, check, ref2)
97 self.assert_(self.cbcalled == 2)
Fred Drake41deb1e2001-02-01 05:27:45 +000098
Fred Drakeb0fefc52001-03-23 04:22:45 +000099 def check_basic_ref(self, factory):
100 o = factory()
101 ref = weakref.ref(o)
102 self.assert_(ref() is not None,
103 "weak reference to live object should be live")
104 o2 = ref()
105 self.assert_(o is o2,
106 "<ref>() should return original object if live")
Fred Drake41deb1e2001-02-01 05:27:45 +0000107
Fred Drakeb0fefc52001-03-23 04:22:45 +0000108 def check_basic_callback(self, factory):
109 self.cbcalled = 0
110 o = factory()
111 ref = weakref.ref(o, self.callback)
112 del o
Fred Drake705088e2001-04-13 17:18:15 +0000113 self.assert_(self.cbcalled == 1,
114 "callback did not properly set 'cbcalled'")
115 self.assert_(ref() is None,
116 "ref2 should be dead after deleting object reference")
Fred Drake41deb1e2001-02-01 05:27:45 +0000117
Fred Drakeb0fefc52001-03-23 04:22:45 +0000118 def test_ref_reuse(self):
119 o = C()
120 ref1 = weakref.ref(o)
121 # create a proxy to make sure that there's an intervening creation
122 # between these two; it should make no difference
123 proxy = weakref.proxy(o)
124 ref2 = weakref.ref(o)
125 self.assert_(ref1 is ref2,
126 "reference object w/out callback should be re-used")
Fred Drake41deb1e2001-02-01 05:27:45 +0000127
Fred Drakeb0fefc52001-03-23 04:22:45 +0000128 o = C()
129 proxy = weakref.proxy(o)
130 ref1 = weakref.ref(o)
131 ref2 = weakref.ref(o)
132 self.assert_(ref1 is ref2,
133 "reference object w/out callback should be re-used")
134 self.assert_(weakref.getweakrefcount(o) == 2,
135 "wrong weak ref count for object")
136 del proxy
137 self.assert_(weakref.getweakrefcount(o) == 1,
138 "wrong weak ref count for object after deleting proxy")
Fred Drake41deb1e2001-02-01 05:27:45 +0000139
Fred Drakeb0fefc52001-03-23 04:22:45 +0000140 def test_proxy_reuse(self):
141 o = C()
142 proxy1 = weakref.proxy(o)
143 ref = weakref.ref(o)
144 proxy2 = weakref.proxy(o)
145 self.assert_(proxy1 is proxy2,
146 "proxy object w/out callback should have been re-used")
147
148 def test_basic_proxy(self):
149 o = C()
150 self.check_proxy(o, weakref.proxy(o))
151
152 def test_callable_proxy(self):
153 o = Callable()
154 ref1 = weakref.proxy(o)
155
156 self.check_proxy(o, ref1)
157
158 self.assert_(type(ref1) is weakref.CallableProxyType,
159 "proxy is not of callable type")
160 ref1('twinkies!')
161 self.assert_(o.bar == 'twinkies!',
162 "call through proxy not passed through to original")
Fred Drake3bb4d212001-10-18 19:28:29 +0000163 ref1(x='Splat.')
164 self.assert_(o.bar == 'Splat.',
165 "call through proxy not passed through to original")
Fred Drakeb0fefc52001-03-23 04:22:45 +0000166
167 # expect due to too few args
168 self.assertRaises(TypeError, ref1)
169
170 # expect due to too many args
171 self.assertRaises(TypeError, ref1, 1, 2, 3)
172
173 def check_proxy(self, o, proxy):
174 o.foo = 1
175 self.assert_(proxy.foo == 1,
176 "proxy does not reflect attribute addition")
177 o.foo = 2
178 self.assert_(proxy.foo == 2,
179 "proxy does not reflect attribute modification")
180 del o.foo
181 self.assert_(not hasattr(proxy, 'foo'),
182 "proxy does not reflect attribute removal")
183
184 proxy.foo = 1
185 self.assert_(o.foo == 1,
186 "object does not reflect attribute addition via proxy")
187 proxy.foo = 2
188 self.assert_(
189 o.foo == 2,
190 "object does not reflect attribute modification via proxy")
191 del proxy.foo
192 self.assert_(not hasattr(o, 'foo'),
193 "object does not reflect attribute removal via proxy")
194
195 def test_getweakrefcount(self):
196 o = C()
197 ref1 = weakref.ref(o)
198 ref2 = weakref.ref(o, self.callback)
199 self.assert_(weakref.getweakrefcount(o) == 2,
200 "got wrong number of weak reference objects")
201
202 proxy1 = weakref.proxy(o)
203 proxy2 = weakref.proxy(o, self.callback)
204 self.assert_(weakref.getweakrefcount(o) == 4,
205 "got wrong number of weak reference objects")
206
207 def test_getweakrefs(self):
208 o = C()
209 ref1 = weakref.ref(o, self.callback)
210 ref2 = weakref.ref(o, self.callback)
211 del ref1
212 self.assert_(weakref.getweakrefs(o) == [ref2],
213 "list of refs does not match")
214
215 o = C()
216 ref1 = weakref.ref(o, self.callback)
217 ref2 = weakref.ref(o, self.callback)
218 del ref2
219 self.assert_(weakref.getweakrefs(o) == [ref1],
220 "list of refs does not match")
221
Fred Drake39c27f12001-10-18 18:06:05 +0000222 def test_newstyle_number_ops(self):
223 class F(float):
224 pass
225 f = F(2.0)
226 p = weakref.proxy(f)
227 self.assert_(p + 1.0 == 3.0)
228 self.assert_(1.0 + p == 3.0) # this used to SEGV
229
Fred Drake2a64f462001-12-10 23:46:02 +0000230 def test_callbacks_protected(self):
231 """Callbacks protected from already-set exceptions?"""
232 # Regression test for SF bug #478534.
233 class BogusError(Exception):
234 pass
235 data = {}
236 def remove(k):
237 del data[k]
238 def encapsulate():
239 f = lambda : ()
240 data[weakref.ref(f, remove)] = None
241 raise BogusError
242 try:
243 encapsulate()
244 except BogusError:
245 pass
246 else:
247 self.fail("exception not properly restored")
248 try:
249 encapsulate()
250 except BogusError:
251 pass
252 else:
253 self.fail("exception not properly restored")
254
Fred Drake41deb1e2001-02-01 05:27:45 +0000255
256class Object:
257 def __init__(self, arg):
258 self.arg = arg
259 def __repr__(self):
260 return "<Object %r>" % self.arg
261
Fred Drake41deb1e2001-02-01 05:27:45 +0000262
Fred Drakeb0fefc52001-03-23 04:22:45 +0000263class MappingTestCase(TestBase):
Martin v. Löwis5e163332001-02-27 18:36:56 +0000264
Fred Drakeb0fefc52001-03-23 04:22:45 +0000265 COUNT = 10
266
267 def test_weak_values(self):
Fred Drake0e540c32001-05-02 05:44:22 +0000268 #
269 # This exercises d.copy(), d.items(), d[], del d[], len(d).
270 #
271 dict, objects = self.make_weak_valued_dict()
Fred Drakeb0fefc52001-03-23 04:22:45 +0000272 for o in objects:
273 self.assert_(weakref.getweakrefcount(o) == 1,
274 "wrong number of weak references to %r!" % o)
275 self.assert_(o is dict[o.arg],
276 "wrong object returned by weak dict!")
277 items1 = dict.items()
278 items2 = dict.copy().items()
279 items1.sort()
280 items2.sort()
281 self.assert_(items1 == items2,
282 "cloning of weak-valued dictionary did not work!")
283 del items1, items2
284 self.assert_(len(dict) == self.COUNT)
285 del objects[0]
286 self.assert_(len(dict) == (self.COUNT - 1),
287 "deleting object did not cause dictionary update")
288 del objects, o
289 self.assert_(len(dict) == 0,
290 "deleting the values did not clear the dictionary")
Fred Drake4fd06e02001-08-03 04:11:27 +0000291 # regression on SF bug #447152:
292 dict = weakref.WeakValueDictionary()
293 self.assertRaises(KeyError, dict.__getitem__, 1)
294 dict[2] = C()
295 self.assertRaises(KeyError, dict.__getitem__, 2)
Fred Drakeb0fefc52001-03-23 04:22:45 +0000296
297 def test_weak_keys(self):
Fred Drake0e540c32001-05-02 05:44:22 +0000298 #
299 # This exercises d.copy(), d.items(), d[] = v, d[], del d[],
Fred Drake752eda42001-11-06 16:38:34 +0000300 # len(d), d.has_key().
Fred Drake0e540c32001-05-02 05:44:22 +0000301 #
302 dict, objects = self.make_weak_keyed_dict()
Fred Drakeb0fefc52001-03-23 04:22:45 +0000303 for o in objects:
304 self.assert_(weakref.getweakrefcount(o) == 1,
305 "wrong number of weak references to %r!" % o)
306 self.assert_(o.arg is dict[o],
307 "wrong object returned by weak dict!")
308 items1 = dict.items()
309 items2 = dict.copy().items()
310 items1.sort()
311 items2.sort()
312 self.assert_(items1 == items2,
313 "cloning of weak-keyed dictionary did not work!")
314 del items1, items2
315 self.assert_(len(dict) == self.COUNT)
316 del objects[0]
317 self.assert_(len(dict) == (self.COUNT - 1),
318 "deleting object did not cause dictionary update")
319 del objects, o
320 self.assert_(len(dict) == 0,
321 "deleting the keys did not clear the dictionary")
Fred Drake752eda42001-11-06 16:38:34 +0000322 o = Object(42)
323 dict[o] = "What is the meaning of the universe?"
324 self.assert_(dict.has_key(o))
325 self.assert_(not dict.has_key(34))
Martin v. Löwis5e163332001-02-27 18:36:56 +0000326
Fred Drake0e540c32001-05-02 05:44:22 +0000327 def test_weak_keyed_iters(self):
328 dict, objects = self.make_weak_keyed_dict()
329 self.check_iters(dict)
330
331 def test_weak_valued_iters(self):
332 dict, objects = self.make_weak_valued_dict()
333 self.check_iters(dict)
334
335 def check_iters(self, dict):
336 # item iterator:
337 items = dict.items()
338 for item in dict.iteritems():
339 items.remove(item)
Fred Drakeaaa48ff2001-05-10 17:16:38 +0000340 self.assert_(len(items) == 0, "iteritems() did not touch all items")
Fred Drake0e540c32001-05-02 05:44:22 +0000341
Fred Drakeaaa48ff2001-05-10 17:16:38 +0000342 # key iterator, via __iter__():
Fred Drake0e540c32001-05-02 05:44:22 +0000343 keys = dict.keys()
344 for k in dict:
345 keys.remove(k)
Fred Drakeaaa48ff2001-05-10 17:16:38 +0000346 self.assert_(len(keys) == 0, "__iter__() did not touch all keys")
347
348 # key iterator, via iterkeys():
349 keys = dict.keys()
350 for k in dict.iterkeys():
351 keys.remove(k)
352 self.assert_(len(keys) == 0, "iterkeys() did not touch all keys")
Fred Drake0e540c32001-05-02 05:44:22 +0000353
354 # value iterator:
355 values = dict.values()
356 for v in dict.itervalues():
357 values.remove(v)
Fred Drakeaaa48ff2001-05-10 17:16:38 +0000358 self.assert_(len(values) == 0, "itervalues() did not touch all values")
Fred Drake0e540c32001-05-02 05:44:22 +0000359
360 def make_weak_keyed_dict(self):
361 dict = weakref.WeakKeyDictionary()
362 objects = map(Object, range(self.COUNT))
363 for o in objects:
364 dict[o] = o.arg
365 return dict, objects
366
367 def make_weak_valued_dict(self):
368 dict = weakref.WeakValueDictionary()
369 objects = map(Object, range(self.COUNT))
370 for o in objects:
371 dict[o.arg] = o
372 return dict, objects
373
Fred Drakeaaa48ff2001-05-10 17:16:38 +0000374 def check_popitem(self, klass, key1, value1, key2, value2):
375 weakdict = klass()
376 weakdict[key1] = value1
377 weakdict[key2] = value2
378 self.assert_(len(weakdict) == 2)
379 k, v = weakdict.popitem()
380 self.assert_(len(weakdict) == 1)
381 if k is key1:
382 self.assert_(v is value1)
383 else:
384 self.assert_(v is value2)
385 k, v = weakdict.popitem()
386 self.assert_(len(weakdict) == 0)
387 if k is key1:
388 self.assert_(v is value1)
389 else:
390 self.assert_(v is value2)
391
392 def test_weak_valued_dict_popitem(self):
393 self.check_popitem(weakref.WeakValueDictionary,
394 "key1", C(), "key2", C())
395
396 def test_weak_keyed_dict_popitem(self):
397 self.check_popitem(weakref.WeakKeyDictionary,
398 C(), "value 1", C(), "value 2")
399
400 def check_setdefault(self, klass, key, value1, value2):
401 self.assert_(value1 is not value2,
402 "invalid test"
403 " -- value parameters must be distinct objects")
404 weakdict = klass()
405 o = weakdict.setdefault(key, value1)
406 self.assert_(o is value1)
407 self.assert_(weakdict.has_key(key))
408 self.assert_(weakdict.get(key) is value1)
409 self.assert_(weakdict[key] is value1)
410
411 o = weakdict.setdefault(key, value2)
412 self.assert_(o is value1)
413 self.assert_(weakdict.has_key(key))
414 self.assert_(weakdict.get(key) is value1)
415 self.assert_(weakdict[key] is value1)
416
417 def test_weak_valued_dict_setdefault(self):
418 self.check_setdefault(weakref.WeakValueDictionary,
419 "key", C(), C())
420
421 def test_weak_keyed_dict_setdefault(self):
422 self.check_setdefault(weakref.WeakKeyDictionary,
423 C(), "value 1", "value 2")
424
Fred Drakea0a4ab12001-04-16 17:37:27 +0000425 def check_update(self, klass, dict):
Fred Drake0e540c32001-05-02 05:44:22 +0000426 #
427 # This exercises d.update(), len(d), d.keys(), d.has_key(),
428 # d.get(), d[].
429 #
Fred Drakea0a4ab12001-04-16 17:37:27 +0000430 weakdict = klass()
431 weakdict.update(dict)
432 self.assert_(len(weakdict) == len(dict))
433 for k in weakdict.keys():
434 self.assert_(dict.has_key(k),
435 "mysterious new key appeared in weak dict")
436 v = dict.get(k)
437 self.assert_(v is weakdict[k])
438 self.assert_(v is weakdict.get(k))
439 for k in dict.keys():
440 self.assert_(weakdict.has_key(k),
441 "original key disappeared in weak dict")
442 v = dict[k]
443 self.assert_(v is weakdict[k])
444 self.assert_(v is weakdict.get(k))
445
446 def test_weak_valued_dict_update(self):
447 self.check_update(weakref.WeakValueDictionary,
448 {1: C(), 'a': C(), C(): C()})
449
450 def test_weak_keyed_dict_update(self):
451 self.check_update(weakref.WeakKeyDictionary,
452 {C(): 1, C(): 2, C(): 3})
453
Fred Drakeccc75622001-09-06 14:52:39 +0000454 def test_weak_keyed_delitem(self):
455 d = weakref.WeakKeyDictionary()
456 o1 = Object('1')
457 o2 = Object('2')
458 d[o1] = 'something'
459 d[o2] = 'something'
460 self.assert_(len(d) == 2)
461 del d[o1]
462 self.assert_(len(d) == 1)
463 self.assert_(d.keys() == [o2])
464
465 def test_weak_valued_delitem(self):
466 d = weakref.WeakValueDictionary()
467 o1 = Object('1')
468 o2 = Object('2')
469 d['something'] = o1
470 d['something else'] = o2
471 self.assert_(len(d) == 2)
472 del d['something']
473 self.assert_(len(d) == 1)
474 self.assert_(d.items() == [('something else', o2)])
475
Martin v. Löwis5e163332001-02-27 18:36:56 +0000476
Fred Drake2e2be372001-09-20 21:33:42 +0000477def test_main():
478 loader = unittest.TestLoader()
479 suite = unittest.TestSuite()
480 suite.addTest(loader.loadTestsFromTestCase(ReferencesTestCase))
481 suite.addTest(loader.loadTestsFromTestCase(MappingTestCase))
482 test_support.run_suite(suite)
483
484
485if __name__ == "__main__":
486 test_main()