From a9a90f9af2899256ca3731e85d65f35f7dee5a01 Mon Sep 17 00:00:00 2001 From: Shrey Naithani Date: Wed, 15 Apr 2026 19:10:27 +0500 Subject: [PATCH 1/7] Improve argument handling in pdb.py --- Lib/pdb.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Lib/pdb.py b/Lib/pdb.py index 7b08d2bb70183d..1a9c1b4549164f 100644 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -3635,9 +3635,14 @@ def parse_args(): opts.module = opt_module.module args = args[2:] elif args[0].startswith('-'): - # Invalid argument before the script name. - invalid_args = list(itertools.takewhile(lambda a: a.startswith('-'), args)) - parser.error(f"unrecognized arguments: {' '.join(invalid_args)}") + if args[0] == '--': + args.pop(0) + if not args: + parser.error("missing script or module to run") + else: + # Invalid argument before the script name. + invalid_args = list(itertools.takewhile(lambda a: a.startswith('-'), args)) + parser.error(f"unrecognized arguments: {' '.join(invalid_args)}") # Otherwise it's debugging a script and we already parsed all -c commands. From 90bf8d74894e3ec446ca8fa23521655c1ad1ca53 Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Wed, 15 Apr 2026 16:08:13 +0000 Subject: [PATCH 2/7] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Library/2026-04-15-16-08-12.gh-issue-148615.Uvx50R.rst | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-04-15-16-08-12.gh-issue-148615.Uvx50R.rst diff --git a/Misc/NEWS.d/next/Library/2026-04-15-16-08-12.gh-issue-148615.Uvx50R.rst b/Misc/NEWS.d/next/Library/2026-04-15-16-08-12.gh-issue-148615.Uvx50R.rst new file mode 100644 index 00000000000000..a61720d52fcf65 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-04-15-16-08-12.gh-issue-148615.Uvx50R.rst @@ -0,0 +1,3 @@ +Fix :mod:`pdb` to accept standard ``--`` end of options separator, +which was inadvertently rejected since the switch from :mod:`getopt` to +:mod:`argparse` in Python 3.13. Patch by Shrey Naithani. From 7bb3741f2a83d9cd145a85d93df989f9ab3434c2 Mon Sep 17 00:00:00 2001 From: Shrey Naithani Date: Wed, 15 Apr 2026 21:39:48 +0530 Subject: [PATCH 3/7] Adding name of the reporter --- .../next/Library/2026-04-15-16-08-12.gh-issue-148615.Uvx50R.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2026-04-15-16-08-12.gh-issue-148615.Uvx50R.rst b/Misc/NEWS.d/next/Library/2026-04-15-16-08-12.gh-issue-148615.Uvx50R.rst index a61720d52fcf65..1f355cda5791a8 100644 --- a/Misc/NEWS.d/next/Library/2026-04-15-16-08-12.gh-issue-148615.Uvx50R.rst +++ b/Misc/NEWS.d/next/Library/2026-04-15-16-08-12.gh-issue-148615.Uvx50R.rst @@ -1,3 +1,3 @@ Fix :mod:`pdb` to accept standard ``--`` end of options separator, which was inadvertently rejected since the switch from :mod:`getopt` to -:mod:`argparse` in Python 3.13. Patch by Shrey Naithani. +:mod:`argparse` in Python 3.13. Reported by haampie. Patched by Shrey Naithani. From 3cb7cdfb57983258d356c4c8d0daca2c40977f74 Mon Sep 17 00:00:00 2001 From: Shrey Naithani Date: Thu, 16 Apr 2026 17:37:47 +0500 Subject: [PATCH 4/7] Refactor the patch based on suggestions from the maintainer --- Lib/pdb.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Lib/pdb.py b/Lib/pdb.py index 1a9c1b4549164f..772e28d21849cd 100644 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -3634,15 +3634,14 @@ def parse_args(): opt_module = parser.parse_args(args[:2]) opts.module = opt_module.module args = args[2:] + elif args[0] == '--': + args.pop(0) + if not args: + parser.error("missing script or module to run") elif args[0].startswith('-'): - if args[0] == '--': - args.pop(0) - if not args: - parser.error("missing script or module to run") - else: - # Invalid argument before the script name. - invalid_args = list(itertools.takewhile(lambda a: a.startswith('-'), args)) - parser.error(f"unrecognized arguments: {' '.join(invalid_args)}") + # Invalid argument before the script name. + invalid_args = list(itertools.takewhile(lambda a: a.startswith('-'), args)) + parser.error(f"unrecognized arguments: {' '.join(invalid_args)}") # Otherwise it's debugging a script and we already parsed all -c commands. From c77a5d909ef97c1650a4425280a95c54a8a5ab24 Mon Sep 17 00:00:00 2001 From: Shrey Naithani Date: Thu, 16 Apr 2026 17:56:05 +0500 Subject: [PATCH 5/7] Add regression tests for pdb -- option separator --- Lib/test/test_pdb.py | 54 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 0e23cd6604379c..95150f1578014a 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -4173,6 +4173,24 @@ def test_run_script_with_args(self): stdout, stderr = self.run_pdb_script(script, commands, script_args=["--bar", "foo"]) self.assertIn("['--bar', 'foo']", stdout) + def test_run_script_with_double_dash(self): + script = "import sys; print(sys.argv)" + commands = "continue\nquit" + + filename = 'main.py' + with open(filename, 'w') as f: + f.write(script) + self.addCleanup(os_helper.unlink, filename) + + stdout, _ = self._run_pdb(["--", filename, "-c", "example"], commands) + self.assertIn(f"['{filename}', '-c', 'example']", stdout) + + stdout, _ = self._run_pdb(["-c", "continue", "--", filename, "-c", "example"], "quit") + self.assertIn(f"['{filename}', '-c', 'example']", stdout) + + stdout, stderr = self._run_pdb(["--"], "", expected_returncode=2) + self.assertIn("pdb: error: missing script or module to run", stderr) + def test_breakpoint(self): script = """ if __name__ == '__main__': @@ -5196,6 +5214,42 @@ def test_interact_completion(self): self.assertIn(b'84', output) +class PdbCommandLineTestCase(unittest.TestCase): + def test_end_of_options_separator(self): + # gh-148615: Test parsing when '--' separator is used + from pdb import parse_args + + with patch('sys.argv', ['pdb.py', '--', 'my_script.py', '-foo']): + opts, args = parse_args() + self.assertEqual(args, ['my_script.py', '-foo']) + + with patch('sys.argv', ['pdb.py', '-c', 'continue', '--', 'my_script.py', '-c', 'foo']): + opts, args = parse_args() + self.assertEqual(opts.commands, ['continue']) + self.assertEqual(args, ['my_script.py', '-c', 'foo']) + + with patch('sys.argv', ['pdb.py', '--']): + with support.captured_stderr() as stderr: + with self.assertRaises(SystemExit): + parse_args() + self.assertIn("missing script or module to run", stderr.getvalue()) + + with patch('sys.argv', ['pdb.py', '-x', '--', 'my_script.py']): + with support.captured_stderr() as stderr: + with self.assertRaises(SystemExit): + parse_args() + self.assertIn("unrecognized arguments: -x", stderr.getvalue()) + + with patch('sys.argv', ['pdb.py', 'foo', '--', 'my_script.py']): + opts, args = parse_args() + self.assertEqual(args, ['foo', '--', 'my_script.py']) + + with patch('sys.argv', ['pdb.py', '-m', 'my_module', '--', 'foo']): + opts, args = parse_args() + self.assertEqual(opts.module, 'my_module') + self.assertEqual(args, ['--', 'foo']) + + def load_tests(loader, tests, pattern): from test import test_pdb From 7ebc1046aaac2a1cadfa360a5664f0647fe461fb Mon Sep 17 00:00:00 2001 From: Shrey Naithani Date: Thu, 16 Apr 2026 19:45:31 +0530 Subject: [PATCH 6/7] Remove unnecessary blank line in test_pdb.py --- Lib/test/test_pdb.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 95150f1578014a..44d46f9a4557ef 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -5249,7 +5249,6 @@ def test_end_of_options_separator(self): self.assertEqual(opts.module, 'my_module') self.assertEqual(args, ['--', 'foo']) - def load_tests(loader, tests, pattern): from test import test_pdb From c16cca977df7fadc1f379f4727a3f9bd08fcfdc1 Mon Sep 17 00:00:00 2001 From: Shrey Naithani Date: Thu, 16 Apr 2026 19:50:34 +0530 Subject: [PATCH 7/7] Remove unnecessary blank lines in test_pdb.py --- Lib/test/test_pdb.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 44d46f9a4557ef..21ecd46a241aa6 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -4176,18 +4176,14 @@ def test_run_script_with_args(self): def test_run_script_with_double_dash(self): script = "import sys; print(sys.argv)" commands = "continue\nquit" - filename = 'main.py' with open(filename, 'w') as f: f.write(script) self.addCleanup(os_helper.unlink, filename) - stdout, _ = self._run_pdb(["--", filename, "-c", "example"], commands) self.assertIn(f"['{filename}', '-c', 'example']", stdout) - stdout, _ = self._run_pdb(["-c", "continue", "--", filename, "-c", "example"], "quit") self.assertIn(f"['{filename}', '-c', 'example']", stdout) - stdout, stderr = self._run_pdb(["--"], "", expected_returncode=2) self.assertIn("pdb: error: missing script or module to run", stderr) @@ -5218,32 +5214,26 @@ class PdbCommandLineTestCase(unittest.TestCase): def test_end_of_options_separator(self): # gh-148615: Test parsing when '--' separator is used from pdb import parse_args - with patch('sys.argv', ['pdb.py', '--', 'my_script.py', '-foo']): opts, args = parse_args() self.assertEqual(args, ['my_script.py', '-foo']) - with patch('sys.argv', ['pdb.py', '-c', 'continue', '--', 'my_script.py', '-c', 'foo']): opts, args = parse_args() self.assertEqual(opts.commands, ['continue']) self.assertEqual(args, ['my_script.py', '-c', 'foo']) - with patch('sys.argv', ['pdb.py', '--']): with support.captured_stderr() as stderr: with self.assertRaises(SystemExit): parse_args() self.assertIn("missing script or module to run", stderr.getvalue()) - with patch('sys.argv', ['pdb.py', '-x', '--', 'my_script.py']): with support.captured_stderr() as stderr: with self.assertRaises(SystemExit): parse_args() self.assertIn("unrecognized arguments: -x", stderr.getvalue()) - with patch('sys.argv', ['pdb.py', 'foo', '--', 'my_script.py']): opts, args = parse_args() self.assertEqual(args, ['foo', '--', 'my_script.py']) - with patch('sys.argv', ['pdb.py', '-m', 'my_module', '--', 'foo']): opts, args = parse_args() self.assertEqual(opts.module, 'my_module')