1414import types
1515import typing
1616
17+ _DEBUG = False
18+
19+ def debug (s ):
20+ if _DEBUG :
21+ eprint (s )
22+
1723def eprint (* args , ** kwargs ):
1824 print (* args , file = sys .stderr , ** kwargs )
1925
@@ -330,6 +336,36 @@ def push_frame(self):
330336 def pop_frame (self ):
331337 self .frames .pop ()
332338
339+ Skip = typing .Literal ['SKIP' , 'DONT_SKIP' ]
340+
341+ class Skipper :
342+ def __init__ (self ):
343+ # skipStartFile is a tuple (filename, counter) or None
344+ # If None, then we are not in skipping mode
345+ # Otherwise, we are in skipping mode. Each call event with the
346+ # same filename increases the counter by 1. Each return event
347+ # with the same filename decreases the counter by 0.
348+ # The counter starts at 0 when entering skipping event. If it
349+ # goes back to zero, we leave skipping mode
350+ self .skipStartFile : tuple [str , int ] | None = None
351+
352+ def handleEvent (self , event : str , filename : str , isExternalMod : bool ) -> Skip :
353+ if event == 'call' :
354+ if self .skipStartFile is None and isExternalMod :
355+ # start skipping
356+ self .skipStartFile = (filename , 1 )
357+ elif self .skipStartFile is not None and filename == self .skipStartFile [0 ]:
358+ self .skipStartFile = (self .skipStartFile [0 ], self .skipStartFile [1 ] + 1 )
359+ elif event == 'return' :
360+ if self .skipStartFile is not None and filename == self .skipStartFile [0 ]:
361+ self .skipStartFile = (self .skipStartFile [0 ], self .skipStartFile [1 ] - 1 )
362+ if self .skipStartFile [1 ] == 0 :
363+ self .skipStartFile = None
364+ return 'SKIP'
365+ if self .skipStartFile is None :
366+ return 'DONT_SKIP'
367+ else :
368+ return 'SKIP'
333369
334370class PyTraceGenerator (bdb .Bdb ):
335371 def __init__ (self , trace_socket ):
@@ -339,7 +375,7 @@ def __init__(self, trace_socket):
339375 self .stack_ignore = []
340376 self .init = False
341377 self .filename = ""
342- self .skip_until = None
378+ self .skipper = Skipper ()
343379 self .import_following = False
344380 self .last_step_was_class = False
345381 self .prev_num_frames = 0
@@ -348,22 +384,14 @@ def __init__(self, trace_socket):
348384 self .captured_stdout = io .StringIO ()
349385 self .last_event = ""
350386
351- def trace_dispatch (self , frame , event , arg ):
387+ def trace_dispatch (self , frame , event : str , arg ):
352388 filename = frame .f_code .co_filename
353389
354- # Skip built-in modules
355- # This might not be the best solution. Adjust if required.
356- skip = False
357- if self .skip_until is not None :
358- skip = filename != self .skip_until
359- elif not filename .startswith (os .path .dirname (self .filename )):
360- skip = True
361- if frame .f_back :
362- self .skip_until = frame .f_back .f_code .co_filename
363- if skip :
390+ skipRes = self .skipper .handleEvent (
391+ event , filename , not filename .startswith (os .path .dirname (self .filename ))
392+ )
393+ if skipRes == 'SKIP' :
364394 return self .trace_dispatch
365- else :
366- self .skip_until = None
367395
368396 line = frame .f_lineno
369397 if not self .init :
0 commit comments