Reputation: 4933
In my application, I have a parser like this:
description = ("Cluster a matrix using bootstrap resampling or "
"Bayesian hierarchical clustering.")
sub_description = ("Use these commands to cluster data depending on "
"the algorithm.")
parser = argparse.ArgumentParser(description=description, add_help=False)
subparsers = parser.add_subparsers(title="Sub-commands",
description=sub_description)
parser.add_argument("--no-logfile", action="store_true", default=False,
help="Don't log to file, use stdout")
parser.add_argument("source", metavar="FILE",
help="Source data to cluster")
parser.add_argument("destination", metavar="FILE",
help="File name for clustering results")
Then I add a series of sub parsers like this (using functions because they're long):
setup_pvclust_parser(subparsers, parser)
setup_native_parser(subparsers, parser)
These call (example with one):
def setup_pvclust_parser(subparser, parent=None):
pvclust_description = ("Perform multiscale bootstrap resampling "
"(Shimodaira et al., 2002)")
pvclust_commands = subparser.add_parser("bootstrap",
description=pvclust_description, parents=[parent])
pvclust_commands.add_argument("-b", "--boot", type=int,
metavar="BOOT",
help="Number of permutations",
default=100)
# Other long list of options...
pvclust_commands.set_defaults(func=cluster_pvclust) # The function doing the processing
The issue is that somehow the parsing of the command line fails, and I'm sure it's my fault, somewhere. Example when run:
my_program.py bootstrap --boot 10 --no-logfile test.txt test.pdf
my_program.py bootstrap: error: too few arguments
As if the parsing is somehow wrong. This behavior disappears if I remove parents=[] in the subparser call, but I'd rather avoid it as it creates massive duplication.
EDIT: Moving the subparsers
call after the add_argument
calls fixes part of the problem. However, now the parser cannot parse properly the subcommands:
my_program.py bootstrap --boot 100 --no-logfile test.txt test.pdf
my_program.py: error: invalid choice: 'test.txt' (choose from 'bootstrap', 'native')
Upvotes: 1
Views: 1339
Reputation: 231395
The fundamental problem is that you are confusing the arguments that the parser
is supposed to handle, with those that the subparsers should handle. In fact by passing the parser as parent to the subparser you end up defining those arguments in both places.
In addition source
and destination
are positional arguments, as is the subparsers. If they are all defined in the base parser, their order matters.
I'd suggest defining a separate parent
parser
parent = argparse.ArgumentParser(add_help=False)
parent.add_argument("--no-logfile", action="store_true". help="...")
parent.add_argument("source", metavar="FILE", help="...")
parent.add_argument("destination", metavar="FILE", help="...")
parser = argparse.ArgumentParser(description=description)
subparsers = parser.add_subparsers(title="Sub-commands", description=sub_description)
setup_pvclust_parser(subparsers, parent)
setup_native_parser(subparsers, parent)
Upvotes: 3