I'm using Python 3.4, I'm trying to use argparse
with subparsers, and I want to have a similar behavior to the one in Python 2.x where if I don't supply a positional argument (to indicate the subparser/subprogram) I'll get a helpful error message. I.e., with python2
I'll get the following error message:
$ python2 subparser_test.py usage: subparser_test.py [-h] {foo} ... subparser_test.py: error: too few arguments
I'm setting the required
attribute as suggested in https://stackoverflow.com/a/22994500/3061818, however that gives me an error with Python 3.4.0: TypeError: sequence item 0: expected str instance, NoneType found
- full traceback:
$ python3 subparser_test.py Traceback (most recent call last): File "subparser_test.py", line 17, in <module> args = parser.parse_args() File "/usr/local/Cellar/python3/3.4.0/Frameworks/Python.framework/Versions/3.4/lib/python3.4/argparse.py", line 1717, in parse_args args, argv = self.parse_known_args(args, namespace) File "/usr/local/Cellar/python3/3.4.0/Frameworks/Python.framework/Versions/3.4/lib/python3.4/argparse.py", line 1749, in parse_known_args namespace, args = self._parse_known_args(args, namespace) File "/usr/local/Cellar/python3/3.4.0/Frameworks/Python.framework/Versions/3.4/lib/python3.4/argparse.py", line 1984, in _parse_known_args ', '.join(required_actions)) TypeError: sequence item 0: expected str instance, NoneType found
This is my program subparser_test.py
- adapted from https://docs.python.org/3.2/library/argparse.html#sub-commands:
import argparse # sub-command functions def foo(args): print('"foo()" called') # create the top-level parser parser = argparse.ArgumentParser() subparsers = parser.add_subparsers() subparsers.required = True # create the parser for the "foo" command parser_foo = subparsers.add_parser('foo') parser_foo.set_defaults(func=foo) args = parser.parse_args() args.func(args)
Related question: Why does this argparse code behave differently between Python 2 and 3?
A “subparser” is an argument parser bound to a namespace. In other words, it works with everything after a certain positional argument. Argh implements commands by creating a subparser for every function.
Optional arguments are useful if you want to give the user a choice to enable certain features. To add an optional argument, simply omit the required parameter in add_argument() . args = parser. parse_args()if args.
Number of Arguments If you want your parameters to accept a list of items you can specify nargs=n for how many arguments to accept. Note, if you set nargs=1 , it will return as a list not a single value.
You need to give subparsers
a dest
.
parser = argparse.ArgumentParser() subparsers = parser.add_subparsers(dest='cmd') subparsers.required = True
Now:
1909:~/mypy$ argdev/python3 stack23349349.py usage: stack23349349.py [-h] {foo} ... stack23349349.py: error: the following arguments are required: cmd
In order to issue this 'missing arguments' error message, the code needs to give that argument a name. For a positional argument (like subparses), that name is (by default) the 'dest'. There's a (minor) note about this in the SO answer you linked.
One of the few 'patches' to argparse
in the last Python release changed how it tests for 'required' arguments. Unfortunately it introduced this bug regarding subparsers. This needs to be fixed in the next release (if not sooner).
If you want this optional subparsers behavior in Py2, it looks like the best option is to use a two stage parser as described in
How to Set a Default Subparser using Argparse Module with Python 2.7
There has been some recent activity in the related bug/issue
https://bugs.python.org/issue9253
A fix to this is in the works: https://github.com/python/cpython/pull/3027
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With