Skip to content

Commit f56de41

Browse files
committed
WIP - start tracking frame depth
1 parent 255180b commit f56de41

3 files changed

Lines changed: 51 additions & 11 deletions

File tree

test/unit/lib/test_lib_stack.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,16 @@
33
import pytest
44
import platform
55

6-
from trepan.lib.stack import count_frames, is_eval_or_exec_stmt
6+
from trepan.lib.stack import FrameInfo, count_frames, is_eval_or_exec_stmt
77

88

99
def test_count_frames():
1010
f = inspect.currentframe()
1111
frame_count = count_frames(f)
12+
assert frame_count == count_frames(f)
13+
assert len(FrameInfo) > 0
1214
assert count_frames(f) > 2
1315
assert frame_count - 1 == count_frames(f.f_back)
14-
assert frame_count - 1 == count_frames(f, 1)
1516
return
1617

1718

trepan/lib/core.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
from trepan.clifns import search_file
4141
from trepan.lib.breakpoint import BreakpointManager
4242
from trepan.lib.default import START_OPTS, STOP_OPTS
43-
from trepan.lib.stack import count_frames
43+
from trepan.lib.stack import ExtraFrameInfo, FrameInfo, count_frames
4444
from trepan.misc import option_set
4545
from trepan.processor.cmdproc import CommandProcessor
4646
from trepan.processor.trace import PrintProcessor
@@ -447,6 +447,12 @@ def trace_dispatch(self, frame, event: str, arg):
447447
# make sure we don't turn off breapoints inside this function which
448448
# we do by returning "self".
449449
return self
450+
if frame not in FrameInfo:
451+
FrameInfo[frame] = ExtraFrameInfo(-1, frame.f_code.co_filename)
452+
elif event == "return":
453+
if frame in FrameInfo:
454+
print("XXX deleting {frame}")
455+
del FrameInfo[frame]
450456

451457
self.event = event
452458

trepan/lib/stack.py

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,11 @@
2323
import os
2424
import os.path as osp
2525
import re
26+
from dataclasses import dataclass
2627
from opcode import opname
2728
from reprlib import repr
2829
from types import CodeType, FrameType
29-
from typing import Optional, Tuple
30+
from typing import Dict, List, Optional, Tuple
3031
import xdis
3132
from xdis.version_info import PYTHON_IMPLEMENTATION, PYTHON_VERSION_TRIPLE
3233

@@ -66,18 +67,41 @@ def deparse_offset(_code, _name: str, _list_i: int, _) -> tuple:
6667

6768
opc = xdis.get_opcode_module(PYTHON_VERSION_TRIPLE, PYTHON_IMPLEMENTATION)
6869

70+
@dataclass
71+
class ExtraFrameInfo:
72+
depth: int = -1
73+
filename: str = "" # Note frame filenames can be remapped.
6974

70-
def count_frames(frame: FrameType, count_start=0) -> int:
75+
76+
# A mapping frame to its ExtraFrameInfo. This is a weak dictionary so that
77+
# frames are automatically removed.
78+
FrameInfo: Dict[FrameType, ExtraFrameInfo] = {}
79+
80+
def count_frames(frame: FrameType) -> int:
7181
"""Return a count of the number of frames"""
72-
count = -count_start
82+
count = 0
83+
# Bottommost frame depth is 1
84+
depth = 1
85+
frames: List[FrameType] = []
7386
for _ in range(1000):
7487
if frame is None:
7588
break
89+
elif frame_info := FrameInfo.get(frame):
90+
depth = frame_info.depth
91+
count += depth
92+
break
7693
else:
94+
frames.append(frame)
7795
count += 1
7896
frame = frame.f_back
7997
else:
8098
return 1000
99+
100+
# Populate or update FrameInfo
101+
while len(frames) > 0 and frame not in FrameInfo:
102+
frame = frames.pop()
103+
FrameInfo[frame] = ExtraFrameInfo(depth, frame.f_code.co_filename)
104+
depth += 1
81105
return count
82106

83107

@@ -317,9 +341,16 @@ def format_stack_entry(
317341

318342
def frame2file(core_obj, frame, canonic=True):
319343
if canonic:
320-
return core_obj.filename(core_obj.canonic_filename(frame))
344+
filename = core_obj.filename(core_obj.canonic_filename(frame))
321345
else:
322-
return core_obj.filename(frame.f_code.co_filename)
346+
filename = core_obj.filename(frame.f_code.co_filename)
347+
348+
# if frame_info := FrameInfo.get(frame):
349+
# if canonic:
350+
# return core_obj.filename(frame_info.filename)
351+
# return frame_info.filename
352+
353+
return filename
323354

324355

325356
def frame2filesize(frame):
@@ -631,9 +662,10 @@ def __init__(self):
631662
)
632663
)
633664

634-
# print("frame count: %d" % count_frames(frame))
635-
# print("frame count: %d" % count_frames(frame.f_back))
636-
# print("frame count: %d" % count_frames(frame, 1))
665+
count1 = count_frames(frame)
666+
print("frame count: %d" % count1)
667+
assert count1 == count_frames(frame)
668+
print("frame count: %d" % count_frames(frame.f_back))
637669
# print("def statement: x=5?: %s" % repr(is_def_stmt("x=5", frame)))
638670
# # Not a "def" statement because frame is wrong spot
639671
# print(is_def_stmt("def foo():", frame))
@@ -657,6 +689,7 @@ def fn(x):
657689
_, mess = format_function_and_parameters(frame, dd, style="tango")
658690
print(mess)
659691
print(get_call_function_name(frame))
692+
print("frame count: %d" % count_frames(frame))
660693
return
661694

662695
print("=" * 30)

0 commit comments

Comments
 (0)