mirror of
https://github.com/python/cpython.git
synced 2025-08-04 00:48:58 +00:00
gh-88116: Enhance the inspect frame APIs to use the extended position information (GH-91531)
This commit is contained in:
parent
a3f2cf3ced
commit
0daa99f68b
5 changed files with 193 additions and 38 deletions
|
@ -1638,7 +1638,30 @@ def getclosurevars(func):
|
|||
|
||||
# -------------------------------------------------- stack frame extraction
|
||||
|
||||
Traceback = namedtuple('Traceback', 'filename lineno function code_context index')
|
||||
_Traceback = namedtuple('_Traceback', 'filename lineno function code_context index')
|
||||
|
||||
class Traceback(_Traceback):
|
||||
def __new__(cls, filename, lineno, function, code_context, index, *, positions=None):
|
||||
instance = super().__new__(cls, filename, lineno, function, code_context, index)
|
||||
instance.positions = positions
|
||||
return instance
|
||||
|
||||
def __repr__(self):
|
||||
return ('Traceback(filename={!r}, lineno={!r}, function={!r}, '
|
||||
'code_context={!r}, index={!r}, positions={!r})'.format(
|
||||
self.filename, self.lineno, self.function, self.code_context,
|
||||
self.index, self.positions))
|
||||
|
||||
def _get_code_position_from_tb(tb):
|
||||
code, instruction_index = tb.tb_frame.f_code, tb.tb_lasti
|
||||
return _get_code_position(code, instruction_index)
|
||||
|
||||
def _get_code_position(code, instruction_index):
|
||||
if instruction_index < 0:
|
||||
return (None, None, None, None)
|
||||
positions_gen = code.co_positions()
|
||||
# The nth entry in code.co_positions() corresponds to instruction (2*n)th since Python 3.10+
|
||||
return next(itertools.islice(positions_gen, instruction_index // 2, None))
|
||||
|
||||
def getframeinfo(frame, context=1):
|
||||
"""Get information about a frame or traceback object.
|
||||
|
@ -1649,10 +1672,20 @@ def getframeinfo(frame, context=1):
|
|||
The optional second argument specifies the number of lines of context
|
||||
to return, which are centered around the current line."""
|
||||
if istraceback(frame):
|
||||
positions = _get_code_position_from_tb(frame)
|
||||
lineno = frame.tb_lineno
|
||||
frame = frame.tb_frame
|
||||
else:
|
||||
lineno = frame.f_lineno
|
||||
positions = _get_code_position(frame.f_code, frame.f_lasti)
|
||||
|
||||
if positions[0] is None:
|
||||
frame, *positions = (frame, lineno, *positions[1:])
|
||||
else:
|
||||
frame, *positions = (frame, *positions)
|
||||
|
||||
lineno = positions[0]
|
||||
|
||||
if not isframe(frame):
|
||||
raise TypeError('{!r} is not a frame or traceback object'.format(frame))
|
||||
|
||||
|
@ -1670,14 +1703,26 @@ def getframeinfo(frame, context=1):
|
|||
else:
|
||||
lines = index = None
|
||||
|
||||
return Traceback(filename, lineno, frame.f_code.co_name, lines, index)
|
||||
return Traceback(filename, lineno, frame.f_code.co_name, lines,
|
||||
index, positions=dis.Positions(*positions))
|
||||
|
||||
def getlineno(frame):
|
||||
"""Get the line number from a frame object, allowing for optimization."""
|
||||
# FrameType.f_lineno is now a descriptor that grovels co_lnotab
|
||||
return frame.f_lineno
|
||||
|
||||
FrameInfo = namedtuple('FrameInfo', ('frame',) + Traceback._fields)
|
||||
_FrameInfo = namedtuple('_FrameInfo', ('frame',) + Traceback._fields)
|
||||
class FrameInfo(_FrameInfo):
|
||||
def __new__(cls, frame, filename, lineno, function, code_context, index, *, positions=None):
|
||||
instance = super().__new__(cls, frame, filename, lineno, function, code_context, index)
|
||||
instance.positions = positions
|
||||
return instance
|
||||
|
||||
def __repr__(self):
|
||||
return ('FrameInfo(frame={!r}, filename={!r}, lineno={!r}, function={!r}, '
|
||||
'code_context={!r}, index={!r}, positions={!r})'.format(
|
||||
self.frame, self.filename, self.lineno, self.function,
|
||||
self.code_context, self.index, self.positions))
|
||||
|
||||
def getouterframes(frame, context=1):
|
||||
"""Get a list of records for a frame and all higher (calling) frames.
|
||||
|
@ -1686,8 +1731,9 @@ def getouterframes(frame, context=1):
|
|||
name, a list of lines of context, and index within the context."""
|
||||
framelist = []
|
||||
while frame:
|
||||
frameinfo = (frame,) + getframeinfo(frame, context)
|
||||
framelist.append(FrameInfo(*frameinfo))
|
||||
traceback_info = getframeinfo(frame, context)
|
||||
frameinfo = (frame,) + traceback_info
|
||||
framelist.append(FrameInfo(*frameinfo, positions=traceback_info.positions))
|
||||
frame = frame.f_back
|
||||
return framelist
|
||||
|
||||
|
@ -1698,8 +1744,9 @@ def getinnerframes(tb, context=1):
|
|||
name, a list of lines of context, and index within the context."""
|
||||
framelist = []
|
||||
while tb:
|
||||
frameinfo = (tb.tb_frame,) + getframeinfo(tb, context)
|
||||
framelist.append(FrameInfo(*frameinfo))
|
||||
traceback_info = getframeinfo(tb, context)
|
||||
frameinfo = (tb.tb_frame,) + traceback_info
|
||||
framelist.append(FrameInfo(*frameinfo, positions=traceback_info.positions))
|
||||
tb = tb.tb_next
|
||||
return framelist
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue