blob: cdd26c76ae5f75f5f405ddf29c3964541183f2a9 [file] [log] [blame]
Fred Drakebc875f52004-02-04 23:14:14 +00001import gc
Fred Drake41deb1e2001-02-01 05:27:45 +00002import sys
Fred Drakeb0fefc52001-03-23 04:22:45 +00003import unittest
Raymond Hettinger53dbe392008-02-12 20:03:09 +00004import collections
Fred Drake41deb1e2001-02-01 05:27:45 +00005import weakref
Georg Brandlb533e262008-05-25 18:19:30 +00006import operator
Antoine Pitrouc1baa602010-01-08 17:54:23 +00007import contextlib
8import copy
Fred Drake41deb1e2001-02-01 05:27:45 +00009
Benjamin Petersonee8712c2008-05-20 21:35:26 +000010from test import support
Fred Drake41deb1e2001-02-01 05:27:45 +000011
Thomas Woutersb2137042007-02-01 18:02:27 +000012# Used in ReferencesTestCase.test_ref_created_during_del() .
13ref_from_del = None
Fred Drake41deb1e2001-02-01 05:27:45 +000014
15class C:
Fred Drakeb0fefc52001-03-23 04:22:45 +000016 def method(self):
17 pass
Fred Drake41deb1e2001-02-01 05:27:45 +000018
19
Fred Drakeb0fefc52001-03-23 04:22:45 +000020class Callable:
21 bar = None
Fred Drake41deb1e2001-02-01 05:27:45 +000022
Fred Drakeb0fefc52001-03-23 04:22:45 +000023 def __call__(self, x):
24 self.bar = x
Fred Drake41deb1e2001-02-01 05:27:45 +000025
26
Fred Drakeb0fefc52001-03-23 04:22:45 +000027def create_function():
28 def f(): pass
29 return f
30
31def create_bound_method():
32 return C().method
33
Fred Drake41deb1e2001-02-01 05:27:45 +000034
Antoine Pitroue11fecb2012-11-11 19:36:51 +010035class Object:
36 def __init__(self, arg):
37 self.arg = arg
38 def __repr__(self):
39 return "<Object %r>" % self.arg
40 def __eq__(self, other):
41 if isinstance(other, Object):
42 return self.arg == other.arg
43 return NotImplemented
44 def __lt__(self, other):
45 if isinstance(other, Object):
46 return self.arg < other.arg
47 return NotImplemented
48 def __hash__(self):
49 return hash(self.arg)
Antoine Pitrouc3afba12012-11-17 18:57:38 +010050 def some_method(self):
51 return 4
52 def other_method(self):
53 return 5
54
Antoine Pitroue11fecb2012-11-11 19:36:51 +010055
56class RefCycle:
57 def __init__(self):
58 self.cycle = self
59
60
Fred Drakeb0fefc52001-03-23 04:22:45 +000061class TestBase(unittest.TestCase):
62
63 def setUp(self):
64 self.cbcalled = 0
65
66 def callback(self, ref):
67 self.cbcalled += 1
Fred Drake41deb1e2001-02-01 05:27:45 +000068
69
Fred Drakeb0fefc52001-03-23 04:22:45 +000070class ReferencesTestCase(TestBase):
Fred Drake41deb1e2001-02-01 05:27:45 +000071
Fred Drakeb0fefc52001-03-23 04:22:45 +000072 def test_basic_ref(self):
73 self.check_basic_ref(C)
74 self.check_basic_ref(create_function)
75 self.check_basic_ref(create_bound_method)
Fred Drake41deb1e2001-02-01 05:27:45 +000076
Fred Drake43735da2002-04-11 03:59:42 +000077 # Just make sure the tp_repr handler doesn't raise an exception.
78 # Live reference:
79 o = C()
80 wr = weakref.ref(o)
Brett Cannon0b70cca2006-08-25 02:59:59 +000081 repr(wr)
Fred Drake43735da2002-04-11 03:59:42 +000082 # Dead reference:
83 del o
Brett Cannon0b70cca2006-08-25 02:59:59 +000084 repr(wr)
Fred Drake43735da2002-04-11 03:59:42 +000085
Fred Drakeb0fefc52001-03-23 04:22:45 +000086 def test_basic_callback(self):
87 self.check_basic_callback(C)
88 self.check_basic_callback(create_function)
89 self.check_basic_callback(create_bound_method)
Fred Drake41deb1e2001-02-01 05:27:45 +000090
Fred Drakeb0fefc52001-03-23 04:22:45 +000091 def test_multiple_callbacks(self):
92 o = C()
93 ref1 = weakref.ref(o, self.callback)
94 ref2 = weakref.ref(o, self.callback)
95 del o
Benjamin Petersonc9c0f202009-06-30 23:06:06 +000096 self.assertTrue(ref1() is None,
Fred Drakeb0fefc52001-03-23 04:22:45 +000097 "expected reference to be invalidated")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +000098 self.assertTrue(ref2() is None,
Fred Drakeb0fefc52001-03-23 04:22:45 +000099 "expected reference to be invalidated")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000100 self.assertTrue(self.cbcalled == 2,
Fred Drakeb0fefc52001-03-23 04:22:45 +0000101 "callback not called the right number of times")
Fred Drake41deb1e2001-02-01 05:27:45 +0000102
Fred Drake705088e2001-04-13 17:18:15 +0000103 def test_multiple_selfref_callbacks(self):
Guido van Rossum9eee5542002-08-22 20:21:30 +0000104 # Make sure all references are invalidated before callbacks are called
Fred Drake705088e2001-04-13 17:18:15 +0000105 #
106 # What's important here is that we're using the first
107 # reference in the callback invoked on the second reference
108 # (the most recently created ref is cleaned up first). This
109 # tests that all references to the object are invalidated
110 # before any of the callbacks are invoked, so that we only
111 # have one invocation of _weakref.c:cleanup_helper() active
112 # for a particular object at a time.
113 #
114 def callback(object, self=self):
115 self.ref()
116 c = C()
117 self.ref = weakref.ref(c, callback)
118 ref1 = weakref.ref(c, callback)
119 del c
120
Fred Drakeb0fefc52001-03-23 04:22:45 +0000121 def test_proxy_ref(self):
122 o = C()
123 o.bar = 1
124 ref1 = weakref.proxy(o, self.callback)
125 ref2 = weakref.proxy(o, self.callback)
126 del o
Fred Drake41deb1e2001-02-01 05:27:45 +0000127
Fred Drakeb0fefc52001-03-23 04:22:45 +0000128 def check(proxy):
129 proxy.bar
Fred Drake41deb1e2001-02-01 05:27:45 +0000130
Neal Norwitz2633c692007-02-26 22:22:47 +0000131 self.assertRaises(ReferenceError, check, ref1)
132 self.assertRaises(ReferenceError, check, ref2)
133 self.assertRaises(ReferenceError, bool, weakref.proxy(C()))
Guido van Rossume61fd5b2007-07-11 12:20:59 +0000134 self.assertEqual(self.cbcalled, 2)
Fred Drake41deb1e2001-02-01 05:27:45 +0000135
Fred Drakeb0fefc52001-03-23 04:22:45 +0000136 def check_basic_ref(self, factory):
137 o = factory()
138 ref = weakref.ref(o)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000139 self.assertTrue(ref() is not None,
Fred Drakeb0fefc52001-03-23 04:22:45 +0000140 "weak reference to live object should be live")
141 o2 = ref()
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000142 self.assertTrue(o is o2,
Fred Drakeb0fefc52001-03-23 04:22:45 +0000143 "<ref>() should return original object if live")
Fred Drake41deb1e2001-02-01 05:27:45 +0000144
Fred Drakeb0fefc52001-03-23 04:22:45 +0000145 def check_basic_callback(self, factory):
146 self.cbcalled = 0
147 o = factory()
148 ref = weakref.ref(o, self.callback)
149 del o
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000150 self.assertTrue(self.cbcalled == 1,
Fred Drake705088e2001-04-13 17:18:15 +0000151 "callback did not properly set 'cbcalled'")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000152 self.assertTrue(ref() is None,
Fred Drake705088e2001-04-13 17:18:15 +0000153 "ref2 should be dead after deleting object reference")
Fred Drake41deb1e2001-02-01 05:27:45 +0000154
Fred Drakeb0fefc52001-03-23 04:22:45 +0000155 def test_ref_reuse(self):
156 o = C()
157 ref1 = weakref.ref(o)
158 # create a proxy to make sure that there's an intervening creation
159 # between these two; it should make no difference
160 proxy = weakref.proxy(o)
161 ref2 = weakref.ref(o)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000162 self.assertTrue(ref1 is ref2,
Fred Drakeb0fefc52001-03-23 04:22:45 +0000163 "reference object w/out callback should be re-used")
Fred Drake41deb1e2001-02-01 05:27:45 +0000164
Fred Drakeb0fefc52001-03-23 04:22:45 +0000165 o = C()
166 proxy = weakref.proxy(o)
167 ref1 = weakref.ref(o)
168 ref2 = weakref.ref(o)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000169 self.assertTrue(ref1 is ref2,
Fred Drakeb0fefc52001-03-23 04:22:45 +0000170 "reference object w/out callback should be re-used")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000171 self.assertTrue(weakref.getweakrefcount(o) == 2,
Fred Drakeb0fefc52001-03-23 04:22:45 +0000172 "wrong weak ref count for object")
173 del proxy
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000174 self.assertTrue(weakref.getweakrefcount(o) == 1,
Fred Drakeb0fefc52001-03-23 04:22:45 +0000175 "wrong weak ref count for object after deleting proxy")
Fred Drake41deb1e2001-02-01 05:27:45 +0000176
Fred Drakeb0fefc52001-03-23 04:22:45 +0000177 def test_proxy_reuse(self):
178 o = C()
179 proxy1 = weakref.proxy(o)
180 ref = weakref.ref(o)
181 proxy2 = weakref.proxy(o)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000182 self.assertTrue(proxy1 is proxy2,
Fred Drakeb0fefc52001-03-23 04:22:45 +0000183 "proxy object w/out callback should have been re-used")
184
185 def test_basic_proxy(self):
186 o = C()
187 self.check_proxy(o, weakref.proxy(o))
188
Raymond Hettinger53dbe392008-02-12 20:03:09 +0000189 L = collections.UserList()
Fred Drake5935ff02001-12-19 16:54:23 +0000190 p = weakref.proxy(L)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000191 self.assertFalse(p, "proxy for empty UserList should be false")
Fred Drake5935ff02001-12-19 16:54:23 +0000192 p.append(12)
193 self.assertEqual(len(L), 1)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000194 self.assertTrue(p, "proxy for non-empty UserList should be true")
Fred Drake5935ff02001-12-19 16:54:23 +0000195 p[:] = [2, 3]
196 self.assertEqual(len(L), 2)
197 self.assertEqual(len(p), 2)
Ezio Melottib58e0bd2010-01-23 15:40:09 +0000198 self.assertIn(3, p, "proxy didn't support __contains__() properly")
Fred Drake5935ff02001-12-19 16:54:23 +0000199 p[1] = 5
200 self.assertEqual(L[1], 5)
201 self.assertEqual(p[1], 5)
Raymond Hettinger53dbe392008-02-12 20:03:09 +0000202 L2 = collections.UserList(L)
Fred Drake5935ff02001-12-19 16:54:23 +0000203 p2 = weakref.proxy(L2)
204 self.assertEqual(p, p2)
Walter Dörwald70a6b492004-02-12 17:35:32 +0000205 ## self.assertEqual(repr(L2), repr(p2))
Raymond Hettinger53dbe392008-02-12 20:03:09 +0000206 L3 = collections.UserList(range(10))
Fred Drake43735da2002-04-11 03:59:42 +0000207 p3 = weakref.proxy(L3)
208 self.assertEqual(L3[:], p3[:])
209 self.assertEqual(L3[5:], p3[5:])
210 self.assertEqual(L3[:5], p3[:5])
211 self.assertEqual(L3[2:5], p3[2:5])
Fred Drake5935ff02001-12-19 16:54:23 +0000212
Benjamin Peterson32019772009-11-19 03:08:32 +0000213 def test_proxy_unicode(self):
214 # See bug 5037
215 class C(object):
216 def __str__(self):
217 return "string"
218 def __bytes__(self):
219 return b"bytes"
220 instance = C()
Benjamin Peterson577473f2010-01-19 00:09:57 +0000221 self.assertIn("__bytes__", dir(weakref.proxy(instance)))
Benjamin Peterson32019772009-11-19 03:08:32 +0000222 self.assertEqual(bytes(weakref.proxy(instance)), b"bytes")
223
Georg Brandlb533e262008-05-25 18:19:30 +0000224 def test_proxy_index(self):
225 class C:
226 def __index__(self):
227 return 10
228 o = C()
229 p = weakref.proxy(o)
230 self.assertEqual(operator.index(p), 10)
231
232 def test_proxy_div(self):
233 class C:
234 def __floordiv__(self, other):
235 return 42
236 def __ifloordiv__(self, other):
237 return 21
238 o = C()
239 p = weakref.proxy(o)
240 self.assertEqual(p // 5, 42)
241 p //= 5
242 self.assertEqual(p, 21)
243
Fred Drakeea2adc92004-02-03 19:56:46 +0000244 # The PyWeakref_* C API is documented as allowing either NULL or
245 # None as the value for the callback, where either means "no
246 # callback". The "no callback" ref and proxy objects are supposed
247 # to be shared so long as they exist by all callers so long as
Thomas Wouters902d6eb2007-01-09 23:18:33 +0000248 # they are active. In Python 2.3.3 and earlier, this guarantee
Fred Drakeea2adc92004-02-03 19:56:46 +0000249 # was not honored, and was broken in different ways for
250 # PyWeakref_NewRef() and PyWeakref_NewProxy(). (Two tests.)
251
252 def test_shared_ref_without_callback(self):
253 self.check_shared_without_callback(weakref.ref)
254
255 def test_shared_proxy_without_callback(self):
256 self.check_shared_without_callback(weakref.proxy)
257
258 def check_shared_without_callback(self, makeref):
259 o = Object(1)
260 p1 = makeref(o, None)
261 p2 = makeref(o, None)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000262 self.assertTrue(p1 is p2, "both callbacks were None in the C API")
Fred Drakeea2adc92004-02-03 19:56:46 +0000263 del p1, p2
264 p1 = makeref(o)
265 p2 = makeref(o, None)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000266 self.assertTrue(p1 is p2, "callbacks were NULL, None in the C API")
Fred Drakeea2adc92004-02-03 19:56:46 +0000267 del p1, p2
268 p1 = makeref(o)
269 p2 = makeref(o)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000270 self.assertTrue(p1 is p2, "both callbacks were NULL in the C API")
Fred Drakeea2adc92004-02-03 19:56:46 +0000271 del p1, p2
272 p1 = makeref(o, None)
273 p2 = makeref(o)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000274 self.assertTrue(p1 is p2, "callbacks were None, NULL in the C API")
Fred Drakeea2adc92004-02-03 19:56:46 +0000275
Fred Drakeb0fefc52001-03-23 04:22:45 +0000276 def test_callable_proxy(self):
277 o = Callable()
278 ref1 = weakref.proxy(o)
279
280 self.check_proxy(o, ref1)
281
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000282 self.assertTrue(type(ref1) is weakref.CallableProxyType,
Fred Drakeb0fefc52001-03-23 04:22:45 +0000283 "proxy is not of callable type")
284 ref1('twinkies!')
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000285 self.assertTrue(o.bar == 'twinkies!',
Fred Drakeb0fefc52001-03-23 04:22:45 +0000286 "call through proxy not passed through to original")
Fred Drake3bb4d212001-10-18 19:28:29 +0000287 ref1(x='Splat.')
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000288 self.assertTrue(o.bar == 'Splat.',
Fred Drake3bb4d212001-10-18 19:28:29 +0000289 "call through proxy not passed through to original")
Fred Drakeb0fefc52001-03-23 04:22:45 +0000290
291 # expect due to too few args
292 self.assertRaises(TypeError, ref1)
293
294 # expect due to too many args
295 self.assertRaises(TypeError, ref1, 1, 2, 3)
296
297 def check_proxy(self, o, proxy):
298 o.foo = 1
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000299 self.assertTrue(proxy.foo == 1,
Fred Drakeb0fefc52001-03-23 04:22:45 +0000300 "proxy does not reflect attribute addition")
301 o.foo = 2
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000302 self.assertTrue(proxy.foo == 2,
Fred Drakeb0fefc52001-03-23 04:22:45 +0000303 "proxy does not reflect attribute modification")
304 del o.foo
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000305 self.assertTrue(not hasattr(proxy, 'foo'),
Fred Drakeb0fefc52001-03-23 04:22:45 +0000306 "proxy does not reflect attribute removal")
307
308 proxy.foo = 1
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000309 self.assertTrue(o.foo == 1,
Fred Drakeb0fefc52001-03-23 04:22:45 +0000310 "object does not reflect attribute addition via proxy")
311 proxy.foo = 2
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000312 self.assertTrue(
Fred Drakeb0fefc52001-03-23 04:22:45 +0000313 o.foo == 2,
314 "object does not reflect attribute modification via proxy")
315 del proxy.foo
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000316 self.assertTrue(not hasattr(o, 'foo'),
Fred Drakeb0fefc52001-03-23 04:22:45 +0000317 "object does not reflect attribute removal via proxy")
318
Raymond Hettingerd693a812003-06-30 04:18:48 +0000319 def test_proxy_deletion(self):
320 # Test clearing of SF bug #762891
321 class Foo:
322 result = None
323 def __delitem__(self, accessor):
324 self.result = accessor
325 g = Foo()
326 f = weakref.proxy(g)
327 del f[0]
328 self.assertEqual(f.result, 0)
329
Raymond Hettingere6c470f2005-03-27 03:04:54 +0000330 def test_proxy_bool(self):
331 # Test clearing of SF bug #1170766
332 class List(list): pass
333 lyst = List()
334 self.assertEqual(bool(weakref.proxy(lyst)), bool(lyst))
335
Fred Drakeb0fefc52001-03-23 04:22:45 +0000336 def test_getweakrefcount(self):
337 o = C()
338 ref1 = weakref.ref(o)
339 ref2 = weakref.ref(o, self.callback)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000340 self.assertTrue(weakref.getweakrefcount(o) == 2,
Fred Drakeb0fefc52001-03-23 04:22:45 +0000341 "got wrong number of weak reference objects")
342
343 proxy1 = weakref.proxy(o)
344 proxy2 = weakref.proxy(o, self.callback)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000345 self.assertTrue(weakref.getweakrefcount(o) == 4,
Fred Drakeb0fefc52001-03-23 04:22:45 +0000346 "got wrong number of weak reference objects")
347
Fred Drakeea2adc92004-02-03 19:56:46 +0000348 del ref1, ref2, proxy1, proxy2
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000349 self.assertTrue(weakref.getweakrefcount(o) == 0,
Fred Drakeea2adc92004-02-03 19:56:46 +0000350 "weak reference objects not unlinked from"
351 " referent when discarded.")
352
Walter Dörwaldb167b042003-12-11 12:34:05 +0000353 # assumes ints do not support weakrefs
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000354 self.assertTrue(weakref.getweakrefcount(1) == 0,
Walter Dörwaldb167b042003-12-11 12:34:05 +0000355 "got wrong number of weak reference objects for int")
356
Fred Drakeb0fefc52001-03-23 04:22:45 +0000357 def test_getweakrefs(self):
358 o = C()
359 ref1 = weakref.ref(o, self.callback)
360 ref2 = weakref.ref(o, self.callback)
361 del ref1
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000362 self.assertTrue(weakref.getweakrefs(o) == [ref2],
Fred Drakeb0fefc52001-03-23 04:22:45 +0000363 "list of refs does not match")
364
365 o = C()
366 ref1 = weakref.ref(o, self.callback)
367 ref2 = weakref.ref(o, self.callback)
368 del ref2
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000369 self.assertTrue(weakref.getweakrefs(o) == [ref1],
Fred Drakeb0fefc52001-03-23 04:22:45 +0000370 "list of refs does not match")
371
Fred Drakeea2adc92004-02-03 19:56:46 +0000372 del ref1
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000373 self.assertTrue(weakref.getweakrefs(o) == [],
Fred Drakeea2adc92004-02-03 19:56:46 +0000374 "list of refs not cleared")
375
Walter Dörwaldb167b042003-12-11 12:34:05 +0000376 # assumes ints do not support weakrefs
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000377 self.assertTrue(weakref.getweakrefs(1) == [],
Walter Dörwaldb167b042003-12-11 12:34:05 +0000378 "list of refs does not match for int")
379
Fred Drake39c27f12001-10-18 18:06:05 +0000380 def test_newstyle_number_ops(self):
381 class F(float):
382 pass
383 f = F(2.0)
384 p = weakref.proxy(f)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000385 self.assertTrue(p + 1.0 == 3.0)
386 self.assertTrue(1.0 + p == 3.0) # this used to SEGV
Fred Drake39c27f12001-10-18 18:06:05 +0000387
Fred Drake2a64f462001-12-10 23:46:02 +0000388 def test_callbacks_protected(self):
Guido van Rossum9eee5542002-08-22 20:21:30 +0000389 # Callbacks protected from already-set exceptions?
Fred Drake2a64f462001-12-10 23:46:02 +0000390 # Regression test for SF bug #478534.
391 class BogusError(Exception):
392 pass
393 data = {}
394 def remove(k):
395 del data[k]
396 def encapsulate():
397 f = lambda : ()
398 data[weakref.ref(f, remove)] = None
399 raise BogusError
400 try:
401 encapsulate()
402 except BogusError:
403 pass
404 else:
405 self.fail("exception not properly restored")
406 try:
407 encapsulate()
408 except BogusError:
409 pass
410 else:
411 self.fail("exception not properly restored")
412
Tim Petersadd09b42003-11-12 20:43:28 +0000413 def test_sf_bug_840829(self):
414 # "weakref callbacks and gc corrupt memory"
415 # subtype_dealloc erroneously exposed a new-style instance
416 # already in the process of getting deallocated to gc,
417 # causing double-deallocation if the instance had a weakref
418 # callback that triggered gc.
419 # If the bug exists, there probably won't be an obvious symptom
420 # in a release build. In a debug build, a segfault will occur
421 # when the second attempt to remove the instance from the "list
422 # of all objects" occurs.
423
424 import gc
425
426 class C(object):
427 pass
428
429 c = C()
430 wr = weakref.ref(c, lambda ignore: gc.collect())
431 del c
432
Tim Petersf7f9e992003-11-13 21:59:32 +0000433 # There endeth the first part. It gets worse.
434 del wr
435
436 c1 = C()
437 c1.i = C()
438 wr = weakref.ref(c1.i, lambda ignore: gc.collect())
439
440 c2 = C()
441 c2.c1 = c1
442 del c1 # still alive because c2 points to it
443
444 # Now when subtype_dealloc gets called on c2, it's not enough just
445 # that c2 is immune from gc while the weakref callbacks associated
446 # with c2 execute (there are none in this 2nd half of the test, btw).
447 # subtype_dealloc goes on to call the base classes' deallocs too,
448 # so any gc triggered by weakref callbacks associated with anything
449 # torn down by a base class dealloc can also trigger double
450 # deallocation of c2.
451 del c2
Fred Drake41deb1e2001-02-01 05:27:45 +0000452
Tim Peters403a2032003-11-20 21:21:46 +0000453 def test_callback_in_cycle_1(self):
454 import gc
455
456 class J(object):
457 pass
458
459 class II(object):
460 def acallback(self, ignore):
461 self.J
462
463 I = II()
464 I.J = J
465 I.wr = weakref.ref(J, I.acallback)
466
467 # Now J and II are each in a self-cycle (as all new-style class
468 # objects are, since their __mro__ points back to them). I holds
469 # both a weak reference (I.wr) and a strong reference (I.J) to class
470 # J. I is also in a cycle (I.wr points to a weakref that references
471 # I.acallback). When we del these three, they all become trash, but
472 # the cycles prevent any of them from getting cleaned up immediately.
473 # Instead they have to wait for cyclic gc to deduce that they're
474 # trash.
475 #
476 # gc used to call tp_clear on all of them, and the order in which
477 # it does that is pretty accidental. The exact order in which we
478 # built up these things manages to provoke gc into running tp_clear
479 # in just the right order (I last). Calling tp_clear on II leaves
480 # behind an insane class object (its __mro__ becomes NULL). Calling
481 # tp_clear on J breaks its self-cycle, but J doesn't get deleted
482 # just then because of the strong reference from I.J. Calling
483 # tp_clear on I starts to clear I's __dict__, and just happens to
484 # clear I.J first -- I.wr is still intact. That removes the last
485 # reference to J, which triggers the weakref callback. The callback
486 # tries to do "self.J", and instances of new-style classes look up
487 # attributes ("J") in the class dict first. The class (II) wants to
488 # search II.__mro__, but that's NULL. The result was a segfault in
489 # a release build, and an assert failure in a debug build.
490 del I, J, II
491 gc.collect()
492
493 def test_callback_in_cycle_2(self):
494 import gc
495
496 # This is just like test_callback_in_cycle_1, except that II is an
497 # old-style class. The symptom is different then: an instance of an
498 # old-style class looks in its own __dict__ first. 'J' happens to
499 # get cleared from I.__dict__ before 'wr', and 'J' was never in II's
500 # __dict__, so the attribute isn't found. The difference is that
501 # the old-style II doesn't have a NULL __mro__ (it doesn't have any
502 # __mro__), so no segfault occurs. Instead it got:
503 # test_callback_in_cycle_2 (__main__.ReferencesTestCase) ...
504 # Exception exceptions.AttributeError:
505 # "II instance has no attribute 'J'" in <bound method II.acallback
506 # of <?.II instance at 0x00B9B4B8>> ignored
507
508 class J(object):
509 pass
510
511 class II:
512 def acallback(self, ignore):
513 self.J
514
515 I = II()
516 I.J = J
517 I.wr = weakref.ref(J, I.acallback)
518
519 del I, J, II
520 gc.collect()
521
522 def test_callback_in_cycle_3(self):
523 import gc
524
525 # This one broke the first patch that fixed the last two. In this
526 # case, the objects reachable from the callback aren't also reachable
527 # from the object (c1) *triggering* the callback: you can get to
528 # c1 from c2, but not vice-versa. The result was that c2's __dict__
529 # got tp_clear'ed by the time the c2.cb callback got invoked.
530
531 class C:
532 def cb(self, ignore):
533 self.me
534 self.c1
535 self.wr
536
537 c1, c2 = C(), C()
538
539 c2.me = c2
540 c2.c1 = c1
541 c2.wr = weakref.ref(c1, c2.cb)
542
543 del c1, c2
544 gc.collect()
545
546 def test_callback_in_cycle_4(self):
547 import gc
548
549 # Like test_callback_in_cycle_3, except c2 and c1 have different
550 # classes. c2's class (C) isn't reachable from c1 then, so protecting
551 # objects reachable from the dying object (c1) isn't enough to stop
552 # c2's class (C) from getting tp_clear'ed before c2.cb is invoked.
553 # The result was a segfault (C.__mro__ was NULL when the callback
554 # tried to look up self.me).
555
556 class C(object):
557 def cb(self, ignore):
558 self.me
559 self.c1
560 self.wr
561
562 class D:
563 pass
564
565 c1, c2 = D(), C()
566
567 c2.me = c2
568 c2.c1 = c1
569 c2.wr = weakref.ref(c1, c2.cb)
570
571 del c1, c2, C, D
572 gc.collect()
573
574 def test_callback_in_cycle_resurrection(self):
575 import gc
576
577 # Do something nasty in a weakref callback: resurrect objects
578 # from dead cycles. For this to be attempted, the weakref and
579 # its callback must also be part of the cyclic trash (else the
580 # objects reachable via the callback couldn't be in cyclic trash
581 # to begin with -- the callback would act like an external root).
582 # But gc clears trash weakrefs with callbacks early now, which
583 # disables the callbacks, so the callbacks shouldn't get called
584 # at all (and so nothing actually gets resurrected).
585
586 alist = []
587 class C(object):
588 def __init__(self, value):
589 self.attribute = value
590
591 def acallback(self, ignore):
592 alist.append(self.c)
593
594 c1, c2 = C(1), C(2)
595 c1.c = c2
596 c2.c = c1
597 c1.wr = weakref.ref(c2, c1.acallback)
598 c2.wr = weakref.ref(c1, c2.acallback)
599
600 def C_went_away(ignore):
601 alist.append("C went away")
602 wr = weakref.ref(C, C_went_away)
603
604 del c1, c2, C # make them all trash
605 self.assertEqual(alist, []) # del isn't enough to reclaim anything
606
607 gc.collect()
608 # c1.wr and c2.wr were part of the cyclic trash, so should have
609 # been cleared without their callbacks executing. OTOH, the weakref
610 # to C is bound to a function local (wr), and wasn't trash, so that
611 # callback should have been invoked when C went away.
612 self.assertEqual(alist, ["C went away"])
613 # The remaining weakref should be dead now (its callback ran).
614 self.assertEqual(wr(), None)
615
616 del alist[:]
617 gc.collect()
618 self.assertEqual(alist, [])
619
620 def test_callbacks_on_callback(self):
621 import gc
622
623 # Set up weakref callbacks *on* weakref callbacks.
624 alist = []
625 def safe_callback(ignore):
626 alist.append("safe_callback called")
627
628 class C(object):
629 def cb(self, ignore):
630 alist.append("cb called")
631
632 c, d = C(), C()
633 c.other = d
634 d.other = c
635 callback = c.cb
636 c.wr = weakref.ref(d, callback) # this won't trigger
637 d.wr = weakref.ref(callback, d.cb) # ditto
638 external_wr = weakref.ref(callback, safe_callback) # but this will
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000639 self.assertTrue(external_wr() is callback)
Tim Peters403a2032003-11-20 21:21:46 +0000640
641 # The weakrefs attached to c and d should get cleared, so that
642 # C.cb is never called. But external_wr isn't part of the cyclic
643 # trash, and no cyclic trash is reachable from it, so safe_callback
644 # should get invoked when the bound method object callback (c.cb)
645 # -- which is itself a callback, and also part of the cyclic trash --
646 # gets reclaimed at the end of gc.
647
648 del callback, c, d, C
649 self.assertEqual(alist, []) # del isn't enough to clean up cycles
650 gc.collect()
651 self.assertEqual(alist, ["safe_callback called"])
652 self.assertEqual(external_wr(), None)
653
654 del alist[:]
655 gc.collect()
656 self.assertEqual(alist, [])
657
Fred Drakebc875f52004-02-04 23:14:14 +0000658 def test_gc_during_ref_creation(self):
659 self.check_gc_during_creation(weakref.ref)
660
661 def test_gc_during_proxy_creation(self):
662 self.check_gc_during_creation(weakref.proxy)
663
664 def check_gc_during_creation(self, makeref):
665 thresholds = gc.get_threshold()
666 gc.set_threshold(1, 1, 1)
667 gc.collect()
Fred Drake55cf4342004-02-13 19:21:57 +0000668 class A:
669 pass
Fred Drakebc875f52004-02-04 23:14:14 +0000670
671 def callback(*args):
672 pass
673
Fred Drake55cf4342004-02-13 19:21:57 +0000674 referenced = A()
Fred Drakebc875f52004-02-04 23:14:14 +0000675
Fred Drake55cf4342004-02-13 19:21:57 +0000676 a = A()
Fred Drakebc875f52004-02-04 23:14:14 +0000677 a.a = a
678 a.wr = makeref(referenced)
679
680 try:
681 # now make sure the object and the ref get labeled as
682 # cyclic trash:
Fred Drake55cf4342004-02-13 19:21:57 +0000683 a = A()
684 weakref.ref(referenced, callback)
Fred Drakebc875f52004-02-04 23:14:14 +0000685
686 finally:
687 gc.set_threshold(*thresholds)
688
Thomas Woutersb2137042007-02-01 18:02:27 +0000689 def test_ref_created_during_del(self):
690 # Bug #1377858
691 # A weakref created in an object's __del__() would crash the
692 # interpreter when the weakref was cleaned up since it would refer to
693 # non-existent memory. This test should not segfault the interpreter.
694 class Target(object):
695 def __del__(self):
696 global ref_from_del
697 ref_from_del = weakref.ref(self)
698
699 w = Target()
700
Benjamin Peterson9aa42992008-09-10 21:57:34 +0000701 def test_init(self):
702 # Issue 3634
703 # <weakref to class>.__init__() doesn't check errors correctly
704 r = weakref.ref(Exception)
705 self.assertRaises(TypeError, r.__init__, 0, 0, 0, 0, 0)
706 # No exception should be raised here
707 gc.collect()
708
Antoine Pitrou3af01a12010-03-31 21:40:47 +0000709 def test_classes(self):
710 # Check that classes are weakrefable.
711 class A(object):
712 pass
713 l = []
714 weakref.ref(int)
715 a = weakref.ref(A, l.append)
716 A = None
717 gc.collect()
718 self.assertEqual(a(), None)
719 self.assertEqual(l, [a])
720
Antoine Pitroue11fecb2012-11-11 19:36:51 +0100721 def test_equality(self):
722 # Alive weakrefs defer equality testing to their underlying object.
723 x = Object(1)
724 y = Object(1)
725 z = Object(2)
726 a = weakref.ref(x)
727 b = weakref.ref(y)
728 c = weakref.ref(z)
729 d = weakref.ref(x)
730 # Note how we directly test the operators here, to stress both
731 # __eq__ and __ne__.
732 self.assertTrue(a == b)
733 self.assertFalse(a != b)
734 self.assertFalse(a == c)
735 self.assertTrue(a != c)
736 self.assertTrue(a == d)
737 self.assertFalse(a != d)
738 del x, y, z
739 gc.collect()
740 for r in a, b, c:
741 # Sanity check
742 self.assertIs(r(), None)
743 # Dead weakrefs compare by identity: whether `a` and `d` are the
744 # same weakref object is an implementation detail, since they pointed
745 # to the same original object and didn't have a callback.
746 # (see issue #16453).
747 self.assertFalse(a == b)
748 self.assertTrue(a != b)
749 self.assertFalse(a == c)
750 self.assertTrue(a != c)
751 self.assertEqual(a == d, a is d)
752 self.assertEqual(a != d, a is not d)
753
754 def test_ordering(self):
755 # weakrefs cannot be ordered, even if the underlying objects can.
756 ops = [operator.lt, operator.gt, operator.le, operator.ge]
757 x = Object(1)
758 y = Object(1)
759 a = weakref.ref(x)
760 b = weakref.ref(y)
761 for op in ops:
762 self.assertRaises(TypeError, op, a, b)
763 # Same when dead.
764 del x, y
765 gc.collect()
766 for op in ops:
767 self.assertRaises(TypeError, op, a, b)
768
769 def test_hashing(self):
770 # Alive weakrefs hash the same as the underlying object
771 x = Object(42)
772 y = Object(42)
773 a = weakref.ref(x)
774 b = weakref.ref(y)
775 self.assertEqual(hash(a), hash(42))
776 del x, y
777 gc.collect()
778 # Dead weakrefs:
779 # - retain their hash is they were hashed when alive;
780 # - otherwise, cannot be hashed.
781 self.assertEqual(hash(a), hash(42))
782 self.assertRaises(TypeError, hash, b)
783
Antoine Pitrou62a0d6e2012-12-08 21:15:26 +0100784 def test_trashcan_16602(self):
785 # Issue #16602: when a weakref's target was part of a long
786 # deallocation chain, the trashcan mechanism could delay clearing
787 # of the weakref and make the target object visible from outside
788 # code even though its refcount had dropped to 0. A crash ensued.
789 class C:
790 def __init__(self, parent):
791 if not parent:
792 return
793 wself = weakref.ref(self)
794 def cb(wparent):
795 o = wself()
796 self.wparent = weakref.ref(parent, cb)
797
798 d = weakref.WeakKeyDictionary()
799 root = c = C(None)
800 for n in range(100):
801 d[c] = c = C(c)
802 del root
803 gc.collect()
804
Fred Drake0a4dd392004-07-02 18:57:45 +0000805
Amaury Forgeot d'Arcc856c7a2008-06-16 19:50:09 +0000806class SubclassableWeakrefTestCase(TestBase):
Fred Drake0a4dd392004-07-02 18:57:45 +0000807
808 def test_subclass_refs(self):
809 class MyRef(weakref.ref):
810 def __init__(self, ob, callback=None, value=42):
811 self.value = value
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000812 super().__init__(ob, callback)
Fred Drake0a4dd392004-07-02 18:57:45 +0000813 def __call__(self):
814 self.called = True
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000815 return super().__call__()
Fred Drake0a4dd392004-07-02 18:57:45 +0000816 o = Object("foo")
817 mr = MyRef(o, value=24)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000818 self.assertTrue(mr() is o)
819 self.assertTrue(mr.called)
Fred Drake0a4dd392004-07-02 18:57:45 +0000820 self.assertEqual(mr.value, 24)
821 del o
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000822 self.assertTrue(mr() is None)
823 self.assertTrue(mr.called)
Fred Drake0a4dd392004-07-02 18:57:45 +0000824
825 def test_subclass_refs_dont_replace_standard_refs(self):
826 class MyRef(weakref.ref):
827 pass
828 o = Object(42)
829 r1 = MyRef(o)
830 r2 = weakref.ref(o)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000831 self.assertTrue(r1 is not r2)
Fred Drake0a4dd392004-07-02 18:57:45 +0000832 self.assertEqual(weakref.getweakrefs(o), [r2, r1])
833 self.assertEqual(weakref.getweakrefcount(o), 2)
834 r3 = MyRef(o)
835 self.assertEqual(weakref.getweakrefcount(o), 3)
836 refs = weakref.getweakrefs(o)
837 self.assertEqual(len(refs), 3)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000838 self.assertTrue(r2 is refs[0])
Benjamin Peterson577473f2010-01-19 00:09:57 +0000839 self.assertIn(r1, refs[1:])
840 self.assertIn(r3, refs[1:])
Fred Drake0a4dd392004-07-02 18:57:45 +0000841
842 def test_subclass_refs_dont_conflate_callbacks(self):
843 class MyRef(weakref.ref):
844 pass
845 o = Object(42)
846 r1 = MyRef(o, id)
847 r2 = MyRef(o, str)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000848 self.assertTrue(r1 is not r2)
Fred Drake0a4dd392004-07-02 18:57:45 +0000849 refs = weakref.getweakrefs(o)
Benjamin Peterson577473f2010-01-19 00:09:57 +0000850 self.assertIn(r1, refs)
851 self.assertIn(r2, refs)
Fred Drake0a4dd392004-07-02 18:57:45 +0000852
853 def test_subclass_refs_with_slots(self):
854 class MyRef(weakref.ref):
855 __slots__ = "slot1", "slot2"
856 def __new__(type, ob, callback, slot1, slot2):
857 return weakref.ref.__new__(type, ob, callback)
858 def __init__(self, ob, callback, slot1, slot2):
859 self.slot1 = slot1
860 self.slot2 = slot2
861 def meth(self):
862 return self.slot1 + self.slot2
863 o = Object(42)
864 r = MyRef(o, None, "abc", "def")
865 self.assertEqual(r.slot1, "abc")
866 self.assertEqual(r.slot2, "def")
867 self.assertEqual(r.meth(), "abcdef")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000868 self.assertFalse(hasattr(r, "__dict__"))
Fred Drake0a4dd392004-07-02 18:57:45 +0000869
Amaury Forgeot d'Arcc856c7a2008-06-16 19:50:09 +0000870 def test_subclass_refs_with_cycle(self):
871 # Bug #3110
872 # An instance of a weakref subclass can have attributes.
873 # If such a weakref holds the only strong reference to the object,
874 # deleting the weakref will delete the object. In this case,
875 # the callback must not be called, because the ref object is
876 # being deleted.
877 class MyRef(weakref.ref):
878 pass
879
880 # Use a local callback, for "regrtest -R::"
881 # to detect refcounting problems
882 def callback(w):
883 self.cbcalled += 1
884
885 o = C()
886 r1 = MyRef(o, callback)
887 r1.o = o
888 del o
889
890 del r1 # Used to crash here
891
892 self.assertEqual(self.cbcalled, 0)
893
894 # Same test, with two weakrefs to the same object
895 # (since code paths are different)
896 o = C()
897 r1 = MyRef(o, callback)
898 r2 = MyRef(o, callback)
899 r1.r = r2
900 r2.o = o
901 del o
902 del r2
903
904 del r1 # Used to crash here
905
906 self.assertEqual(self.cbcalled, 0)
907
Fred Drake0a4dd392004-07-02 18:57:45 +0000908
Antoine Pitrouc3afba12012-11-17 18:57:38 +0100909class WeakMethodTestCase(unittest.TestCase):
910
911 def _subclass(self):
912 """Return a Object subclass overriding `some_method`."""
913 class C(Object):
914 def some_method(self):
915 return 6
916 return C
917
918 def test_alive(self):
919 o = Object(1)
920 r = weakref.WeakMethod(o.some_method)
921 self.assertIsInstance(r, weakref.ReferenceType)
922 self.assertIsInstance(r(), type(o.some_method))
923 self.assertIs(r().__self__, o)
924 self.assertIs(r().__func__, o.some_method.__func__)
925 self.assertEqual(r()(), 4)
926
927 def test_object_dead(self):
928 o = Object(1)
929 r = weakref.WeakMethod(o.some_method)
930 del o
931 gc.collect()
932 self.assertIs(r(), None)
933
934 def test_method_dead(self):
935 C = self._subclass()
936 o = C(1)
937 r = weakref.WeakMethod(o.some_method)
938 del C.some_method
939 gc.collect()
940 self.assertIs(r(), None)
941
942 def test_callback_when_object_dead(self):
943 # Test callback behaviour when object dies first.
944 C = self._subclass()
945 calls = []
946 def cb(arg):
947 calls.append(arg)
948 o = C(1)
949 r = weakref.WeakMethod(o.some_method, cb)
950 del o
951 gc.collect()
952 self.assertEqual(calls, [r])
953 # Callback is only called once.
954 C.some_method = Object.some_method
955 gc.collect()
956 self.assertEqual(calls, [r])
957
958 def test_callback_when_method_dead(self):
959 # Test callback behaviour when method dies first.
960 C = self._subclass()
961 calls = []
962 def cb(arg):
963 calls.append(arg)
964 o = C(1)
965 r = weakref.WeakMethod(o.some_method, cb)
966 del C.some_method
967 gc.collect()
968 self.assertEqual(calls, [r])
969 # Callback is only called once.
970 del o
971 gc.collect()
972 self.assertEqual(calls, [r])
973
974 @support.cpython_only
975 def test_no_cycles(self):
976 # A WeakMethod doesn't create any reference cycle to itself.
977 o = Object(1)
978 def cb(_):
979 pass
980 r = weakref.WeakMethod(o.some_method, cb)
981 wr = weakref.ref(r)
982 del r
983 self.assertIs(wr(), None)
984
985 def test_equality(self):
986 def _eq(a, b):
987 self.assertTrue(a == b)
988 self.assertFalse(a != b)
989 def _ne(a, b):
990 self.assertTrue(a != b)
991 self.assertFalse(a == b)
992 x = Object(1)
993 y = Object(1)
994 a = weakref.WeakMethod(x.some_method)
995 b = weakref.WeakMethod(y.some_method)
996 c = weakref.WeakMethod(x.other_method)
997 d = weakref.WeakMethod(y.other_method)
998 # Objects equal, same method
999 _eq(a, b)
1000 _eq(c, d)
1001 # Objects equal, different method
1002 _ne(a, c)
1003 _ne(a, d)
1004 _ne(b, c)
1005 _ne(b, d)
1006 # Objects unequal, same or different method
1007 z = Object(2)
1008 e = weakref.WeakMethod(z.some_method)
1009 f = weakref.WeakMethod(z.other_method)
1010 _ne(a, e)
1011 _ne(a, f)
1012 _ne(b, e)
1013 _ne(b, f)
1014 del x, y, z
1015 gc.collect()
1016 # Dead WeakMethods compare by identity
1017 refs = a, b, c, d, e, f
1018 for q in refs:
1019 for r in refs:
1020 self.assertEqual(q == r, q is r)
1021 self.assertEqual(q != r, q is not r)
1022
1023 def test_hashing(self):
1024 # Alive WeakMethods are hashable if the underlying object is
1025 # hashable.
1026 x = Object(1)
1027 y = Object(1)
1028 a = weakref.WeakMethod(x.some_method)
1029 b = weakref.WeakMethod(y.some_method)
1030 c = weakref.WeakMethod(y.other_method)
1031 # Since WeakMethod objects are equal, the hashes should be equal.
1032 self.assertEqual(hash(a), hash(b))
1033 ha = hash(a)
1034 # Dead WeakMethods retain their old hash value
1035 del x, y
1036 gc.collect()
1037 self.assertEqual(hash(a), ha)
1038 self.assertEqual(hash(b), ha)
1039 # If it wasn't hashed when alive, a dead WeakMethod cannot be hashed.
1040 self.assertRaises(TypeError, hash, c)
1041
1042
Fred Drakeb0fefc52001-03-23 04:22:45 +00001043class MappingTestCase(TestBase):
Martin v. Löwis5e163332001-02-27 18:36:56 +00001044
Fred Drakeb0fefc52001-03-23 04:22:45 +00001045 COUNT = 10
1046
Antoine Pitroubbe2f602012-03-01 16:26:35 +01001047 def check_len_cycles(self, dict_type, cons):
1048 N = 20
1049 items = [RefCycle() for i in range(N)]
1050 dct = dict_type(cons(o) for o in items)
1051 # Keep an iterator alive
1052 it = dct.items()
1053 try:
1054 next(it)
1055 except StopIteration:
1056 pass
1057 del items
1058 gc.collect()
1059 n1 = len(dct)
1060 del it
1061 gc.collect()
1062 n2 = len(dct)
1063 # one item may be kept alive inside the iterator
1064 self.assertIn(n1, (0, 1))
1065 self.assertEqual(n2, 0)
1066
1067 def test_weak_keyed_len_cycles(self):
1068 self.check_len_cycles(weakref.WeakKeyDictionary, lambda k: (k, 1))
1069
1070 def test_weak_valued_len_cycles(self):
1071 self.check_len_cycles(weakref.WeakValueDictionary, lambda k: (1, k))
1072
1073 def check_len_race(self, dict_type, cons):
1074 # Extended sanity checks for len() in the face of cyclic collection
1075 self.addCleanup(gc.set_threshold, *gc.get_threshold())
1076 for th in range(1, 100):
1077 N = 20
1078 gc.collect(0)
1079 gc.set_threshold(th, th, th)
1080 items = [RefCycle() for i in range(N)]
1081 dct = dict_type(cons(o) for o in items)
1082 del items
1083 # All items will be collected at next garbage collection pass
1084 it = dct.items()
1085 try:
1086 next(it)
1087 except StopIteration:
1088 pass
1089 n1 = len(dct)
1090 del it
1091 n2 = len(dct)
1092 self.assertGreaterEqual(n1, 0)
1093 self.assertLessEqual(n1, N)
1094 self.assertGreaterEqual(n2, 0)
1095 self.assertLessEqual(n2, n1)
1096
1097 def test_weak_keyed_len_race(self):
1098 self.check_len_race(weakref.WeakKeyDictionary, lambda k: (k, 1))
1099
1100 def test_weak_valued_len_race(self):
1101 self.check_len_race(weakref.WeakValueDictionary, lambda k: (1, k))
1102
Fred Drakeb0fefc52001-03-23 04:22:45 +00001103 def test_weak_values(self):
Fred Drake0e540c32001-05-02 05:44:22 +00001104 #
1105 # This exercises d.copy(), d.items(), d[], del d[], len(d).
1106 #
1107 dict, objects = self.make_weak_valued_dict()
Fred Drakeb0fefc52001-03-23 04:22:45 +00001108 for o in objects:
Guido van Rossum3cf5b1e2006-07-27 21:53:35 +00001109 self.assertEqual(weakref.getweakrefcount(o), 1)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001110 self.assertTrue(o is dict[o.arg],
Fred Drakeb0fefc52001-03-23 04:22:45 +00001111 "wrong object returned by weak dict!")
Barry Warsawecaab832008-09-04 01:42:51 +00001112 items1 = list(dict.items())
1113 items2 = list(dict.copy().items())
Fred Drakeb0fefc52001-03-23 04:22:45 +00001114 items1.sort()
1115 items2.sort()
Guido van Rossumc1f779c2007-07-03 08:25:58 +00001116 self.assertEqual(items1, items2,
Fred Drakeb0fefc52001-03-23 04:22:45 +00001117 "cloning of weak-valued dictionary did not work!")
1118 del items1, items2
Guido van Rossumc1f779c2007-07-03 08:25:58 +00001119 self.assertEqual(len(dict), self.COUNT)
Fred Drakeb0fefc52001-03-23 04:22:45 +00001120 del objects[0]
Guido van Rossumc1f779c2007-07-03 08:25:58 +00001121 self.assertEqual(len(dict), self.COUNT - 1,
Fred Drakeb0fefc52001-03-23 04:22:45 +00001122 "deleting object did not cause dictionary update")
1123 del objects, o
Guido van Rossumc1f779c2007-07-03 08:25:58 +00001124 self.assertEqual(len(dict), 0,
Fred Drakeb0fefc52001-03-23 04:22:45 +00001125 "deleting the values did not clear the dictionary")
Fred Drake4fd06e02001-08-03 04:11:27 +00001126 # regression on SF bug #447152:
1127 dict = weakref.WeakValueDictionary()
1128 self.assertRaises(KeyError, dict.__getitem__, 1)
1129 dict[2] = C()
1130 self.assertRaises(KeyError, dict.__getitem__, 2)
Fred Drakeb0fefc52001-03-23 04:22:45 +00001131
1132 def test_weak_keys(self):
Fred Drake0e540c32001-05-02 05:44:22 +00001133 #
1134 # This exercises d.copy(), d.items(), d[] = v, d[], del d[],
Guido van Rossume2b70bc2006-08-18 22:13:04 +00001135 # len(d), k in d.
Fred Drake0e540c32001-05-02 05:44:22 +00001136 #
1137 dict, objects = self.make_weak_keyed_dict()
Fred Drakeb0fefc52001-03-23 04:22:45 +00001138 for o in objects:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001139 self.assertTrue(weakref.getweakrefcount(o) == 1,
Fred Drakeb0fefc52001-03-23 04:22:45 +00001140 "wrong number of weak references to %r!" % o)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001141 self.assertTrue(o.arg is dict[o],
Fred Drakeb0fefc52001-03-23 04:22:45 +00001142 "wrong object returned by weak dict!")
1143 items1 = dict.items()
1144 items2 = dict.copy().items()
Guido van Rossume61fd5b2007-07-11 12:20:59 +00001145 self.assertEqual(set(items1), set(items2),
Fred Drakeb0fefc52001-03-23 04:22:45 +00001146 "cloning of weak-keyed dictionary did not work!")
1147 del items1, items2
Guido van Rossume61fd5b2007-07-11 12:20:59 +00001148 self.assertEqual(len(dict), self.COUNT)
Fred Drakeb0fefc52001-03-23 04:22:45 +00001149 del objects[0]
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001150 self.assertTrue(len(dict) == (self.COUNT - 1),
Fred Drakeb0fefc52001-03-23 04:22:45 +00001151 "deleting object did not cause dictionary update")
1152 del objects, o
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001153 self.assertTrue(len(dict) == 0,
Fred Drakeb0fefc52001-03-23 04:22:45 +00001154 "deleting the keys did not clear the dictionary")
Fred Drake752eda42001-11-06 16:38:34 +00001155 o = Object(42)
1156 dict[o] = "What is the meaning of the universe?"
Benjamin Peterson577473f2010-01-19 00:09:57 +00001157 self.assertIn(o, dict)
1158 self.assertNotIn(34, dict)
Martin v. Löwis5e163332001-02-27 18:36:56 +00001159
Fred Drake0e540c32001-05-02 05:44:22 +00001160 def test_weak_keyed_iters(self):
1161 dict, objects = self.make_weak_keyed_dict()
1162 self.check_iters(dict)
1163
Thomas Wouters477c8d52006-05-27 19:21:47 +00001164 # Test keyrefs()
1165 refs = dict.keyrefs()
1166 self.assertEqual(len(refs), len(objects))
1167 objects2 = list(objects)
1168 for wr in refs:
1169 ob = wr()
Benjamin Peterson577473f2010-01-19 00:09:57 +00001170 self.assertIn(ob, dict)
1171 self.assertIn(ob, dict)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001172 self.assertEqual(ob.arg, dict[ob])
1173 objects2.remove(ob)
1174 self.assertEqual(len(objects2), 0)
1175
1176 # Test iterkeyrefs()
1177 objects2 = list(objects)
Barry Warsawecaab832008-09-04 01:42:51 +00001178 self.assertEqual(len(list(dict.keyrefs())), len(objects))
1179 for wr in dict.keyrefs():
Thomas Wouters477c8d52006-05-27 19:21:47 +00001180 ob = wr()
Benjamin Peterson577473f2010-01-19 00:09:57 +00001181 self.assertIn(ob, dict)
1182 self.assertIn(ob, dict)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001183 self.assertEqual(ob.arg, dict[ob])
1184 objects2.remove(ob)
1185 self.assertEqual(len(objects2), 0)
1186
Fred Drake0e540c32001-05-02 05:44:22 +00001187 def test_weak_valued_iters(self):
1188 dict, objects = self.make_weak_valued_dict()
1189 self.check_iters(dict)
1190
Thomas Wouters477c8d52006-05-27 19:21:47 +00001191 # Test valuerefs()
1192 refs = dict.valuerefs()
1193 self.assertEqual(len(refs), len(objects))
1194 objects2 = list(objects)
1195 for wr in refs:
1196 ob = wr()
1197 self.assertEqual(ob, dict[ob.arg])
1198 self.assertEqual(ob.arg, dict[ob.arg].arg)
1199 objects2.remove(ob)
1200 self.assertEqual(len(objects2), 0)
1201
1202 # Test itervaluerefs()
1203 objects2 = list(objects)
1204 self.assertEqual(len(list(dict.itervaluerefs())), len(objects))
1205 for wr in dict.itervaluerefs():
1206 ob = wr()
1207 self.assertEqual(ob, dict[ob.arg])
1208 self.assertEqual(ob.arg, dict[ob.arg].arg)
1209 objects2.remove(ob)
1210 self.assertEqual(len(objects2), 0)
1211
Fred Drake0e540c32001-05-02 05:44:22 +00001212 def check_iters(self, dict):
1213 # item iterator:
Barry Warsawecaab832008-09-04 01:42:51 +00001214 items = list(dict.items())
Guido van Rossumcc2b0162007-02-11 06:12:03 +00001215 for item in dict.items():
Fred Drake0e540c32001-05-02 05:44:22 +00001216 items.remove(item)
Barry Warsawecaab832008-09-04 01:42:51 +00001217 self.assertFalse(items, "items() did not touch all items")
Fred Drake0e540c32001-05-02 05:44:22 +00001218
Fred Drakeaaa48ff2001-05-10 17:16:38 +00001219 # key iterator, via __iter__():
Guido van Rossum07f24362007-02-11 22:59:48 +00001220 keys = list(dict.keys())
Fred Drake0e540c32001-05-02 05:44:22 +00001221 for k in dict:
1222 keys.remove(k)
Barry Warsawecaab832008-09-04 01:42:51 +00001223 self.assertFalse(keys, "__iter__() did not touch all keys")
Fred Drakeaaa48ff2001-05-10 17:16:38 +00001224
1225 # key iterator, via iterkeys():
Guido van Rossum07f24362007-02-11 22:59:48 +00001226 keys = list(dict.keys())
Guido van Rossumcc2b0162007-02-11 06:12:03 +00001227 for k in dict.keys():
Fred Drakeaaa48ff2001-05-10 17:16:38 +00001228 keys.remove(k)
Barry Warsawecaab832008-09-04 01:42:51 +00001229 self.assertFalse(keys, "iterkeys() did not touch all keys")
Fred Drake0e540c32001-05-02 05:44:22 +00001230
1231 # value iterator:
Guido van Rossum07f24362007-02-11 22:59:48 +00001232 values = list(dict.values())
Guido van Rossumcc2b0162007-02-11 06:12:03 +00001233 for v in dict.values():
Fred Drake0e540c32001-05-02 05:44:22 +00001234 values.remove(v)
Barry Warsawecaab832008-09-04 01:42:51 +00001235 self.assertFalse(values,
Fred Drakef425b1e2003-07-14 21:37:17 +00001236 "itervalues() did not touch all values")
Fred Drake0e540c32001-05-02 05:44:22 +00001237
Antoine Pitrouc1baa602010-01-08 17:54:23 +00001238 def check_weak_destroy_while_iterating(self, dict, objects, iter_name):
1239 n = len(dict)
1240 it = iter(getattr(dict, iter_name)())
1241 next(it) # Trigger internal iteration
1242 # Destroy an object
1243 del objects[-1]
1244 gc.collect() # just in case
1245 # We have removed either the first consumed object, or another one
1246 self.assertIn(len(list(it)), [len(objects), len(objects) - 1])
1247 del it
1248 # The removal has been committed
1249 self.assertEqual(len(dict), n - 1)
1250
1251 def check_weak_destroy_and_mutate_while_iterating(self, dict, testcontext):
1252 # Check that we can explicitly mutate the weak dict without
1253 # interfering with delayed removal.
1254 # `testcontext` should create an iterator, destroy one of the
1255 # weakref'ed objects and then return a new key/value pair corresponding
1256 # to the destroyed object.
1257 with testcontext() as (k, v):
Ezio Melottib58e0bd2010-01-23 15:40:09 +00001258 self.assertNotIn(k, dict)
Antoine Pitrouc1baa602010-01-08 17:54:23 +00001259 with testcontext() as (k, v):
1260 self.assertRaises(KeyError, dict.__delitem__, k)
Ezio Melottib58e0bd2010-01-23 15:40:09 +00001261 self.assertNotIn(k, dict)
Antoine Pitrouc1baa602010-01-08 17:54:23 +00001262 with testcontext() as (k, v):
1263 self.assertRaises(KeyError, dict.pop, k)
Ezio Melottib58e0bd2010-01-23 15:40:09 +00001264 self.assertNotIn(k, dict)
Antoine Pitrouc1baa602010-01-08 17:54:23 +00001265 with testcontext() as (k, v):
1266 dict[k] = v
1267 self.assertEqual(dict[k], v)
1268 ddict = copy.copy(dict)
1269 with testcontext() as (k, v):
1270 dict.update(ddict)
1271 self.assertEqual(dict, ddict)
1272 with testcontext() as (k, v):
1273 dict.clear()
1274 self.assertEqual(len(dict), 0)
1275
1276 def test_weak_keys_destroy_while_iterating(self):
1277 # Issue #7105: iterators shouldn't crash when a key is implicitly removed
1278 dict, objects = self.make_weak_keyed_dict()
1279 self.check_weak_destroy_while_iterating(dict, objects, 'keys')
1280 self.check_weak_destroy_while_iterating(dict, objects, 'items')
1281 self.check_weak_destroy_while_iterating(dict, objects, 'values')
1282 self.check_weak_destroy_while_iterating(dict, objects, 'keyrefs')
1283 dict, objects = self.make_weak_keyed_dict()
1284 @contextlib.contextmanager
1285 def testcontext():
1286 try:
1287 it = iter(dict.items())
1288 next(it)
1289 # Schedule a key/value for removal and recreate it
1290 v = objects.pop().arg
1291 gc.collect() # just in case
1292 yield Object(v), v
1293 finally:
1294 it = None # should commit all removals
1295 self.check_weak_destroy_and_mutate_while_iterating(dict, testcontext)
1296
1297 def test_weak_values_destroy_while_iterating(self):
1298 # Issue #7105: iterators shouldn't crash when a key is implicitly removed
1299 dict, objects = self.make_weak_valued_dict()
1300 self.check_weak_destroy_while_iterating(dict, objects, 'keys')
1301 self.check_weak_destroy_while_iterating(dict, objects, 'items')
1302 self.check_weak_destroy_while_iterating(dict, objects, 'values')
1303 self.check_weak_destroy_while_iterating(dict, objects, 'itervaluerefs')
1304 self.check_weak_destroy_while_iterating(dict, objects, 'valuerefs')
1305 dict, objects = self.make_weak_valued_dict()
1306 @contextlib.contextmanager
1307 def testcontext():
1308 try:
1309 it = iter(dict.items())
1310 next(it)
1311 # Schedule a key/value for removal and recreate it
1312 k = objects.pop().arg
1313 gc.collect() # just in case
1314 yield k, Object(k)
1315 finally:
1316 it = None # should commit all removals
1317 self.check_weak_destroy_and_mutate_while_iterating(dict, testcontext)
1318
Guido van Rossum009afb72002-06-10 20:00:52 +00001319 def test_make_weak_keyed_dict_from_dict(self):
1320 o = Object(3)
1321 dict = weakref.WeakKeyDictionary({o:364})
Guido van Rossume61fd5b2007-07-11 12:20:59 +00001322 self.assertEqual(dict[o], 364)
Guido van Rossum009afb72002-06-10 20:00:52 +00001323
1324 def test_make_weak_keyed_dict_from_weak_keyed_dict(self):
1325 o = Object(3)
1326 dict = weakref.WeakKeyDictionary({o:364})
1327 dict2 = weakref.WeakKeyDictionary(dict)
Guido van Rossume61fd5b2007-07-11 12:20:59 +00001328 self.assertEqual(dict[o], 364)
Guido van Rossum009afb72002-06-10 20:00:52 +00001329
Fred Drake0e540c32001-05-02 05:44:22 +00001330 def make_weak_keyed_dict(self):
1331 dict = weakref.WeakKeyDictionary()
Guido van Rossumc1f779c2007-07-03 08:25:58 +00001332 objects = list(map(Object, range(self.COUNT)))
Fred Drake0e540c32001-05-02 05:44:22 +00001333 for o in objects:
1334 dict[o] = o.arg
1335 return dict, objects
1336
Antoine Pitrouc06de472009-05-30 21:04:26 +00001337 def test_make_weak_valued_dict_from_dict(self):
1338 o = Object(3)
1339 dict = weakref.WeakValueDictionary({364:o})
1340 self.assertEqual(dict[364], o)
1341
1342 def test_make_weak_valued_dict_from_weak_valued_dict(self):
1343 o = Object(3)
1344 dict = weakref.WeakValueDictionary({364:o})
1345 dict2 = weakref.WeakValueDictionary(dict)
1346 self.assertEqual(dict[364], o)
1347
Fred Drake0e540c32001-05-02 05:44:22 +00001348 def make_weak_valued_dict(self):
1349 dict = weakref.WeakValueDictionary()
Guido van Rossumc1f779c2007-07-03 08:25:58 +00001350 objects = list(map(Object, range(self.COUNT)))
Fred Drake0e540c32001-05-02 05:44:22 +00001351 for o in objects:
1352 dict[o.arg] = o
1353 return dict, objects
1354
Fred Drakeaaa48ff2001-05-10 17:16:38 +00001355 def check_popitem(self, klass, key1, value1, key2, value2):
1356 weakdict = klass()
1357 weakdict[key1] = value1
1358 weakdict[key2] = value2
Guido van Rossume61fd5b2007-07-11 12:20:59 +00001359 self.assertEqual(len(weakdict), 2)
Fred Drakeaaa48ff2001-05-10 17:16:38 +00001360 k, v = weakdict.popitem()
Guido van Rossume61fd5b2007-07-11 12:20:59 +00001361 self.assertEqual(len(weakdict), 1)
Fred Drakeaaa48ff2001-05-10 17:16:38 +00001362 if k is key1:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001363 self.assertTrue(v is value1)
Fred Drakeaaa48ff2001-05-10 17:16:38 +00001364 else:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001365 self.assertTrue(v is value2)
Fred Drakeaaa48ff2001-05-10 17:16:38 +00001366 k, v = weakdict.popitem()
Guido van Rossume61fd5b2007-07-11 12:20:59 +00001367 self.assertEqual(len(weakdict), 0)
Fred Drakeaaa48ff2001-05-10 17:16:38 +00001368 if k is key1:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001369 self.assertTrue(v is value1)
Fred Drakeaaa48ff2001-05-10 17:16:38 +00001370 else:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001371 self.assertTrue(v is value2)
Fred Drakeaaa48ff2001-05-10 17:16:38 +00001372
1373 def test_weak_valued_dict_popitem(self):
1374 self.check_popitem(weakref.WeakValueDictionary,
1375 "key1", C(), "key2", C())
1376
1377 def test_weak_keyed_dict_popitem(self):
1378 self.check_popitem(weakref.WeakKeyDictionary,
1379 C(), "value 1", C(), "value 2")
1380
1381 def check_setdefault(self, klass, key, value1, value2):
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001382 self.assertTrue(value1 is not value2,
Fred Drakeaaa48ff2001-05-10 17:16:38 +00001383 "invalid test"
1384 " -- value parameters must be distinct objects")
1385 weakdict = klass()
1386 o = weakdict.setdefault(key, value1)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001387 self.assertTrue(o is value1)
Benjamin Peterson577473f2010-01-19 00:09:57 +00001388 self.assertIn(key, weakdict)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001389 self.assertTrue(weakdict.get(key) is value1)
1390 self.assertTrue(weakdict[key] is value1)
Fred Drakeaaa48ff2001-05-10 17:16:38 +00001391
1392 o = weakdict.setdefault(key, value2)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001393 self.assertTrue(o is value1)
Benjamin Peterson577473f2010-01-19 00:09:57 +00001394 self.assertIn(key, weakdict)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001395 self.assertTrue(weakdict.get(key) is value1)
1396 self.assertTrue(weakdict[key] is value1)
Fred Drakeaaa48ff2001-05-10 17:16:38 +00001397
1398 def test_weak_valued_dict_setdefault(self):
1399 self.check_setdefault(weakref.WeakValueDictionary,
1400 "key", C(), C())
1401
1402 def test_weak_keyed_dict_setdefault(self):
1403 self.check_setdefault(weakref.WeakKeyDictionary,
1404 C(), "value 1", "value 2")
1405
Fred Drakea0a4ab12001-04-16 17:37:27 +00001406 def check_update(self, klass, dict):
Fred Drake0e540c32001-05-02 05:44:22 +00001407 #
Guido van Rossume2b70bc2006-08-18 22:13:04 +00001408 # This exercises d.update(), len(d), d.keys(), k in d,
Fred Drake0e540c32001-05-02 05:44:22 +00001409 # d.get(), d[].
1410 #
Fred Drakea0a4ab12001-04-16 17:37:27 +00001411 weakdict = klass()
1412 weakdict.update(dict)
Guido van Rossume61fd5b2007-07-11 12:20:59 +00001413 self.assertEqual(len(weakdict), len(dict))
Fred Drakea0a4ab12001-04-16 17:37:27 +00001414 for k in weakdict.keys():
Ezio Melottib58e0bd2010-01-23 15:40:09 +00001415 self.assertIn(k, dict, "mysterious new key appeared in weak dict")
Fred Drakea0a4ab12001-04-16 17:37:27 +00001416 v = dict.get(k)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001417 self.assertTrue(v is weakdict[k])
1418 self.assertTrue(v is weakdict.get(k))
Fred Drakea0a4ab12001-04-16 17:37:27 +00001419 for k in dict.keys():
Ezio Melottib58e0bd2010-01-23 15:40:09 +00001420 self.assertIn(k, weakdict, "original key disappeared in weak dict")
Fred Drakea0a4ab12001-04-16 17:37:27 +00001421 v = dict[k]
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001422 self.assertTrue(v is weakdict[k])
1423 self.assertTrue(v is weakdict.get(k))
Fred Drakea0a4ab12001-04-16 17:37:27 +00001424
1425 def test_weak_valued_dict_update(self):
1426 self.check_update(weakref.WeakValueDictionary,
1427 {1: C(), 'a': C(), C(): C()})
1428
1429 def test_weak_keyed_dict_update(self):
1430 self.check_update(weakref.WeakKeyDictionary,
1431 {C(): 1, C(): 2, C(): 3})
1432
Fred Drakeccc75622001-09-06 14:52:39 +00001433 def test_weak_keyed_delitem(self):
1434 d = weakref.WeakKeyDictionary()
1435 o1 = Object('1')
1436 o2 = Object('2')
1437 d[o1] = 'something'
1438 d[o2] = 'something'
Guido van Rossume61fd5b2007-07-11 12:20:59 +00001439 self.assertEqual(len(d), 2)
Fred Drakeccc75622001-09-06 14:52:39 +00001440 del d[o1]
Guido van Rossume61fd5b2007-07-11 12:20:59 +00001441 self.assertEqual(len(d), 1)
Barry Warsawecaab832008-09-04 01:42:51 +00001442 self.assertEqual(list(d.keys()), [o2])
Fred Drakeccc75622001-09-06 14:52:39 +00001443
1444 def test_weak_valued_delitem(self):
1445 d = weakref.WeakValueDictionary()
1446 o1 = Object('1')
1447 o2 = Object('2')
1448 d['something'] = o1
1449 d['something else'] = o2
Guido van Rossume61fd5b2007-07-11 12:20:59 +00001450 self.assertEqual(len(d), 2)
Fred Drakeccc75622001-09-06 14:52:39 +00001451 del d['something']
Guido van Rossume61fd5b2007-07-11 12:20:59 +00001452 self.assertEqual(len(d), 1)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001453 self.assertTrue(list(d.items()) == [('something else', o2)])
Fred Drakeccc75622001-09-06 14:52:39 +00001454
Tim Peters886128f2003-05-25 01:45:11 +00001455 def test_weak_keyed_bad_delitem(self):
1456 d = weakref.WeakKeyDictionary()
1457 o = Object('1')
1458 # An attempt to delete an object that isn't there should raise
Tim Peters50d8b8b2003-05-25 17:44:31 +00001459 # KeyError. It didn't before 2.3.
Tim Peters886128f2003-05-25 01:45:11 +00001460 self.assertRaises(KeyError, d.__delitem__, o)
Tim Peters50d8b8b2003-05-25 17:44:31 +00001461 self.assertRaises(KeyError, d.__getitem__, o)
1462
1463 # If a key isn't of a weakly referencable type, __getitem__ and
1464 # __setitem__ raise TypeError. __delitem__ should too.
1465 self.assertRaises(TypeError, d.__delitem__, 13)
1466 self.assertRaises(TypeError, d.__getitem__, 13)
1467 self.assertRaises(TypeError, d.__setitem__, 13, 13)
Tim Peters886128f2003-05-25 01:45:11 +00001468
1469 def test_weak_keyed_cascading_deletes(self):
1470 # SF bug 742860. For some reason, before 2.3 __delitem__ iterated
1471 # over the keys via self.data.iterkeys(). If things vanished from
1472 # the dict during this (or got added), that caused a RuntimeError.
1473
1474 d = weakref.WeakKeyDictionary()
1475 mutate = False
1476
1477 class C(object):
1478 def __init__(self, i):
1479 self.value = i
1480 def __hash__(self):
1481 return hash(self.value)
1482 def __eq__(self, other):
1483 if mutate:
1484 # Side effect that mutates the dict, by removing the
1485 # last strong reference to a key.
1486 del objs[-1]
1487 return self.value == other.value
1488
1489 objs = [C(i) for i in range(4)]
1490 for o in objs:
1491 d[o] = o.value
1492 del o # now the only strong references to keys are in objs
1493 # Find the order in which iterkeys sees the keys.
Barry Warsawecaab832008-09-04 01:42:51 +00001494 objs = list(d.keys())
Tim Peters886128f2003-05-25 01:45:11 +00001495 # Reverse it, so that the iteration implementation of __delitem__
1496 # has to keep looping to find the first object we delete.
1497 objs.reverse()
Tim Peters50d8b8b2003-05-25 17:44:31 +00001498
Tim Peters886128f2003-05-25 01:45:11 +00001499 # Turn on mutation in C.__eq__. The first time thru the loop,
1500 # under the iterkeys() business the first comparison will delete
1501 # the last item iterkeys() would see, and that causes a
1502 # RuntimeError: dictionary changed size during iteration
1503 # when the iterkeys() loop goes around to try comparing the next
Tim Peters50d8b8b2003-05-25 17:44:31 +00001504 # key. After this was fixed, it just deletes the last object *our*
Tim Peters886128f2003-05-25 01:45:11 +00001505 # "for o in obj" loop would have gotten to.
1506 mutate = True
1507 count = 0
1508 for o in objs:
1509 count += 1
1510 del d[o]
1511 self.assertEqual(len(d), 0)
1512 self.assertEqual(count, 2)
1513
Walter Dörwald0a6d0ff2004-05-31 16:29:04 +00001514from test import mapping_tests
Raymond Hettinger2c2d3222003-03-09 07:05:43 +00001515
Walter Dörwald0a6d0ff2004-05-31 16:29:04 +00001516class WeakValueDictionaryTestCase(mapping_tests.BasicTestMappingProtocol):
Fred Drakef425b1e2003-07-14 21:37:17 +00001517 """Check that WeakValueDictionary conforms to the mapping protocol"""
Raymond Hettinger2c2d3222003-03-09 07:05:43 +00001518 __ref = {"key1":Object(1), "key2":Object(2), "key3":Object(3)}
Walter Dörwald118f9312004-06-02 18:42:25 +00001519 type2test = weakref.WeakValueDictionary
Raymond Hettinger2c2d3222003-03-09 07:05:43 +00001520 def _reference(self):
1521 return self.__ref.copy()
1522
Walter Dörwald0a6d0ff2004-05-31 16:29:04 +00001523class WeakKeyDictionaryTestCase(mapping_tests.BasicTestMappingProtocol):
Fred Drakef425b1e2003-07-14 21:37:17 +00001524 """Check that WeakKeyDictionary conforms to the mapping protocol"""
Raymond Hettinger2c2d3222003-03-09 07:05:43 +00001525 __ref = {Object("key1"):1, Object("key2"):2, Object("key3"):3}
Walter Dörwald118f9312004-06-02 18:42:25 +00001526 type2test = weakref.WeakKeyDictionary
Raymond Hettinger2c2d3222003-03-09 07:05:43 +00001527 def _reference(self):
1528 return self.__ref.copy()
Martin v. Löwis5e163332001-02-27 18:36:56 +00001529
Georg Brandlb533e262008-05-25 18:19:30 +00001530libreftest = """ Doctest for examples in the library reference: weakref.rst
Georg Brandl9a65d582005-07-02 19:07:30 +00001531
1532>>> import weakref
1533>>> class Dict(dict):
1534... pass
1535...
1536>>> obj = Dict(red=1, green=2, blue=3) # this object is weak referencable
1537>>> r = weakref.ref(obj)
Guido van Rossum7131f842007-02-09 20:13:25 +00001538>>> print(r() is obj)
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001539True
Georg Brandl9a65d582005-07-02 19:07:30 +00001540
1541>>> import weakref
1542>>> class Object:
1543... pass
1544...
1545>>> o = Object()
1546>>> r = weakref.ref(o)
1547>>> o2 = r()
1548>>> o is o2
1549True
1550>>> del o, o2
Guido van Rossum7131f842007-02-09 20:13:25 +00001551>>> print(r())
Georg Brandl9a65d582005-07-02 19:07:30 +00001552None
1553
1554>>> import weakref
1555>>> class ExtendedRef(weakref.ref):
1556... def __init__(self, ob, callback=None, **annotations):
Guido van Rossumcd16bf62007-06-13 18:07:49 +00001557... super().__init__(ob, callback)
Georg Brandl9a65d582005-07-02 19:07:30 +00001558... self.__counter = 0
Guido van Rossumcc2b0162007-02-11 06:12:03 +00001559... for k, v in annotations.items():
Georg Brandl9a65d582005-07-02 19:07:30 +00001560... setattr(self, k, v)
1561... def __call__(self):
1562... '''Return a pair containing the referent and the number of
1563... times the reference has been called.
1564... '''
Guido van Rossumcd16bf62007-06-13 18:07:49 +00001565... ob = super().__call__()
Georg Brandl9a65d582005-07-02 19:07:30 +00001566... if ob is not None:
1567... self.__counter += 1
1568... ob = (ob, self.__counter)
1569... return ob
Guido van Rossumd8faa362007-04-27 19:54:29 +00001570...
Georg Brandl9a65d582005-07-02 19:07:30 +00001571>>> class A: # not in docs from here, just testing the ExtendedRef
1572... pass
1573...
1574>>> a = A()
1575>>> r = ExtendedRef(a, foo=1, bar="baz")
1576>>> r.foo
15771
1578>>> r.bar
1579'baz'
1580>>> r()[1]
15811
1582>>> r()[1]
15832
1584>>> r()[0] is a
1585True
1586
1587
1588>>> import weakref
1589>>> _id2obj_dict = weakref.WeakValueDictionary()
1590>>> def remember(obj):
1591... oid = id(obj)
1592... _id2obj_dict[oid] = obj
1593... return oid
1594...
1595>>> def id2obj(oid):
1596... return _id2obj_dict[oid]
1597...
1598>>> a = A() # from here, just testing
1599>>> a_id = remember(a)
1600>>> id2obj(a_id) is a
1601True
1602>>> del a
1603>>> try:
1604... id2obj(a_id)
1605... except KeyError:
Guido van Rossum7131f842007-02-09 20:13:25 +00001606... print('OK')
Georg Brandl9a65d582005-07-02 19:07:30 +00001607... else:
Guido van Rossum7131f842007-02-09 20:13:25 +00001608... print('WeakValueDictionary error')
Georg Brandl9a65d582005-07-02 19:07:30 +00001609OK
1610
1611"""
1612
1613__test__ = {'libreftest' : libreftest}
1614
Fred Drake2e2be372001-09-20 21:33:42 +00001615def test_main():
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001616 support.run_unittest(
Walter Dörwald21d3a322003-05-01 17:45:56 +00001617 ReferencesTestCase,
Antoine Pitrouc3afba12012-11-17 18:57:38 +01001618 WeakMethodTestCase,
Walter Dörwald21d3a322003-05-01 17:45:56 +00001619 MappingTestCase,
1620 WeakValueDictionaryTestCase,
Fred Drakef425b1e2003-07-14 21:37:17 +00001621 WeakKeyDictionaryTestCase,
Amaury Forgeot d'Arcc856c7a2008-06-16 19:50:09 +00001622 SubclassableWeakrefTestCase,
Fred Drakef425b1e2003-07-14 21:37:17 +00001623 )
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001624 support.run_doctest(sys.modules[__name__])
Fred Drake2e2be372001-09-20 21:33:42 +00001625
1626
1627if __name__ == "__main__":
1628 test_main()