From d7ac427a796a3f869b813dac37b030889b56cd3b Mon Sep 17 00:00:00 2001 From: Tian Gao Date: Tue, 30 Apr 2024 11:18:01 -0700 Subject: gh-117618: Make package.module searchable for breakpoints and clean up docs (#117619) --- Doc/library/pdb.rst | 19 ++++++---- Lib/pdb.py | 24 ++++++++----- Lib/test/test_pdb.py | 40 ++++++++++++++++++++++ .../2024-04-08-03-23-22.gh-issue-117618.-4DCUw.rst | 1 + 4 files changed, 69 insertions(+), 15 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-04-08-03-23-22.gh-issue-117618.-4DCUw.rst diff --git a/Doc/library/pdb.rst b/Doc/library/pdb.rst index ac3007f..a640976 100644 --- a/Doc/library/pdb.rst +++ b/Doc/library/pdb.rst @@ -328,12 +328,16 @@ can be overridden by the local file. .. pdbcommand:: b(reak) [([filename:]lineno | function) [, condition]] - With a *lineno* argument, set a break there in the current file. With a - *function* argument, set a break at the first executable statement within - that function. The line number may be prefixed with a filename and a colon, - to specify a breakpoint in another file (probably one that hasn't been loaded - yet). The file is searched on :data:`sys.path`. Note that each breakpoint - is assigned a number to which all the other breakpoint commands refer. + With a *lineno* argument, set a break at line *lineno* in the current file. + The line number may be prefixed with a *filename* and a colon, + to specify a breakpoint in another file (possibly one that hasn't been loaded + yet). The file is searched on :data:`sys.path`. Accepatable forms of *filename* + are ``/abspath/to/file.py``, ``relpath/file.py``, ``module`` and + ``package.module``. + + With a *function* argument, set a break at the first executable statement within + that function. *function* can be any expression that evaluates to a function + in the current namespace. If a second argument is present, it is an expression which must evaluate to true before the breakpoint is honored. @@ -342,6 +346,9 @@ can be overridden by the local file. of times that breakpoint has been hit, the current ignore count, and the associated condition if any. + Each breakpoint is assigned a number to which all the other + breakpoint commands refer. + .. pdbcommand:: tbreak [([filename:]lineno | function) [, condition]] Temporary breakpoint, which is removed automatically when it is first hit. diff --git a/Lib/pdb.py b/Lib/pdb.py index d4138b9..fa2e1ec 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -2007,17 +2007,23 @@ class Pdb(bdb.Bdb, cmd.Cmd): lookupmodule() translates (possibly incomplete) file or module name into an absolute file name. + + filename could be in format of: + * an absolute path like '/path/to/file.py' + * a relative path like 'file.py' or 'dir/file.py' + * a module name like 'module' or 'package.module' + + files and modules will be searched in sys.path. """ - if os.path.isabs(filename) and os.path.exists(filename): - return filename - f = os.path.join(sys.path[0], filename) - if os.path.exists(f) and self.canonic(f) == self.mainpyfile: - return f - root, ext = os.path.splitext(filename) - if ext == '': - filename = filename + '.py' + if not filename.endswith('.py'): + # A module is passed in so convert it to equivalent file + filename = filename.replace('.', os.sep) + '.py' + if os.path.isabs(filename): - return filename + if os.path.exists(filename): + return filename + return None + for dirname in sys.path: while os.path.islink(dirname): dirname = os.readlink(dirname) diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 2d057e2..5635d17 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -354,6 +354,46 @@ def test_pdb_breakpoint_commands(): 4 """ +def test_pdb_breakpoint_with_filename(): + """Breakpoints with filename:lineno + + >>> def test_function(): + ... # inspect_fodder2 is a great module as the line number is stable + ... from test.test_inspect import inspect_fodder2 as mod2 + ... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + ... mod2.func88() + ... mod2.func114() + ... # Be a good citizen and clean up the mess + ... reset_Breakpoint() + + First, need to clear bdb state that might be left over from previous tests. + Otherwise, the new breakpoints might get assigned different numbers. + + >>> reset_Breakpoint() + + >>> with PdbTestInput([ # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS + ... 'break test.test_inspect.inspect_fodder2:90', + ... 'continue', # will stop at func88 + ... 'break test/test_inspect/inspect_fodder2.py:115', + ... 'continue', # will stop at func114 + ... 'continue', + ... ]): + ... test_function() + > (5)test_function() + -> mod2.func88() + (Pdb) break test.test_inspect.inspect_fodder2:90 + Breakpoint 1 at ...inspect_fodder2.py:90 + (Pdb) continue + > ...inspect_fodder2.py(90)func88() + -> return 90 + (Pdb) break test/test_inspect/inspect_fodder2.py:115 + Breakpoint 2 at ...inspect_fodder2.py:115 + (Pdb) continue + > ...inspect_fodder2.py(115)func114() + -> return 115 + (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-04-08-03-23-22.gh-issue-117618.-4DCUw.rst b/Misc/NEWS.d/next/Library/2024-04-08-03-23-22.gh-issue-117618.-4DCUw.rst new file mode 100644 index 0000000..569c5d5 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-04-08-03-23-22.gh-issue-117618.-4DCUw.rst @@ -0,0 +1 @@ +Support ``package.module`` as ``filename`` for ``break`` command of :mod:`pdb` -- cgit v0.12