From 1c9a0c40794f0cb3234533d5e83234e7dce4ccd4 Mon Sep 17 00:00:00 2001 From: Tian Gao Date: Fri, 27 Oct 2023 14:01:31 -0700 Subject: gh-59013: Make line number of function breakpoint more precise (#110582) --- Lib/pdb.py | 19 ++++++++- Lib/test/test_pdb.py | 46 +++++++++++++++++++++- .../2023-10-09-23-59-04.gh-issue-59013.qPbS-G.rst | 1 + 3 files changed, 63 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-10-09-23-59-04.gh-issue-59013.qPbS-G.rst diff --git a/Lib/pdb.py b/Lib/pdb.py index 1e4d0a2..dbb7f55 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -887,7 +887,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 = code.co_firstlineno + lineno = self._find_first_executable_line(code) filename = code.co_filename except: # last thing to try @@ -990,6 +990,23 @@ 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 ...] diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 4701fa0..5fef836 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -1516,7 +1516,7 @@ def test_next_until_return_at_return_event(): > (3)test_function() -> test_function_2() (Pdb) break test_function_2 - Breakpoint 1 at :1 + Breakpoint 1 at :2 (Pdb) continue > (2)test_function_2() -> x = 1 @@ -1938,7 +1938,7 @@ def test_pdb_next_command_in_generator_for_loop(): > (3)test_function() -> for i in test_gen(): (Pdb) break test_gen - Breakpoint 1 at :1 + Breakpoint 1 at :2 (Pdb) continue > (2)test_gen() -> yield 0 @@ -2350,6 +2350,48 @@ def test_pdb_ambiguous_statements(): (Pdb) continue """ +def test_pdb_function_break(): + """Testing the line number of break on function + + >>> def foo(): pass + + >>> def bar(): + ... + ... pass + + >>> def boo(): + ... # comments + ... global x + ... x = 1 + + >>> def gen(): + ... yield 42 + + >>> def test_function(): + ... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + ... pass + + >>> with PdbTestInput([ # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE + ... 'break foo', + ... 'break bar', + ... 'break boo', + ... 'break gen', + ... 'continue' + ... ]): + ... test_function() + > (3)test_function() + -> pass + (Pdb) break foo + Breakpoint ... at :1 + (Pdb) break bar + Breakpoint ... at :3 + (Pdb) break boo + Breakpoint ... at :4 + (Pdb) break gen + Breakpoint ... at :2 + (Pdb) continue + """ + def test_pdb_issue_gh_65052(): """See GH-65052 diff --git a/Misc/NEWS.d/next/Library/2023-10-09-23-59-04.gh-issue-59013.qPbS-G.rst b/Misc/NEWS.d/next/Library/2023-10-09-23-59-04.gh-issue-59013.qPbS-G.rst new file mode 100644 index 0000000..57915f5 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-10-09-23-59-04.gh-issue-59013.qPbS-G.rst @@ -0,0 +1 @@ +Make line number of function breakpoint more precise in :mod:`pdb` -- cgit v0.12