Skip to content

Commit 69e0bd0

Browse files
committed
fix trace generator for python 3.14
1 parent 8da7415 commit 69e0bd0

1 file changed

Lines changed: 42 additions & 14 deletions

File tree

pytrace-generator/main.py

Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@
1414
import types
1515
import typing
1616

17+
_DEBUG = False
18+
19+
def debug(s):
20+
if _DEBUG:
21+
eprint(s)
22+
1723
def 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

334370
class 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

Comments
 (0)