This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: ArgumentParser subparser error display at the wrong level
Type: behavior Stage: resolved
Components: Library (Lib) Versions: Python 3.6, Python 3.4, Python 3.5
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: Nosy List: paul.j3, siming85
Priority: normal Keywords:

Created on 2018-08-23 15:32 by siming85, last changed 2022-04-11 14:59 by admin. This issue is now closed.

Messages (3)
msg323956 - (view) Author: Siming Yuan (siming85) * Date: 2018-08-23 15:32
If you take the example from
https://docs.python.org/3/library/argparse.html#argparse.ArgumentParser.add_subparsers

# create the top-level parser
parser = argparse.ArgumentParser(prog='PROG')
parser.add_argument('--foo', action='store_true', help='foo help')
subparsers = parser.add_subparsers(help='sub-command help')
# create the parser for the "a" command
parser_a = subparsers.add_parser('a', help='a help')
parser_a.add_argument('-bar', type=int, help='bar help')
# create the parser for the "b" command
parser_b = subparsers.add_parser('b', help='b help')
parser_b.add_argument('--baz', choices='XYZ', help='baz help')


and run a subcommand but with an argument the subcommand doesn't understand

parser.parse_args(['a', '-x'])

the output doesn't help much - because the usage is coming from the main parser

usage: PROG [-h] [--foo] {a,b} ...
PROG: error: unrecognized arguments: -x


the reason for failure is because the error api being called in this case is
parser.error(msg)

not the subparser
parser_a.error(msg)

the proper error should've been

usage: PROG a [-h] [-bar BAR]
PROG a: error: unrecognized arguments: -x
msg324285 - (view) Author: paul j3 (paul.j3) * (Python triager) Date: 2018-08-28 20:27
The subparser is called with `parse_known_args` which just puts unknown args in a _UNRECOGNIZED_ARGS_ATTR attribute slot in the namespace, which is then passed back to the main parser.

(this occurs in _SubParsersAction.__call__)

If `parser.parse_known_args` is used, then these arguments will appear in the `extras` list.  Otherwise `parser.parse_args` issues the 'unrecognized arguments' error message (with the main parser usage).

I suspect this issue has been raised previously.  And I don't see any easy way of altering the behavior.
msg324295 - (view) Author: paul j3 (paul.j3) * (Python triager) Date: 2018-08-28 22:19
Errors that are associated with a specific argument, such as a wrong 'type' do get usage from the appropriate subparser.  

e.g.

In [164]: p.parse_args('--foo 1 cmd1 --bar x'.split())
usage: ipython3 cmd1 [-h] [--bar BAR]
ipython3 cmd1: error: argument --bar: invalid int value: 'x'

`required` tests also issue subparser specific usage; mutually exclusive tests probably do so as well.

But this unrecognized argument error is a bit less specific.  In your example '-x a' and 'a -x' will both produce the same error message.  The route by which the '-x' is put into the 'extras' list is different in the two cases, but in both it's the top 'parse_(known_)args' that determines whether to just return them, or raise an error.  '-x a -x' will put 2 '-x' in the unrecognized list.

If you really need a subparser specific message it might be possible to do so by modifying, or subclassing the _SubParsersAction class, making it raise an error when there are 'extras' rather than returning them as 'unrecognized'.  But that's not a backward compatible change.
History
Date User Action Args
2022-04-11 14:59:05adminsetgithub: 78660
2018-09-23 01:21:23paul.j3setresolution: not a bug
2018-09-20 19:16:57paul.j3setstatus: open -> closed
stage: resolved
2018-08-28 22:19:31paul.j3setmessages: + msg324295
2018-08-28 20:27:06paul.j3setnosy: + paul.j3
messages: + msg324285
2018-08-23 15:32:12siming85create