Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(84766)

Delta Between Two Patch Sets: Lib/test/test_gc.py

Issue 16510: Using appropriate checks in tests
Left Patch Set: Created 5 years, 11 months ago
Right Patch Set: Created 5 years, 6 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « Lib/test/test_functools.py ('k') | Lib/test/test_gdb.py » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 import unittest 1 import unittest
2 from test.support import (verbose, refcount_test, run_unittest, 2 from test.support import (verbose, refcount_test, run_unittest,
3 strip_python_stderr) 3 strip_python_stderr, cpython_only)
4 from test.script_helper import assert_python_ok, make_script, temp_dir
5
4 import sys 6 import sys
5 import time 7 import time
6 import gc 8 import gc
7 import weakref 9 import weakref
8 10
9 try: 11 try:
10 import threading 12 import threading
11 except ImportError: 13 except ImportError:
12 threading = None 14 threading = None
15
16 try:
17 from _testcapi import with_tp_del
18 except ImportError:
19 def with_tp_del(cls):
20 class C(object):
21 def __new__(cls, *args, **kwargs):
22 raise TypeError('requires _testcapi.with_tp_del')
23 return C
13 24
14 ### Support code 25 ### Support code
15 ############################################################################### 26 ###############################################################################
16 27
17 # Bug 1055820 has several tests of longstanding bugs involving weakrefs and 28 # Bug 1055820 has several tests of longstanding bugs involving weakrefs and
18 # cyclic gc. 29 # cyclic gc.
19 30
20 # An instance of C1055820 has a self-loop, so becomes cyclic trash when 31 # An instance of C1055820 has a self-loop, so becomes cyclic trash when
21 # unreachable. 32 # unreachable.
22 class C1055820(object): 33 class C1055820(object):
23 def __init__(self, i): 34 def __init__(self, i):
24 self.i = i 35 self.i = i
25 self.loop = self 36 self.loop = self
26 37
27 class GC_Detector(object): 38 class GC_Detector(object):
28 # Create an instance I. Then gc hasn't happened again so long as 39 # Create an instance I. Then gc hasn't happened again so long as
29 # I.gc_happened is false. 40 # I.gc_happened is false.
30 41
31 def __init__(self): 42 def __init__(self):
32 self.gc_happened = False 43 self.gc_happened = False
33 44
34 def it_happened(ignored): 45 def it_happened(ignored):
35 self.gc_happened = True 46 self.gc_happened = True
36 47
37 # Create a piece of cyclic trash that triggers it_happened when 48 # Create a piece of cyclic trash that triggers it_happened when
38 # gc collects it. 49 # gc collects it.
39 self.wr = weakref.ref(C1055820(666), it_happened) 50 self.wr = weakref.ref(C1055820(666), it_happened)
40 51
52 @with_tp_del
41 class Uncollectable(object): 53 class Uncollectable(object):
42 """Create a reference cycle with multiple __del__ methods. 54 """Create a reference cycle with multiple __del__ methods.
43 55
44 An object in a reference cycle will never have zero references, 56 An object in a reference cycle will never have zero references,
45 and so must be garbage collected. If one or more objects in the 57 and so must be garbage collected. If one or more objects in the
46 cycle have __del__ methods, the gc refuses to guess an order, 58 cycle have __del__ methods, the gc refuses to guess an order,
47 and leaves the cycle uncollected.""" 59 and leaves the cycle uncollected."""
48 def __init__(self, partner=None): 60 def __init__(self, partner=None):
49 if partner is None: 61 if partner is None:
50 self.partner = Uncollectable(partner=self) 62 self.partner = Uncollectable(partner=self)
51 else: 63 else:
52 self.partner = partner 64 self.partner = partner
53 def __del__(self): 65 def __tp_del__(self):
54 pass 66 pass
55 67
56 ### Tests 68 ### Tests
57 ############################################################################### 69 ###############################################################################
58 70
59 class GCTests(unittest.TestCase): 71 class GCTests(unittest.TestCase):
60 def test_list(self): 72 def test_list(self):
61 l = [] 73 l = []
62 l.append(l) 74 l.append(l)
63 gc.collect() 75 gc.collect()
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
132 def test_method(self): 144 def test_method(self):
133 # Tricky: self.__init__ is a bound method, it references the instance. 145 # Tricky: self.__init__ is a bound method, it references the instance.
134 class A: 146 class A:
135 def __init__(self): 147 def __init__(self):
136 self.init = self.__init__ 148 self.init = self.__init__
137 a = A() 149 a = A()
138 gc.collect() 150 gc.collect()
139 del a 151 del a
140 self.assertNotEqual(gc.collect(), 0) 152 self.assertNotEqual(gc.collect(), 0)
141 153
142 def test_finalizer(self): 154 @cpython_only
155 def test_legacy_finalizer(self):
143 # A() is uncollectable if it is part of a cycle, make sure it shows up 156 # A() is uncollectable if it is part of a cycle, make sure it shows up
144 # in gc.garbage. 157 # in gc.garbage.
158 @with_tp_del
145 class A: 159 class A:
146 def __del__(self): pass 160 def __tp_del__(self): pass
147 class B: 161 class B:
148 pass 162 pass
149 a = A() 163 a = A()
150 a.a = a 164 a.a = a
151 id_a = id(a) 165 id_a = id(a)
152 b = B() 166 b = B()
153 b.b = b 167 b.b = b
154 gc.collect() 168 gc.collect()
155 del a 169 del a
156 del b 170 del b
157 self.assertNotEqual(gc.collect(), 0) 171 self.assertNotEqual(gc.collect(), 0)
158 for obj in gc.garbage: 172 for obj in gc.garbage:
159 if id(obj) == id_a: 173 if id(obj) == id_a:
160 del obj.a 174 del obj.a
161 break 175 break
162 else: 176 else:
163 self.fail("didn't find obj in garbage (finalizer)") 177 self.fail("didn't find obj in garbage (finalizer)")
164 gc.garbage.remove(obj) 178 gc.garbage.remove(obj)
165 179
166 def test_finalizer_newclass(self): 180 @cpython_only
181 def test_legacy_finalizer_newclass(self):
167 # A() is uncollectable if it is part of a cycle, make sure it shows up 182 # A() is uncollectable if it is part of a cycle, make sure it shows up
168 # in gc.garbage. 183 # in gc.garbage.
184 @with_tp_del
169 class A(object): 185 class A(object):
170 def __del__(self): pass 186 def __tp_del__(self): pass
171 class B(object): 187 class B(object):
172 pass 188 pass
173 a = A() 189 a = A()
174 a.a = a 190 a.a = a
175 id_a = id(a) 191 id_a = id(a)
176 b = B() 192 b = B()
177 b.b = b 193 b.b = b
178 gc.collect() 194 gc.collect()
179 del a 195 del a
180 del b 196 del b
(...skipping 376 matching lines...) Expand 10 before | Expand all | Expand 10 after
557 # the callback materialized a strong reference to an instance, but gc 573 # the callback materialized a strong reference to an instance, but gc
558 # cleared the instance's dict anyway. 574 # cleared the instance's dict anyway.
559 Cs = None 575 Cs = None
560 gc.collect() 576 gc.collect()
561 self.assertEqual(len(ouch), 2) # else the callbacks didn't run 577 self.assertEqual(len(ouch), 2) # else the callbacks didn't run
562 for x in ouch: 578 for x in ouch:
563 # If the callback resurrected one of these guys, the instance 579 # If the callback resurrected one of these guys, the instance
564 # would be damaged, with an empty __dict__. 580 # would be damaged, with an empty __dict__.
565 self.assertEqual(x, None) 581 self.assertEqual(x, None)
566 582
583 @cpython_only
567 def test_garbage_at_shutdown(self): 584 def test_garbage_at_shutdown(self):
568 import subprocess 585 import subprocess
569 code = """if 1: 586 code = """if 1:
570 import gc 587 import gc
588 import _testcapi
589 @_testcapi.with_tp_del
571 class X: 590 class X:
572 def __init__(self, name): 591 def __init__(self, name):
573 self.name = name 592 self.name = name
574 def __repr__(self): 593 def __repr__(self):
575 return "<X %%r>" %% self.name 594 return "<X %%r>" %% self.name
576 def __del__(self): 595 def __tp_del__(self):
577 pass 596 pass
578 597
579 x = X('first') 598 x = X('first')
580 x.x = x 599 x.x = x
581 x.y = X('second') 600 x.y = X('second')
582 del x 601 del x
583 gc.set_debug(%s) 602 gc.set_debug(%s)
584 """ 603 """
585 def run_command(code): 604 def run_command(code):
586 p = subprocess.Popen([sys.executable, "-Wd", "-c", code], 605 p = subprocess.Popen([sys.executable, "-Wd", "-c", code],
(...skipping 15 matching lines...) Expand all
602 self.assertIn(b"ResourceWarning: gc: 2 uncollectable objects at " 621 self.assertIn(b"ResourceWarning: gc: 2 uncollectable objects at "
603 b"shutdown", stderr) 622 b"shutdown", stderr)
604 self.assertTrue( 623 self.assertTrue(
605 (b"[<X 'first'>, <X 'second'>]" in stderr) or 624 (b"[<X 'first'>, <X 'second'>]" in stderr) or
606 (b"[<X 'second'>, <X 'first'>]" in stderr), stderr) 625 (b"[<X 'second'>, <X 'first'>]" in stderr), stderr)
607 # With DEBUG_SAVEALL, no additional message should get printed 626 # With DEBUG_SAVEALL, no additional message should get printed
608 # (because gc.garbage also contains normally reclaimable cyclic 627 # (because gc.garbage also contains normally reclaimable cyclic
609 # references, and its elements get printed at runtime anyway). 628 # references, and its elements get printed at runtime anyway).
610 stderr = run_command(code % "gc.DEBUG_SAVEALL") 629 stderr = run_command(code % "gc.DEBUG_SAVEALL")
611 self.assertNotIn(b"uncollectable objects at shutdown", stderr) 630 self.assertNotIn(b"uncollectable objects at shutdown", stderr)
631
632 def test_gc_main_module_at_shutdown(self):
633 # Create a reference cycle through the __main__ module and check
634 # it gets collected at interpreter shutdown.
635 code = """if 1:
636 import weakref
637 class C:
638 def __del__(self):
639 print('__del__ called')
640 l = [C()]
641 l.append(l)
642 """
643 rc, out, err = assert_python_ok('-c', code)
644 self.assertEqual(out.strip(), b'__del__ called')
645
646 def test_gc_ordinary_module_at_shutdown(self):
647 # Same as above, but with a non-__main__ module.
648 with temp_dir() as script_dir:
649 module = """if 1:
650 import weakref
651 class C:
652 def __del__(self):
653 print('__del__ called')
654 l = [C()]
655 l.append(l)
656 """
657 code = """if 1:
658 import sys
659 sys.path.insert(0, %r)
660 import gctest
661 """ % (script_dir,)
662 make_script(script_dir, 'gctest', module)
663 rc, out, err = assert_python_ok('-c', code)
664 self.assertEqual(out.strip(), b'__del__ called')
612 665
613 def test_get_stats(self): 666 def test_get_stats(self):
614 stats = gc.get_stats() 667 stats = gc.get_stats()
615 self.assertEqual(len(stats), 3) 668 self.assertEqual(len(stats), 3)
616 for st in stats: 669 for st in stats:
617 self.assertIsInstance(st, dict) 670 self.assertIsInstance(st, dict)
618 self.assertEqual(set(st), 671 self.assertEqual(set(st),
619 {"collected", "collections", "uncollectable"}) 672 {"collected", "collections", "uncollectable"})
620 self.assertGreaterEqual(st["collected"], 0) 673 self.assertGreaterEqual(st["collected"], 0)
621 self.assertGreaterEqual(st["collections"], 0) 674 self.assertGreaterEqual(st["collections"], 0)
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
715 self.assertIn("collected", info) 768 self.assertIn("collected", info)
716 self.assertIn("uncollectable", info) 769 self.assertIn("uncollectable", info)
717 770
718 def test_collect_generation(self): 771 def test_collect_generation(self):
719 self.preclean() 772 self.preclean()
720 gc.collect(2) 773 gc.collect(2)
721 for v in self.visit: 774 for v in self.visit:
722 info = v[2] 775 info = v[2]
723 self.assertEqual(info["generation"], 2) 776 self.assertEqual(info["generation"], 2)
724 777
778 @cpython_only
725 def test_collect_garbage(self): 779 def test_collect_garbage(self):
726 self.preclean() 780 self.preclean()
727 # Each of these cause four objects to be garbage: Two 781 # Each of these cause four objects to be garbage: Two
728 # Uncolectables and their instance dicts. 782 # Uncolectables and their instance dicts.
729 Uncollectable() 783 Uncollectable()
730 Uncollectable() 784 Uncollectable()
731 C1055820(666) 785 C1055820(666)
732 gc.collect() 786 gc.collect()
733 for v in self.visit: 787 for v in self.visit:
734 if v[1] != "stop": 788 if v[1] != "stop":
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after
918 if verbose: 972 if verbose:
919 print("restoring automatic collection") 973 print("restoring automatic collection")
920 # make sure to always test gc.enable() 974 # make sure to always test gc.enable()
921 gc.enable() 975 gc.enable()
922 assert gc.isenabled() 976 assert gc.isenabled()
923 if not enabled: 977 if not enabled:
924 gc.disable() 978 gc.disable()
925 979
926 if __name__ == "__main__": 980 if __name__ == "__main__":
927 test_main() 981 test_main()
LEFTRIGHT

RSS Feeds Recent Issues | This issue
This is Rietveld 894c83f36cb7+