1+ from __future__ import generators
2+
13import pprint
24import sys
35import unittest
@@ -40,6 +42,7 @@ def __init__(self):
4042 HookWatcher .__init__ (self )
4143
4244 def callback (self , frame , event , arg ):
45+ # Callback registered with sys.setprofile()/sys.settrace()
4346 self .dispatch [event ](self , frame )
4447
4548 def trace_call (self , frame ):
@@ -55,6 +58,8 @@ def trace_exception(self, frame):
5558 self .add_event ('propogate-from' , self .stack [- 1 ])
5659 self .stack .pop ()
5760 else :
61+ # Either an exception was raised in Python or a C function
62+ # raised an exception; this does not represent propogation.
5863 self .add_event ('ignore' , frame )
5964
6065 dispatch = {
@@ -192,6 +197,79 @@ def f(p):
192197 (0 , 'exception' , protect_ident )
193198 ])
194199
200+ def test_distant_exception (self ):
201+ def f ():
202+ 1 / 0
203+ def g ():
204+ f ()
205+ def h ():
206+ g ()
207+ def i ():
208+ h ()
209+ def j (p ):
210+ i ()
211+ f_ident = ident (f )
212+ g_ident = ident (g )
213+ h_ident = ident (h )
214+ i_ident = ident (i )
215+ j_ident = ident (j )
216+ self .check_events (j , [(1 , 'call' , j_ident ),
217+ (2 , 'call' , i_ident ),
218+ (3 , 'call' , h_ident ),
219+ (4 , 'call' , g_ident ),
220+ (5 , 'call' , f_ident ),
221+ (5 , 'exception' , f_ident ),
222+ (4 , 'exception' , g_ident ),
223+ (3 , 'exception' , h_ident ),
224+ (2 , 'exception' , i_ident ),
225+ (1 , 'exception' , j_ident ),
226+ (0 , 'exception' , protect_ident ),
227+ ])
228+
229+ def test_generator (self ):
230+ def f ():
231+ for i in range (2 ):
232+ yield i
233+ def g (p ):
234+ for i in f ():
235+ pass
236+ f_ident = ident (f )
237+ g_ident = ident (g )
238+ self .check_events (g , [(1 , 'call' , g_ident ),
239+ # call the iterator twice to generate values
240+ (2 , 'call' , f_ident ),
241+ (2 , 'return' , f_ident ),
242+ (2 , 'call' , f_ident ),
243+ (2 , 'return' , f_ident ),
244+ # once more; returns end-of-iteration with
245+ # actually raising an exception
246+ (2 , 'call' , f_ident ),
247+ (2 , 'return' , f_ident ),
248+ (1 , 'return' , g_ident ),
249+ ])
250+
251+ def test_stop_iteration (self ):
252+ def f ():
253+ for i in range (2 ):
254+ yield i
255+ raise StopIteration
256+ def g (p ):
257+ for i in f ():
258+ pass
259+ f_ident = ident (f )
260+ g_ident = ident (g )
261+ self .check_events (g , [(1 , 'call' , g_ident ),
262+ # call the iterator twice to generate values
263+ (2 , 'call' , f_ident ),
264+ (2 , 'return' , f_ident ),
265+ (2 , 'call' , f_ident ),
266+ (2 , 'return' , f_ident ),
267+ # once more to hit the raise:
268+ (2 , 'call' , f_ident ),
269+ (2 , 'exception' , f_ident ),
270+ (1 , 'return' , g_ident ),
271+ ])
272+
195273
196274class ProfileSimulatorTestCase (TestCaseBase ):
197275 def new_watcher (self ):
@@ -214,6 +292,45 @@ def f(p):
214292 (1 , 'propogate-from' , f_ident ),
215293 ])
216294
295+ def test_caught_exception (self ):
296+ def f (p ):
297+ try : 1 / 0
298+ except : pass
299+ f_ident = ident (f )
300+ self .check_events (f , [(1 , 'call' , f_ident ),
301+ (1 , 'ignore' , f_ident ),
302+ (1 , 'return' , f_ident ),
303+ ])
304+
305+ def test_distant_exception (self ):
306+ def f ():
307+ 1 / 0
308+ def g ():
309+ f ()
310+ def h ():
311+ g ()
312+ def i ():
313+ h ()
314+ def j (p ):
315+ i ()
316+ f_ident = ident (f )
317+ g_ident = ident (g )
318+ h_ident = ident (h )
319+ i_ident = ident (i )
320+ j_ident = ident (j )
321+ self .check_events (j , [(1 , 'call' , j_ident ),
322+ (2 , 'call' , i_ident ),
323+ (3 , 'call' , h_ident ),
324+ (4 , 'call' , g_ident ),
325+ (5 , 'call' , f_ident ),
326+ (5 , 'ignore' , f_ident ),
327+ (5 , 'propogate-from' , f_ident ),
328+ (4 , 'propogate-from' , g_ident ),
329+ (3 , 'propogate-from' , h_ident ),
330+ (2 , 'propogate-from' , i_ident ),
331+ (1 , 'propogate-from' , j_ident ),
332+ ])
333+
217334
218335def ident (function ):
219336 if hasattr (function , "f_code" ):
0 commit comments