0001 import pprint 0002 import sys 0003 import unittest 0004 0005 from test import test_support 0006 0007 0008 class HookWatcher: 0009 def __init__(self): 0010 self.frames = [] 0011 self.events = [] 0012 0013 def callback(self, frame, event, arg): 0014 if (event == "call" 0015 or event == "return" 0016 or event == "exception"): 0017 self.add_event(event, frame) 0018 0019 def add_event(self, event, frame=None): 0020 """Add an event to the log.""" 0021 if frame is None: 0022 frame = sys._getframe(1) 0023 0024 try: 0025 frameno = self.frames.index(frame) 0026 except ValueError: 0027 frameno = len(self.frames) 0028 self.frames.append(frame) 0029 0030 self.events.append((frameno, event, ident(frame))) 0031 0032 def get_events(self): 0033 """Remove calls to add_event().""" 0034 disallowed = [ident(self.add_event.im_func), ident(ident)] 0035 self.frames = None 0036 0037 return [item for item in self.events if item[2] not in disallowed] 0038 0039 0040 class ProfileSimulator(HookWatcher): 0041 def __init__(self, testcase): 0042 self.testcase = testcase 0043 self.stack = [] 0044 HookWatcher.__init__(self) 0045 0046 def callback(self, frame, event, arg): 0047 # Callback registered with sys.setprofile()/sys.settrace() 0048 self.dispatch[event](self, frame) 0049 0050 def trace_call(self, frame): 0051 self.add_event('call', frame) 0052 self.stack.append(frame) 0053 0054 def trace_return(self, frame): 0055 self.add_event('return', frame) 0056 self.stack.pop() 0057 0058 def trace_exception(self, frame): 0059 self.testcase.fail( 0060 "the profiler should never receive exception events") 0061 0062 def trace_pass(self, frame): 0063 pass 0064 0065 dispatch = { 0066 'call': trace_call, 0067 'exception': trace_exception, 0068 'return': trace_return, 0069 'c_call': trace_pass, 0070 'c_return': trace_pass, 0071 'c_exception': trace_pass, 0072 } 0073 0074 0075 class TestCaseBase(unittest.TestCase): 0076 def check_events(self, callable, expected): 0077 events = capture_events(callable, self.new_watcher()) 0078 if events != expected: 0079 self.fail("Expected events:\n%s\nReceived events:\n%s" 0080 % (pprint.pformat(expected), pprint.pformat(events))) 0081 0082 0083 class ProfileHookTestCase(TestCaseBase): 0084 def new_watcher(self): 0085 return HookWatcher() 0086 0087 def test_simple(self): 0088 def f(p): 0089 pass 0090 f_ident = ident(f) 0091 self.check_events(f, [(1, 'call', f_ident), 0092 (1, 'return', f_ident), 0093 ]) 0094 0095 def test_exception(self): 0096 def f(p): 0097 1/0 0098 f_ident = ident(f) 0099 self.check_events(f, [(1, 'call', f_ident), 0100 (1, 'return', f_ident), 0101 ]) 0102 0103 def test_caught_exception(self): 0104 def f(p): 0105 try: 1/0 0106 except: pass 0107 f_ident = ident(f) 0108 self.check_events(f, [(1, 'call', f_ident), 0109 (1, 'return', f_ident), 0110 ]) 0111 0112 def test_caught_nested_exception(self): 0113 def f(p): 0114 try: 1/0 0115 except: pass 0116 f_ident = ident(f) 0117 self.check_events(f, [(1, 'call', f_ident), 0118 (1, 'return', f_ident), 0119 ]) 0120 0121 def test_nested_exception(self): 0122 def f(p): 0123 1/0 0124 f_ident = ident(f) 0125 self.check_events(f, [(1, 'call', f_ident), 0126 # This isn't what I expected: 0127 # (0, 'exception', protect_ident), 0128 # I expected this again: 0129 (1, 'return', f_ident), 0130 ]) 0131 0132 def test_exception_in_except_clause(self): 0133 def f(p): 0134 1/0 0135 def g(p): 0136 try: 0137 f(p) 0138 except: 0139 try: f(p) 0140 except: pass 0141 f_ident = ident(f) 0142 g_ident = ident(g) 0143 self.check_events(g, [(1, 'call', g_ident), 0144 (2, 'call', f_ident), 0145 (2, 'return', f_ident), 0146 (3, 'call', f_ident), 0147 (3, 'return', f_ident), 0148 (1, 'return', g_ident), 0149 ]) 0150 0151 def test_exception_propogation(self): 0152 def f(p): 0153 1/0 0154 def g(p): 0155 try: f(p) 0156 finally: p.add_event("falling through") 0157 f_ident = ident(f) 0158 g_ident = ident(g) 0159 self.check_events(g, [(1, 'call', g_ident), 0160 (2, 'call', f_ident), 0161 (2, 'return', f_ident), 0162 (1, 'falling through', g_ident), 0163 (1, 'return', g_ident), 0164 ]) 0165 0166 def test_raise_twice(self): 0167 def f(p): 0168 try: 1/0 0169 except: 1/0 0170 f_ident = ident(f) 0171 self.check_events(f, [(1, 'call', f_ident), 0172 (1, 'return', f_ident), 0173 ]) 0174 0175 def test_raise_reraise(self): 0176 def f(p): 0177 try: 1/0 0178 except: raise 0179 f_ident = ident(f) 0180 self.check_events(f, [(1, 'call', f_ident), 0181 (1, 'return', f_ident), 0182 ]) 0183 0184 def test_raise(self): 0185 def f(p): 0186 raise Exception() 0187 f_ident = ident(f) 0188 self.check_events(f, [(1, 'call', f_ident), 0189 (1, 'return', f_ident), 0190 ]) 0191 0192 def test_distant_exception(self): 0193 def f(): 0194 1/0 0195 def g(): 0196 f() 0197 def h(): 0198 g() 0199 def i(): 0200 h() 0201 def j(p): 0202 i() 0203 f_ident = ident(f) 0204 g_ident = ident(g) 0205 h_ident = ident(h) 0206 i_ident = ident(i) 0207 j_ident = ident(j) 0208 self.check_events(j, [(1, 'call', j_ident), 0209 (2, 'call', i_ident), 0210 (3, 'call', h_ident), 0211 (4, 'call', g_ident), 0212 (5, 'call', f_ident), 0213 (5, 'return', f_ident), 0214 (4, 'return', g_ident), 0215 (3, 'return', h_ident), 0216 (2, 'return', i_ident), 0217 (1, 'return', j_ident), 0218 ]) 0219 0220 def test_generator(self): 0221 def f(): 0222 for i in range(2): 0223 yield i 0224 def g(p): 0225 for i in f(): 0226 pass 0227 f_ident = ident(f) 0228 g_ident = ident(g) 0229 self.check_events(g, [(1, 'call', g_ident), 0230 # call the iterator twice to generate values 0231 (2, 'call', f_ident), 0232 (2, 'return', f_ident), 0233 (2, 'call', f_ident), 0234 (2, 'return', f_ident), 0235 # once more; returns end-of-iteration with 0236 # actually raising an exception 0237 (2, 'call', f_ident), 0238 (2, 'return', f_ident), 0239 (1, 'return', g_ident), 0240 ]) 0241 0242 def test_stop_iteration(self): 0243 def f(): 0244 for i in range(2): 0245 yield i 0246 raise StopIteration 0247 def g(p): 0248 for i in f(): 0249 pass 0250 f_ident = ident(f) 0251 g_ident = ident(g) 0252 self.check_events(g, [(1, 'call', g_ident), 0253 # call the iterator twice to generate values 0254 (2, 'call', f_ident), 0255 (2, 'return', f_ident), 0256 (2, 'call', f_ident), 0257 (2, 'return', f_ident), 0258 # once more to hit the raise: 0259 (2, 'call', f_ident), 0260 (2, 'return', f_ident), 0261 (1, 'return', g_ident), 0262 ]) 0263 0264 0265 class ProfileSimulatorTestCase(TestCaseBase): 0266 def new_watcher(self): 0267 return ProfileSimulator(self) 0268 0269 def test_simple(self): 0270 def f(p): 0271 pass 0272 f_ident = ident(f) 0273 self.check_events(f, [(1, 'call', f_ident), 0274 (1, 'return', f_ident), 0275 ]) 0276 0277 def test_basic_exception(self): 0278 def f(p): 0279 1/0 0280 f_ident = ident(f) 0281 self.check_events(f, [(1, 'call', f_ident), 0282 (1, 'return', f_ident), 0283 ]) 0284 0285 def test_caught_exception(self): 0286 def f(p): 0287 try: 1/0 0288 except: pass 0289 f_ident = ident(f) 0290 self.check_events(f, [(1, 'call', f_ident), 0291 (1, 'return', f_ident), 0292 ]) 0293 0294 def test_distant_exception(self): 0295 def f(): 0296 1/0 0297 def g(): 0298 f() 0299 def h(): 0300 g() 0301 def i(): 0302 h() 0303 def j(p): 0304 i() 0305 f_ident = ident(f) 0306 g_ident = ident(g) 0307 h_ident = ident(h) 0308 i_ident = ident(i) 0309 j_ident = ident(j) 0310 self.check_events(j, [(1, 'call', j_ident), 0311 (2, 'call', i_ident), 0312 (3, 'call', h_ident), 0313 (4, 'call', g_ident), 0314 (5, 'call', f_ident), 0315 (5, 'return', f_ident), 0316 (4, 'return', g_ident), 0317 (3, 'return', h_ident), 0318 (2, 'return', i_ident), 0319 (1, 'return', j_ident), 0320 ]) 0321 0322 0323 def ident(function): 0324 if hasattr(function, "f_code"): 0325 code = function.f_code 0326 else: 0327 code = function.func_code 0328 return code.co_firstlineno, code.co_name 0329 0330 0331 def protect(f, p): 0332 try: f(p) 0333 except: pass 0334 0335 protect_ident = ident(protect) 0336 0337 0338 def capture_events(callable, p=None): 0339 try: 0340 sys.setprofile() 0341 except TypeError: 0342 pass 0343 else: 0344 raise test_support.TestFailed( 0345 'sys.setprofile() did not raise TypeError') 0346 0347 if p is None: 0348 p = HookWatcher() 0349 sys.setprofile(p.callback) 0350 protect(callable, p) 0351 sys.setprofile(None) 0352 return p.get_events()[1:-1] 0353 0354 0355 def show_events(callable): 0356 import pprint 0357 pprint.pprint(capture_events(callable)) 0358 0359 0360 def test_main(): 0361 test_support.run_unittest( 0362 ProfileHookTestCase, 0363 ProfileSimulatorTestCase 0364 ) 0365 0366 0367 if __name__ == "__main__": 0368 test_main() 0369
Generated by PyXR 0.9.4