From 2f41a009b7311a4b44bae5b3583cde3d6d10d8d1 Mon Sep 17 00:00:00 2001 From: Tian Gao Date: Tue, 11 Apr 2023 15:40:30 -0700 Subject: gh-103143: Polish pdb help messages and doc strings (GH-103144) * Made all the command part of the docstring match the official documentation * Always have a space between the command and the description in docstring * Added a helper function to format the help message Before: ``` (Pdb) h a a(rgs) Print the argument list of the current function. (Pdb) h commands commands [bpnumber] (com) ... (com) end (Pdb) ... (Pdb) h interact interact Start an interactive interpreter whose global namespace contains all the (global and local) names found in the current scope. ``` After ``` (Pdb) h a Usage: a(rgs) Print the argument list of the current function. (Pdb) h commands Usage: (Pdb) commands [bpnumber] (com) ... (com) end (Pdb) ... (Pdb) h interact Usage: interact Start an interactive interpreter whose global namespace contains all the (global and local) names found in the current scope. ``` Automerge-Triggered-By: GH:brandtbucher --- Doc/library/pdb.rst | 4 +- Lib/pdb.py | 67 +++++++++++++++++++--- .../2023-03-31-01-13-00.gh-issue-103143.6eMluy.rst | 1 + 3 files changed, 62 insertions(+), 10 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-03-31-01-13-00.gh-issue-103143.6eMluy.rst diff --git a/Doc/library/pdb.rst b/Doc/library/pdb.rst index d80c5ee..4170882 100644 --- a/Doc/library/pdb.rst +++ b/Doc/library/pdb.rst @@ -315,14 +315,14 @@ can be overridden by the local file. With a space separated list of breakpoint numbers, clear those breakpoints. Without argument, clear all breaks (but first ask confirmation). -.. pdbcommand:: disable [bpnumber ...] +.. pdbcommand:: disable bpnumber [bpnumber ...] Disable the breakpoints given as a space separated list of breakpoint numbers. Disabling a breakpoint means it cannot cause the program to stop execution, but unlike clearing a breakpoint, it remains in the list of breakpoints and can be (re-)enabled. -.. pdbcommand:: enable [bpnumber ...] +.. pdbcommand:: enable bpnumber [bpnumber ...] Enable the breakpoints specified. diff --git a/Lib/pdb.py b/Lib/pdb.py index e03142e..a3553b3 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -586,7 +586,7 @@ class Pdb(bdb.Bdb, cmd.Cmd): # Return true to exit from the command loop def do_commands(self, arg): - """commands [bpnumber] + """(Pdb) commands [bpnumber] (com) ... (com) end (Pdb) @@ -672,6 +672,7 @@ class Pdb(bdb.Bdb, cmd.Cmd): def do_break(self, arg, temporary = 0): """b(reak) [ ([filename:]lineno | function) [, condition] ] + Without argument, list all breaks. With a line number argument, set a break at this line in the @@ -780,6 +781,7 @@ class Pdb(bdb.Bdb, cmd.Cmd): def do_tbreak(self, arg): """tbreak [ ([filename:]lineno | function) [, condition] ] + Same arguments as break, but sets a temporary breakpoint: it is automatically deleted when first hit. """ @@ -844,6 +846,7 @@ class Pdb(bdb.Bdb, cmd.Cmd): def do_enable(self, arg): """enable bpnumber [bpnumber ...] + Enables the breakpoints given as a space separated list of breakpoint numbers. """ @@ -861,6 +864,7 @@ class Pdb(bdb.Bdb, cmd.Cmd): def do_disable(self, arg): """disable bpnumber [bpnumber ...] + Disables the breakpoints given as a space separated list of breakpoint numbers. Disabling a breakpoint means it cannot cause the program to stop execution, but unlike clearing a @@ -881,6 +885,7 @@ class Pdb(bdb.Bdb, cmd.Cmd): def do_condition(self, arg): """condition bpnumber [condition] + Set a new condition for the breakpoint, an expression which must evaluate to true before the breakpoint is honored. If condition is absent, any existing condition is removed; i.e., @@ -911,6 +916,7 @@ class Pdb(bdb.Bdb, cmd.Cmd): def do_ignore(self, arg): """ignore bpnumber [count] + Set the ignore count for the given breakpoint number. If count is omitted, the ignore count is set to 0. A breakpoint becomes active when the ignore count is zero. When non-zero, @@ -945,7 +951,8 @@ class Pdb(bdb.Bdb, cmd.Cmd): complete_ignore = _complete_bpnumber def do_clear(self, arg): - """cl(ear) filename:lineno\ncl(ear) [bpnumber [bpnumber...]] + """cl(ear) [filename:lineno | bpnumber ...] + With a space separated list of breakpoint numbers, clear those breakpoints. Without argument, clear all breaks (but first ask confirmation). With a filename:lineno argument, @@ -997,6 +1004,7 @@ class Pdb(bdb.Bdb, cmd.Cmd): def do_where(self, arg): """w(here) + Print a stack trace, with the most recent frame at the bottom. An arrow indicates the "current frame", which determines the context of most commands. 'bt' is an alias for this command. @@ -1015,6 +1023,7 @@ class Pdb(bdb.Bdb, cmd.Cmd): def do_up(self, arg): """u(p) [count] + Move the current frame count (default one) levels up in the stack trace (to an older frame). """ @@ -1035,6 +1044,7 @@ class Pdb(bdb.Bdb, cmd.Cmd): def do_down(self, arg): """d(own) [count] + Move the current frame count (default one) levels down in the stack trace (to a newer frame). """ @@ -1055,6 +1065,7 @@ class Pdb(bdb.Bdb, cmd.Cmd): def do_until(self, arg): """unt(il) [lineno] + Without argument, continue execution until the line with a number greater than the current one is reached. With a line number, continue execution until a line with a number greater @@ -1079,6 +1090,7 @@ class Pdb(bdb.Bdb, cmd.Cmd): def do_step(self, arg): """s(tep) + Execute the current line, stop at the first possible occasion (either in a function that is called or in the current function). @@ -1089,6 +1101,7 @@ class Pdb(bdb.Bdb, cmd.Cmd): def do_next(self, arg): """n(ext) + Continue execution until the next line in the current function is reached or it returns. """ @@ -1098,6 +1111,7 @@ class Pdb(bdb.Bdb, cmd.Cmd): def do_run(self, arg): """run [args...] + Restart the debugged python program. If a string is supplied it is split with "shlex", and the result is used as the new sys.argv. History, breakpoints, actions and debugger options @@ -1119,6 +1133,7 @@ class Pdb(bdb.Bdb, cmd.Cmd): def do_return(self, arg): """r(eturn) + Continue execution until the current function returns. """ self.set_return(self.curframe) @@ -1127,6 +1142,7 @@ class Pdb(bdb.Bdb, cmd.Cmd): def do_continue(self, arg): """c(ont(inue)) + Continue execution, only stop when a breakpoint is encountered. """ if not self.nosigint: @@ -1145,6 +1161,7 @@ class Pdb(bdb.Bdb, cmd.Cmd): def do_jump(self, arg): """j(ump) lineno + Set the next line that will be executed. Only available in the bottom-most frame. This lets you jump back and execute code again, or jump forward to skip code that you don't want @@ -1174,6 +1191,7 @@ class Pdb(bdb.Bdb, cmd.Cmd): def do_debug(self, arg): """debug code + Enter a recursive debugger that steps through the code argument (which is an arbitrary expression or statement to be executed in the current environment). @@ -1195,7 +1213,8 @@ class Pdb(bdb.Bdb, cmd.Cmd): complete_debug = _complete_expression def do_quit(self, arg): - """q(uit)\nexit + """q(uit) | exit + Quit from the debugger. The program being executed is aborted. """ self._user_requested_quit = True @@ -1207,6 +1226,7 @@ class Pdb(bdb.Bdb, cmd.Cmd): def do_EOF(self, arg): """EOF + Handles the receipt of EOF as a command. """ self.message('') @@ -1216,6 +1236,7 @@ class Pdb(bdb.Bdb, cmd.Cmd): def do_args(self, arg): """a(rgs) + Print the argument list of the current function. """ co = self.curframe.f_code @@ -1233,6 +1254,7 @@ class Pdb(bdb.Bdb, cmd.Cmd): def do_retval(self, arg): """retval + Print the return value for the last return of a function. """ if '__return__' in self.curframe_locals: @@ -1273,12 +1295,14 @@ class Pdb(bdb.Bdb, cmd.Cmd): def do_p(self, arg): """p expression + Print the value of the expression. """ self._msg_val_func(arg, repr) def do_pp(self, arg): """pp expression + Pretty-print the value of the expression. """ self._msg_val_func(arg, pprint.pformat) @@ -1288,7 +1312,7 @@ class Pdb(bdb.Bdb, cmd.Cmd): complete_pp = _complete_expression def do_list(self, arg): - """l(ist) [first [,last] | .] + """l(ist) [first[, last] | .] List source code for the current file. Without arguments, list 11 lines around the current line or continue the previous @@ -1345,7 +1369,8 @@ class Pdb(bdb.Bdb, cmd.Cmd): do_l = do_list def do_longlist(self, arg): - """longlist | ll + """ll | longlist + List the whole source code for the current function or frame. """ filename = self.curframe.f_code.co_filename @@ -1360,6 +1385,7 @@ class Pdb(bdb.Bdb, cmd.Cmd): def do_source(self, arg): """source expression + Try to get source code for the given object and display it. """ try: @@ -1397,7 +1423,8 @@ class Pdb(bdb.Bdb, cmd.Cmd): self.message(s + '\t' + line.rstrip()) def do_whatis(self, arg): - """whatis arg + """whatis expression + Print the type of the argument. """ try: @@ -1485,7 +1512,8 @@ class Pdb(bdb.Bdb, cmd.Cmd): code.interact("*interactive*", local=ns) def do_alias(self, arg): - """alias [name [command [parameter parameter ...] ]] + """alias [name [command]] + Create an alias called 'name' that executes 'command'. The command must *not* be enclosed in quotes. Replaceable parameters can be indicated by %1, %2, and so on, while %* is @@ -1521,6 +1549,7 @@ class Pdb(bdb.Bdb, cmd.Cmd): def do_unalias(self, arg): """unalias name + Delete the specified alias. """ args = arg.split() @@ -1563,6 +1592,7 @@ class Pdb(bdb.Bdb, cmd.Cmd): def do_help(self, arg): """h(elp) + Without argument, print the list of available commands. With a command name as argument, print help about that command. "help pdb" shows the full pdb documentation. @@ -1586,12 +1616,13 @@ class Pdb(bdb.Bdb, cmd.Cmd): if command.__doc__ is None: self.error('No help for %r; __doc__ string missing' % arg) return - self.message(command.__doc__.rstrip()) + self.message(self._help_message_from_doc(command.__doc__)) do_h = do_help def help_exec(self): """(!) statement + Execute the (one-line) statement in the context of the current stack frame. The exclamation point can be omitted unless the first word of the statement resembles a debugger command. To @@ -1672,6 +1703,26 @@ class Pdb(bdb.Bdb, cmd.Cmd): lineno = max(1, lineno) return lines, lineno + def _help_message_from_doc(self, doc): + lines = [line.strip() for line in doc.rstrip().splitlines()] + if not lines: + return "No help message found." + if "" in lines: + usage_end = lines.index("") + else: + usage_end = 1 + formatted = [] + indent = " " * len(self.prompt) + for i, line in enumerate(lines): + if i == 0: + prefix = "Usage: " + elif i < usage_end: + prefix = " " + else: + prefix = "" + formatted.append(indent + prefix + line) + return "\n".join(formatted) + # Collect all command help into docstring, if not run with -OO if __doc__ is not None: diff --git a/Misc/NEWS.d/next/Library/2023-03-31-01-13-00.gh-issue-103143.6eMluy.rst b/Misc/NEWS.d/next/Library/2023-03-31-01-13-00.gh-issue-103143.6eMluy.rst new file mode 100644 index 0000000..32bd62d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-31-01-13-00.gh-issue-103143.6eMluy.rst @@ -0,0 +1 @@ +Polish the help messages and docstrings of :mod:`pdb`. -- cgit v0.12