Skip to content

Commit 9c2bb7d

Browse files
gh-125115: Pass unknown pdb command line args to script instead of fail (#125424)
Co-authored-by: Irit Katriel <[email protected]>
1 parent 3ea488a commit 9c2bb7d

File tree

3 files changed

+45
-7
lines changed

3 files changed

+45
-7
lines changed

Lib/pdb.py

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@
8282
import inspect
8383
import textwrap
8484
import tokenize
85+
import itertools
8586
import traceback
8687
import linecache
8788
import _colorize
@@ -2433,30 +2434,47 @@ def main():
24332434
parser.add_argument('-c', '--command', action='append', default=[], metavar='command', dest='commands',
24342435
help='pdb commands to execute as if given in a .pdbrc file')
24352436
parser.add_argument('-m', metavar='module', dest='module')
2436-
parser.add_argument('args', nargs='*',
2437-
help="when -m is not specified, the first arg is the script to debug")
24382437

24392438
if len(sys.argv) == 1:
24402439
# If no arguments were given (python -m pdb), print the whole help message.
24412440
# Without this check, argparse would only complain about missing required arguments.
24422441
parser.print_help()
24432442
sys.exit(2)
24442443

2445-
opts = parser.parse_args()
2444+
opts, args = parser.parse_known_args()
2445+
2446+
if opts.module:
2447+
# If a module is being debugged, we consider the arguments after "-m module" to
2448+
# be potential arguments to the module itself. We need to parse the arguments
2449+
# before "-m" to check if there is any invalid argument.
2450+
# e.g. "python -m pdb -m foo --spam" means passing "--spam" to "foo"
2451+
# "python -m pdb --spam -m foo" means passing "--spam" to "pdb" and is invalid
2452+
idx = sys.argv.index('-m')
2453+
args_to_pdb = sys.argv[1:idx]
2454+
# This will raise an error if there are invalid arguments
2455+
parser.parse_args(args_to_pdb)
2456+
else:
2457+
# If a script is being debugged, then pdb expects the script name as the first argument.
2458+
# Anything before the script is considered an argument to pdb itself, which would
2459+
# be invalid because it's not parsed by argparse.
2460+
invalid_args = list(itertools.takewhile(lambda a: a.startswith('-'), args))
2461+
if invalid_args:
2462+
parser.error(f"unrecognized arguments: {' '.join(invalid_args)}")
2463+
sys.exit(2)
24462464

24472465
if opts.module:
24482466
file = opts.module
24492467
target = _ModuleTarget(file)
24502468
else:
2451-
if not opts.args:
2469+
if not args:
24522470
parser.error("no module or script to run")
2453-
file = opts.args.pop(0)
2471+
file = args.pop(0)
24542472
if file.endswith('.pyz'):
24552473
target = _ZipTarget(file)
24562474
else:
24572475
target = _ScriptTarget(file)
24582476

2459-
sys.argv[:] = [file] + opts.args # Hide "pdb.py" and pdb options from argument list
2477+
sys.argv[:] = [file] + args # Hide "pdb.py" and pdb options from argument list
24602478

24612479
# Note on saving/restoring sys.argv: it's a good idea when sys.argv was
24622480
# modified by the script being debugged. It's a bad idea when it was

Lib/test/test_pdb.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3089,6 +3089,7 @@ def _run_pdb(self, pdb_args, commands,
30893089
def run_pdb_script(self, script, commands,
30903090
expected_returncode=0,
30913091
extra_env=None,
3092+
script_args=None,
30923093
pdbrc=None,
30933094
remove_home=False):
30943095
"""Run 'script' lines with pdb and the pdb 'commands'."""
@@ -3106,7 +3107,9 @@ def run_pdb_script(self, script, commands,
31063107
if remove_home:
31073108
homesave = os.environ.pop('HOME', None)
31083109
try:
3109-
stdout, stderr = self._run_pdb([filename], commands, expected_returncode, extra_env)
3110+
if script_args is None:
3111+
script_args = []
3112+
stdout, stderr = self._run_pdb([filename] + script_args, commands, expected_returncode, extra_env)
31103113
finally:
31113114
if homesave is not None:
31123115
os.environ['HOME'] = homesave
@@ -3559,6 +3562,22 @@ def test_run_module_with_args(self):
35593562
stdout, _ = self._run_pdb(["-m", "calendar", "1"], commands)
35603563
self.assertIn("December", stdout)
35613564

3565+
stdout, _ = self._run_pdb(["-m", "calendar", "--type", "text"], commands)
3566+
self.assertIn("December", stdout)
3567+
3568+
def test_run_script_with_args(self):
3569+
script = """
3570+
import sys
3571+
print(sys.argv[1:])
3572+
"""
3573+
commands = """
3574+
continue
3575+
quit
3576+
"""
3577+
3578+
stdout, stderr = self.run_pdb_script(script, commands, script_args=["--bar", "foo"])
3579+
self.assertIn("['--bar', 'foo']", stdout)
3580+
35623581
def test_breakpoint(self):
35633582
script = """
35643583
if __name__ == '__main__':
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fixed a bug in :mod:`pdb` where arguments starting with ``-`` can't be passed to the debugged script.

0 commit comments

Comments
 (0)