Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion Lib/pdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -1758,7 +1758,10 @@ def do_quit(self, arg):

Quit from the debugger. The program being executed is aborted.
"""
if self.mode == 'inline':
# Show prompt to kill process when in 'inline' mode and if pdb was not
# started from an interactive console. The attribute sys.ps1 is only
# defined if the interpreter is in interactive mode.
if self.mode == 'inline' and not hasattr(sys, 'ps1'):
while True:
try:
reply = input('Quitting pdb will kill the process. Quit anyway? [y/n] ')
Expand Down
31 changes: 29 additions & 2 deletions Lib/test/test_pdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
from test.support import force_not_colorized, os_helper
from test.support.import_helper import import_module
from test.support.pty_helper import run_pty, FakeInput
from test.support.script_helper import kill_python
# Deferred import: from test.test_repl import spawn_repl
from unittest.mock import patch

SKIP_CORO_TESTS = False
Expand Down Expand Up @@ -4278,6 +4280,8 @@ def test_checkline_is_not_executable(self):
self.assertFalse(db.checkline(os_helper.TESTFN, lineno))


QUIT_PROMPT_QUESTION = "Quit anyway"

@support.requires_subprocess()
class PdbTestInline(unittest.TestCase):
@unittest.skipIf(sys.flags.safe_path,
Expand Down Expand Up @@ -4331,15 +4335,38 @@ def test_quit(self):

stdout, stderr = self._run_script(script, commands)
self.assertIn("2", stdout)
self.assertIn("Quit anyway", stdout)
self.assertIn(QUIT_PROMPT_QUESTION, stdout)
# Closing stdin will quit the debugger anyway so we need to confirm
# it's the quit command that does the job
# call/return event will print --Call-- and --Return--
self.assertNotIn("--", stdout)
# Normal exit should not print anything to stderr
self.assertEqual(stderr, "")
# The quit prompt should be printed exactly twice
self.assertEqual(stdout.count("Quit anyway"), 2)
self.assertEqual(stdout.count(QUIT_PROMPT_QUESTION), 2)


@support.force_not_colorized_test_class
@support.requires_subprocess()
class TestREPLSession(unittest.TestCase):
def test_return_from_inline_mode_to_REPL(self):
# GH-124703: Raise BdbQuit when exiting pdb in REPL session.
# This allows the REPL session to continue.
user_input = """
x = 'Spam'
import pdb
pdb.set_trace(commands=['x * 3', 'q'])
x[::-1] * 3
"""
from test.test_repl import spawn_repl
p = spawn_repl()
p.stdin.write(textwrap.dedent(user_input))
output = kill_python(p)
self.assertIn('SpamSpamSpam', output)
self.assertNotIn(QUIT_PROMPT_QUESTION, output)
self.assertIn('BdbQuit', output)
self.assertIn('mapSmapSmapS', output)
self.assertEqual(p.returncode, 0)


@support.requires_subprocess()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Executing ``quit`` command in :mod:`pdb` will raise :exc:`bdb.BdbQuit` when :mod:`pdb` is started from an interactive console using :func:`breakpoint` or :func:`pdb.set_trace`.
Loading