blob: 2dd5780c8890dd540b2f2c8d1ed938385aa0bfe1 [file] [log] [blame]
Antoine Pitrou9e3d27b2013-08-05 23:35:43 +02001import gc
2import sys
3import unittest
4import weakref
5
6from test import support
7
8
9class ClearTest(unittest.TestCase):
10 """
11 Tests for frame.clear().
12 """
13
14 def inner(self, x=5, **kwargs):
15 1/0
16
17 def outer(self, **kwargs):
18 try:
19 self.inner(**kwargs)
20 except ZeroDivisionError as e:
21 exc = e
22 return exc
23
24 def clear_traceback_frames(self, tb):
25 """
26 Clear all frames in a traceback.
27 """
28 while tb is not None:
29 tb.tb_frame.clear()
30 tb = tb.tb_next
31
32 def test_clear_locals(self):
33 class C:
34 pass
35 c = C()
36 wr = weakref.ref(c)
37 exc = self.outer(c=c)
38 del c
39 support.gc_collect()
40 # A reference to c is held through the frames
41 self.assertIsNot(None, wr())
42 self.clear_traceback_frames(exc.__traceback__)
43 support.gc_collect()
44 # The reference was released by .clear()
45 self.assertIs(None, wr())
46
47 def test_clear_generator(self):
48 endly = False
49 def g():
50 nonlocal endly
51 try:
52 yield
53 inner()
54 finally:
55 endly = True
56 gen = g()
57 next(gen)
58 self.assertFalse(endly)
59 # Clearing the frame closes the generator
60 gen.gi_frame.clear()
61 self.assertTrue(endly)
62
63 def test_clear_executing(self):
64 # Attempting to clear an executing frame is forbidden.
65 try:
66 1/0
67 except ZeroDivisionError as e:
68 f = e.__traceback__.tb_frame
69 with self.assertRaises(RuntimeError):
70 f.clear()
71 with self.assertRaises(RuntimeError):
72 f.f_back.clear()
73
74 def test_clear_executing_generator(self):
75 # Attempting to clear an executing generator frame is forbidden.
76 endly = False
77 def g():
78 nonlocal endly
79 try:
80 1/0
81 except ZeroDivisionError as e:
82 f = e.__traceback__.tb_frame
83 with self.assertRaises(RuntimeError):
84 f.clear()
85 with self.assertRaises(RuntimeError):
86 f.f_back.clear()
87 yield f
88 finally:
89 endly = True
90 gen = g()
91 f = next(gen)
92 self.assertFalse(endly)
Antoine Pitroudbfc1292013-08-06 23:05:23 +020093 # Clearing the frame closes the generator
94 f.clear()
95 self.assertTrue(endly)
Antoine Pitrou9e3d27b2013-08-05 23:35:43 +020096
97 @support.cpython_only
98 def test_clear_refcycles(self):
Antoine Pitrou236a5472013-08-06 23:06:59 +020099 # .clear() doesn't leave any refcycle behind
Antoine Pitrou9e3d27b2013-08-05 23:35:43 +0200100 with support.disable_gc():
101 class C:
102 pass
103 c = C()
104 wr = weakref.ref(c)
105 exc = self.outer(c=c)
106 del c
107 self.assertIsNot(None, wr())
108 self.clear_traceback_frames(exc.__traceback__)
109 self.assertIs(None, wr())
110
111
112def test_main():
113 support.run_unittest(__name__)
114
115if __name__ == "__main__":
116 test_main()