-
-
Notifications
You must be signed in to change notification settings - Fork 33.8k
gh-125115 : Refactor the pdb parsing issue so positional arguments can pass through #140933
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
Changes from all commits
ea796a0
4e23ab6
3e32277
4616aea
20160e2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3542,7 +3542,15 @@ def exit_with_permission_help_text(): | |
| sys.exit(1) | ||
|
|
||
|
|
||
| def main(): | ||
| def parse_args(): | ||
| # We want pdb to be as intuitive as possible to users, so we need to do some | ||
| # heuristic parsing to deal with ambiguity. | ||
| # For example: | ||
| # "python -m pdb -m foo -p 1" should pass "-p 1" to "foo". | ||
| # "python -m pdb foo.py -m bar" should pass "-m bar" to "foo.py". | ||
| # "python -m pdb -m foo -m bar" should pass "-m bar" to "foo". | ||
| # This require some customized parsing logic to find the actual debug target. | ||
|
|
||
| import argparse | ||
|
|
||
| parser = argparse.ArgumentParser( | ||
|
|
@@ -3553,28 +3561,48 @@ def main(): | |
| color=True, | ||
| ) | ||
|
|
||
| # We need to maunally get the script from args, because the first positional | ||
| # arguments could be either the script we need to debug, or the argument | ||
| # to the -m module | ||
| # Get all the commands out first. For backwards compatibility, we allow | ||
| # -c commands to be after the target. | ||
| parser.add_argument('-c', '--command', action='append', default=[], metavar='command', dest='commands', | ||
| help='pdb commands to execute as if given in a .pdbrc file') | ||
| parser.add_argument('-m', metavar='module', dest='module') | ||
| parser.add_argument('-p', '--pid', type=int, help="attach to the specified PID", default=None) | ||
|
|
||
| if len(sys.argv) == 1: | ||
| opts, args = parser.parse_known_args() | ||
|
|
||
| if not args: | ||
| # If no arguments were given (python -m pdb), print the whole help message. | ||
| # Without this check, argparse would only complain about missing required arguments. | ||
| # We need to add the arguments definitions here to get a proper help message. | ||
| parser.add_argument('-m', metavar='module', dest='module') | ||
| parser.add_argument('-p', '--pid', type=int, help="attach to the specified PID", default=None) | ||
| parser.print_help() | ||
| sys.exit(2) | ||
| elif args[0] == '-p' or args[0] == '--pid': | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is -p always the first arg?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So we already skimmed all the |
||
| # Attach to a pid | ||
| parser.add_argument('-p', '--pid', type=int, help="attach to the specified PID", default=None) | ||
| opts, args = parser.parse_known_args() | ||
| if args: | ||
| # For --pid, any extra arguments are invalid. | ||
| parser.error(f"unrecognized arguments: {' '.join(args)}") | ||
| elif args[0] == '-m': | ||
| # Debug a module, we only need the first -m module argument. | ||
| # The rest is passed to the module itself. | ||
| parser.add_argument('-m', metavar='module', dest='module') | ||
| opt_module = parser.parse_args(args[:2]) | ||
| 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)}") | ||
|
|
||
| opts, args = parser.parse_known_args() | ||
| # Otherwise it's debugging a script and we already parsed all -c commands. | ||
|
|
||
| return opts, args | ||
|
|
||
| if opts.pid: | ||
| # If attaching to a remote pid, unrecognized arguments are not allowed. | ||
| # This will raise an error if there are extra unrecognized arguments. | ||
| opts = parser.parse_args() | ||
| if opts.module: | ||
| parser.error("argument -m: not allowed with argument --pid") | ||
| def main(): | ||
| opts, args = parse_args() | ||
|
|
||
| if getattr(opts, 'pid', None) is not None: | ||
| try: | ||
| attach(opts.pid, opts.commands) | ||
| except RuntimeError: | ||
|
|
@@ -3586,30 +3614,10 @@ def main(): | |
| except PermissionError: | ||
| exit_with_permission_help_text() | ||
| return | ||
| elif opts.module: | ||
| # If a module is being debugged, we consider the arguments after "-m module" to | ||
| # be potential arguments to the module itself. We need to parse the arguments | ||
| # before "-m" to check if there is any invalid argument. | ||
| # e.g. "python -m pdb -m foo --spam" means passing "--spam" to "foo" | ||
| # "python -m pdb --spam -m foo" means passing "--spam" to "pdb" and is invalid | ||
| idx = sys.argv.index('-m') | ||
| args_to_pdb = sys.argv[1:idx] | ||
| # This will raise an error if there are invalid arguments | ||
| parser.parse_args(args_to_pdb) | ||
| else: | ||
| # If a script is being debugged, then pdb expects the script name as the first argument. | ||
| # Anything before the script is considered an argument to pdb itself, which would | ||
| # be invalid because it's not parsed by argparse. | ||
| invalid_args = list(itertools.takewhile(lambda a: a.startswith('-'), args)) | ||
| if invalid_args: | ||
| parser.error(f"unrecognized arguments: {' '.join(invalid_args)}") | ||
|
|
||
| if opts.module: | ||
| elif getattr(opts, 'module', None) is not None: | ||
| file = opts.module | ||
| target = _ModuleTarget(file) | ||
| else: | ||
| if not args: | ||
| parser.error("no module or script to run") | ||
| file = args.pop(0) | ||
| if file.endswith('.pyz'): | ||
| target = _ZipTarget(file) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| Refactor the :mod:`pdb` parsing issue so positional arguments can pass through intuitively. | ||
savannahostrowski marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Uh oh!
There was an error while loading. Please reload this page.