5 from test
import test_support
13 def callback(self
, frame
, event
, arg
):
16 or event
== "exception"):
17 self
.add_event(event
, frame
)
19 def add_event(self
, event
, frame
=None):
20 """Add an event to the log."""
22 frame
= sys
._getframe
(1)
25 frameno
= self
.frames
.index(frame
)
27 frameno
= len(self
.frames
)
28 self
.frames
.append(frame
)
30 self
.events
.append((frameno
, event
, ident(frame
)))
33 """Remove calls to add_event()."""
34 disallowed
= [ident(self
.add_event
.im_func
), ident(ident
)]
37 return [item
for item
in self
.events
if item
[2] not in disallowed
]
40 class ProfileSimulator(HookWatcher
):
41 def __init__(self
, testcase
):
42 self
.testcase
= testcase
44 HookWatcher
.__init
__(self
)
46 def callback(self
, frame
, event
, arg
):
47 # Callback registered with sys.setprofile()/sys.settrace()
48 self
.dispatch
[event
](self
, frame
)
50 def trace_call(self
, frame
):
51 self
.add_event('call', frame
)
52 self
.stack
.append(frame
)
54 def trace_return(self
, frame
):
55 self
.add_event('return', frame
)
58 def trace_exception(self
, frame
):
60 "the profiler should never receive exception events")
62 def trace_pass(self
, frame
):
67 'exception': trace_exception
,
68 'return': trace_return
,
70 'c_return': trace_pass
,
71 'c_exception': trace_pass
,
75 class TestCaseBase(unittest
.TestCase
):
76 def check_events(self
, callable, expected
):
77 events
= capture_events(callable, self
.new_watcher())
78 if events
!= expected
:
79 self
.fail("Expected events:\n%s\nReceived events:\n%s"
80 % (pprint
.pformat(expected
), pprint
.pformat(events
)))
83 class ProfileHookTestCase(TestCaseBase
):
84 def new_watcher(self
):
87 def test_simple(self
):
91 self
.check_events(f
, [(1, 'call', f_ident
),
92 (1, 'return', f_ident
),
95 def test_exception(self
):
99 self
.check_events(f
, [(1, 'call', f_ident
),
100 (1, 'return', f_ident
),
103 def test_caught_exception(self
):
108 self
.check_events(f
, [(1, 'call', f_ident
),
109 (1, 'return', f_ident
),
112 def test_caught_nested_exception(self
):
117 self
.check_events(f
, [(1, 'call', f_ident
),
118 (1, 'return', f_ident
),
121 def test_nested_exception(self
):
125 self
.check_events(f
, [(1, 'call', f_ident
),
126 # This isn't what I expected:
127 # (0, 'exception', protect_ident),
128 # I expected this again:
129 (1, 'return', f_ident
),
132 def test_exception_in_except_clause(self
):
143 self
.check_events(g
, [(1, 'call', g_ident
),
144 (2, 'call', f_ident
),
145 (2, 'return', f_ident
),
146 (3, 'call', f_ident
),
147 (3, 'return', f_ident
),
148 (1, 'return', g_ident
),
151 def test_exception_propogation(self
):
156 finally: p
.add_event("falling through")
159 self
.check_events(g
, [(1, 'call', g_ident
),
160 (2, 'call', f_ident
),
161 (2, 'return', f_ident
),
162 (1, 'falling through', g_ident
),
163 (1, 'return', g_ident
),
166 def test_raise_twice(self
):
171 self
.check_events(f
, [(1, 'call', f_ident
),
172 (1, 'return', f_ident
),
175 def test_raise_reraise(self
):
180 self
.check_events(f
, [(1, 'call', f_ident
),
181 (1, 'return', f_ident
),
184 def test_raise(self
):
188 self
.check_events(f
, [(1, 'call', f_ident
),
189 (1, 'return', f_ident
),
192 def test_distant_exception(self
):
208 self
.check_events(j
, [(1, 'call', j_ident
),
209 (2, 'call', i_ident
),
210 (3, 'call', h_ident
),
211 (4, 'call', g_ident
),
212 (5, 'call', f_ident
),
213 (5, 'return', f_ident
),
214 (4, 'return', g_ident
),
215 (3, 'return', h_ident
),
216 (2, 'return', i_ident
),
217 (1, 'return', j_ident
),
220 def test_generator(self
):
229 self
.check_events(g
, [(1, 'call', g_ident
),
230 # call the iterator twice to generate values
231 (2, 'call', f_ident
),
232 (2, 'return', f_ident
),
233 (2, 'call', f_ident
),
234 (2, 'return', f_ident
),
235 # once more; returns end-of-iteration with
236 # actually raising an exception
237 (2, 'call', f_ident
),
238 (2, 'return', f_ident
),
239 (1, 'return', g_ident
),
242 def test_stop_iteration(self
):
252 self
.check_events(g
, [(1, 'call', g_ident
),
253 # call the iterator twice to generate values
254 (2, 'call', f_ident
),
255 (2, 'return', f_ident
),
256 (2, 'call', f_ident
),
257 (2, 'return', f_ident
),
258 # once more to hit the raise:
259 (2, 'call', f_ident
),
260 (2, 'return', f_ident
),
261 (1, 'return', g_ident
),
265 class ProfileSimulatorTestCase(TestCaseBase
):
266 def new_watcher(self
):
267 return ProfileSimulator(self
)
269 def test_simple(self
):
273 self
.check_events(f
, [(1, 'call', f_ident
),
274 (1, 'return', f_ident
),
277 def test_basic_exception(self
):
281 self
.check_events(f
, [(1, 'call', f_ident
),
282 (1, 'return', f_ident
),
285 def test_caught_exception(self
):
290 self
.check_events(f
, [(1, 'call', f_ident
),
291 (1, 'return', f_ident
),
294 def test_distant_exception(self
):
310 self
.check_events(j
, [(1, 'call', j_ident
),
311 (2, 'call', i_ident
),
312 (3, 'call', h_ident
),
313 (4, 'call', g_ident
),
314 (5, 'call', f_ident
),
315 (5, 'return', f_ident
),
316 (4, 'return', g_ident
),
317 (3, 'return', h_ident
),
318 (2, 'return', i_ident
),
319 (1, 'return', j_ident
),
324 if hasattr(function
, "f_code"):
325 code
= function
.f_code
327 code
= function
.func_code
328 return code
.co_firstlineno
, code
.co_name
335 protect_ident
= ident(protect
)
338 def capture_events(callable, p
=None):
344 raise test_support
.TestFailed(
345 'sys.setprofile() did not raise TypeError')
349 sys
.setprofile(p
.callback
)
352 return p
.get_events()[1:-1]
355 def show_events(callable):
357 pprint
.pprint(capture_events(callable))
361 test_support
.run_unittest(
363 ProfileSimulatorTestCase
367 if __name__
== "__main__":