1import gc 2import sys 3import unittest 4import collections 5import weakref 6import operator 7import contextlib 8import copy 9import threading 10import time 11import random 12 13from test import support 14from test.support import script_helper 15 16# Used in ReferencesTestCase.test_ref_created_during_del() . 17ref_from_del = None 18 19# Used by FinalizeTestCase as a global that may be replaced by None 20# when the interpreter shuts down. 21_global_var = 'foobar' 22 23class C: 24 def method(self): 25 pass 26 27 28class Callable: 29 bar = None 30 31 def __call__(self, x): 32 self.bar = x 33 34 35def create_function(): 36 def f(): pass 37 return f 38 39def create_bound_method(): 40 return C().method 41 42 43class Object: 44 def __init__(self, arg): 45 self.arg = arg 46 def __repr__(self): 47 return "<Object %r>" % self.arg 48 def __eq__(self, other): 49 if isinstance(other, Object): 50 return self.arg == other.arg 51 return NotImplemented 52 def __lt__(self, other): 53 if isinstance(other, Object): 54 return self.arg < other.arg 55 return NotImplemented 56 def __hash__(self): 57 return hash(self.arg) 58 def some_method(self): 59 return 4 60 def other_method(self): 61 return 5 62 63 64class RefCycle: 65 def __init__(self): 66 self.cycle = self 67 68 69class TestBase(unittest.TestCase): 70 71 def setUp(self): 72 self.cbcalled = 0 73 74 def callback(self, ref): 75 self.cbcalled += 1 76 77 78@contextlib.contextmanager 79def collect_in_thread(period=0.0001): 80 """ 81 Ensure GC collections happen in a different thread, at a high frequency. 82 """ 83 please_stop = False 84 85 def collect(): 86 while not please_stop: 87 time.sleep(period) 88 gc.collect() 89 90 with support.disable_gc(): 91 t = threading.Thread(target=collect) 92 t.start() 93 try: 94 yield 95 finally: 96 please_stop = True 97 t.join() 98 99 100class ReferencesTestCase(TestBase): 101 102 def test_basic_ref(self): 103 self.check_basic_ref(C) 104 self.check_basic_ref(create_function) 105 self.check_basic_ref(create_bound_method) 106 107 # Just make sure the tp_repr handler doesn't raise an exception. 108 # Live reference: 109 o = C() 110 wr = weakref.ref(o) 111 repr(wr) 112 # Dead reference: 113 del o 114 repr(wr) 115 116 def test_basic_callback(self): 117 self.check_basic_callback(C) 118 self.check_basic_callback(create_function) 119 self.check_basic_callback(create_bound_method) 120 121 @support.cpython_only 122 def test_cfunction(self): 123 import _testcapi 124 create_cfunction = _testcapi.create_cfunction 125 f = create_cfunction() 126 wr = weakref.ref(f) 127 self.assertIs(wr(), f) 128 del f 129 self.assertIsNone(wr()) 130 self.check_basic_ref(create_cfunction) 131 self.check_basic_callback(create_cfunction) 132 133 def test_multiple_callbacks(self): 134 o = C() 135 ref1 = weakref.ref(o, self.callback) 136 ref2 = weakref.ref(o, self.callback) 137 del o 138 self.assertIsNone(ref1(), "expected reference to be invalidated") 139 self.assertIsNone(ref2(), "expected reference to be invalidated") 140 self.assertEqual(self.cbcalled, 2, 141 "callback not called the right number of times") 142 143 def test_multiple_selfref_callbacks(self): 144 # Make sure all references are invalidated before callbacks are called 145 # 146 # What's important here is that we're using the first 147 # reference in the callback invoked on the second reference 148 # (the most recently created ref is cleaned up first). This 149 # tests that all references to the object are invalidated 150 # before any of the callbacks are invoked, so that we only 151 # have one invocation of _weakref.c:cleanup_helper() active 152 # for a particular object at a time. 153 # 154 def callback(object, self=self): 155 self.ref() 156 c = C() 157 self.ref = weakref.ref(c, callback) 158 ref1 = weakref.ref(c, callback) 159 del c 160 161 def test_constructor_kwargs(self): 162 c = C() 163 self.assertRaises(TypeError, weakref.ref, c, callback=None) 164 165 def test_proxy_ref(self): 166 o = C() 167 o.bar = 1 168 ref1 = weakref.proxy(o, self.callback) 169 ref2 = weakref.proxy(o, self.callback) 170 del o 171 172 def check(proxy): 173 proxy.bar 174 175 self.assertRaises(ReferenceError, check, ref1) 176 self.assertRaises(ReferenceError, check, ref2) 177 self.assertRaises(ReferenceError, bool, weakref.proxy(C())) 178 self.assertEqual(self.cbcalled, 2) 179 180 def check_basic_ref(self, factory): 181 o = factory() 182 ref = weakref.ref(o) 183 self.assertIsNotNone(ref(), 184 "weak reference to live object should be live") 185 o2 = ref() 186 self.assertIs(o, o2, 187 "<ref>() should return original object if live") 188 189 def check_basic_callback(self, factory): 190 self.cbcalled = 0 191 o = factory() 192 ref = weakref.ref(o, self.callback) 193 del o 194 self.assertEqual(self.cbcalled, 1, 195 "callback did not properly set 'cbcalled'") 196 self.assertIsNone(ref(), 197 "ref2 should be dead after deleting object reference") 198 199 def test_ref_reuse(self): 200 o = C() 201 ref1 = weakref.ref(o) 202 # create a proxy to make sure that there's an intervening creation 203 # between these two; it should make no difference 204 proxy = weakref.proxy(o) 205 ref2 = weakref.ref(o) 206 self.assertIs(ref1, ref2, 207 "reference object w/out callback should be re-used") 208 209 o = C() 210 proxy = weakref.proxy(o) 211 ref1 = weakref.ref(o) 212 ref2 = weakref.ref(o) 213 self.assertIs(ref1, ref2, 214 "reference object w/out callback should be re-used") 215 self.assertEqual(weakref.getweakrefcount(o), 2, 216 "wrong weak ref count for object") 217 del proxy 218 self.assertEqual(weakref.getweakrefcount(o), 1, 219 "wrong weak ref count for object after deleting proxy") 220 221 def test_proxy_reuse(self): 222 o = C() 223 proxy1 = weakref.proxy(o) 224 ref = weakref.ref(o) 225 proxy2 = weakref.proxy(o) 226 self.assertIs(proxy1, proxy2, 227 "proxy object w/out callback should have been re-used") 228 229 def test_basic_proxy(self): 230 o = C() 231 self.check_proxy(o, weakref.proxy(o)) 232 233 L = collections.UserList() 234 p = weakref.proxy(L) 235 self.assertFalse(p, "proxy for empty UserList should be false") 236 p.append(12) 237 self.assertEqual(len(L), 1) 238 self.assertTrue(p, "proxy for non-empty UserList should be true") 239 p[:] = [2, 3] 240 self.assertEqual(len(L), 2) 241 self.assertEqual(len(p), 2) 242 self.assertIn(3, p, "proxy didn't support __contains__() properly") 243 p[1] = 5 244 self.assertEqual(L[1], 5) 245 self.assertEqual(p[1], 5) 246 L2 = collections.UserList(L) 247 p2 = weakref.proxy(L2) 248 self.assertEqual(p, p2) 249 ## self.assertEqual(repr(L2), repr(p2)) 250 L3 = collections.UserList(range(10)) 251 p3 = weakref.proxy(L3) 252 self.assertEqual(L3[:], p3[:]) 253 self.assertEqual(L3[5:], p3[5:]) 254 self.assertEqual(L3[:5], p3[:5]) 255 self.assertEqual(L3[2:5], p3[2:5]) 256 257 def test_proxy_unicode(self): 258 # See bug 5037 259 class C(object): 260 def __str__(self): 261 return "string" 262 def __bytes__(self): 263 return b"bytes" 264 instance = C() 265 self.assertIn("__bytes__", dir(weakref.proxy(instance))) 266 self.assertEqual(bytes(weakref.proxy(instance)), b"bytes") 267 268 def test_proxy_index(self): 269 class C: 270 def __index__(self): 271 return 10 272 o = C() 273 p = weakref.proxy(o) 274 self.assertEqual(operator.index(p), 10) 275 276 def test_proxy_div(self): 277 class C: 278 def __floordiv__(self, other): 279 return 42 280 def __ifloordiv__(self, other): 281 return 21 282 o = C() 283 p = weakref.proxy(o) 284 self.assertEqual(p // 5, 42) 285 p //= 5 286 self.assertEqual(p, 21) 287 288 def test_proxy_matmul(self): 289 class C: 290 def __matmul__(self, other): 291 return 1729 292 def __rmatmul__(self, other): 293 return -163 294 def __imatmul__(self, other): 295 return 561 296 o = C() 297 p = weakref.proxy(o) 298 self.assertEqual(p @ 5, 1729) 299 self.assertEqual(5 @ p, -163) 300 p @= 5 301 self.assertEqual(p, 561) 302 303 # The PyWeakref_* C API is documented as allowing either NULL or 304 # None as the value for the callback, where either means "no 305 # callback". The "no callback" ref and proxy objects are supposed 306 # to be shared so long as they exist by all callers so long as 307 # they are active. In Python 2.3.3 and earlier, this guarantee 308 # was not honored, and was broken in different ways for 309 # PyWeakref_NewRef() and PyWeakref_NewProxy(). (Two tests.) 310 311 def test_shared_ref_without_callback(self): 312 self.check_shared_without_callback(weakref.ref) 313 314 def test_shared_proxy_without_callback(self): 315 self.check_shared_without_callback(weakref.proxy) 316 317 def check_shared_without_callback(self, makeref): 318 o = Object(1) 319 p1 = makeref(o, None) 320 p2 = makeref(o, None) 321 self.assertIs(p1, p2, "both callbacks were None in the C API") 322 del p1, p2 323 p1 = makeref(o) 324 p2 = makeref(o, None) 325 self.assertIs(p1, p2, "callbacks were NULL, None in the C API") 326 del p1, p2 327 p1 = makeref(o) 328 p2 = makeref(o) 329 self.assertIs(p1, p2, "both callbacks were NULL in the C API") 330 del p1, p2 331 p1 = makeref(o, None) 332 p2 = makeref(o) 333 self.assertIs(p1, p2, "callbacks were None, NULL in the C API") 334 335 def test_callable_proxy(self): 336 o = Callable() 337 ref1 = weakref.proxy(o) 338 339 self.check_proxy(o, ref1) 340 341 self.assertIs(type(ref1), weakref.CallableProxyType, 342 "proxy is not of callable type") 343 ref1('twinkies!') 344 self.assertEqual(o.bar, 'twinkies!', 345 "call through proxy not passed through to original") 346 ref1(x='Splat.') 347 self.assertEqual(o.bar, 'Splat.', 348 "call through proxy not passed through to original") 349 350 # expect due to too few args 351 self.assertRaises(TypeError, ref1) 352 353 # expect due to too many args 354 self.assertRaises(TypeError, ref1, 1, 2, 3) 355 356 def check_proxy(self, o, proxy): 357 o.foo = 1 358 self.assertEqual(proxy.foo, 1, 359 "proxy does not reflect attribute addition") 360 o.foo = 2 361 self.assertEqual(proxy.foo, 2, 362 "proxy does not reflect attribute modification") 363 del o.foo 364 self.assertFalse(hasattr(proxy, 'foo'), 365 "proxy does not reflect attribute removal") 366 367 proxy.foo = 1 368 self.assertEqual(o.foo, 1, 369 "object does not reflect attribute addition via proxy") 370 proxy.foo = 2 371 self.assertEqual(o.foo, 2, 372 "object does not reflect attribute modification via proxy") 373 del proxy.foo 374 self.assertFalse(hasattr(o, 'foo'), 375 "object does not reflect attribute removal via proxy") 376 377 def test_proxy_deletion(self): 378 # Test clearing of SF bug #762891 379 class Foo: 380 result = None 381 def __delitem__(self, accessor): 382 self.result = accessor 383 g = Foo() 384 f = weakref.proxy(g) 385 del f[0] 386 self.assertEqual(f.result, 0) 387 388 def test_proxy_bool(self): 389 # Test clearing of SF bug #1170766 390 class List(list): pass 391 lyst = List() 392 self.assertEqual(bool(weakref.proxy(lyst)), bool(lyst)) 393 394 def test_proxy_iter(self): 395 # Test fails with a debug build of the interpreter 396 # (see bpo-38395). 397 398 obj = None 399 400 class MyObj: 401 def __iter__(self): 402 nonlocal obj 403 del obj 404 return NotImplemented 405 406 obj = MyObj() 407 p = weakref.proxy(obj) 408 with self.assertRaises(TypeError): 409 # "blech" in p calls MyObj.__iter__ through the proxy, 410 # without keeping a reference to the real object, so it 411 # can be killed in the middle of the call 412 "blech" in p 413 414 def test_getweakrefcount(self): 415 o = C() 416 ref1 = weakref.ref(o) 417 ref2 = weakref.ref(o, self.callback) 418 self.assertEqual(weakref.getweakrefcount(o), 2, 419 "got wrong number of weak reference objects") 420 421 proxy1 = weakref.proxy(o) 422 proxy2 = weakref.proxy(o, self.callback) 423 self.assertEqual(weakref.getweakrefcount(o), 4, 424 "got wrong number of weak reference objects") 425 426 del ref1, ref2, proxy1, proxy2 427 self.assertEqual(weakref.getweakrefcount(o), 0, 428 "weak reference objects not unlinked from" 429 " referent when discarded.") 430 431 # assumes ints do not support weakrefs 432 self.assertEqual(weakref.getweakrefcount(1), 0, 433 "got wrong number of weak reference objects for int") 434 435 def test_getweakrefs(self): 436 o = C() 437 ref1 = weakref.ref(o, self.callback) 438 ref2 = weakref.ref(o, self.callback) 439 del ref1 440 self.assertEqual(weakref.getweakrefs(o), [ref2], 441 "list of refs does not match") 442 443 o = C() 444 ref1 = weakref.ref(o, self.callback) 445 ref2 = weakref.ref(o, self.callback) 446 del ref2 447 self.assertEqual(weakref.getweakrefs(o), [ref1], 448 "list of refs does not match") 449 450 del ref1 451 self.assertEqual(weakref.getweakrefs(o), [], 452 "list of refs not cleared") 453 454 # assumes ints do not support weakrefs 455 self.assertEqual(weakref.getweakrefs(1), [], 456 "list of refs does not match for int") 457 458 def test_newstyle_number_ops(self): 459 class F(float): 460 pass 461 f = F(2.0) 462 p = weakref.proxy(f) 463 self.assertEqual(p + 1.0, 3.0) 464 self.assertEqual(1.0 + p, 3.0) # this used to SEGV 465 466 def test_callbacks_protected(self): 467 # Callbacks protected from already-set exceptions? 468 # Regression test for SF bug #478534. 469 class BogusError(Exception): 470 pass 471 data = {} 472 def remove(k): 473 del data[k] 474 def encapsulate(): 475 f = lambda : () 476 data[weakref.ref(f, remove)] = None 477 raise BogusError 478 try: 479 encapsulate() 480 except BogusError: 481 pass 482 else: 483 self.fail("exception not properly restored") 484 try: 485 encapsulate() 486 except BogusError: 487 pass 488 else: 489 self.fail("exception not properly restored") 490 491 def test_sf_bug_840829(self): 492 # "weakref callbacks and gc corrupt memory" 493 # subtype_dealloc erroneously exposed a new-style instance 494 # already in the process of getting deallocated to gc, 495 # causing double-deallocation if the instance had a weakref 496 # callback that triggered gc. 497 # If the bug exists, there probably won't be an obvious symptom 498 # in a release build. In a debug build, a segfault will occur 499 # when the second attempt to remove the instance from the "list 500 # of all objects" occurs. 501 502 import gc 503 504 class C(object): 505 pass 506 507 c = C() 508 wr = weakref.ref(c, lambda ignore: gc.collect()) 509 del c 510 511 # There endeth the first part. It gets worse. 512 del wr 513 514 c1 = C() 515 c1.i = C() 516 wr = weakref.ref(c1.i, lambda ignore: gc.collect()) 517 518 c2 = C() 519 c2.c1 = c1 520 del c1 # still alive because c2 points to it 521 522 # Now when subtype_dealloc gets called on c2, it's not enough just 523 # that c2 is immune from gc while the weakref callbacks associated 524 # with c2 execute (there are none in this 2nd half of the test, btw). 525 # subtype_dealloc goes on to call the base classes' deallocs too, 526 # so any gc triggered by weakref callbacks associated with anything 527 # torn down by a base class dealloc can also trigger double 528 # deallocation of c2. 529 del c2 530 531 def test_callback_in_cycle_1(self): 532 import gc 533 534 class J(object): 535 pass 536 537 class II(object): 538 def acallback(self, ignore): 539 self.J 540 541 I = II() 542 I.J = J 543 I.wr = weakref.ref(J, I.acallback) 544 545 # Now J and II are each in a self-cycle (as all new-style class 546 # objects are, since their __mro__ points back to them). I holds 547 # both a weak reference (I.wr) and a strong reference (I.J) to class 548 # J. I is also in a cycle (I.wr points to a weakref that references 549 # I.acallback). When we del these three, they all become trash, but 550 # the cycles prevent any of them from getting cleaned up immediately. 551 # Instead they have to wait for cyclic gc to deduce that they're 552 # trash. 553 # 554 # gc used to call tp_clear on all of them, and the order in which 555 # it does that is pretty accidental. The exact order in which we 556 # built up these things manages to provoke gc into running tp_clear 557 # in just the right order (I last). Calling tp_clear on II leaves 558 # behind an insane class object (its __mro__ becomes NULL). Calling 559 # tp_clear on J breaks its self-cycle, but J doesn't get deleted 560 # just then because of the strong reference from I.J. Calling 561 # tp_clear on I starts to clear I's __dict__, and just happens to 562 # clear I.J first -- I.wr is still intact. That removes the last 563 # reference to J, which triggers the weakref callback. The callback 564 # tries to do "self.J", and instances of new-style classes look up 565 # attributes ("J") in the class dict first. The class (II) wants to 566 # search II.__mro__, but that's NULL. The result was a segfault in 567 # a release build, and an assert failure in a debug build. 568 del I, J, II 569 gc.collect() 570 571 def test_callback_in_cycle_2(self): 572 import gc 573 574 # This is just like test_callback_in_cycle_1, except that II is an 575 # old-style class. The symptom is different then: an instance of an 576 # old-style class looks in its own __dict__ first. 'J' happens to 577 # get cleared from I.__dict__ before 'wr', and 'J' was never in II's 578 # __dict__, so the attribute isn't found. The difference is that 579 # the old-style II doesn't have a NULL __mro__ (it doesn't have any 580 # __mro__), so no segfault occurs. Instead it got: 581 # test_callback_in_cycle_2 (__main__.ReferencesTestCase) ... 582 # Exception exceptions.AttributeError: 583 # "II instance has no attribute 'J'" in <bound method II.acallback 584 # of <?.II instance at 0x00B9B4B8>> ignored 585 586 class J(object): 587 pass 588 589 class II: 590 def acallback(self, ignore): 591 self.J 592 593 I = II() 594 I.J = J 595 I.wr = weakref.ref(J, I.acallback) 596 597 del I, J, II 598 gc.collect() 599 600 def test_callback_in_cycle_3(self): 601 import gc 602 603 # This one broke the first patch that fixed the last two. In this 604 # case, the objects reachable from the callback aren't also reachable 605 # from the object (c1) *triggering* the callback: you can get to 606 # c1 from c2, but not vice-versa. The result was that c2's __dict__ 607 # got tp_clear'ed by the time the c2.cb callback got invoked. 608 609 class C: 610 def cb(self, ignore): 611 self.me 612 self.c1 613 self.wr 614 615 c1, c2 = C(), C() 616 617 c2.me = c2 618 c2.c1 = c1 619 c2.wr = weakref.ref(c1, c2.cb) 620 621 del c1, c2 622 gc.collect() 623 624 def test_callback_in_cycle_4(self): 625 import gc 626 627 # Like test_callback_in_cycle_3, except c2 and c1 have different 628 # classes. c2's class (C) isn't reachable from c1 then, so protecting 629 # objects reachable from the dying object (c1) isn't enough to stop 630 # c2's class (C) from getting tp_clear'ed before c2.cb is invoked. 631 # The result was a segfault (C.__mro__ was NULL when the callback 632 # tried to look up self.me). 633 634 class C(object): 635 def cb(self, ignore): 636 self.me 637 self.c1 638 self.wr 639 640 class D: 641 pass 642 643 c1, c2 = D(), C() 644 645 c2.me = c2 646 c2.c1 = c1 647 c2.wr = weakref.ref(c1, c2.cb) 648 649 del c1, c2, C, D 650 gc.collect() 651 652 @support.requires_type_collecting 653 def test_callback_in_cycle_resurrection(self): 654 import gc 655 656 # Do something nasty in a weakref callback: resurrect objects 657 # from dead cycles. For this to be attempted, the weakref and 658 # its callback must also be part of the cyclic trash (else the 659 # objects reachable via the callback couldn't be in cyclic trash 660 # to begin with -- the callback would act like an external root). 661 # But gc clears trash weakrefs with callbacks early now, which 662 # disables the callbacks, so the callbacks shouldn't get called 663 # at all (and so nothing actually gets resurrected). 664 665 alist = [] 666 class C(object): 667 def __init__(self, value): 668 self.attribute = value 669 670 def acallback(self, ignore): 671 alist.append(self.c) 672 673 c1, c2 = C(1), C(2) 674 c1.c = c2 675 c2.c = c1 676 c1.wr = weakref.ref(c2, c1.acallback) 677 c2.wr = weakref.ref(c1, c2.acallback) 678 679 def C_went_away(ignore): 680 alist.append("C went away") 681 wr = weakref.ref(C, C_went_away) 682 683 del c1, c2, C # make them all trash 684 self.assertEqual(alist, []) # del isn't enough to reclaim anything 685 686 gc.collect() 687 # c1.wr and c2.wr were part of the cyclic trash, so should have 688 # been cleared without their callbacks executing. OTOH, the weakref 689 # to C is bound to a function local (wr), and wasn't trash, so that 690 # callback should have been invoked when C went away. 691 self.assertEqual(alist, ["C went away"]) 692 # The remaining weakref should be dead now (its callback ran). 693 self.assertEqual(wr(), None) 694 695 del alist[:] 696 gc.collect() 697 self.assertEqual(alist, []) 698 699 def test_callbacks_on_callback(self): 700 import gc 701 702 # Set up weakref callbacks *on* weakref callbacks. 703 alist = [] 704 def safe_callback(ignore): 705 alist.append("safe_callback called") 706 707 class C(object): 708 def cb(self, ignore): 709 alist.append("cb called") 710 711 c, d = C(), C() 712 c.other = d 713 d.other = c 714 callback = c.cb 715 c.wr = weakref.ref(d, callback) # this won't trigger 716 d.wr = weakref.ref(callback, d.cb) # ditto 717 external_wr = weakref.ref(callback, safe_callback) # but this will 718 self.assertIs(external_wr(), callback) 719 720 # The weakrefs attached to c and d should get cleared, so that 721 # C.cb is never called. But external_wr isn't part of the cyclic 722 # trash, and no cyclic trash is reachable from it, so safe_callback 723 # should get invoked when the bound method object callback (c.cb) 724 # -- which is itself a callback, and also part of the cyclic trash -- 725 # gets reclaimed at the end of gc. 726 727 del callback, c, d, C 728 self.assertEqual(alist, []) # del isn't enough to clean up cycles 729 gc.collect() 730 self.assertEqual(alist, ["safe_callback called"]) 731 self.assertEqual(external_wr(), None) 732 733 del alist[:] 734 gc.collect() 735 self.assertEqual(alist, []) 736 737 def test_gc_during_ref_creation(self): 738 self.check_gc_during_creation(weakref.ref) 739 740 def test_gc_during_proxy_creation(self): 741 self.check_gc_during_creation(weakref.proxy) 742 743 def check_gc_during_creation(self, makeref): 744 thresholds = gc.get_threshold() 745 gc.set_threshold(1, 1, 1) 746 gc.collect() 747 class A: 748 pass 749 750 def callback(*args): 751 pass 752 753 referenced = A() 754 755 a = A() 756 a.a = a 757 a.wr = makeref(referenced) 758 759 try: 760 # now make sure the object and the ref get labeled as 761 # cyclic trash: 762 a = A() 763 weakref.ref(referenced, callback) 764 765 finally: 766 gc.set_threshold(*thresholds) 767 768 def test_ref_created_during_del(self): 769 # Bug #1377858 770 # A weakref created in an object's __del__() would crash the 771 # interpreter when the weakref was cleaned up since it would refer to 772 # non-existent memory. This test should not segfault the interpreter. 773 class Target(object): 774 def __del__(self): 775 global ref_from_del 776 ref_from_del = weakref.ref(self) 777 778 w = Target() 779 780 def test_init(self): 781 # Issue 3634 782 # <weakref to class>.__init__() doesn't check errors correctly 783 r = weakref.ref(Exception) 784 self.assertRaises(TypeError, r.__init__, 0, 0, 0, 0, 0) 785 # No exception should be raised here 786 gc.collect() 787 788 def test_classes(self): 789 # Check that classes are weakrefable. 790 class A(object): 791 pass 792 l = [] 793 weakref.ref(int) 794 a = weakref.ref(A, l.append) 795 A = None 796 gc.collect() 797 self.assertEqual(a(), None) 798 self.assertEqual(l, [a]) 799 800 def test_equality(self): 801 # Alive weakrefs defer equality testing to their underlying object. 802 x = Object(1) 803 y = Object(1) 804 z = Object(2) 805 a = weakref.ref(x) 806 b = weakref.ref(y) 807 c = weakref.ref(z) 808 d = weakref.ref(x) 809 # Note how we directly test the operators here, to stress both 810 # __eq__ and __ne__. 811 self.assertTrue(a == b) 812 self.assertFalse(a != b) 813 self.assertFalse(a == c) 814 self.assertTrue(a != c) 815 self.assertTrue(a == d) 816 self.assertFalse(a != d) 817 del x, y, z 818 gc.collect() 819 for r in a, b, c: 820 # Sanity check 821 self.assertIs(r(), None) 822 # Dead weakrefs compare by identity: whether `a` and `d` are the 823 # same weakref object is an implementation detail, since they pointed 824 # to the same original object and didn't have a callback. 825 # (see issue #16453). 826 self.assertFalse(a == b) 827 self.assertTrue(a != b) 828 self.assertFalse(a == c) 829 self.assertTrue(a != c) 830 self.assertEqual(a == d, a is d) 831 self.assertEqual(a != d, a is not d) 832 833 def test_ordering(self): 834 # weakrefs cannot be ordered, even if the underlying objects can. 835 ops = [operator.lt, operator.gt, operator.le, operator.ge] 836 x = Object(1) 837 y = Object(1) 838 a = weakref.ref(x) 839 b = weakref.ref(y) 840 for op in ops: 841 self.assertRaises(TypeError, op, a, b) 842 # Same when dead. 843 del x, y 844 gc.collect() 845 for op in ops: 846 self.assertRaises(TypeError, op, a, b) 847 848 def test_hashing(self): 849 # Alive weakrefs hash the same as the underlying object 850 x = Object(42) 851 y = Object(42) 852 a = weakref.ref(x) 853 b = weakref.ref(y) 854 self.assertEqual(hash(a), hash(42)) 855 del x, y 856 gc.collect() 857 # Dead weakrefs: 858 # - retain their hash is they were hashed when alive; 859 # - otherwise, cannot be hashed. 860 self.assertEqual(hash(a), hash(42)) 861 self.assertRaises(TypeError, hash, b) 862 863 def test_trashcan_16602(self): 864 # Issue #16602: when a weakref's target was part of a long 865 # deallocation chain, the trashcan mechanism could delay clearing 866 # of the weakref and make the target object visible from outside 867 # code even though its refcount had dropped to 0. A crash ensued. 868 class C: 869 def __init__(self, parent): 870 if not parent: 871 return 872 wself = weakref.ref(self) 873 def cb(wparent): 874 o = wself() 875 self.wparent = weakref.ref(parent, cb) 876 877 d = weakref.WeakKeyDictionary() 878 root = c = C(None) 879 for n in range(100): 880 d[c] = c = C(c) 881 del root 882 gc.collect() 883 884 def test_callback_attribute(self): 885 x = Object(1) 886 callback = lambda ref: None 887 ref1 = weakref.ref(x, callback) 888 self.assertIs(ref1.__callback__, callback) 889 890 ref2 = weakref.ref(x) 891 self.assertIsNone(ref2.__callback__) 892 893 def test_callback_attribute_after_deletion(self): 894 x = Object(1) 895 ref = weakref.ref(x, self.callback) 896 self.assertIsNotNone(ref.__callback__) 897 del x 898 support.gc_collect() 899 self.assertIsNone(ref.__callback__) 900 901 def test_set_callback_attribute(self): 902 x = Object(1) 903 callback = lambda ref: None 904 ref1 = weakref.ref(x, callback) 905 with self.assertRaises(AttributeError): 906 ref1.__callback__ = lambda ref: None 907 908 def test_callback_gcs(self): 909 class ObjectWithDel(Object): 910 def __del__(self): pass 911 x = ObjectWithDel(1) 912 ref1 = weakref.ref(x, lambda ref: support.gc_collect()) 913 del x 914 support.gc_collect() 915 916 917class SubclassableWeakrefTestCase(TestBase): 918 919 def test_subclass_refs(self): 920 class MyRef(weakref.ref): 921 def __init__(self, ob, callback=None, value=42): 922 self.value = value 923 super().__init__(ob, callback) 924 def __call__(self): 925 self.called = True 926 return super().__call__() 927 o = Object("foo") 928 mr = MyRef(o, value=24) 929 self.assertIs(mr(), o) 930 self.assertTrue(mr.called) 931 self.assertEqual(mr.value, 24) 932 del o 933 self.assertIsNone(mr()) 934 self.assertTrue(mr.called) 935 936 def test_subclass_refs_dont_replace_standard_refs(self): 937 class MyRef(weakref.ref): 938 pass 939 o = Object(42) 940 r1 = MyRef(o) 941 r2 = weakref.ref(o) 942 self.assertIsNot(r1, r2) 943 self.assertEqual(weakref.getweakrefs(o), [r2, r1]) 944 self.assertEqual(weakref.getweakrefcount(o), 2) 945 r3 = MyRef(o) 946 self.assertEqual(weakref.getweakrefcount(o), 3) 947 refs = weakref.getweakrefs(o) 948 self.assertEqual(len(refs), 3) 949 self.assertIs(r2, refs[0]) 950 self.assertIn(r1, refs[1:]) 951 self.assertIn(r3, refs[1:]) 952 953 def test_subclass_refs_dont_conflate_callbacks(self): 954 class MyRef(weakref.ref): 955 pass 956 o = Object(42) 957 r1 = MyRef(o, id) 958 r2 = MyRef(o, str) 959 self.assertIsNot(r1, r2) 960 refs = weakref.getweakrefs(o) 961 self.assertIn(r1, refs) 962 self.assertIn(r2, refs) 963 964 def test_subclass_refs_with_slots(self): 965 class MyRef(weakref.ref): 966 __slots__ = "slot1", "slot2" 967 def __new__(type, ob, callback, slot1, slot2): 968 return weakref.ref.__new__(type, ob, callback) 969 def __init__(self, ob, callback, slot1, slot2): 970 self.slot1 = slot1 971 self.slot2 = slot2 972 def meth(self): 973 return self.slot1 + self.slot2 974 o = Object(42) 975 r = MyRef(o, None, "abc", "def") 976 self.assertEqual(r.slot1, "abc") 977 self.assertEqual(r.slot2, "def") 978 self.assertEqual(r.meth(), "abcdef") 979 self.assertFalse(hasattr(r, "__dict__")) 980 981 def test_subclass_refs_with_cycle(self): 982 """Confirm https://bugs.python.org/issue3100 is fixed.""" 983 # An instance of a weakref subclass can have attributes. 984 # If such a weakref holds the only strong reference to the object, 985 # deleting the weakref will delete the object. In this case, 986 # the callback must not be called, because the ref object is 987 # being deleted. 988 class MyRef(weakref.ref): 989 pass 990 991 # Use a local callback, for "regrtest -R::" 992 # to detect refcounting problems 993 def callback(w): 994 self.cbcalled += 1 995 996 o = C() 997 r1 = MyRef(o, callback) 998 r1.o = o 999 del o 1000 1001 del r1 # Used to crash here 1002 1003 self.assertEqual(self.cbcalled, 0) 1004 1005 # Same test, with two weakrefs to the same object 1006 # (since code paths are different) 1007 o = C() 1008 r1 = MyRef(o, callback) 1009 r2 = MyRef(o, callback) 1010 r1.r = r2 1011 r2.o = o 1012 del o 1013 del r2 1014 1015 del r1 # Used to crash here 1016 1017 self.assertEqual(self.cbcalled, 0) 1018 1019 1020class WeakMethodTestCase(unittest.TestCase): 1021 1022 def _subclass(self): 1023 """Return an Object subclass overriding `some_method`.""" 1024 class C(Object): 1025 def some_method(self): 1026 return 6 1027 return C 1028 1029 def test_alive(self): 1030 o = Object(1) 1031 r = weakref.WeakMethod(o.some_method) 1032 self.assertIsInstance(r, weakref.ReferenceType) 1033 self.assertIsInstance(r(), type(o.some_method)) 1034 self.assertIs(r().__self__, o) 1035 self.assertIs(r().__func__, o.some_method.__func__) 1036 self.assertEqual(r()(), 4) 1037 1038 def test_object_dead(self): 1039 o = Object(1) 1040 r = weakref.WeakMethod(o.some_method) 1041 del o 1042 gc.collect() 1043 self.assertIs(r(), None) 1044 1045 def test_method_dead(self): 1046 C = self._subclass() 1047 o = C(1) 1048 r = weakref.WeakMethod(o.some_method) 1049 del C.some_method 1050 gc.collect() 1051 self.assertIs(r(), None) 1052 1053 def test_callback_when_object_dead(self): 1054 # Test callback behaviour when object dies first. 1055 C = self._subclass() 1056 calls = [] 1057 def cb(arg): 1058 calls.append(arg) 1059 o = C(1) 1060 r = weakref.WeakMethod(o.some_method, cb) 1061 del o 1062 gc.collect() 1063 self.assertEqual(calls, [r]) 1064 # Callback is only called once. 1065 C.some_method = Object.some_method 1066 gc.collect() 1067 self.assertEqual(calls, [r]) 1068 1069 def test_callback_when_method_dead(self): 1070 # Test callback behaviour when method dies first. 1071 C = self._subclass() 1072 calls = [] 1073 def cb(arg): 1074 calls.append(arg) 1075 o = C(1) 1076 r = weakref.WeakMethod(o.some_method, cb) 1077 del C.some_method 1078 gc.collect() 1079 self.assertEqual(calls, [r]) 1080 # Callback is only called once. 1081 del o 1082 gc.collect() 1083 self.assertEqual(calls, [r]) 1084 1085 @support.cpython_only 1086 def test_no_cycles(self): 1087 # A WeakMethod doesn't create any reference cycle to itself. 1088 o = Object(1) 1089 def cb(_): 1090 pass 1091 r = weakref.WeakMethod(o.some_method, cb) 1092 wr = weakref.ref(r) 1093 del r 1094 self.assertIs(wr(), None) 1095 1096 def test_equality(self): 1097 def _eq(a, b): 1098 self.assertTrue(a == b) 1099 self.assertFalse(a != b) 1100 def _ne(a, b): 1101 self.assertTrue(a != b) 1102 self.assertFalse(a == b) 1103 x = Object(1) 1104 y = Object(1) 1105 a = weakref.WeakMethod(x.some_method) 1106 b = weakref.WeakMethod(y.some_method) 1107 c = weakref.WeakMethod(x.other_method) 1108 d = weakref.WeakMethod(y.other_method) 1109 # Objects equal, same method 1110 _eq(a, b) 1111 _eq(c, d) 1112 # Objects equal, different method 1113 _ne(a, c) 1114 _ne(a, d) 1115 _ne(b, c) 1116 _ne(b, d) 1117 # Objects unequal, same or different method 1118 z = Object(2) 1119 e = weakref.WeakMethod(z.some_method) 1120 f = weakref.WeakMethod(z.other_method) 1121 _ne(a, e) 1122 _ne(a, f) 1123 _ne(b, e) 1124 _ne(b, f) 1125 del x, y, z 1126 gc.collect() 1127 # Dead WeakMethods compare by identity 1128 refs = a, b, c, d, e, f 1129 for q in refs: 1130 for r in refs: 1131 self.assertEqual(q == r, q is r) 1132 self.assertEqual(q != r, q is not r) 1133 1134 def test_hashing(self): 1135 # Alive WeakMethods are hashable if the underlying object is 1136 # hashable. 1137 x = Object(1) 1138 y = Object(1) 1139 a = weakref.WeakMethod(x.some_method) 1140 b = weakref.WeakMethod(y.some_method) 1141 c = weakref.WeakMethod(y.other_method) 1142 # Since WeakMethod objects are equal, the hashes should be equal. 1143 self.assertEqual(hash(a), hash(b)) 1144 ha = hash(a) 1145 # Dead WeakMethods retain their old hash value 1146 del x, y 1147 gc.collect() 1148 self.assertEqual(hash(a), ha) 1149 self.assertEqual(hash(b), ha) 1150 # If it wasn't hashed when alive, a dead WeakMethod cannot be hashed. 1151 self.assertRaises(TypeError, hash, c) 1152 1153 1154class MappingTestCase(TestBase): 1155 1156 COUNT = 10 1157 1158 def check_len_cycles(self, dict_type, cons): 1159 N = 20 1160 items = [RefCycle() for i in range(N)] 1161 dct = dict_type(cons(o) for o in items) 1162 # Keep an iterator alive 1163 it = dct.items() 1164 try: 1165 next(it) 1166 except StopIteration: 1167 pass 1168 del items 1169 gc.collect() 1170 n1 = len(dct) 1171 del it 1172 gc.collect() 1173 n2 = len(dct) 1174 # one item may be kept alive inside the iterator 1175 self.assertIn(n1, (0, 1)) 1176 self.assertEqual(n2, 0) 1177 1178 def test_weak_keyed_len_cycles(self): 1179 self.check_len_cycles(weakref.WeakKeyDictionary, lambda k: (k, 1)) 1180 1181 def test_weak_valued_len_cycles(self): 1182 self.check_len_cycles(weakref.WeakValueDictionary, lambda k: (1, k)) 1183 1184 def check_len_race(self, dict_type, cons): 1185 # Extended sanity checks for len() in the face of cyclic collection 1186 self.addCleanup(gc.set_threshold, *gc.get_threshold()) 1187 for th in range(1, 100): 1188 N = 20 1189 gc.collect(0) 1190 gc.set_threshold(th, th, th) 1191 items = [RefCycle() for i in range(N)] 1192 dct = dict_type(cons(o) for o in items) 1193 del items 1194 # All items will be collected at next garbage collection pass 1195 it = dct.items() 1196 try: 1197 next(it) 1198 except StopIteration: 1199 pass 1200 n1 = len(dct) 1201 del it 1202 n2 = len(dct) 1203 self.assertGreaterEqual(n1, 0) 1204 self.assertLessEqual(n1, N) 1205 self.assertGreaterEqual(n2, 0) 1206 self.assertLessEqual(n2, n1) 1207 1208 def test_weak_keyed_len_race(self): 1209 self.check_len_race(weakref.WeakKeyDictionary, lambda k: (k, 1)) 1210 1211 def test_weak_valued_len_race(self): 1212 self.check_len_race(weakref.WeakValueDictionary, lambda k: (1, k)) 1213 1214 def test_weak_values(self): 1215 # 1216 # This exercises d.copy(), d.items(), d[], del d[], len(d). 1217 # 1218 dict, objects = self.make_weak_valued_dict() 1219 for o in objects: 1220 self.assertEqual(weakref.getweakrefcount(o), 1) 1221 self.assertIs(o, dict[o.arg], 1222 "wrong object returned by weak dict!") 1223 items1 = list(dict.items()) 1224 items2 = list(dict.copy().items()) 1225 items1.sort() 1226 items2.sort() 1227 self.assertEqual(items1, items2, 1228 "cloning of weak-valued dictionary did not work!") 1229 del items1, items2 1230 self.assertEqual(len(dict), self.COUNT) 1231 del objects[0] 1232 self.assertEqual(len(dict), self.COUNT - 1, 1233 "deleting object did not cause dictionary update") 1234 del objects, o 1235 self.assertEqual(len(dict), 0, 1236 "deleting the values did not clear the dictionary") 1237 # regression on SF bug #447152: 1238 dict = weakref.WeakValueDictionary() 1239 self.assertRaises(KeyError, dict.__getitem__, 1) 1240 dict[2] = C() 1241 self.assertRaises(KeyError, dict.__getitem__, 2) 1242 1243 def test_weak_keys(self): 1244 # 1245 # This exercises d.copy(), d.items(), d[] = v, d[], del d[], 1246 # len(d), k in d. 1247 # 1248 dict, objects = self.make_weak_keyed_dict() 1249 for o in objects: 1250 self.assertEqual(weakref.getweakrefcount(o), 1, 1251 "wrong number of weak references to %r!" % o) 1252 self.assertIs(o.arg, dict[o], 1253 "wrong object returned by weak dict!") 1254 items1 = dict.items() 1255 items2 = dict.copy().items() 1256 self.assertEqual(set(items1), set(items2), 1257 "cloning of weak-keyed dictionary did not work!") 1258 del items1, items2 1259 self.assertEqual(len(dict), self.COUNT) 1260 del objects[0] 1261 self.assertEqual(len(dict), (self.COUNT - 1), 1262 "deleting object did not cause dictionary update") 1263 del objects, o 1264 self.assertEqual(len(dict), 0, 1265 "deleting the keys did not clear the dictionary") 1266 o = Object(42) 1267 dict[o] = "What is the meaning of the universe?" 1268 self.assertIn(o, dict) 1269 self.assertNotIn(34, dict) 1270 1271 def test_weak_keyed_iters(self): 1272 dict, objects = self.make_weak_keyed_dict() 1273 self.check_iters(dict) 1274 1275 # Test keyrefs() 1276 refs = dict.keyrefs() 1277 self.assertEqual(len(refs), len(objects)) 1278 objects2 = list(objects) 1279 for wr in refs: 1280 ob = wr() 1281 self.assertIn(ob, dict) 1282 self.assertIn(ob, dict) 1283 self.assertEqual(ob.arg, dict[ob]) 1284 objects2.remove(ob) 1285 self.assertEqual(len(objects2), 0) 1286 1287 # Test iterkeyrefs() 1288 objects2 = list(objects) 1289 self.assertEqual(len(list(dict.keyrefs())), len(objects)) 1290 for wr in dict.keyrefs(): 1291 ob = wr() 1292 self.assertIn(ob, dict) 1293 self.assertIn(ob, dict) 1294 self.assertEqual(ob.arg, dict[ob]) 1295 objects2.remove(ob) 1296 self.assertEqual(len(objects2), 0) 1297 1298 def test_weak_valued_iters(self): 1299 dict, objects = self.make_weak_valued_dict() 1300 self.check_iters(dict) 1301 1302 # Test valuerefs() 1303 refs = dict.valuerefs() 1304 self.assertEqual(len(refs), len(objects)) 1305 objects2 = list(objects) 1306 for wr in refs: 1307 ob = wr() 1308 self.assertEqual(ob, dict[ob.arg]) 1309 self.assertEqual(ob.arg, dict[ob.arg].arg) 1310 objects2.remove(ob) 1311 self.assertEqual(len(objects2), 0) 1312 1313 # Test itervaluerefs() 1314 objects2 = list(objects) 1315 self.assertEqual(len(list(dict.itervaluerefs())), len(objects)) 1316 for wr in dict.itervaluerefs(): 1317 ob = wr() 1318 self.assertEqual(ob, dict[ob.arg]) 1319 self.assertEqual(ob.arg, dict[ob.arg].arg) 1320 objects2.remove(ob) 1321 self.assertEqual(len(objects2), 0) 1322 1323 def check_iters(self, dict): 1324 # item iterator: 1325 items = list(dict.items()) 1326 for item in dict.items(): 1327 items.remove(item) 1328 self.assertFalse(items, "items() did not touch all items") 1329 1330 # key iterator, via __iter__(): 1331 keys = list(dict.keys()) 1332 for k in dict: 1333 keys.remove(k) 1334 self.assertFalse(keys, "__iter__() did not touch all keys") 1335 1336 # key iterator, via iterkeys(): 1337 keys = list(dict.keys()) 1338 for k in dict.keys(): 1339 keys.remove(k) 1340 self.assertFalse(keys, "iterkeys() did not touch all keys") 1341 1342 # value iterator: 1343 values = list(dict.values()) 1344 for v in dict.values(): 1345 values.remove(v) 1346 self.assertFalse(values, 1347 "itervalues() did not touch all values") 1348 1349 def check_weak_destroy_while_iterating(self, dict, objects, iter_name): 1350 n = len(dict) 1351 it = iter(getattr(dict, iter_name)()) 1352 next(it) # Trigger internal iteration 1353 # Destroy an object 1354 del objects[-1] 1355 gc.collect() # just in case 1356 # We have removed either the first consumed object, or another one 1357 self.assertIn(len(list(it)), [len(objects), len(objects) - 1]) 1358 del it 1359 # The removal has been committed 1360 self.assertEqual(len(dict), n - 1) 1361 1362 def check_weak_destroy_and_mutate_while_iterating(self, dict, testcontext): 1363 # Check that we can explicitly mutate the weak dict without 1364 # interfering with delayed removal. 1365 # `testcontext` should create an iterator, destroy one of the 1366 # weakref'ed objects and then return a new key/value pair corresponding 1367 # to the destroyed object. 1368 with testcontext() as (k, v): 1369 self.assertNotIn(k, dict) 1370 with testcontext() as (k, v): 1371 self.assertRaises(KeyError, dict.__delitem__, k) 1372 self.assertNotIn(k, dict) 1373 with testcontext() as (k, v): 1374 self.assertRaises(KeyError, dict.pop, k) 1375 self.assertNotIn(k, dict) 1376 with testcontext() as (k, v): 1377 dict[k] = v 1378 self.assertEqual(dict[k], v) 1379 ddict = copy.copy(dict) 1380 with testcontext() as (k, v): 1381 dict.update(ddict) 1382 self.assertEqual(dict, ddict) 1383 with testcontext() as (k, v): 1384 dict.clear() 1385 self.assertEqual(len(dict), 0) 1386 1387 def check_weak_del_and_len_while_iterating(self, dict, testcontext): 1388 # Check that len() works when both iterating and removing keys 1389 # explicitly through various means (.pop(), .clear()...), while 1390 # implicit mutation is deferred because an iterator is alive. 1391 # (each call to testcontext() should schedule one item for removal 1392 # for this test to work properly) 1393 o = Object(123456) 1394 with testcontext(): 1395 n = len(dict) 1396 # Since underlaying dict is ordered, first item is popped 1397 dict.pop(next(dict.keys())) 1398 self.assertEqual(len(dict), n - 1) 1399 dict[o] = o 1400 self.assertEqual(len(dict), n) 1401 # last item in objects is removed from dict in context shutdown 1402 with testcontext(): 1403 self.assertEqual(len(dict), n - 1) 1404 # Then, (o, o) is popped 1405 dict.popitem() 1406 self.assertEqual(len(dict), n - 2) 1407 with testcontext(): 1408 self.assertEqual(len(dict), n - 3) 1409 del dict[next(dict.keys())] 1410 self.assertEqual(len(dict), n - 4) 1411 with testcontext(): 1412 self.assertEqual(len(dict), n - 5) 1413 dict.popitem() 1414 self.assertEqual(len(dict), n - 6) 1415 with testcontext(): 1416 dict.clear() 1417 self.assertEqual(len(dict), 0) 1418 self.assertEqual(len(dict), 0) 1419 1420 def test_weak_keys_destroy_while_iterating(self): 1421 # Issue #7105: iterators shouldn't crash when a key is implicitly removed 1422 dict, objects = self.make_weak_keyed_dict() 1423 self.check_weak_destroy_while_iterating(dict, objects, 'keys') 1424 self.check_weak_destroy_while_iterating(dict, objects, 'items') 1425 self.check_weak_destroy_while_iterating(dict, objects, 'values') 1426 self.check_weak_destroy_while_iterating(dict, objects, 'keyrefs') 1427 dict, objects = self.make_weak_keyed_dict() 1428 @contextlib.contextmanager 1429 def testcontext(): 1430 try: 1431 it = iter(dict.items()) 1432 next(it) 1433 # Schedule a key/value for removal and recreate it 1434 v = objects.pop().arg 1435 gc.collect() # just in case 1436 yield Object(v), v 1437 finally: 1438 it = None # should commit all removals 1439 gc.collect() 1440 self.check_weak_destroy_and_mutate_while_iterating(dict, testcontext) 1441 # Issue #21173: len() fragile when keys are both implicitly and 1442 # explicitly removed. 1443 dict, objects = self.make_weak_keyed_dict() 1444 self.check_weak_del_and_len_while_iterating(dict, testcontext) 1445 1446 def test_weak_values_destroy_while_iterating(self): 1447 # Issue #7105: iterators shouldn't crash when a key is implicitly removed 1448 dict, objects = self.make_weak_valued_dict() 1449 self.check_weak_destroy_while_iterating(dict, objects, 'keys') 1450 self.check_weak_destroy_while_iterating(dict, objects, 'items') 1451 self.check_weak_destroy_while_iterating(dict, objects, 'values') 1452 self.check_weak_destroy_while_iterating(dict, objects, 'itervaluerefs') 1453 self.check_weak_destroy_while_iterating(dict, objects, 'valuerefs') 1454 dict, objects = self.make_weak_valued_dict() 1455 @contextlib.contextmanager 1456 def testcontext(): 1457 try: 1458 it = iter(dict.items()) 1459 next(it) 1460 # Schedule a key/value for removal and recreate it 1461 k = objects.pop().arg 1462 gc.collect() # just in case 1463 yield k, Object(k) 1464 finally: 1465 it = None # should commit all removals 1466 gc.collect() 1467 self.check_weak_destroy_and_mutate_while_iterating(dict, testcontext) 1468 dict, objects = self.make_weak_valued_dict() 1469 self.check_weak_del_and_len_while_iterating(dict, testcontext) 1470 1471 def test_make_weak_keyed_dict_from_dict(self): 1472 o = Object(3) 1473 dict = weakref.WeakKeyDictionary({o:364}) 1474 self.assertEqual(dict[o], 364) 1475 1476 def test_make_weak_keyed_dict_from_weak_keyed_dict(self): 1477 o = Object(3) 1478 dict = weakref.WeakKeyDictionary({o:364}) 1479 dict2 = weakref.WeakKeyDictionary(dict) 1480 self.assertEqual(dict[o], 364) 1481 1482 def make_weak_keyed_dict(self): 1483 dict = weakref.WeakKeyDictionary() 1484 objects = list(map(Object, range(self.COUNT))) 1485 for o in objects: 1486 dict[o] = o.arg 1487 return dict, objects 1488 1489 def test_make_weak_valued_dict_from_dict(self): 1490 o = Object(3) 1491 dict = weakref.WeakValueDictionary({364:o}) 1492 self.assertEqual(dict[364], o) 1493 1494 def test_make_weak_valued_dict_from_weak_valued_dict(self): 1495 o = Object(3) 1496 dict = weakref.WeakValueDictionary({364:o}) 1497 dict2 = weakref.WeakValueDictionary(dict) 1498 self.assertEqual(dict[364], o) 1499 1500 def test_make_weak_valued_dict_misc(self): 1501 # errors 1502 self.assertRaises(TypeError, weakref.WeakValueDictionary.__init__) 1503 self.assertRaises(TypeError, weakref.WeakValueDictionary, {}, {}) 1504 self.assertRaises(TypeError, weakref.WeakValueDictionary, (), ()) 1505 # special keyword arguments 1506 o = Object(3) 1507 for kw in 'self', 'dict', 'other', 'iterable': 1508 d = weakref.WeakValueDictionary(**{kw: o}) 1509 self.assertEqual(list(d.keys()), [kw]) 1510 self.assertEqual(d[kw], o) 1511 1512 def make_weak_valued_dict(self): 1513 dict = weakref.WeakValueDictionary() 1514 objects = list(map(Object, range(self.COUNT))) 1515 for o in objects: 1516 dict[o.arg] = o 1517 return dict, objects 1518 1519 def check_popitem(self, klass, key1, value1, key2, value2): 1520 weakdict = klass() 1521 weakdict[key1] = value1 1522 weakdict[key2] = value2 1523 self.assertEqual(len(weakdict), 2) 1524 k, v = weakdict.popitem() 1525 self.assertEqual(len(weakdict), 1) 1526 if k is key1: 1527 self.assertIs(v, value1) 1528 else: 1529 self.assertIs(v, value2) 1530 k, v = weakdict.popitem() 1531 self.assertEqual(len(weakdict), 0) 1532 if k is key1: 1533 self.assertIs(v, value1) 1534 else: 1535 self.assertIs(v, value2) 1536 1537 def test_weak_valued_dict_popitem(self): 1538 self.check_popitem(weakref.WeakValueDictionary, 1539 "key1", C(), "key2", C()) 1540 1541 def test_weak_keyed_dict_popitem(self): 1542 self.check_popitem(weakref.WeakKeyDictionary, 1543 C(), "value 1", C(), "value 2") 1544 1545 def check_setdefault(self, klass, key, value1, value2): 1546 self.assertIsNot(value1, value2, 1547 "invalid test" 1548 " -- value parameters must be distinct objects") 1549 weakdict = klass() 1550 o = weakdict.setdefault(key, value1) 1551 self.assertIs(o, value1) 1552 self.assertIn(key, weakdict) 1553 self.assertIs(weakdict.get(key), value1) 1554 self.assertIs(weakdict[key], value1) 1555 1556 o = weakdict.setdefault(key, value2) 1557 self.assertIs(o, value1) 1558 self.assertIn(key, weakdict) 1559 self.assertIs(weakdict.get(key), value1) 1560 self.assertIs(weakdict[key], value1) 1561 1562 def test_weak_valued_dict_setdefault(self): 1563 self.check_setdefault(weakref.WeakValueDictionary, 1564 "key", C(), C()) 1565 1566 def test_weak_keyed_dict_setdefault(self): 1567 self.check_setdefault(weakref.WeakKeyDictionary, 1568 C(), "value 1", "value 2") 1569 1570 def check_update(self, klass, dict): 1571 # 1572 # This exercises d.update(), len(d), d.keys(), k in d, 1573 # d.get(), d[]. 1574 # 1575 weakdict = klass() 1576 weakdict.update(dict) 1577 self.assertEqual(len(weakdict), len(dict)) 1578 for k in weakdict.keys(): 1579 self.assertIn(k, dict, "mysterious new key appeared in weak dict") 1580 v = dict.get(k) 1581 self.assertIs(v, weakdict[k]) 1582 self.assertIs(v, weakdict.get(k)) 1583 for k in dict.keys(): 1584 self.assertIn(k, weakdict, "original key disappeared in weak dict") 1585 v = dict[k] 1586 self.assertIs(v, weakdict[k]) 1587 self.assertIs(v, weakdict.get(k)) 1588 1589 def test_weak_valued_dict_update(self): 1590 self.check_update(weakref.WeakValueDictionary, 1591 {1: C(), 'a': C(), C(): C()}) 1592 # errors 1593 self.assertRaises(TypeError, weakref.WeakValueDictionary.update) 1594 d = weakref.WeakValueDictionary() 1595 self.assertRaises(TypeError, d.update, {}, {}) 1596 self.assertRaises(TypeError, d.update, (), ()) 1597 self.assertEqual(list(d.keys()), []) 1598 # special keyword arguments 1599 o = Object(3) 1600 for kw in 'self', 'dict', 'other', 'iterable': 1601 d = weakref.WeakValueDictionary() 1602 d.update(**{kw: o}) 1603 self.assertEqual(list(d.keys()), [kw]) 1604 self.assertEqual(d[kw], o) 1605 1606 def test_weak_keyed_dict_update(self): 1607 self.check_update(weakref.WeakKeyDictionary, 1608 {C(): 1, C(): 2, C(): 3}) 1609 1610 def test_weak_keyed_delitem(self): 1611 d = weakref.WeakKeyDictionary() 1612 o1 = Object('1') 1613 o2 = Object('2') 1614 d[o1] = 'something' 1615 d[o2] = 'something' 1616 self.assertEqual(len(d), 2) 1617 del d[o1] 1618 self.assertEqual(len(d), 1) 1619 self.assertEqual(list(d.keys()), [o2]) 1620 1621 def test_weak_valued_delitem(self): 1622 d = weakref.WeakValueDictionary() 1623 o1 = Object('1') 1624 o2 = Object('2') 1625 d['something'] = o1 1626 d['something else'] = o2 1627 self.assertEqual(len(d), 2) 1628 del d['something'] 1629 self.assertEqual(len(d), 1) 1630 self.assertEqual(list(d.items()), [('something else', o2)]) 1631 1632 def test_weak_keyed_bad_delitem(self): 1633 d = weakref.WeakKeyDictionary() 1634 o = Object('1') 1635 # An attempt to delete an object that isn't there should raise 1636 # KeyError. It didn't before 2.3. 1637 self.assertRaises(KeyError, d.__delitem__, o) 1638 self.assertRaises(KeyError, d.__getitem__, o) 1639 1640 # If a key isn't of a weakly referencable type, __getitem__ and 1641 # __setitem__ raise TypeError. __delitem__ should too. 1642 self.assertRaises(TypeError, d.__delitem__, 13) 1643 self.assertRaises(TypeError, d.__getitem__, 13) 1644 self.assertRaises(TypeError, d.__setitem__, 13, 13) 1645 1646 def test_weak_keyed_cascading_deletes(self): 1647 # SF bug 742860. For some reason, before 2.3 __delitem__ iterated 1648 # over the keys via self.data.iterkeys(). If things vanished from 1649 # the dict during this (or got added), that caused a RuntimeError. 1650 1651 d = weakref.WeakKeyDictionary() 1652 mutate = False 1653 1654 class C(object): 1655 def __init__(self, i): 1656 self.value = i 1657 def __hash__(self): 1658 return hash(self.value) 1659 def __eq__(self, other): 1660 if mutate: 1661 # Side effect that mutates the dict, by removing the 1662 # last strong reference to a key. 1663 del objs[-1] 1664 return self.value == other.value 1665 1666 objs = [C(i) for i in range(4)] 1667 for o in objs: 1668 d[o] = o.value 1669 del o # now the only strong references to keys are in objs 1670 # Find the order in which iterkeys sees the keys. 1671 objs = list(d.keys()) 1672 # Reverse it, so that the iteration implementation of __delitem__ 1673 # has to keep looping to find the first object we delete. 1674 objs.reverse() 1675 1676 # Turn on mutation in C.__eq__. The first time through the loop, 1677 # under the iterkeys() business the first comparison will delete 1678 # the last item iterkeys() would see, and that causes a 1679 # RuntimeError: dictionary changed size during iteration 1680 # when the iterkeys() loop goes around to try comparing the next 1681 # key. After this was fixed, it just deletes the last object *our* 1682 # "for o in obj" loop would have gotten to. 1683 mutate = True 1684 count = 0 1685 for o in objs: 1686 count += 1 1687 del d[o] 1688 self.assertEqual(len(d), 0) 1689 self.assertEqual(count, 2) 1690 1691 def test_make_weak_valued_dict_repr(self): 1692 dict = weakref.WeakValueDictionary() 1693 self.assertRegex(repr(dict), '<WeakValueDictionary at 0x.*>') 1694 1695 def test_make_weak_keyed_dict_repr(self): 1696 dict = weakref.WeakKeyDictionary() 1697 self.assertRegex(repr(dict), '<WeakKeyDictionary at 0x.*>') 1698 1699 def test_threaded_weak_valued_setdefault(self): 1700 d = weakref.WeakValueDictionary() 1701 with collect_in_thread(): 1702 for i in range(100000): 1703 x = d.setdefault(10, RefCycle()) 1704 self.assertIsNot(x, None) # we never put None in there! 1705 del x 1706 1707 def test_threaded_weak_valued_pop(self): 1708 d = weakref.WeakValueDictionary() 1709 with collect_in_thread(): 1710 for i in range(100000): 1711 d[10] = RefCycle() 1712 x = d.pop(10, 10) 1713 self.assertIsNot(x, None) # we never put None in there! 1714 1715 def test_threaded_weak_valued_consistency(self): 1716 # Issue #28427: old keys should not remove new values from 1717 # WeakValueDictionary when collecting from another thread. 1718 d = weakref.WeakValueDictionary() 1719 with collect_in_thread(): 1720 for i in range(200000): 1721 o = RefCycle() 1722 d[10] = o 1723 # o is still alive, so the dict can't be empty 1724 self.assertEqual(len(d), 1) 1725 o = None # lose ref 1726 1727 def check_threaded_weak_dict_copy(self, type_, deepcopy): 1728 # `type_` should be either WeakKeyDictionary or WeakValueDictionary. 1729 # `deepcopy` should be either True or False. 1730 exc = [] 1731 1732 class DummyKey: 1733 def __init__(self, ctr): 1734 self.ctr = ctr 1735 1736 class DummyValue: 1737 def __init__(self, ctr): 1738 self.ctr = ctr 1739 1740 def dict_copy(d, exc): 1741 try: 1742 if deepcopy is True: 1743 _ = copy.deepcopy(d) 1744 else: 1745 _ = d.copy() 1746 except Exception as ex: 1747 exc.append(ex) 1748 1749 def pop_and_collect(lst): 1750 gc_ctr = 0 1751 while lst: 1752 i = random.randint(0, len(lst) - 1) 1753 gc_ctr += 1 1754 lst.pop(i) 1755 if gc_ctr % 10000 == 0: 1756 gc.collect() # just in case 1757 1758 self.assertIn(type_, (weakref.WeakKeyDictionary, weakref.WeakValueDictionary)) 1759 1760 d = type_() 1761 keys = [] 1762 values = [] 1763 # Initialize d with many entries 1764 for i in range(70000): 1765 k, v = DummyKey(i), DummyValue(i) 1766 keys.append(k) 1767 values.append(v) 1768 d[k] = v 1769 del k 1770 del v 1771 1772 t_copy = threading.Thread(target=dict_copy, args=(d, exc,)) 1773 if type_ is weakref.WeakKeyDictionary: 1774 t_collect = threading.Thread(target=pop_and_collect, args=(keys,)) 1775 else: # weakref.WeakValueDictionary 1776 t_collect = threading.Thread(target=pop_and_collect, args=(values,)) 1777 1778 t_copy.start() 1779 t_collect.start() 1780 1781 t_copy.join() 1782 t_collect.join() 1783 1784 # Test exceptions 1785 if exc: 1786 raise exc[0] 1787 1788 def test_threaded_weak_key_dict_copy(self): 1789 # Issue #35615: Weakref keys or values getting GC'ed during dict 1790 # copying should not result in a crash. 1791 self.check_threaded_weak_dict_copy(weakref.WeakKeyDictionary, False) 1792 1793 def test_threaded_weak_key_dict_deepcopy(self): 1794 # Issue #35615: Weakref keys or values getting GC'ed during dict 1795 # copying should not result in a crash. 1796 self.check_threaded_weak_dict_copy(weakref.WeakKeyDictionary, True) 1797 1798 def test_threaded_weak_value_dict_copy(self): 1799 # Issue #35615: Weakref keys or values getting GC'ed during dict 1800 # copying should not result in a crash. 1801 self.check_threaded_weak_dict_copy(weakref.WeakValueDictionary, False) 1802 1803 def test_threaded_weak_value_dict_deepcopy(self): 1804 # Issue #35615: Weakref keys or values getting GC'ed during dict 1805 # copying should not result in a crash. 1806 self.check_threaded_weak_dict_copy(weakref.WeakValueDictionary, True) 1807 1808 @support.cpython_only 1809 def test_remove_closure(self): 1810 d = weakref.WeakValueDictionary() 1811 self.assertIsNone(d._remove.__closure__) 1812 1813 1814from test import mapping_tests 1815 1816class WeakValueDictionaryTestCase(mapping_tests.BasicTestMappingProtocol): 1817 """Check that WeakValueDictionary conforms to the mapping protocol""" 1818 __ref = {"key1":Object(1), "key2":Object(2), "key3":Object(3)} 1819 type2test = weakref.WeakValueDictionary 1820 def _reference(self): 1821 return self.__ref.copy() 1822 1823class WeakKeyDictionaryTestCase(mapping_tests.BasicTestMappingProtocol): 1824 """Check that WeakKeyDictionary conforms to the mapping protocol""" 1825 __ref = {Object("key1"):1, Object("key2"):2, Object("key3"):3} 1826 type2test = weakref.WeakKeyDictionary 1827 def _reference(self): 1828 return self.__ref.copy() 1829 1830 1831class FinalizeTestCase(unittest.TestCase): 1832 1833 class A: 1834 pass 1835 1836 def _collect_if_necessary(self): 1837 # we create no ref-cycles so in CPython no gc should be needed 1838 if sys.implementation.name != 'cpython': 1839 support.gc_collect() 1840 1841 def test_finalize(self): 1842 def add(x,y,z): 1843 res.append(x + y + z) 1844 return x + y + z 1845 1846 a = self.A() 1847 1848 res = [] 1849 f = weakref.finalize(a, add, 67, 43, z=89) 1850 self.assertEqual(f.alive, True) 1851 self.assertEqual(f.peek(), (a, add, (67,43), {'z':89})) 1852 self.assertEqual(f(), 199) 1853 self.assertEqual(f(), None) 1854 self.assertEqual(f(), None) 1855 self.assertEqual(f.peek(), None) 1856 self.assertEqual(f.detach(), None) 1857 self.assertEqual(f.alive, False) 1858 self.assertEqual(res, [199]) 1859 1860 res = [] 1861 f = weakref.finalize(a, add, 67, 43, 89) 1862 self.assertEqual(f.peek(), (a, add, (67,43,89), {})) 1863 self.assertEqual(f.detach(), (a, add, (67,43,89), {})) 1864 self.assertEqual(f(), None) 1865 self.assertEqual(f(), None) 1866 self.assertEqual(f.peek(), None) 1867 self.assertEqual(f.detach(), None) 1868 self.assertEqual(f.alive, False) 1869 self.assertEqual(res, []) 1870 1871 res = [] 1872 f = weakref.finalize(a, add, x=67, y=43, z=89) 1873 del a 1874 self._collect_if_necessary() 1875 self.assertEqual(f(), None) 1876 self.assertEqual(f(), None) 1877 self.assertEqual(f.peek(), None) 1878 self.assertEqual(f.detach(), None) 1879 self.assertEqual(f.alive, False) 1880 self.assertEqual(res, [199]) 1881 1882 def test_arg_errors(self): 1883 def fin(*args, **kwargs): 1884 res.append((args, kwargs)) 1885 1886 a = self.A() 1887 1888 res = [] 1889 f = weakref.finalize(a, fin, 1, 2, func=3, obj=4) 1890 self.assertEqual(f.peek(), (a, fin, (1, 2), {'func': 3, 'obj': 4})) 1891 f() 1892 self.assertEqual(res, [((1, 2), {'func': 3, 'obj': 4})]) 1893 1894 res = [] 1895 with self.assertWarns(DeprecationWarning): 1896 f = weakref.finalize(a, func=fin, arg=1) 1897 self.assertEqual(f.peek(), (a, fin, (), {'arg': 1})) 1898 f() 1899 self.assertEqual(res, [((), {'arg': 1})]) 1900 1901 res = [] 1902 with self.assertWarns(DeprecationWarning): 1903 f = weakref.finalize(obj=a, func=fin, arg=1) 1904 self.assertEqual(f.peek(), (a, fin, (), {'arg': 1})) 1905 f() 1906 self.assertEqual(res, [((), {'arg': 1})]) 1907 1908 self.assertRaises(TypeError, weakref.finalize, a) 1909 self.assertRaises(TypeError, weakref.finalize) 1910 1911 def test_order(self): 1912 a = self.A() 1913 res = [] 1914 1915 f1 = weakref.finalize(a, res.append, 'f1') 1916 f2 = weakref.finalize(a, res.append, 'f2') 1917 f3 = weakref.finalize(a, res.append, 'f3') 1918 f4 = weakref.finalize(a, res.append, 'f4') 1919 f5 = weakref.finalize(a, res.append, 'f5') 1920 1921 # make sure finalizers can keep themselves alive 1922 del f1, f4 1923 1924 self.assertTrue(f2.alive) 1925 self.assertTrue(f3.alive) 1926 self.assertTrue(f5.alive) 1927 1928 self.assertTrue(f5.detach()) 1929 self.assertFalse(f5.alive) 1930 1931 f5() # nothing because previously unregistered 1932 res.append('A') 1933 f3() # => res.append('f3') 1934 self.assertFalse(f3.alive) 1935 res.append('B') 1936 f3() # nothing because previously called 1937 res.append('C') 1938 del a 1939 self._collect_if_necessary() 1940 # => res.append('f4') 1941 # => res.append('f2') 1942 # => res.append('f1') 1943 self.assertFalse(f2.alive) 1944 res.append('D') 1945 f2() # nothing because previously called by gc 1946 1947 expected = ['A', 'f3', 'B', 'C', 'f4', 'f2', 'f1', 'D'] 1948 self.assertEqual(res, expected) 1949 1950 def test_all_freed(self): 1951 # we want a weakrefable subclass of weakref.finalize 1952 class MyFinalizer(weakref.finalize): 1953 pass 1954 1955 a = self.A() 1956 res = [] 1957 def callback(): 1958 res.append(123) 1959 f = MyFinalizer(a, callback) 1960 1961 wr_callback = weakref.ref(callback) 1962 wr_f = weakref.ref(f) 1963 del callback, f 1964 1965 self.assertIsNotNone(wr_callback()) 1966 self.assertIsNotNone(wr_f()) 1967 1968 del a 1969 self._collect_if_necessary() 1970 1971 self.assertIsNone(wr_callback()) 1972 self.assertIsNone(wr_f()) 1973 self.assertEqual(res, [123]) 1974 1975 @classmethod 1976 def run_in_child(cls): 1977 def error(): 1978 # Create an atexit finalizer from inside a finalizer called 1979 # at exit. This should be the next to be run. 1980 g1 = weakref.finalize(cls, print, 'g1') 1981 print('f3 error') 1982 1/0 1983 1984 # cls should stay alive till atexit callbacks run 1985 f1 = weakref.finalize(cls, print, 'f1', _global_var) 1986 f2 = weakref.finalize(cls, print, 'f2', _global_var) 1987 f3 = weakref.finalize(cls, error) 1988 f4 = weakref.finalize(cls, print, 'f4', _global_var) 1989 1990 assert f1.atexit == True 1991 f2.atexit = False 1992 assert f3.atexit == True 1993 assert f4.atexit == True 1994 1995 def test_atexit(self): 1996 prog = ('from test.test_weakref import FinalizeTestCase;'+ 1997 'FinalizeTestCase.run_in_child()') 1998 rc, out, err = script_helper.assert_python_ok('-c', prog) 1999 out = out.decode('ascii').splitlines() 2000 self.assertEqual(out, ['f4 foobar', 'f3 error', 'g1', 'f1 foobar']) 2001 self.assertTrue(b'ZeroDivisionError' in err) 2002 2003 2004libreftest = """ Doctest for examples in the library reference: weakref.rst 2005 2006>>> import weakref 2007>>> class Dict(dict): 2008... pass 2009... 2010>>> obj = Dict(red=1, green=2, blue=3) # this object is weak referencable 2011>>> r = weakref.ref(obj) 2012>>> print(r() is obj) 2013True 2014 2015>>> import weakref 2016>>> class Object: 2017... pass 2018... 2019>>> o = Object() 2020>>> r = weakref.ref(o) 2021>>> o2 = r() 2022>>> o is o2 2023True 2024>>> del o, o2 2025>>> print(r()) 2026None 2027 2028>>> import weakref 2029>>> class ExtendedRef(weakref.ref): 2030... def __init__(self, ob, callback=None, **annotations): 2031... super().__init__(ob, callback) 2032... self.__counter = 0 2033... for k, v in annotations.items(): 2034... setattr(self, k, v) 2035... def __call__(self): 2036... '''Return a pair containing the referent and the number of 2037... times the reference has been called. 2038... ''' 2039... ob = super().__call__() 2040... if ob is not None: 2041... self.__counter += 1 2042... ob = (ob, self.__counter) 2043... return ob 2044... 2045>>> class A: # not in docs from here, just testing the ExtendedRef 2046... pass 2047... 2048>>> a = A() 2049>>> r = ExtendedRef(a, foo=1, bar="baz") 2050>>> r.foo 20511 2052>>> r.bar 2053'baz' 2054>>> r()[1] 20551 2056>>> r()[1] 20572 2058>>> r()[0] is a 2059True 2060 2061 2062>>> import weakref 2063>>> _id2obj_dict = weakref.WeakValueDictionary() 2064>>> def remember(obj): 2065... oid = id(obj) 2066... _id2obj_dict[oid] = obj 2067... return oid 2068... 2069>>> def id2obj(oid): 2070... return _id2obj_dict[oid] 2071... 2072>>> a = A() # from here, just testing 2073>>> a_id = remember(a) 2074>>> id2obj(a_id) is a 2075True 2076>>> del a 2077>>> try: 2078... id2obj(a_id) 2079... except KeyError: 2080... print('OK') 2081... else: 2082... print('WeakValueDictionary error') 2083OK 2084 2085""" 2086 2087__test__ = {'libreftest' : libreftest} 2088 2089def test_main(): 2090 support.run_unittest( 2091 ReferencesTestCase, 2092 WeakMethodTestCase, 2093 MappingTestCase, 2094 WeakValueDictionaryTestCase, 2095 WeakKeyDictionaryTestCase, 2096 SubclassableWeakrefTestCase, 2097 FinalizeTestCase, 2098 ) 2099 support.run_doctest(sys.modules[__name__]) 2100 2101 2102if __name__ == "__main__": 2103 test_main() 2104