5 from test
import test_support
13 def callback(self
, frame
, event
, arg
):
14 self
.add_event(event
, frame
)
16 def add_event(self
, event
, frame
=None):
17 """Add an event to the log."""
19 frame
= sys
._getframe
(1)
22 frameno
= self
.frames
.index(frame
)
24 frameno
= len(self
.frames
)
25 self
.frames
.append(frame
)
27 self
.events
.append((frameno
, event
, ident(frame
)))
30 """Remove calls to add_event()."""
31 disallowed
= [ident(self
.add_event
.im_func
), ident(ident
)]
34 return [item
for item
in self
.events
if item
[2] not in disallowed
]
37 class ProfileSimulator(HookWatcher
):
38 def __init__(self
, testcase
):
39 self
.testcase
= testcase
41 HookWatcher
.__init
__(self
)
43 def callback(self
, frame
, event
, arg
):
44 # Callback registered with sys.setprofile()/sys.settrace()
45 self
.dispatch
[event
](self
, frame
)
47 def trace_call(self
, frame
):
48 self
.add_event('call', frame
)
49 self
.stack
.append(frame
)
51 def trace_return(self
, frame
):
52 self
.add_event('return', frame
)
55 def trace_exception(self
, frame
):
57 "the profiler should never receive exception events")
61 'exception': trace_exception
,
62 'return': trace_return
,
66 class TestCaseBase(unittest
.TestCase
):
67 def check_events(self
, callable, expected
):
68 events
= capture_events(callable, self
.new_watcher())
69 if events
!= expected
:
70 self
.fail("Expected events:\n%s\nReceived events:\n%s"
71 % (pprint
.pformat(expected
), pprint
.pformat(events
)))
74 class ProfileHookTestCase(TestCaseBase
):
75 def new_watcher(self
):
78 def test_simple(self
):
82 self
.check_events(f
, [(1, 'call', f_ident
),
83 (1, 'return', f_ident
),
86 def test_exception(self
):
90 self
.check_events(f
, [(1, 'call', f_ident
),
91 (1, 'return', f_ident
),
94 def test_caught_exception(self
):
99 self
.check_events(f
, [(1, 'call', f_ident
),
100 (1, 'return', f_ident
),
103 def test_caught_nested_exception(self
):
108 self
.check_events(f
, [(1, 'call', f_ident
),
109 (1, 'return', f_ident
),
112 def test_nested_exception(self
):
116 self
.check_events(f
, [(1, 'call', f_ident
),
117 # This isn't what I expected:
118 # (0, 'exception', protect_ident),
119 # I expected this again:
120 (1, 'return', f_ident
),
123 def test_exception_in_except_clause(self
):
134 self
.check_events(g
, [(1, 'call', g_ident
),
135 (2, 'call', f_ident
),
136 (2, 'return', f_ident
),
137 (3, 'call', f_ident
),
138 (3, 'return', f_ident
),
139 (1, 'return', g_ident
),
142 def test_exception_propogation(self
):
147 finally: p
.add_event("falling through")
150 self
.check_events(g
, [(1, 'call', g_ident
),
151 (2, 'call', f_ident
),
152 (2, 'return', f_ident
),
153 (1, 'falling through', g_ident
),
154 (1, 'return', g_ident
),
157 def test_raise_twice(self
):
162 self
.check_events(f
, [(1, 'call', f_ident
),
163 (1, 'return', f_ident
),
166 def test_raise_reraise(self
):
171 self
.check_events(f
, [(1, 'call', f_ident
),
172 (1, 'return', f_ident
),
175 def test_raise(self
):
179 self
.check_events(f
, [(1, 'call', f_ident
),
180 (1, 'return', f_ident
),
183 def test_distant_exception(self
):
199 self
.check_events(j
, [(1, 'call', j_ident
),
200 (2, 'call', i_ident
),
201 (3, 'call', h_ident
),
202 (4, 'call', g_ident
),
203 (5, 'call', f_ident
),
204 (5, 'return', f_ident
),
205 (4, 'return', g_ident
),
206 (3, 'return', h_ident
),
207 (2, 'return', i_ident
),
208 (1, 'return', j_ident
),
211 def test_generator(self
):
220 self
.check_events(g
, [(1, 'call', g_ident
),
221 # call the iterator twice to generate values
222 (2, 'call', f_ident
),
223 (2, 'return', f_ident
),
224 (2, 'call', f_ident
),
225 (2, 'return', f_ident
),
226 # once more; returns end-of-iteration with
227 # actually raising an exception
228 (2, 'call', f_ident
),
229 (2, 'return', f_ident
),
230 (1, 'return', g_ident
),
233 def test_stop_iteration(self
):
243 self
.check_events(g
, [(1, 'call', g_ident
),
244 # call the iterator twice to generate values
245 (2, 'call', f_ident
),
246 (2, 'return', f_ident
),
247 (2, 'call', f_ident
),
248 (2, 'return', f_ident
),
249 # once more to hit the raise:
250 (2, 'call', f_ident
),
251 (2, 'return', f_ident
),
252 (1, 'return', g_ident
),
256 class ProfileSimulatorTestCase(TestCaseBase
):
257 def new_watcher(self
):
258 return ProfileSimulator(self
)
260 def test_simple(self
):
264 self
.check_events(f
, [(1, 'call', f_ident
),
265 (1, 'return', f_ident
),
268 def test_basic_exception(self
):
272 self
.check_events(f
, [(1, 'call', f_ident
),
273 (1, 'return', f_ident
),
276 def test_caught_exception(self
):
281 self
.check_events(f
, [(1, 'call', f_ident
),
282 (1, 'return', f_ident
),
285 def test_distant_exception(self
):
301 self
.check_events(j
, [(1, 'call', j_ident
),
302 (2, 'call', i_ident
),
303 (3, 'call', h_ident
),
304 (4, 'call', g_ident
),
305 (5, 'call', f_ident
),
306 (5, 'return', f_ident
),
307 (4, 'return', g_ident
),
308 (3, 'return', h_ident
),
309 (2, 'return', i_ident
),
310 (1, 'return', j_ident
),
315 if hasattr(function
, "f_code"):
316 code
= function
.f_code
318 code
= function
.func_code
319 return code
.co_firstlineno
, code
.co_name
326 protect_ident
= ident(protect
)
329 def capture_events(callable, p
=None):
335 raise test_support
.TestFailed(
336 'sys.setprofile() did not raise TypeError')
340 sys
.setprofile(p
.callback
)
343 return p
.get_events()[1:-1]
346 def show_events(callable):
348 pprint
.pprint(capture_events(callable))
352 test_support
.run_unittest(
354 ProfileSimulatorTestCase
358 if __name__
== "__main__":