From b7240ed3f09ffb4bb8bffac3a1ff88b1e99afa26 Mon Sep 17 00:00:00 2001 From: Tian Gao Date: Sun, 23 Jun 2024 14:11:55 -0700 Subject: [PATCH] [3.13] gh-119824: Revert the `where` solution and use meta commands (#120919) --- Lib/pdb.py | 64 ++++++--------- Lib/test/test_pdb.py | 81 +++++++++---------- ...-05-31-21-17-43.gh-issue-119824.CQlxWV.rst | 1 - ...-06-20-01-31-24.gh-issue-120769.PfiMrc.rst | 1 + 4 files changed, 66 insertions(+), 81 deletions(-) delete mode 100644 Misc/NEWS.d/next/Library/2024-05-31-21-17-43.gh-issue-119824.CQlxWV.rst create mode 100644 Misc/NEWS.d/next/Library/2024-06-20-01-31-24.gh-issue-120769.PfiMrc.rst diff --git a/Lib/pdb.py b/Lib/pdb.py index 9e324232b845a2..87837737dcda09 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -519,7 +519,7 @@ def _validate_file_mtime(self): # Called before loop, handles display expressions # Set up convenience variable containers - def preloop(self): + def _show_display(self): displaying = self.displaying.get(self.curframe) if displaying: for expr, oldvalue in displaying.items(): @@ -607,15 +607,13 @@ def interaction(self, frame, tb_or_exc): self.setup(frame, tb) # We should print the stack entry if and only if the user input # is expected, and we should print it right before the user input. - # If self.cmdqueue is not empty, we append a "w 0" command to the - # queue, which is equivalent to print_stack_entry - if self.cmdqueue: - self.cmdqueue.append('w 0') - else: - self.print_stack_entry(self.stack[self.curindex]) + # We achieve this by appending _pdbcmd_print_frame_status to the + # command queue. If cmdqueue is not exausted, the user input is + # not expected and we will not print the stack entry. + self.cmdqueue.append('_pdbcmd_print_frame_status') self._cmdloop() - # If "w 0" is not used, pop it out - if self.cmdqueue and self.cmdqueue[-1] == 'w 0': + # If _pdbcmd_print_frame_status is not used, pop it out + if self.cmdqueue and self.cmdqueue[-1] == '_pdbcmd_print_frame_status': self.cmdqueue.pop() self.forget() @@ -848,6 +846,10 @@ def onecmd(self, line): """ if not self.commands_defining: self._validate_file_mtime() + if line.startswith('_pdbcmd'): + command, arg, line = self.parseline(line) + if hasattr(self, command): + return getattr(self, command)(arg) return cmd.Cmd.onecmd(self, line) else: return self.handle_command_def(line) @@ -981,6 +983,12 @@ def completedefault(self, text, line, begidx, endidx): state += 1 return matches + # Pdb meta commands, only intended to be used internally by pdb + + def _pdbcmd_print_frame_status(self, arg): + self.print_stack_entry(self.stack[self.curindex]) + self._show_display() + # Command definitions, called by cmdloop() # The argument is the remaining string on the command line # Return true to exit from the command loop @@ -1411,24 +1419,16 @@ def do_clear(self, arg): complete_cl = _complete_location def do_where(self, arg): - """w(here) [count] + """w(here) - Print a stack trace. If count is not specified, print the full stack. - If count is 0, print the current frame entry. If count is positive, - print count entries from the most recent frame. If count is negative, - print -count entries from the least recent frame. + 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. """ - if not arg: - count = None - else: - try: - count = int(arg) - except ValueError: - self.error('Invalid count (%s)' % arg) - return - self.print_stack_trace(count) + if arg: + self._print_invalid_arg(arg) + return + self.print_stack_trace() do_w = do_where do_bt = do_where @@ -2083,22 +2083,10 @@ def complete_unalias(self, text, line, begidx, endidx): # It is also consistent with the up/down commands (which are # compatible with dbx and gdb: up moves towards 'main()' # and down moves towards the most recent stack frame). - # * if count is None, prints the full stack - # * if count = 0, prints the current frame entry - # * if count < 0, prints -count least recent frame entries - # * if count > 0, prints count most recent frame entries - - def print_stack_trace(self, count=None): - if count is None: - stack_to_print = self.stack - elif count == 0: - stack_to_print = [self.stack[self.curindex]] - elif count < 0: - stack_to_print = self.stack[:-count] - else: - stack_to_print = self.stack[-count:] + + def print_stack_trace(self): try: - for frame_lineno in stack_to_print: + for frame_lineno in self.stack: self.print_stack_entry(frame_lineno) except KeyboardInterrupt: pass diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index d43e7445aa51cc..4b3557f9b0d389 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -491,6 +491,37 @@ def test_pdb_pp_repr_exc(): (Pdb) continue """ +def test_pdb_empty_line(): + """Test that empty line repeats the last command. + + >>> def test_function(): + ... x = 1 + ... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + ... y = 2 + + >>> with PdbTestInput([ # doctest: +NORMALIZE_WHITESPACE + ... 'p x', + ... '', # Should repeat p x + ... 'n ;; p 0 ;; p x', # Fill cmdqueue with multiple commands + ... '', # Should still repeat p x + ... 'continue', + ... ]): + ... test_function() + > (3)test_function() + -> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + (Pdb) p x + 1 + (Pdb) + 1 + (Pdb) n ;; p 0 ;; p x + 0 + 1 + > (4)test_function() + -> y = 2 + (Pdb) + 1 + (Pdb) continue + """ def do_nothing(): pass @@ -781,7 +812,7 @@ def test_pdb_where_command(): ... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() >>> def f(): - ... g() + ... g(); >>> def test_function(): ... f() @@ -789,13 +820,8 @@ def test_pdb_where_command(): >>> with PdbTestInput([ # doctest: +ELLIPSIS ... 'w', ... 'where', - ... 'w 1', - ... 'w invalid', ... 'u', ... 'w', - ... 'w 0', - ... 'w 100', - ... 'w -100', ... 'continue', ... ]): ... test_function() @@ -803,63 +829,35 @@ def test_pdb_where_command(): -> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() (Pdb) w ... - (13)() + (8)() -> test_function() (2)test_function() -> f() (2)f() - -> g() + -> g(); > (2)g() -> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() (Pdb) where ... - (13)() + (8)() -> test_function() (2)test_function() -> f() (2)f() - -> g() + -> g(); > (2)g() -> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() - (Pdb) w 1 - > (2)g() - -> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() - (Pdb) w invalid - *** Invalid count (invalid) (Pdb) u > (2)f() - -> g() + -> g(); (Pdb) w ... - (13)() - -> test_function() - (2)test_function() - -> f() - > (2)f() - -> g() - (2)g() - -> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() - (Pdb) w 0 - > (2)f() - -> g() - (Pdb) w 100 - ... - (13)() + (8)() -> test_function() (2)test_function() -> f() > (2)f() - -> g() - (2)g() - -> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() - (Pdb) w -100 - ... - (13)() - -> test_function() - (2)test_function() - -> f() - > (2)f() - -> g() + -> g(); (2)g() -> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() (Pdb) continue @@ -3198,7 +3196,6 @@ def test_pdbrc_basic(self): stdout, stderr = self.run_pdb_script(script, 'q\n', pdbrc=pdbrc, remove_home=True) self.assertNotIn("SyntaxError", stdout) self.assertIn("a+8=9", stdout) - self.assertIn("-> b = 2", stdout) def test_pdbrc_empty_line(self): """Test that empty lines in .pdbrc are ignored.""" diff --git a/Misc/NEWS.d/next/Library/2024-05-31-21-17-43.gh-issue-119824.CQlxWV.rst b/Misc/NEWS.d/next/Library/2024-05-31-21-17-43.gh-issue-119824.CQlxWV.rst deleted file mode 100644 index fd6d8d79a9d157..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-31-21-17-43.gh-issue-119824.CQlxWV.rst +++ /dev/null @@ -1 +0,0 @@ -Print stack entry in :mod:`pdb` when and only when user input is needed. diff --git a/Misc/NEWS.d/next/Library/2024-06-20-01-31-24.gh-issue-120769.PfiMrc.rst b/Misc/NEWS.d/next/Library/2024-06-20-01-31-24.gh-issue-120769.PfiMrc.rst new file mode 100644 index 00000000000000..8ee6bf1a9c6480 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-06-20-01-31-24.gh-issue-120769.PfiMrc.rst @@ -0,0 +1 @@ +Make empty line in :mod:`pdb` repeats the last command even when the command is from ``cmdqueue``.