diff --git a/Lib/pdb.py b/Lib/pdb.py index 4abf216b773780..cf0fa66e2f0c8b 100644 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -1286,6 +1286,9 @@ def do_enable(self, arg): Enables the breakpoints given as a space separated list of breakpoint numbers. """ + if not arg: + self._print_invalid_arg(arg) + return args = arg.split() for i in args: try: @@ -1307,6 +1310,9 @@ def do_disable(self, arg): breakpoint, it remains in the list of breakpoints and can be (re-)enabled. """ + if not arg: + self._print_invalid_arg(arg) + return args = arg.split() for i in args: try: @@ -1327,6 +1333,9 @@ def do_condition(self, arg): condition is absent, any existing condition is removed; i.e., the breakpoint is made unconditional. """ + if not arg: + self._print_invalid_arg(arg) + return args = arg.split(' ', 1) try: cond = args[1] @@ -1360,6 +1369,9 @@ def do_ignore(self, arg): and the breakpoint is not disabled and any associated condition evaluates to true. """ + if not arg: + self._print_invalid_arg(arg) + return args = arg.split() if not args: self.error('Breakpoint number expected') @@ -1690,6 +1702,9 @@ def do_jump(self, arg): instance it is not possible to jump into the middle of a for loop or out of a finally clause. """ + if not arg: + self._print_invalid_arg(arg) + return if self.curindex + 1 != len(self.stack): self.error('You can only jump within the bottom frame') return @@ -1715,6 +1730,9 @@ def do_debug(self, arg): argument (which is an arbitrary expression or statement to be executed in the current environment). """ + if not arg: + self._print_invalid_arg(arg) + return sys.settrace(None) globals = self.curframe.f_globals locals = self.curframe.f_locals @@ -1840,6 +1858,9 @@ def do_p(self, arg): Print the value of the expression. """ + if not arg: + self._print_invalid_arg(arg) + return self._msg_val_func(arg, repr) def do_pp(self, arg): @@ -1847,6 +1868,9 @@ def do_pp(self, arg): Pretty-print the value of the expression. """ + if not arg: + self._print_invalid_arg(arg) + return self._msg_val_func(arg, pprint.pformat) complete_print = _complete_expression @@ -1935,6 +1959,9 @@ def do_source(self, arg): Try to get source code for the given object and display it. """ + if not arg: + self._print_invalid_arg(arg) + return try: obj = self._getval(arg) except: @@ -1974,6 +2001,9 @@ def do_whatis(self, arg): Print the type of the argument. """ + if not arg: + self._print_invalid_arg(arg) + return try: value = self._getval(arg) except: @@ -2318,7 +2348,10 @@ def _help_message_from_doc(self, doc, usage_only=False): def _print_invalid_arg(self, arg): """Return the usage string for a function.""" - self.error(f"Invalid argument: {arg}") + if not arg: + self.error("Argument is required for this command") + else: + self.error(f"Invalid argument: {arg}") # Yes it's a bit hacky. Get the caller name, get the method based on # that name, and get the docstring from that method. diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 4d371a6e754b96..7e8bd73625bb4a 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -1758,10 +1758,12 @@ def test_pdb_invalid_arg(): >>> def test_function(): ... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() - >>> with PdbTestInput([ + >>> with PdbTestInput([ # doctest: +NORMALIZE_WHITESPACE ... 'a = 3', ... 'll 4', ... 'step 1', + ... 'p', + ... 'enable ', ... 'continue' ... ]): ... test_function() @@ -1776,6 +1778,12 @@ def test_pdb_invalid_arg(): (Pdb) step 1 *** Invalid argument: 1 Usage: s(tep) + (Pdb) p + *** Argument is required for this command + Usage: p expression + (Pdb) enable + *** Argument is required for this command + Usage: enable bpnumber [bpnumber ...] (Pdb) continue """ diff --git a/Misc/NEWS.d/next/Library/2025-02-17-21-01-25.gh-issue-126944.49YTHZ.rst b/Misc/NEWS.d/next/Library/2025-02-17-21-01-25.gh-issue-126944.49YTHZ.rst new file mode 100644 index 00000000000000..afc3ab777646cb --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-02-17-21-01-25.gh-issue-126944.49YTHZ.rst @@ -0,0 +1 @@ +Show explicit errors when required arguments of :mod:`pdb` commands are missing