mirror of https://github.com/python/cpython
gh-59013: Set breakpoint on the first executable line of function when using `break func` in pdb (#112470)
This commit is contained in:
parent
1c2ea8b33c
commit
765b9ce9fb
51
Lib/pdb.py
51
Lib/pdb.py
|
@ -97,17 +97,47 @@ class Restart(Exception):
|
|||
__all__ = ["run", "pm", "Pdb", "runeval", "runctx", "runcall", "set_trace",
|
||||
"post_mortem", "help"]
|
||||
|
||||
|
||||
def find_first_executable_line(code):
|
||||
""" Try to find the first executable line of the code object.
|
||||
|
||||
Equivalently, find the line number of the instruction that's
|
||||
after RESUME
|
||||
|
||||
Return code.co_firstlineno if no executable line is found.
|
||||
"""
|
||||
prev = None
|
||||
for instr in dis.get_instructions(code):
|
||||
if prev is not None and prev.opname == 'RESUME':
|
||||
if instr.positions.lineno is not None:
|
||||
return instr.positions.lineno
|
||||
return code.co_firstlineno
|
||||
prev = instr
|
||||
return code.co_firstlineno
|
||||
|
||||
def find_function(funcname, filename):
|
||||
cre = re.compile(r'def\s+%s\s*[(]' % re.escape(funcname))
|
||||
try:
|
||||
fp = tokenize.open(filename)
|
||||
except OSError:
|
||||
return None
|
||||
funcdef = ""
|
||||
funcstart = None
|
||||
# consumer of this info expects the first line to be 1
|
||||
with fp:
|
||||
for lineno, line in enumerate(fp, start=1):
|
||||
if cre.match(line):
|
||||
return funcname, filename, lineno
|
||||
funcstart, funcdef = lineno, line
|
||||
elif funcdef:
|
||||
funcdef += line
|
||||
|
||||
if funcdef:
|
||||
try:
|
||||
funccode = compile(funcdef, filename, 'exec').co_consts[0]
|
||||
except SyntaxError:
|
||||
continue
|
||||
lineno_offset = find_first_executable_line(funccode)
|
||||
return funcname, filename, funcstart + lineno_offset - 1
|
||||
return None
|
||||
|
||||
def lasti2lineno(code, lasti):
|
||||
|
@ -975,7 +1005,7 @@ class Pdb(bdb.Bdb, cmd.Cmd):
|
|||
#use co_name to identify the bkpt (function names
|
||||
#could be aliased, but co_name is invariant)
|
||||
funcname = code.co_name
|
||||
lineno = self._find_first_executable_line(code)
|
||||
lineno = find_first_executable_line(code)
|
||||
filename = code.co_filename
|
||||
except:
|
||||
# last thing to try
|
||||
|
@ -1078,23 +1108,6 @@ class Pdb(bdb.Bdb, cmd.Cmd):
|
|||
return 0
|
||||
return lineno
|
||||
|
||||
def _find_first_executable_line(self, code):
|
||||
""" Try to find the first executable line of the code object.
|
||||
|
||||
Equivalently, find the line number of the instruction that's
|
||||
after RESUME
|
||||
|
||||
Return code.co_firstlineno if no executable line is found.
|
||||
"""
|
||||
prev = None
|
||||
for instr in dis.get_instructions(code):
|
||||
if prev is not None and prev.opname == 'RESUME':
|
||||
if instr.positions.lineno is not None:
|
||||
return instr.positions.lineno
|
||||
return code.co_firstlineno
|
||||
prev = instr
|
||||
return code.co_firstlineno
|
||||
|
||||
def do_enable(self, arg):
|
||||
"""enable bpnumber [bpnumber ...]
|
||||
|
||||
|
|
|
@ -2661,7 +2661,7 @@ def quux():
|
|||
pass
|
||||
""".encode(),
|
||||
'bœr',
|
||||
('bœr', 4),
|
||||
('bœr', 5),
|
||||
)
|
||||
|
||||
def test_find_function_found_with_encoding_cookie(self):
|
||||
|
@ -2678,7 +2678,7 @@ def quux():
|
|||
pass
|
||||
""".encode('iso-8859-15'),
|
||||
'bœr',
|
||||
('bœr', 5),
|
||||
('bœr', 6),
|
||||
)
|
||||
|
||||
def test_find_function_found_with_bom(self):
|
||||
|
@ -2688,9 +2688,34 @@ def bœr():
|
|||
pass
|
||||
""".encode(),
|
||||
'bœr',
|
||||
('bœr', 1),
|
||||
('bœr', 2),
|
||||
)
|
||||
|
||||
def test_find_function_first_executable_line(self):
|
||||
code = textwrap.dedent("""\
|
||||
def foo(): pass
|
||||
|
||||
def bar():
|
||||
pass # line 4
|
||||
|
||||
def baz():
|
||||
# comment
|
||||
pass # line 8
|
||||
|
||||
def mul():
|
||||
# code on multiple lines
|
||||
code = compile( # line 12
|
||||
'def f()',
|
||||
'<string>',
|
||||
'exec',
|
||||
)
|
||||
""").encode()
|
||||
|
||||
self._assert_find_function(code, 'foo', ('foo', 1))
|
||||
self._assert_find_function(code, 'bar', ('bar', 4))
|
||||
self._assert_find_function(code, 'baz', ('baz', 8))
|
||||
self._assert_find_function(code, 'mul', ('mul', 12))
|
||||
|
||||
def test_issue7964(self):
|
||||
# open the file as binary so we can force \r\n newline
|
||||
with open(os_helper.TESTFN, 'wb') as f:
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Set breakpoint on the first executable line of the function, instead of the line of function definition when the user do ``break func`` using :mod:`pdb`
|
Loading…
Reference in New Issue