argparse subcommands are great, but they have a quirk in which options are only available right after the subcommand that define them.
So, if you for example add the --verbose / -v
argument to your main parser,
and you have subcommands, you need to give the -v
option before the
subcommand name. For example, given this script:
#!/usr/bin/python3
import argparse
parser = argparse.ArgumentParser(description="test")
parser.add_argument("-v", "--verbose", action="store_true")
subparsers = parser.add_subparsers(dest="handler", required=True)
subparsers.add_parser("test")
args = parser.parse_args()
print(args.verbose)
You get this behaviour:
$ ./mycmd test
False
$ ./mycmd -v test
True
$ ./mycmd test -v
usage: mycmd [-h] [-v] {test} ...
mycmd: error: unrecognized arguments: -v
This sometimes makes sense, and many other times it's really annoying, since the user has to remember at which level an option was defined.
Last night some pieces clicked in my head, and I created a not-too-dirty
ArgumentParser subclass
that adds a shared
option to arguments, that propagates them to subparsers:
#!/usr/bin/python3
from hacks import argparse
parser = argparse.ArgumentParser(description="test")
parser.add_argument("-v", "--verbose", action="store_true", shared=True)
subparsers = parser.add_subparsers(dest="handler", required=True)
subparsers.add_parser("test")
args = parser.parse_args()
print(args.verbose)
And finally, -v
can be given at all levels:
$ ./mycmd test
False
$ ./mycmd -v test
True
$ ./mycmd test -v
True
It even works recursively, forwarding arguments to sub-subparsers, but at the
moment it can only do it for store_true
and store
kind of arguments.