Reputation: 403
I am using the Argparse Module to parse command line options. I have a main script which calls either subscript A or subscript B. I now have a a subparser instance for A and B and the main parser instance which should contain info about variables that A and B need. Something like:
def __init__(self):
parser = argparse.ArgumentParser("Parser")
parser.addArgument('--input') #this should be availabe for A and B
subparsers = parser.add_subparsers('Description')
A_parser = subparsers.add_parser(A)
A_paser.add_argument('--a_option')
B_parser = parser.add_subparser('Description')
B_parser.add_arguemnt('--b_option')
args = parser.parse_args()
But if I use it like this, I can only change args.options via the --input option if I do not specify A or B on program call. Execution of
program.py A --input ./
or
program.py --input ./ A
both fail.
Upvotes: 2
Views: 7705
Reputation: 5026
I think you messed up the example usage from the python documentation. I attempted to edit your code example, but there were so many typos that I gave up. Expecially the usage of add_subparsers()
and add_parser()
was mixed up.
The cleaned up (and self-contained) version of the code looks like this:
import argparse
parser = argparse.ArgumentParser("Parser")
parser.add_argument('--input') #this should be available for A and B
subparsers = parser.add_subparsers(help='Description')
A_parser = subparsers.add_parser('A')
A_parser.add_argument('--a_option')
B_parser = subparsers.add_parser('B')
B_parser.add_argument('--b_option')
Now you can call
args = parser.parse_args(['--input', 'foo'])
but also
args = parser.parse_args(['--input', 'bar', 'A', '--a_option', 'a_option_arg'])
and
args = parser.parse_args(['--input', 'baz', 'B', '--b_option', 'b_option_arg'])
Update
In the comments, you ask:
Is it possible that I can also pass a unknown number of arguments for the --input option and still have the A option after that? Something like:
program.py --input ./ ../ ../../ A -a_option
If you want to pass an unknown number of arguments to the --input
option you need to pass nargs='*'
to the argument definition of --input
. However, you cannot use tags like A
and B
anymore to select your subparsers, because these would be taken as further arguments to --input
.
You can resort to parent parsers in that case. With parent parsers, you can merge the options of several parsers into one:
import argparse
A_parser = argparse.ArgumentParser(add_help=False)
A_parser.add_argument('--a_option')
B_parser = argparse.ArgumentParser(add_help=False)
B_parser.add_argument('--b_option')
parser = argparse.ArgumentParser("Parser", parents=[A_parser, B_parser])
parser.add_argument('--input', nargs='*') # this should be available for A and B
Now all options are available every time:
args = parser.parse_args(['--input', 'foo'])
args = parser.parse_args(['--input', 'foo' , 'bar', '--a_option', 'a_option_arg'])
args = parser.parse_args(['--input', 'baz', '--b_option', 'b_option_arg'])
Note that there is no more 'A' and 'B' tag. Selecting 'A' occurs by choosing one of the options defined by A_parser
. It is even allowed to use both:
args = parser.parse_args(['--input', 'foo' ,'--a_option', 'a_option_arg', '--b_option', 'b_option_arg'])
If you don't want this, you would need to implement a check for conflicting parameters.
Upvotes: 2