Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gh-103124: Multiline statement support for pdb #103125

Merged
merged 5 commits into from
Jun 15, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
26 changes: 25 additions & 1 deletion Lib/pdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
import dis
import code
import glob
import codeop
import pprint
import signal
import inspect
Expand Down Expand Up @@ -438,7 +439,30 @@ def default(self, line):
locals = self.curframe_locals
globals = self.curframe.f_globals
try:
code = compile(line + '\n', '<stdin>', 'single')
if (code := codeop.compile_command(line + '\n', '<stdin>', 'single')) is None:
brandtbucher marked this conversation as resolved.
Show resolved Hide resolved
# Multi-line mode
buffer = line
continue_prompt = "... "
while (code := codeop.compile_command(buffer, '<stdin>', 'single')) is None:
if self.use_rawinput:
try:
line = input(continue_prompt)
except (EOFError, KeyboardInterrupt):
self.lastcmd = ""
print('\n')
return
else:
self.stdout.write(continue_prompt)
self.stdout.flush()
line = self.stdin.readline()
if not len(line):
self.lastcmd = ""
self.stdout.write('\n')
self.stdout.flush()
return
else:
line = line.rstrip('\r\n')
brandtbucher marked this conversation as resolved.
Show resolved Hide resolved
buffer += '\n' + line
save_stdout = sys.stdout
save_stdin = sys.stdin
save_displayhook = sys.displayhook
Expand Down
33 changes: 30 additions & 3 deletions Lib/test/test_pdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ def test_pdb_breakpoints_preserved_across_interactive_sessions():
1 breakpoint keep yes at ...test_pdb.py:...
2 breakpoint keep yes at ...test_pdb.py:...
(Pdb) break pdb.find_function
Breakpoint 3 at ...pdb.py:97
Breakpoint 3 at ...pdb.py:...
(Pdb) break
Num Type Disp Enb Where
1 breakpoint keep yes at ...test_pdb.py:...
Expand Down Expand Up @@ -1481,6 +1481,32 @@ def test_pdb_next_command_subiterator():
(Pdb) continue
"""

def test_pdb_multiline_statement():
"""Test for multiline statement

>>> def test_function():
... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
... pass

>>> with PdbTestInput([ # doctest: +NORMALIZE_WHITESPACE
... 'def f(x):',
... ' return x * 2',
... '',
... 'f(2)',
... 'c'
... ]):
... test_function()
> <doctest test.test_pdb.test_pdb_multiline_statement[0]>(3)test_function()
-> pass
(Pdb) def f(x):
... return x * 2
...
(Pdb) f(2)
4
(Pdb) c
"""


def test_pdb_issue_20766():
"""Test for reference leaks when the SIGINT handler is set.

Expand Down Expand Up @@ -2185,7 +2211,7 @@ def test_relative_imports_on_plain_module(self):

def test_errors_in_command(self):
commands = "\n".join([
'print(',
'print(]',
'debug print(',
'debug doesnotexist',
'c',
Expand All @@ -2194,7 +2220,8 @@ def test_errors_in_command(self):

self.assertEqual(stdout.splitlines()[1:], [
'-> pass',
'(Pdb) *** SyntaxError: \'(\' was never closed',
"(Pdb) *** SyntaxError: closing parenthesis ']' does not match opening "
"parenthesis '('",

'(Pdb) ENTERING RECURSIVE DEBUGGER',
'*** SyntaxError: \'(\' was never closed',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added multiline statement support for :mod:`pdb`