2323import os
2424import os .path as osp
2525import re
26+ from dataclasses import dataclass
2627from opcode import opname
2728from reprlib import repr
2829from types import CodeType , FrameType
29- from typing import Optional , Tuple
30+ from typing import Dict , List , Optional , Tuple
3031import xdis
3132from 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
6768opc = 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
318342def 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
325356def 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