blob: cabfef236dd95c08f9f79579b16633c9c37dbed1 [file] [log] [blame]
Antoine Pitrouacc8cf22014-07-04 20:24:13 -04001import types
Antoine Pitrou9e3d27b2013-08-05 23:35:43 +02002import unittest
3import weakref
4
5from test import support
6
7
8class ClearTest(unittest.TestCase):
9 """
10 Tests for frame.clear().
11 """
12
13 def inner(self, x=5, **kwargs):
14 1/0
15
16 def outer(self, **kwargs):
17 try:
18 self.inner(**kwargs)
19 except ZeroDivisionError as e:
20 exc = e
21 return exc
22
23 def clear_traceback_frames(self, tb):
24 """
25 Clear all frames in a traceback.
26 """
27 while tb is not None:
28 tb.tb_frame.clear()
29 tb = tb.tb_next
30
31 def test_clear_locals(self):
32 class C:
33 pass
34 c = C()
35 wr = weakref.ref(c)
36 exc = self.outer(c=c)
37 del c
38 support.gc_collect()
39 # A reference to c is held through the frames
40 self.assertIsNot(None, wr())
41 self.clear_traceback_frames(exc.__traceback__)
42 support.gc_collect()
43 # The reference was released by .clear()
44 self.assertIs(None, wr())
45
46 def test_clear_generator(self):
47 endly = False
48 def g():
49 nonlocal endly
50 try:
51 yield
52 inner()
53 finally:
54 endly = True
55 gen = g()
56 next(gen)
57 self.assertFalse(endly)
58 # Clearing the frame closes the generator
59 gen.gi_frame.clear()
60 self.assertTrue(endly)
61
62 def test_clear_executing(self):
63 # Attempting to clear an executing frame is forbidden.
64 try:
65 1/0
66 except ZeroDivisionError as e:
67 f = e.__traceback__.tb_frame
68 with self.assertRaises(RuntimeError):
69 f.clear()
70 with self.assertRaises(RuntimeError):
71 f.f_back.clear()
72
73 def test_clear_executing_generator(self):
74 # Attempting to clear an executing generator frame is forbidden.
75 endly = False
76 def g():
77 nonlocal endly
78 try:
79 1/0
80 except ZeroDivisionError as e:
81 f = e.__traceback__.tb_frame
82 with self.assertRaises(RuntimeError):
83 f.clear()
84 with self.assertRaises(RuntimeError):
85 f.f_back.clear()
86 yield f
87 finally:
88 endly = True
89 gen = g()
90 f = next(gen)
91 self.assertFalse(endly)
Antoine Pitroudbfc1292013-08-06 23:05:23 +020092 # Clearing the frame closes the generator
93 f.clear()
94 self.assertTrue(endly)
Antoine Pitrou9e3d27b2013-08-05 23:35:43 +020095
96 @support.cpython_only
97 def test_clear_refcycles(self):
Antoine Pitrou236a5472013-08-06 23:06:59 +020098 # .clear() doesn't leave any refcycle behind
Antoine Pitrou9e3d27b2013-08-05 23:35:43 +020099 with support.disable_gc():
100 class C:
101 pass
102 c = C()
103 wr = weakref.ref(c)
104 exc = self.outer(c=c)
105 del c
106 self.assertIsNot(None, wr())
107 self.clear_traceback_frames(exc.__traceback__)
108 self.assertIs(None, wr())
109
110
Antoine Pitrouacc8cf22014-07-04 20:24:13 -0400111class FrameLocalsTest(unittest.TestCase):
112 """
113 Tests for the .f_locals attribute.
114 """
115
116 def make_frames(self):
117 def outer():
118 x = 5
119 y = 6
120 def inner():
121 z = x + 2
122 1/0
123 t = 9
124 return inner()
125 try:
126 outer()
127 except ZeroDivisionError as e:
128 tb = e.__traceback__
129 frames = []
130 while tb:
131 frames.append(tb.tb_frame)
132 tb = tb.tb_next
133 return frames
134
135 def test_locals(self):
136 f, outer, inner = self.make_frames()
137 outer_locals = outer.f_locals
138 self.assertIsInstance(outer_locals.pop('inner'), types.FunctionType)
139 self.assertEqual(outer_locals, {'x': 5, 'y': 6})
140 inner_locals = inner.f_locals
141 self.assertEqual(inner_locals, {'x': 5, 'z': 7})
142
143 def test_clear_locals(self):
144 # Test f_locals after clear() (issue #21897)
145 f, outer, inner = self.make_frames()
146 outer.clear()
147 inner.clear()
148 self.assertEqual(outer.f_locals, {})
149 self.assertEqual(inner.f_locals, {})
150
151 def test_locals_clear_locals(self):
152 # Test f_locals before and after clear() (to exercise caching)
153 f, outer, inner = self.make_frames()
154 outer.f_locals
155 inner.f_locals
156 outer.clear()
157 inner.clear()
158 self.assertEqual(outer.f_locals, {})
159 self.assertEqual(inner.f_locals, {})
160
161
Antoine Pitrou9e3d27b2013-08-05 23:35:43 +0200162if __name__ == "__main__":
Zachary Ware38c707e2015-04-13 15:00:43 -0500163 unittest.main()