From 7d275611f62c9008c2d90b08c9f21462f80a8328 Mon Sep 17 00:00:00 2001 From: Tian Gao Date: Sun, 26 Jan 2025 22:29:16 -0500 Subject: [PATCH] gh-124703: Do not raise an exception when quitting pdb (#124704) --- Lib/pdb.py | 17 +++++- Lib/test/test_pdb.py | 56 +++++++++++++++++++ ...-09-27-19-21-53.gh-issue-124703.lYTLEv.rst | 1 + 3 files changed, 71 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-09-27-19-21-53.gh-issue-124703.lYTLEv.rst diff --git a/Lib/pdb.py b/Lib/pdb.py index 10d1923cdad2d6..beef74d792250b 100644 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -1725,6 +1725,19 @@ def do_quit(self, arg): Quit from the debugger. The program being executed is aborted. """ + if self.mode == 'inline': + while True: + try: + reply = input('Quitting pdb will kill the process. Quit anyway? [y/n] ') + reply = reply.lower().strip() + except EOFError: + reply = 'y' + self.message('') + if reply == 'y' or reply == '': + sys.exit(0) + elif reply.lower() == 'n': + return + self._user_requested_quit = True self.set_quit() return 1 @@ -1738,9 +1751,7 @@ def do_EOF(self, arg): Handles the receipt of EOF as a command. """ self.message('') - self._user_requested_quit = True - self.set_quit() - return 1 + return self.do_quit(arg) def do_args(self, arg): """a(rgs) diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 09601623b29ac1..4d371a6e754b96 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -4237,6 +4237,62 @@ def test_checkline_is_not_executable(self): self.assertFalse(db.checkline(os_helper.TESTFN, lineno)) +@support.requires_subprocess() +class PdbTestInline(unittest.TestCase): + @unittest.skipIf(sys.flags.safe_path, + 'PYTHONSAFEPATH changes default sys.path') + def _run_script(self, script, commands, + expected_returncode=0, + extra_env=None): + self.addCleanup(os_helper.rmtree, '__pycache__') + filename = 'main.py' + with open(filename, 'w') as f: + f.write(textwrap.dedent(script)) + self.addCleanup(os_helper.unlink, filename) + + commands = textwrap.dedent(commands) + + cmd = [sys.executable, 'main.py'] + if extra_env is not None: + env = os.environ | extra_env + else: + env = os.environ + with subprocess.Popen( + cmd, + stdout=subprocess.PIPE, + stdin=subprocess.PIPE, + stderr=subprocess.PIPE, + env = {**env, 'PYTHONIOENCODING': 'utf-8'} + ) as proc: + stdout, stderr = proc.communicate(str.encode(commands)) + stdout = bytes.decode(stdout) if isinstance(stdout, bytes) else stdout + stderr = bytes.decode(stderr) if isinstance(stderr, bytes) else stderr + self.assertEqual( + proc.returncode, + expected_returncode, + f"Unexpected return code\nstdout: {stdout}\nstderr: {stderr}" + ) + return stdout, stderr + + def test_quit(self): + script = """ + x = 1 + breakpoint() + """ + + commands = """ + quit + n + p x + 1 + quit + y + """ + + stdout, stderr = self._run_script(script, commands) + self.assertIn("2", stdout) + self.assertIn("Quit anyway", stdout) + + @support.requires_subprocess() class PdbTestReadline(unittest.TestCase): def setUpClass(): diff --git a/Misc/NEWS.d/next/Library/2024-09-27-19-21-53.gh-issue-124703.lYTLEv.rst b/Misc/NEWS.d/next/Library/2024-09-27-19-21-53.gh-issue-124703.lYTLEv.rst new file mode 100644 index 00000000000000..e55d3539355d73 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-09-27-19-21-53.gh-issue-124703.lYTLEv.rst @@ -0,0 +1 @@ +Quitting :mod:`pdb` in ``inline`` mode will emit a confirmation prompt and exit gracefully now, instead of printing an exception traceback.