blob: cc97df8dc4512cbe794118ee4a0bccea338e00de [file] [log] [blame]
Fred Drake0099ba72001-10-03 21:15:32 +00001from __future__ import generators
2
Fred Drake3208d4b2001-09-22 04:28:19 +00003import pprint
4import sys
5import unittest
6
7import test_support
8
9
10class HookWatcher:
11 def __init__(self):
12 self.frames = []
13 self.events = []
14
15 def callback(self, frame, event, arg):
16 self.add_event(event, frame)
17
18 def add_event(self, event, frame=None):
19 """Add an event to the log."""
20 if frame is None:
21 frame = sys._getframe(1)
22
23 try:
24 frameno = self.frames.index(frame)
25 except ValueError:
26 frameno = len(self.frames)
27 self.frames.append(frame)
28
29 self.events.append((frameno, event, ident(frame)))
30
31 def get_events(self):
32 """Remove calls to add_event()."""
Fred Drake2d879012001-09-24 18:44:11 +000033 disallowed = [ident(self.add_event.im_func), ident(ident)]
34 self.frames = None
Fred Drake3208d4b2001-09-22 04:28:19 +000035
Fred Drake2d879012001-09-24 18:44:11 +000036 return [item for item in self.events if item[2] not in disallowed]
Fred Drake3208d4b2001-09-22 04:28:19 +000037
38
Fred Drake39cd6032001-09-26 21:00:33 +000039class ProfileSimulator(HookWatcher):
Fred Drake7c0a93d2001-10-04 14:49:46 +000040 def __init__(self, testcase):
41 self.testcase = testcase
Fred Drake39cd6032001-09-26 21:00:33 +000042 self.stack = []
43 HookWatcher.__init__(self)
Fred Drake3208d4b2001-09-22 04:28:19 +000044
Fred Drake39cd6032001-09-26 21:00:33 +000045 def callback(self, frame, event, arg):
Fred Drake0099ba72001-10-03 21:15:32 +000046 # Callback registered with sys.setprofile()/sys.settrace()
Fred Drake39cd6032001-09-26 21:00:33 +000047 self.dispatch[event](self, frame)
48
49 def trace_call(self, frame):
50 self.add_event('call', frame)
51 self.stack.append(frame)
52
53 def trace_return(self, frame):
54 self.add_event('return', frame)
55 self.stack.pop()
56
57 def trace_exception(self, frame):
Fred Drake7c0a93d2001-10-04 14:49:46 +000058 self.testcase.fail(
59 "the profiler should never receive exception events")
Fred Drake39cd6032001-09-26 21:00:33 +000060
61 dispatch = {
62 'call': trace_call,
63 'exception': trace_exception,
64 'return': trace_return,
65 }
66
67
68class TestCaseBase(unittest.TestCase):
Fred Drake3208d4b2001-09-22 04:28:19 +000069 def check_events(self, callable, expected):
Fred Drake39cd6032001-09-26 21:00:33 +000070 events = capture_events(callable, self.new_watcher())
Fred Drake3208d4b2001-09-22 04:28:19 +000071 if events != expected:
72 self.fail("Expected events:\n%s\nReceived events:\n%s"
73 % (pprint.pformat(expected), pprint.pformat(events)))
74
Fred Drake39cd6032001-09-26 21:00:33 +000075
76class ProfileHookTestCase(TestCaseBase):
77 def new_watcher(self):
78 return HookWatcher()
79
Fred Drake3208d4b2001-09-22 04:28:19 +000080 def test_simple(self):
81 def f(p):
82 pass
83 f_ident = ident(f)
Fred Drakecc91ac02001-09-25 20:48:14 +000084 self.check_events(f, [(1, 'call', f_ident),
85 (1, 'return', f_ident),
Fred Drake3208d4b2001-09-22 04:28:19 +000086 ])
87
88 def test_exception(self):
89 def f(p):
Fred Drakecc91ac02001-09-25 20:48:14 +000090 1/0
91 f_ident = ident(f)
92 self.check_events(f, [(1, 'call', f_ident),
Fred Drake7c0a93d2001-10-04 14:49:46 +000093 (1, 'return', f_ident),
Fred Drakecc91ac02001-09-25 20:48:14 +000094 ])
95
96 def test_caught_exception(self):
97 def f(p):
Fred Drake2d879012001-09-24 18:44:11 +000098 try: 1/0
99 except: pass
Fred Drake3208d4b2001-09-22 04:28:19 +0000100 f_ident = ident(f)
Fred Drakecc91ac02001-09-25 20:48:14 +0000101 self.check_events(f, [(1, 'call', f_ident),
Fred Drakecc91ac02001-09-25 20:48:14 +0000102 (1, 'return', f_ident),
Fred Drake3208d4b2001-09-22 04:28:19 +0000103 ])
104
Fred Drake2d879012001-09-24 18:44:11 +0000105 def test_caught_nested_exception(self):
106 def f(p):
107 try: 1/0
108 except: pass
Fred Drake2d879012001-09-24 18:44:11 +0000109 f_ident = ident(f)
Fred Drakecc91ac02001-09-25 20:48:14 +0000110 self.check_events(f, [(1, 'call', f_ident),
Fred Drake2d879012001-09-24 18:44:11 +0000111 (1, 'return', f_ident),
Fred Drake2d879012001-09-24 18:44:11 +0000112 ])
113
Fred Drake3208d4b2001-09-22 04:28:19 +0000114 def test_nested_exception(self):
115 def f(p):
116 1/0
Fred Drake3208d4b2001-09-22 04:28:19 +0000117 f_ident = ident(f)
Fred Drakecc91ac02001-09-25 20:48:14 +0000118 self.check_events(f, [(1, 'call', f_ident),
Fred Drake3208d4b2001-09-22 04:28:19 +0000119 # This isn't what I expected:
Fred Drake7c0a93d2001-10-04 14:49:46 +0000120 # (0, 'exception', protect_ident),
Fred Drake2d879012001-09-24 18:44:11 +0000121 # I expected this again:
Fred Drake7c0a93d2001-10-04 14:49:46 +0000122 (1, 'return', f_ident),
Fred Drake3208d4b2001-09-22 04:28:19 +0000123 ])
124
Fred Drake2d879012001-09-24 18:44:11 +0000125 def test_exception_in_except_clause(self):
126 def f(p):
127 1/0
128 def g(p):
129 try:
130 f(p)
131 except:
132 try: f(p)
133 except: pass
134 f_ident = ident(f)
135 g_ident = ident(g)
Fred Drakecc91ac02001-09-25 20:48:14 +0000136 self.check_events(g, [(1, 'call', g_ident),
Fred Drake2d879012001-09-24 18:44:11 +0000137 (2, 'call', f_ident),
Fred Drake7c0a93d2001-10-04 14:49:46 +0000138 (2, 'return', f_ident),
Fred Drakecc91ac02001-09-25 20:48:14 +0000139 (3, 'call', f_ident),
Fred Drake7c0a93d2001-10-04 14:49:46 +0000140 (3, 'return', f_ident),
Fred Drakecc91ac02001-09-25 20:48:14 +0000141 (1, 'return', g_ident),
Fred Drake2d879012001-09-24 18:44:11 +0000142 ])
143
144 def test_exception_propogation(self):
145 def f(p):
146 1/0
147 def g(p):
148 try: f(p)
149 finally: p.add_event("falling through")
Fred Drake2d879012001-09-24 18:44:11 +0000150 f_ident = ident(f)
151 g_ident = ident(g)
Fred Drakecc91ac02001-09-25 20:48:14 +0000152 self.check_events(g, [(1, 'call', g_ident),
Fred Drake2d879012001-09-24 18:44:11 +0000153 (2, 'call', f_ident),
Fred Drake7c0a93d2001-10-04 14:49:46 +0000154 (2, 'return', f_ident),
Fred Drake2d879012001-09-24 18:44:11 +0000155 (1, 'falling through', g_ident),
Fred Drake7c0a93d2001-10-04 14:49:46 +0000156 (1, 'return', g_ident),
Fred Drake2d879012001-09-24 18:44:11 +0000157 ])
Fred Drake3208d4b2001-09-22 04:28:19 +0000158
Fred Drakecc91ac02001-09-25 20:48:14 +0000159 def test_raise_twice(self):
160 def f(p):
161 try: 1/0
162 except: 1/0
163 f_ident = ident(f)
164 self.check_events(f, [(1, 'call', f_ident),
Fred Drake7c0a93d2001-10-04 14:49:46 +0000165 (1, 'return', f_ident),
Fred Drakecc91ac02001-09-25 20:48:14 +0000166 ])
167
168 def test_raise_reraise(self):
169 def f(p):
170 try: 1/0
171 except: raise
172 f_ident = ident(f)
173 self.check_events(f, [(1, 'call', f_ident),
Fred Drake7c0a93d2001-10-04 14:49:46 +0000174 (1, 'return', f_ident),
Fred Drakecc91ac02001-09-25 20:48:14 +0000175 ])
176
177 def test_raise(self):
178 def f(p):
179 raise Exception()
180 f_ident = ident(f)
181 self.check_events(f, [(1, 'call', f_ident),
Fred Drake7c0a93d2001-10-04 14:49:46 +0000182 (1, 'return', f_ident),
Fred Drakecc91ac02001-09-25 20:48:14 +0000183 ])
184
Fred Drake0099ba72001-10-03 21:15:32 +0000185 def test_distant_exception(self):
186 def f():
187 1/0
188 def g():
189 f()
190 def h():
191 g()
192 def i():
193 h()
194 def j(p):
195 i()
196 f_ident = ident(f)
197 g_ident = ident(g)
198 h_ident = ident(h)
199 i_ident = ident(i)
200 j_ident = ident(j)
201 self.check_events(j, [(1, 'call', j_ident),
202 (2, 'call', i_ident),
203 (3, 'call', h_ident),
204 (4, 'call', g_ident),
205 (5, 'call', f_ident),
Fred Drake7c0a93d2001-10-04 14:49:46 +0000206 (5, 'return', f_ident),
207 (4, 'return', g_ident),
208 (3, 'return', h_ident),
209 (2, 'return', i_ident),
210 (1, 'return', j_ident),
Fred Drake0099ba72001-10-03 21:15:32 +0000211 ])
212
213 def test_generator(self):
214 def f():
215 for i in range(2):
216 yield i
217 def g(p):
218 for i in f():
219 pass
220 f_ident = ident(f)
221 g_ident = ident(g)
222 self.check_events(g, [(1, 'call', g_ident),
223 # call the iterator twice to generate values
224 (2, 'call', f_ident),
225 (2, 'return', f_ident),
226 (2, 'call', f_ident),
227 (2, 'return', f_ident),
228 # once more; returns end-of-iteration with
229 # actually raising an exception
230 (2, 'call', f_ident),
231 (2, 'return', f_ident),
232 (1, 'return', g_ident),
233 ])
234
235 def test_stop_iteration(self):
236 def f():
237 for i in range(2):
238 yield i
239 raise StopIteration
240 def g(p):
241 for i in f():
242 pass
243 f_ident = ident(f)
244 g_ident = ident(g)
245 self.check_events(g, [(1, 'call', g_ident),
246 # call the iterator twice to generate values
247 (2, 'call', f_ident),
248 (2, 'return', f_ident),
249 (2, 'call', f_ident),
250 (2, 'return', f_ident),
251 # once more to hit the raise:
252 (2, 'call', f_ident),
Fred Drake7c0a93d2001-10-04 14:49:46 +0000253 (2, 'return', f_ident),
Fred Drake0099ba72001-10-03 21:15:32 +0000254 (1, 'return', g_ident),
255 ])
256
Fred Drakecc91ac02001-09-25 20:48:14 +0000257
Fred Drake39cd6032001-09-26 21:00:33 +0000258class ProfileSimulatorTestCase(TestCaseBase):
259 def new_watcher(self):
Fred Drake7c0a93d2001-10-04 14:49:46 +0000260 return ProfileSimulator(self)
Fred Drake39cd6032001-09-26 21:00:33 +0000261
262 def test_simple(self):
263 def f(p):
264 pass
265 f_ident = ident(f)
266 self.check_events(f, [(1, 'call', f_ident),
267 (1, 'return', f_ident),
268 ])
269
270 def test_basic_exception(self):
271 def f(p):
272 1/0
273 f_ident = ident(f)
274 self.check_events(f, [(1, 'call', f_ident),
Fred Drake7c0a93d2001-10-04 14:49:46 +0000275 (1, 'return', f_ident),
Fred Drake39cd6032001-09-26 21:00:33 +0000276 ])
277
Fred Drake0099ba72001-10-03 21:15:32 +0000278 def test_caught_exception(self):
279 def f(p):
280 try: 1/0
281 except: pass
282 f_ident = ident(f)
283 self.check_events(f, [(1, 'call', f_ident),
Fred Drake0099ba72001-10-03 21:15:32 +0000284 (1, 'return', f_ident),
285 ])
286
287 def test_distant_exception(self):
288 def f():
289 1/0
290 def g():
291 f()
292 def h():
293 g()
294 def i():
295 h()
296 def j(p):
297 i()
298 f_ident = ident(f)
299 g_ident = ident(g)
300 h_ident = ident(h)
301 i_ident = ident(i)
302 j_ident = ident(j)
303 self.check_events(j, [(1, 'call', j_ident),
304 (2, 'call', i_ident),
305 (3, 'call', h_ident),
306 (4, 'call', g_ident),
307 (5, 'call', f_ident),
Fred Drake7c0a93d2001-10-04 14:49:46 +0000308 (5, 'return', f_ident),
309 (4, 'return', g_ident),
310 (3, 'return', h_ident),
311 (2, 'return', i_ident),
312 (1, 'return', j_ident),
Fred Drake0099ba72001-10-03 21:15:32 +0000313 ])
314
Fred Drake39cd6032001-09-26 21:00:33 +0000315
Fred Drake3208d4b2001-09-22 04:28:19 +0000316def ident(function):
317 if hasattr(function, "f_code"):
318 code = function.f_code
319 else:
320 code = function.func_code
321 return code.co_firstlineno, code.co_name
322
323
Fred Drakecc91ac02001-09-25 20:48:14 +0000324def protect(f, p):
325 try: f(p)
326 except: pass
327
328protect_ident = ident(protect)
329
330
Fred Drake39cd6032001-09-26 21:00:33 +0000331def capture_events(callable, p=None):
332 if p is None:
333 p = HookWatcher()
Fred Drake3208d4b2001-09-22 04:28:19 +0000334 sys.setprofile(p.callback)
Fred Drakecc91ac02001-09-25 20:48:14 +0000335 protect(callable, p)
Fred Drake3208d4b2001-09-22 04:28:19 +0000336 sys.setprofile(None)
Fred Drakecc91ac02001-09-25 20:48:14 +0000337 return p.get_events()[1:-1]
Fred Drake3208d4b2001-09-22 04:28:19 +0000338
339
340def show_events(callable):
341 import pprint
342 pprint.pprint(capture_events(callable))
343
344
345def test_main():
Fred Drake39cd6032001-09-26 21:00:33 +0000346 loader = unittest.TestLoader()
347 suite = unittest.TestSuite()
348 suite.addTest(loader.loadTestsFromTestCase(ProfileHookTestCase))
349 suite.addTest(loader.loadTestsFromTestCase(ProfileSimulatorTestCase))
350 test_support.run_suite(suite)
Fred Drake3208d4b2001-09-22 04:28:19 +0000351
352
353if __name__ == "__main__":
354 test_main()