blob: 53f882a3feb04e63c549cfb855d9e8d96e296a92 [file] [log] [blame]
Fred Drake3208d4b2001-09-22 04:28:19 +00001import pprint
2import sys
3import unittest
4
Barry Warsaw04f357c2002-07-23 19:04:11 +00005from test import test_support
Fred Drake3208d4b2001-09-22 04:28:19 +00006
7
8class HookWatcher:
9 def __init__(self):
10 self.frames = []
11 self.events = []
12
13 def callback(self, frame, event, arg):
Nicholas Bastinc69ebe82004-03-24 21:57:10 +000014 if (event == "call"
15 or event == "return"
16 or event == "exception"):
17 self.add_event(event, frame)
Fred Drake3208d4b2001-09-22 04:28:19 +000018
19 def add_event(self, event, frame=None):
20 """Add an event to the log."""
21 if frame is None:
22 frame = sys._getframe(1)
23
24 try:
25 frameno = self.frames.index(frame)
26 except ValueError:
27 frameno = len(self.frames)
28 self.frames.append(frame)
29
30 self.events.append((frameno, event, ident(frame)))
31
32 def get_events(self):
33 """Remove calls to add_event()."""
Fred Drake2d879012001-09-24 18:44:11 +000034 disallowed = [ident(self.add_event.im_func), ident(ident)]
35 self.frames = None
Fred Drake3208d4b2001-09-22 04:28:19 +000036
Fred Drake2d879012001-09-24 18:44:11 +000037 return [item for item in self.events if item[2] not in disallowed]
Fred Drake3208d4b2001-09-22 04:28:19 +000038
39
Fred Drake39cd6032001-09-26 21:00:33 +000040class ProfileSimulator(HookWatcher):
Fred Drake7c0a93d2001-10-04 14:49:46 +000041 def __init__(self, testcase):
42 self.testcase = testcase
Fred Drake39cd6032001-09-26 21:00:33 +000043 self.stack = []
44 HookWatcher.__init__(self)
Fred Drake3208d4b2001-09-22 04:28:19 +000045
Fred Drake39cd6032001-09-26 21:00:33 +000046 def callback(self, frame, event, arg):
Fred Drake0099ba72001-10-03 21:15:32 +000047 # Callback registered with sys.setprofile()/sys.settrace()
Fred Drake39cd6032001-09-26 21:00:33 +000048 self.dispatch[event](self, frame)
49
50 def trace_call(self, frame):
51 self.add_event('call', frame)
52 self.stack.append(frame)
53
54 def trace_return(self, frame):
55 self.add_event('return', frame)
56 self.stack.pop()
57
58 def trace_exception(self, frame):
Fred Drake7c0a93d2001-10-04 14:49:46 +000059 self.testcase.fail(
60 "the profiler should never receive exception events")
Fred Drake39cd6032001-09-26 21:00:33 +000061
Nicholas Bastinc69ebe82004-03-24 21:57:10 +000062 def trace_pass(self, frame):
63 pass
64
Fred Drake39cd6032001-09-26 21:00:33 +000065 dispatch = {
66 'call': trace_call,
67 'exception': trace_exception,
68 'return': trace_return,
Nicholas Bastinc69ebe82004-03-24 21:57:10 +000069 'c_call': trace_pass,
70 'c_return': trace_pass,
71 'c_exception': trace_pass,
Fred Drake39cd6032001-09-26 21:00:33 +000072 }
73
74
75class TestCaseBase(unittest.TestCase):
Fred Drake3208d4b2001-09-22 04:28:19 +000076 def check_events(self, callable, expected):
Fred Drake39cd6032001-09-26 21:00:33 +000077 events = capture_events(callable, self.new_watcher())
Fred Drake3208d4b2001-09-22 04:28:19 +000078 if events != expected:
79 self.fail("Expected events:\n%s\nReceived events:\n%s"
80 % (pprint.pformat(expected), pprint.pformat(events)))
81
Fred Drake39cd6032001-09-26 21:00:33 +000082
83class ProfileHookTestCase(TestCaseBase):
84 def new_watcher(self):
85 return HookWatcher()
86
Fred Drake3208d4b2001-09-22 04:28:19 +000087 def test_simple(self):
88 def f(p):
89 pass
90 f_ident = ident(f)
Fred Drakecc91ac02001-09-25 20:48:14 +000091 self.check_events(f, [(1, 'call', f_ident),
92 (1, 'return', f_ident),
Fred Drake3208d4b2001-09-22 04:28:19 +000093 ])
94
95 def test_exception(self):
96 def f(p):
Fred Drakecc91ac02001-09-25 20:48:14 +000097 1/0
98 f_ident = ident(f)
99 self.check_events(f, [(1, 'call', f_ident),
Fred Drake7c0a93d2001-10-04 14:49:46 +0000100 (1, 'return', f_ident),
Fred Drakecc91ac02001-09-25 20:48:14 +0000101 ])
102
103 def test_caught_exception(self):
104 def f(p):
Fred Drake2d879012001-09-24 18:44:11 +0000105 try: 1/0
106 except: pass
Fred Drake3208d4b2001-09-22 04:28:19 +0000107 f_ident = ident(f)
Fred Drakecc91ac02001-09-25 20:48:14 +0000108 self.check_events(f, [(1, 'call', f_ident),
Fred Drakecc91ac02001-09-25 20:48:14 +0000109 (1, 'return', f_ident),
Fred Drake3208d4b2001-09-22 04:28:19 +0000110 ])
111
Fred Drake2d879012001-09-24 18:44:11 +0000112 def test_caught_nested_exception(self):
113 def f(p):
114 try: 1/0
115 except: pass
Fred Drake2d879012001-09-24 18:44:11 +0000116 f_ident = ident(f)
Fred Drakecc91ac02001-09-25 20:48:14 +0000117 self.check_events(f, [(1, 'call', f_ident),
Fred Drake2d879012001-09-24 18:44:11 +0000118 (1, 'return', f_ident),
Fred Drake2d879012001-09-24 18:44:11 +0000119 ])
120
Fred Drake3208d4b2001-09-22 04:28:19 +0000121 def test_nested_exception(self):
122 def f(p):
123 1/0
Fred Drake3208d4b2001-09-22 04:28:19 +0000124 f_ident = ident(f)
Fred Drakecc91ac02001-09-25 20:48:14 +0000125 self.check_events(f, [(1, 'call', f_ident),
Fred Drake3208d4b2001-09-22 04:28:19 +0000126 # This isn't what I expected:
Fred Drake7c0a93d2001-10-04 14:49:46 +0000127 # (0, 'exception', protect_ident),
Fred Drake2d879012001-09-24 18:44:11 +0000128 # I expected this again:
Fred Drake7c0a93d2001-10-04 14:49:46 +0000129 (1, 'return', f_ident),
Fred Drake3208d4b2001-09-22 04:28:19 +0000130 ])
131
Fred Drake2d879012001-09-24 18:44:11 +0000132 def test_exception_in_except_clause(self):
133 def f(p):
134 1/0
135 def g(p):
136 try:
137 f(p)
138 except:
139 try: f(p)
140 except: pass
141 f_ident = ident(f)
142 g_ident = ident(g)
Fred Drakecc91ac02001-09-25 20:48:14 +0000143 self.check_events(g, [(1, 'call', g_ident),
Fred Drake2d879012001-09-24 18:44:11 +0000144 (2, 'call', f_ident),
Fred Drake7c0a93d2001-10-04 14:49:46 +0000145 (2, 'return', f_ident),
Fred Drakecc91ac02001-09-25 20:48:14 +0000146 (3, 'call', f_ident),
Fred Drake7c0a93d2001-10-04 14:49:46 +0000147 (3, 'return', f_ident),
Fred Drakecc91ac02001-09-25 20:48:14 +0000148 (1, 'return', g_ident),
Fred Drake2d879012001-09-24 18:44:11 +0000149 ])
150
151 def test_exception_propogation(self):
152 def f(p):
153 1/0
154 def g(p):
155 try: f(p)
156 finally: p.add_event("falling through")
Fred Drake2d879012001-09-24 18:44:11 +0000157 f_ident = ident(f)
158 g_ident = ident(g)
Fred Drakecc91ac02001-09-25 20:48:14 +0000159 self.check_events(g, [(1, 'call', g_ident),
Fred Drake2d879012001-09-24 18:44:11 +0000160 (2, 'call', f_ident),
Fred Drake7c0a93d2001-10-04 14:49:46 +0000161 (2, 'return', f_ident),
Fred Drake2d879012001-09-24 18:44:11 +0000162 (1, 'falling through', g_ident),
Fred Drake7c0a93d2001-10-04 14:49:46 +0000163 (1, 'return', g_ident),
Fred Drake2d879012001-09-24 18:44:11 +0000164 ])
Fred Drake3208d4b2001-09-22 04:28:19 +0000165
Fred Drakecc91ac02001-09-25 20:48:14 +0000166 def test_raise_twice(self):
167 def f(p):
168 try: 1/0
169 except: 1/0
170 f_ident = ident(f)
171 self.check_events(f, [(1, 'call', f_ident),
Fred Drake7c0a93d2001-10-04 14:49:46 +0000172 (1, 'return', f_ident),
Fred Drakecc91ac02001-09-25 20:48:14 +0000173 ])
174
175 def test_raise_reraise(self):
176 def f(p):
177 try: 1/0
178 except: raise
179 f_ident = ident(f)
180 self.check_events(f, [(1, 'call', f_ident),
Fred Drake7c0a93d2001-10-04 14:49:46 +0000181 (1, 'return', f_ident),
Fred Drakecc91ac02001-09-25 20:48:14 +0000182 ])
183
184 def test_raise(self):
185 def f(p):
186 raise Exception()
187 f_ident = ident(f)
188 self.check_events(f, [(1, 'call', f_ident),
Fred Drake7c0a93d2001-10-04 14:49:46 +0000189 (1, 'return', f_ident),
Fred Drakecc91ac02001-09-25 20:48:14 +0000190 ])
191
Fred Drake0099ba72001-10-03 21:15:32 +0000192 def test_distant_exception(self):
193 def f():
194 1/0
195 def g():
196 f()
197 def h():
198 g()
199 def i():
200 h()
201 def j(p):
202 i()
203 f_ident = ident(f)
204 g_ident = ident(g)
205 h_ident = ident(h)
206 i_ident = ident(i)
207 j_ident = ident(j)
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),
Fred Drake7c0a93d2001-10-04 14:49:46 +0000213 (5, 'return', f_ident),
214 (4, 'return', g_ident),
215 (3, 'return', h_ident),
216 (2, 'return', i_ident),
217 (1, 'return', j_ident),
Fred Drake0099ba72001-10-03 21:15:32 +0000218 ])
219
220 def test_generator(self):
221 def f():
222 for i in range(2):
223 yield i
224 def g(p):
225 for i in f():
226 pass
227 f_ident = ident(f)
228 g_ident = ident(g)
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),
240 ])
241
242 def test_stop_iteration(self):
243 def f():
244 for i in range(2):
245 yield i
246 raise StopIteration
247 def g(p):
248 for i in f():
249 pass
250 f_ident = ident(f)
251 g_ident = ident(g)
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),
Fred Drake7c0a93d2001-10-04 14:49:46 +0000260 (2, 'return', f_ident),
Fred Drake0099ba72001-10-03 21:15:32 +0000261 (1, 'return', g_ident),
262 ])
263
Fred Drakecc91ac02001-09-25 20:48:14 +0000264
Fred Drake39cd6032001-09-26 21:00:33 +0000265class ProfileSimulatorTestCase(TestCaseBase):
266 def new_watcher(self):
Fred Drake7c0a93d2001-10-04 14:49:46 +0000267 return ProfileSimulator(self)
Fred Drake39cd6032001-09-26 21:00:33 +0000268
269 def test_simple(self):
270 def f(p):
271 pass
272 f_ident = ident(f)
273 self.check_events(f, [(1, 'call', f_ident),
274 (1, 'return', f_ident),
275 ])
276
277 def test_basic_exception(self):
278 def f(p):
279 1/0
280 f_ident = ident(f)
281 self.check_events(f, [(1, 'call', f_ident),
Fred Drake7c0a93d2001-10-04 14:49:46 +0000282 (1, 'return', f_ident),
Fred Drake39cd6032001-09-26 21:00:33 +0000283 ])
284
Fred Drake0099ba72001-10-03 21:15:32 +0000285 def test_caught_exception(self):
286 def f(p):
287 try: 1/0
288 except: pass
289 f_ident = ident(f)
290 self.check_events(f, [(1, 'call', f_ident),
Fred Drake0099ba72001-10-03 21:15:32 +0000291 (1, 'return', f_ident),
292 ])
293
294 def test_distant_exception(self):
295 def f():
296 1/0
297 def g():
298 f()
299 def h():
300 g()
301 def i():
302 h()
303 def j(p):
304 i()
305 f_ident = ident(f)
306 g_ident = ident(g)
307 h_ident = ident(h)
308 i_ident = ident(i)
309 j_ident = ident(j)
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),
Fred Drake7c0a93d2001-10-04 14:49:46 +0000315 (5, 'return', f_ident),
316 (4, 'return', g_ident),
317 (3, 'return', h_ident),
318 (2, 'return', i_ident),
319 (1, 'return', j_ident),
Fred Drake0099ba72001-10-03 21:15:32 +0000320 ])
321
Fred Drake39cd6032001-09-26 21:00:33 +0000322
Fred Drake3208d4b2001-09-22 04:28:19 +0000323def ident(function):
324 if hasattr(function, "f_code"):
325 code = function.f_code
326 else:
327 code = function.func_code
328 return code.co_firstlineno, code.co_name
329
330
Fred Drakecc91ac02001-09-25 20:48:14 +0000331def protect(f, p):
332 try: f(p)
333 except: pass
334
335protect_ident = ident(protect)
336
337
Fred Drake39cd6032001-09-26 21:00:33 +0000338def capture_events(callable, p=None):
Barry Warsaw04f357c2002-07-23 19:04:11 +0000339 try:
340 sys.setprofile()
341 except TypeError:
342 pass
343 else:
344 raise test_support.TestFailed(
345 'sys.setprofile() did not raise TypeError')
Neal Norwitz290d31e2002-03-03 15:12:58 +0000346
Fred Drake39cd6032001-09-26 21:00:33 +0000347 if p is None:
348 p = HookWatcher()
Fred Drake3208d4b2001-09-22 04:28:19 +0000349 sys.setprofile(p.callback)
Fred Drakecc91ac02001-09-25 20:48:14 +0000350 protect(callable, p)
Fred Drake3208d4b2001-09-22 04:28:19 +0000351 sys.setprofile(None)
Fred Drakecc91ac02001-09-25 20:48:14 +0000352 return p.get_events()[1:-1]
Fred Drake3208d4b2001-09-22 04:28:19 +0000353
354
355def show_events(callable):
356 import pprint
357 pprint.pprint(capture_events(callable))
358
359
360def test_main():
Walter Dörwald21d3a322003-05-01 17:45:56 +0000361 test_support.run_unittest(
362 ProfileHookTestCase,
363 ProfileSimulatorTestCase
364 )
Fred Drake3208d4b2001-09-22 04:28:19 +0000365
366
367if __name__ == "__main__":
368 test_main()