From 5ccebc56ca5d3fb328d258cf2559e4ac30d2e73b Mon Sep 17 00:00:00 2001 From: Tian Gao Date: Wed, 23 Oct 2024 15:04:30 -0700 Subject: [PATCH 1/3] [3.12] gh-125884: Support breakpoint on functions with annotations (GH-125892) (cherry picked from commit 8f2c0f7a03b71485b5635cb47c000e4e8ace8800) Co-authored-by: Tian Gao --- Lib/pdb.py | 19 +++++++++- Lib/test/test_pdb.py | 36 +++++++++++++++++++ ...-10-23-17-45-40.gh-issue-125884.41E_PD.rst | 1 + 3 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2024-10-23-17-45-40.gh-issue-125884.41E_PD.rst diff --git a/Lib/pdb.py b/Lib/pdb.py index 559517813cf600..2e56b738a7222c 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -96,7 +96,7 @@ class Restart(Exception): "post_mortem", "help"] def find_function(funcname, filename): - cre = re.compile(r'def\s+%s\s*[(]' % re.escape(funcname)) + cre = re.compile(r'def\s+%s(\s*\[.+\])?\s*[(]' % re.escape(funcname)) try: fp = tokenize.open(filename) except OSError: @@ -105,7 +105,24 @@ def find_function(funcname, filename): with fp: for lineno, line in enumerate(fp, start=1): if cre.match(line): +<<<<<<< HEAD return funcname, filename, lineno +======= + funcstart, funcdef = lineno, line + elif funcdef: + funcdef += line + + if funcdef: + try: + code = compile(funcdef, filename, 'exec') + except SyntaxError: + continue + # We should always be able to find the code object here + funccode = next(c for c in code.co_consts if + isinstance(c, CodeType) and c.co_name == funcname) + lineno_offset = find_first_executable_line(funccode) + return funcname, filename, funcstart + lineno_offset - 1 +>>>>>>> 8f2c0f7a03b... gh-125884: Support breakpoint on functions with annotations (#125892) return None def lasti2lineno(code, lasti): diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 1542bb3bee1aea..a99dd08810bcd1 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -352,6 +352,42 @@ def test_pdb_breakpoint_commands(): 4 """ +def test_pdb_breakpoint_on_annotated_function_def(): + """Test breakpoints on function definitions with annotation. + + >>> def foo[T](): + ... return 0 + + >>> def bar() -> int: + ... return 0 + + >>> def foobar[T]() -> int: + ... return 0 + + >>> reset_Breakpoint() + + >>> def test_function(): + ... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + ... pass + + >>> with PdbTestInput([ # doctest: +NORMALIZE_WHITESPACE + ... 'break foo', + ... 'break bar', + ... 'break foobar', + ... 'continue', + ... ]): + ... test_function() + > (3)test_function() + -> pass + (Pdb) break foo + Breakpoint 1 at :2 + (Pdb) break bar + Breakpoint 2 at :2 + (Pdb) break foobar + Breakpoint 3 at :2 + (Pdb) continue + """ + def test_pdb_breakpoints_preserved_across_interactive_sessions(): """Breakpoints are remembered between interactive sessions diff --git a/Misc/NEWS.d/next/Library/2024-10-23-17-45-40.gh-issue-125884.41E_PD.rst b/Misc/NEWS.d/next/Library/2024-10-23-17-45-40.gh-issue-125884.41E_PD.rst new file mode 100644 index 00000000000000..684b1f282b143e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-10-23-17-45-40.gh-issue-125884.41E_PD.rst @@ -0,0 +1 @@ +Fixed the bug for :mod:`pdb` where it can't set breakpoints on functions with certain annotations. From 11efd57c96c3b647bad2fc37a31c19fe2b5bc550 Mon Sep 17 00:00:00 2001 From: Tian Gao Date: Wed, 23 Oct 2024 18:18:41 -0400 Subject: [PATCH 2/3] Remove first executable line changes --- Lib/pdb.py | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/Lib/pdb.py b/Lib/pdb.py index 2e56b738a7222c..1e1b5ea4f0a184 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -105,24 +105,7 @@ def find_function(funcname, filename): with fp: for lineno, line in enumerate(fp, start=1): if cre.match(line): -<<<<<<< HEAD return funcname, filename, lineno -======= - funcstart, funcdef = lineno, line - elif funcdef: - funcdef += line - - if funcdef: - try: - code = compile(funcdef, filename, 'exec') - except SyntaxError: - continue - # We should always be able to find the code object here - funccode = next(c for c in code.co_consts if - isinstance(c, CodeType) and c.co_name == funcname) - lineno_offset = find_first_executable_line(funccode) - return funcname, filename, funcstart + lineno_offset - 1 ->>>>>>> 8f2c0f7a03b... gh-125884: Support breakpoint on functions with annotations (#125892) return None def lasti2lineno(code, lasti): From 383da9188ab30111b8e841497bfcacdb3ed08fd6 Mon Sep 17 00:00:00 2001 From: Tian Gao Date: Wed, 23 Oct 2024 18:19:26 -0400 Subject: [PATCH 3/3] Make test happy for 3.12 --- Lib/test/test_pdb.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index a99dd08810bcd1..bd61de0ad3494c 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -380,11 +380,11 @@ def test_pdb_breakpoint_on_annotated_function_def(): > (3)test_function() -> pass (Pdb) break foo - Breakpoint 1 at :2 + Breakpoint 1 at :1 (Pdb) break bar - Breakpoint 2 at :2 + Breakpoint 2 at :1 (Pdb) break foobar - Breakpoint 3 at :2 + Breakpoint 3 at :1 (Pdb) continue """