]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-59013: Make line number of function breakpoint more precise (#110582)
authorTian Gao <gaogaotiantian@hotmail.com>
Fri, 27 Oct 2023 21:01:31 +0000 (14:01 -0700)
committerGitHub <noreply@github.com>
Fri, 27 Oct 2023 21:01:31 +0000 (22:01 +0100)
Lib/pdb.py
Lib/test/test_pdb.py
Misc/NEWS.d/next/Library/2023-10-09-23-59-04.gh-issue-59013.qPbS-G.rst [new file with mode: 0644]

index 1e4d0a20515fa3306b0d51ad08a66201e29dfb71..dbb7f556555bccc3539263953faafdde1051ac55 100755 (executable)
@@ -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 ...]
 
index 4701fa0cc9656ade878fc85d3590f3b8d85e84b2..5fef8365f597101ace67018b4a80d3895e0c7717 100644 (file)
@@ -1516,7 +1516,7 @@ def test_next_until_return_at_return_event():
     > <doctest test.test_pdb.test_next_until_return_at_return_event[1]>(3)test_function()
     -> test_function_2()
     (Pdb) break test_function_2
-    Breakpoint 1 at <doctest test.test_pdb.test_next_until_return_at_return_event[0]>:1
+    Breakpoint 1 at <doctest test.test_pdb.test_next_until_return_at_return_event[0]>:2
     (Pdb) continue
     > <doctest test.test_pdb.test_next_until_return_at_return_event[0]>(2)test_function_2()
     -> x = 1
@@ -1938,7 +1938,7 @@ def test_pdb_next_command_in_generator_for_loop():
     > <doctest test.test_pdb.test_pdb_next_command_in_generator_for_loop[1]>(3)test_function()
     -> for i in test_gen():
     (Pdb) break test_gen
-    Breakpoint 1 at <doctest test.test_pdb.test_pdb_next_command_in_generator_for_loop[0]>:1
+    Breakpoint 1 at <doctest test.test_pdb.test_pdb_next_command_in_generator_for_loop[0]>:2
     (Pdb) continue
     > <doctest test.test_pdb.test_pdb_next_command_in_generator_for_loop[0]>(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()
+    > <doctest test.test_pdb.test_pdb_function_break[4]>(3)test_function()
+    -> pass
+    (Pdb) break foo
+    Breakpoint ... at <doctest test.test_pdb.test_pdb_function_break[0]>:1
+    (Pdb) break bar
+    Breakpoint ... at <doctest test.test_pdb.test_pdb_function_break[1]>:3
+    (Pdb) break boo
+    Breakpoint ... at <doctest test.test_pdb.test_pdb_function_break[2]>:4
+    (Pdb) break gen
+    Breakpoint ... at <doctest test.test_pdb.test_pdb_function_break[3]>: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 (file)
index 0000000..57915f5
--- /dev/null
@@ -0,0 +1 @@
+Make line number of function breakpoint more precise in :mod:`pdb`