[3.13] gh-119824: Print stack entry when user input is needed (GH-119882) (#120533)

Co-authored-by: Irit Katriel <1055913+iritkatriel@users.noreply.github.com>
This commit is contained in:
Tian Gao 2024-06-16 12:05:07 -07:00 committed by GitHub
parent 6ee68fbf9b
commit 1c41aa78d8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 81 additions and 18 deletions

View File

@ -605,10 +605,18 @@ class Pdb(bdb.Bdb, cmd.Cmd):
assert tb is not None, "main exception must have a traceback" assert tb is not None, "main exception must have a traceback"
with self._hold_exceptions(_chained_exceptions): with self._hold_exceptions(_chained_exceptions):
self.setup(frame, tb) self.setup(frame, tb)
# if we have more commands to process, do not show the stack entry # We should print the stack entry if and only if the user input
if not self.cmdqueue: # 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.print_stack_entry(self.stack[self.curindex])
self._cmdloop() 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() self.forget()
def displayhook(self, obj): def displayhook(self, obj):
@ -1403,16 +1411,24 @@ class Pdb(bdb.Bdb, cmd.Cmd):
complete_cl = _complete_location complete_cl = _complete_location
def do_where(self, arg): 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 An arrow indicates the "current frame", which determines the
context of most commands. 'bt' is an alias for this command. context of most commands. 'bt' is an alias for this command.
""" """
if arg: if not arg:
self._print_invalid_arg(arg) count = None
return else:
self.print_stack_trace() try:
count = int(arg)
except ValueError:
self.error('Invalid count (%s)' % arg)
return
self.print_stack_trace(count)
do_w = do_where do_w = do_where
do_bt = do_where do_bt = do_where
@ -2067,10 +2083,22 @@ class Pdb(bdb.Bdb, cmd.Cmd):
# It is also consistent with the up/down commands (which are # It is also consistent with the up/down commands (which are
# compatible with dbx and gdb: up moves towards 'main()' # compatible with dbx and gdb: up moves towards 'main()'
# and down moves towards the most recent stack frame). # 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): 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: try:
for frame_lineno in self.stack: for frame_lineno in stack_to_print:
self.print_stack_entry(frame_lineno) self.print_stack_entry(frame_lineno)
except KeyboardInterrupt: except KeyboardInterrupt:
pass pass

View File

@ -781,7 +781,7 @@ def test_pdb_where_command():
... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() ... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
>>> def f(): >>> def f():
... g(); ... g()
>>> def test_function(): >>> def test_function():
... f() ... f()
@ -789,8 +789,13 @@ def test_pdb_where_command():
>>> with PdbTestInput([ # doctest: +ELLIPSIS >>> with PdbTestInput([ # doctest: +ELLIPSIS
... 'w', ... 'w',
... 'where', ... 'where',
... 'w 1',
... 'w invalid',
... 'u', ... 'u',
... 'w', ... 'w',
... 'w 0',
... 'w 100',
... 'w -100',
... 'continue', ... 'continue',
... ]): ... ]):
... test_function() ... test_function()
@ -798,35 +803,63 @@ def test_pdb_where_command():
-> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() -> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
(Pdb) w (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() -> test_function()
<doctest test.test_pdb.test_pdb_where_command[2]>(2)test_function() <doctest test.test_pdb.test_pdb_where_command[2]>(2)test_function()
-> f() -> f()
<doctest test.test_pdb.test_pdb_where_command[1]>(2)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() > <doctest test.test_pdb.test_pdb_where_command[0]>(2)g()
-> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() -> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
(Pdb) where (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() -> test_function()
<doctest test.test_pdb.test_pdb_where_command[2]>(2)test_function() <doctest test.test_pdb.test_pdb_where_command[2]>(2)test_function()
-> f() -> f()
<doctest test.test_pdb.test_pdb_where_command[1]>(2)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() > <doctest test.test_pdb.test_pdb_where_command[0]>(2)g()
-> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() -> 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 (Pdb) u
> <doctest test.test_pdb.test_pdb_where_command[1]>(2)f() > <doctest test.test_pdb.test_pdb_where_command[1]>(2)f()
-> g(); -> g()
(Pdb) w (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() -> test_function()
<doctest test.test_pdb.test_pdb_where_command[2]>(2)test_function() <doctest test.test_pdb.test_pdb_where_command[2]>(2)test_function()
-> f() -> f()
> <doctest test.test_pdb.test_pdb_where_command[1]>(2)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 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()
<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() <doctest test.test_pdb.test_pdb_where_command[0]>(2)g()
-> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() -> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
(Pdb) continue (Pdb) continue
@ -3165,6 +3198,7 @@ def bœr():
stdout, stderr = self.run_pdb_script(script, 'q\n', pdbrc=pdbrc, remove_home=True) stdout, stderr = self.run_pdb_script(script, 'q\n', pdbrc=pdbrc, remove_home=True)
self.assertNotIn("SyntaxError", stdout) self.assertNotIn("SyntaxError", stdout)
self.assertIn("a+8=9", stdout) self.assertIn("a+8=9", stdout)
self.assertIn("-> b = 2", stdout)
def test_pdbrc_empty_line(self): def test_pdbrc_empty_line(self):
"""Test that empty lines in .pdbrc are ignored.""" """Test that empty lines in .pdbrc are ignored."""

View File

@ -0,0 +1 @@
Print stack entry in :mod:`pdb` when and only when user input is needed.