Reputation: 151
I'm trying to write a program that is able to execute multiple sub-commands. The argparse module is very helpful, but I think it is lacking the ability to specify more than one sub-command. For example, if I have the following code:
parser = argparse.ArgumentParser(prog='My Prog')
sub_parsers = parser.add_subparsers()
subcommand_a = sub_parsers.add_parser('subcommand_a', help='a help')
subcommand_a.add_argument('req1', help='required argument 1 help')
subcommand_a.add_argument('--opt1', help='option 1 help')
subcommand_a.add_argument('--opt2', nargs='+', help='option 2 help')
subcommand_b = sub_parsers.add_parser('subcommand_b', help='b help')
subcommand_b.add_argument('req1', help='required argument 1 help')
subcommand_b.add_argument('--opt1', help='option 1 help')
subcommand_b.add_argument('--opt2', help='option 2 help')
subcommand_b.add_argument('--opt3', nargs='+', help='option 3 help')
parser.parse_args()
I cannot specify both subcommand_a and subcommand_b on the command line. I can only do one of them at a time. I'd imagine that this would require a custom action or possibly even subclassing argparse, but I'm not sure where to start. I'd like to be able to call this program like the following:
./prog.py subcommand_a FOO --opt1=bar --opt2 1 2 3 -- subcommand_b BAR --opt1='foo' --opt3 a b c --
Any ideas?
Upvotes: 2
Views: 2034
Reputation: 231385
Your problem is essentially the same as the one asked a few months back
Multiple invocation of the same subcommand in a single command line
That one wanted to call the same subcommand several times, but the issue the same - how to handle more than one subparsers
argument.
The solutions there are either to split the command line before passing it in pieces that are parsed separately, or collect the 'unused' pieces from one parsing for using in a second or third.
Here's tweak to your code that returns 2 commands:
import argparse
parser = argparse.ArgumentParser(prog='My Prog')
sub_parsers = parser.add_subparsers(dest='cmd')
subcommand_a = sub_parsers.add_parser('subcommand_a', help='a help')
subcommand_a.add_argument('req1', help='required argument 1 help')
subcommand_a.add_argument('--opt1', help='option 1 help')
subcommand_a.add_argument('--opt2', nargs=3, help='option 2 help')
subcommand_b = sub_parsers.add_parser('subcommand_b', help='b help')
subcommand_b.add_argument('req1', help='required argument 1 help')
subcommand_b.add_argument('--opt1', help='option 1 help')
subcommand_b.add_argument('--opt2', help='option 2 help')
subcommand_b.add_argument('--opt3', nargs=3, help='option 3 help')
argv = "subcommand_a FOO --opt1=bar --opt2 1 2 3 subcommand_b BAR --opt1=foo --opt3 a b c"
rest = argv.split()
while rest:
[args, rest] = parser.parse_known_args(rest)
print args
print rest
which prints:
Namespace(cmd='subcommand_a', opt1='foo', opt2=['1', '2', '3'], req1='FOO')
['subcommand_b', 'BAR', '--opt3', 'a', 'b', 'c']
Namespace(cmd='subcommand_b', opt1=None, opt2=None, opt3=['a', 'b', 'c'], req1='BAR')
[]
I removed the '--'
(see the end of my other answer)
I changed opt2
and opt3
to take 3 arguments, not the variable +
. With +
it can't tell where the list for opt2
ends and the next command begins.
It is also important that the different commands take different optionals (flags). Note that the first opt1
ends up with the second value, 'foo', leaving none for the 2nd command. See the other thread for a discussion of the issues and ways around that.
Upvotes: 2
Reputation: 1962
I've done some testing and changing the subcommand to other string worked. if you use:
parser = argparse.ArgumentParser(prog='My Prog')
sub_parsers = parser.add_subparsers()
subcommand_a = sub_parsers.add_parser('subcommand_a', help='a help')
subcommand_a.add_argument('req1', help='required argument 1 help')
subcommand_a.add_argument('--opt1', help='option 1 help')
subcommand_a.add_argument('--opt2', nargs='+' help='option 2 help')
subcommand_b = sub_parsers.add_parser('subcommand_b', help='b help')
subcommand_b.add_argument('req1', help='required argument 1 help')
subcommand_b.add_argument('--opt3', help='option 1 help')
subcommand_b.add_argument('--opt4', help='option 2 help')
subcommand_b.add_argument('--opt5', nargs='+', help='option 3 help')
parser.parse_args()
it works.
I've done some research and not found a subcommand with a equal string. A overview of the documentation don't say nothing either. I presume it's a limitation ( by choice ) or a bug. Maybe you can check it in the Source Code Hosting
Upvotes: 0