Skip to content

Commit

Permalink
[3.13] pythongh-119824: Print stack entry when user input is needed (p…
Browse files Browse the repository at this point in the history
…ythonGH-119882) (python#120533)

Co-authored-by: Irit Katriel <[email protected]>
  • Loading branch information
gaogaotiantian and iritkatriel authored Jun 16, 2024
1 parent 6ee68fb commit 1c41aa7
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 19 deletions.
50 changes: 39 additions & 11 deletions Lib/pdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -605,10 +605,18 @@ def interaction(self, frame, tb_or_exc):
assert tb is not None, "main exception must have a traceback"
with self._hold_exceptions(_chained_exceptions):
self.setup(frame, tb)
# if we have more commands to process, do not show the stack entry
if not self.cmdqueue:
# 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])
self._cmdloop()
# If "w 0" is not used, pop it out
if self.cmdqueue and self.cmdqueue[-1] == 'w 0':
self.cmdqueue.pop()
self.forget()

def displayhook(self, obj):
Expand Down Expand Up @@ -1403,16 +1411,24 @@ def do_clear(self, arg):
complete_cl = _complete_location

def do_where(self, arg):
"""w(here)
"""w(here) [count]
Print a stack trace, with the most recent frame at the bottom.
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.
An arrow indicates the "current frame", which determines the
context of most commands. 'bt' is an alias for this command.
"""
if arg:
self._print_invalid_arg(arg)
return
self.print_stack_trace()
if not arg:
count = None
else:
try:
count = int(arg)
except ValueError:
self.error('Invalid count (%s)' % arg)
return
self.print_stack_trace(count)
do_w = do_where
do_bt = do_where

Expand Down Expand Up @@ -2067,10 +2083,22 @@ 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).

def print_stack_trace(self):
# * 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:]
try:
for frame_lineno in self.stack:
for frame_lineno in stack_to_print:
self.print_stack_entry(frame_lineno)
except KeyboardInterrupt:
pass
Expand Down
50 changes: 42 additions & 8 deletions Lib/test/test_pdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -781,52 +781,85 @@ def test_pdb_where_command():
... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
>>> def f():
... g();
... g()
>>> def test_function():
... f()
>>> with PdbTestInput([ # doctest: +ELLIPSIS
... 'w',
... 'where',
... 'w 1',
... 'w invalid',
... 'u',
... 'w',
... 'w 0',
... 'w 100',
... 'w -100',
... 'continue',
... ]):
... test_function()
> <doctest test.test_pdb.test_pdb_where_command[0]>(2)g()
-> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
(Pdb) w
...
<doctest test.test_pdb.test_pdb_where_command[3]>(8)<module>()
<doctest test.test_pdb.test_pdb_where_command[3]>(13)<module>()
-> test_function()
<doctest test.test_pdb.test_pdb_where_command[2]>(2)test_function()
-> f()
<doctest test.test_pdb.test_pdb_where_command[1]>(2)f()
-> g();
-> g()
> <doctest test.test_pdb.test_pdb_where_command[0]>(2)g()
-> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
(Pdb) where
...
<doctest test.test_pdb.test_pdb_where_command[3]>(8)<module>()
<doctest test.test_pdb.test_pdb_where_command[3]>(13)<module>()
-> test_function()
<doctest test.test_pdb.test_pdb_where_command[2]>(2)test_function()
-> f()
<doctest test.test_pdb.test_pdb_where_command[1]>(2)f()
-> g();
-> g()
> <doctest test.test_pdb.test_pdb_where_command[0]>(2)g()
-> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
(Pdb) w 1
> <doctest test.test_pdb.test_pdb_where_command[0]>(2)g()
-> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
(Pdb) w invalid
*** Invalid count (invalid)
(Pdb) u
> <doctest test.test_pdb.test_pdb_where_command[1]>(2)f()
-> g();
-> g()
(Pdb) w
...
<doctest test.test_pdb.test_pdb_where_command[3]>(8)<module>()
<doctest test.test_pdb.test_pdb_where_command[3]>(13)<module>()
-> test_function()
<doctest test.test_pdb.test_pdb_where_command[2]>(2)test_function()
-> f()
> <doctest test.test_pdb.test_pdb_where_command[1]>(2)f()
-> g()
<doctest test.test_pdb.test_pdb_where_command[0]>(2)g()
-> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
(Pdb) w 0
> <doctest test.test_pdb.test_pdb_where_command[1]>(2)f()
-> g()
(Pdb) w 100
...
<doctest test.test_pdb.test_pdb_where_command[3]>(13)<module>()
-> test_function()
<doctest test.test_pdb.test_pdb_where_command[2]>(2)test_function()
-> f()
> <doctest test.test_pdb.test_pdb_where_command[1]>(2)f()
-> g();
-> g()
<doctest test.test_pdb.test_pdb_where_command[0]>(2)g()
-> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
(Pdb) w -100
...
<doctest test.test_pdb.test_pdb_where_command[3]>(13)<module>()
-> test_function()
<doctest test.test_pdb.test_pdb_where_command[2]>(2)test_function()
-> f()
> <doctest test.test_pdb.test_pdb_where_command[1]>(2)f()
-> g()
<doctest test.test_pdb.test_pdb_where_command[0]>(2)g()
-> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
(Pdb) continue
Expand Down Expand Up @@ -3165,6 +3198,7 @@ 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."""
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Print stack entry in :mod:`pdb` when and only when user input is needed.

0 comments on commit 1c41aa7

Please sign in to comment.