Reputation: 327
I'm trying to have a mutually exclusive group between different groups: I have the arguments -a,-b,-c, and I want to have a conflict with -a and -b together, or -a and -c together. The help should show something like [-a | ([-b] [-c])].
The following code does not seem to do have mutually exclusive options:
import argparse
parser = argparse.ArgumentParser(description='My desc')
main_group = parser.add_mutually_exclusive_group()
mysub_group = main_group.add_argument_group()
main_group.add_argument("-a", dest='a', action='store_true', default=False, help='a help')
mysub_group.add_argument("-b", dest='b', action='store_true',default=False,help='b help')
mysub_group.add_argument("-c", dest='c', action='store_true',default=False,help='c help')
parser.parse_args()
Parsing different combinations - all pass:
> python myscript.py -h
usage: myscript.py [-h] [-a] [-b] [-c]
My desc
optional arguments:
-h, --help show this help message and exit
-a a help
> python myscript.py -a -c
> python myscript.py -a -b
> python myscript.py -b -c
I tried changing the mysub_group
to be add_mutually_exclusive_group
turns everything into mutually exclusive:
> python myscript.py -h
usage: myscript.py [-h] [-a | -b | -c]
My desc
optional arguments:
-h, --help show this help message and exit
-a a help
-b b help
-c c help
How can I add arguments for [-a | ([-b] [-c])]?
Upvotes: 9
Views: 842
Reputation: 231615
argument_groups
don't affect the parsing. They just contribute to the help formatting. So defining a group within an mutually_exclusive_group
does not help with this problem.
There is a proposed patch, http://bugs.python.org/issue10984, 'argparse add_mutually_exclusive_group should accept existing arguments to register conflicts'
, that would allow you to define two mutually_exclusive_groups
, one [-a | -b]
and the other [-a | -c]
. Creating a 2nd group that includes an argument (-a
) that is already defined is the trivial part of this patch. Producing a meaningful usage line is more difficult, and required a rewrite of several HelpFormatter
methods.
import argparse
parser = argparse.ArgumentParser(description='My desc')
group1 = parser.add_mutually_exclusive_group()
action_a = group1.add_argument("-a", dest='a', action='store_true', default=False, help='a help')
group1.add_argument("-b", dest='b', action='store_true',default=False,help='b help')
group2 = parser.add_mutually_exclusive_group()
group2.add_argument("-c", dest='c', action='store_true',default=False,help='c help')
group2._group_actions.append(action_a) # THE KLUDGE
print parser.format_usage()
# usage: stack16769409.py [-h] [-a | -b] [-c]
args = parser.parse_args()
Usage
does not show the 2 groups correctly. But it does accept -b -c
, while objecting to -a -b
and -a -c
. But you can write a custom usage line.
Upvotes: 0
Reputation: 2191
So, this has been asked a number of times. The simple answer is "with argparse, you can't". However, that's the simple answer. You could make use of subparsers, so:
import argparse
parser = argparse.ArgumentParser(description='My desc')
sub_parsers = parser.add_subparsers()
parser_a = sub_parsers.add_parser("a", help='a help')
parser_b = sub_parsers.add_parser("b", help='b help')
parser_b.add_argument("-c", dest='c', action='store_true',default=False,help='c help')
parser.parse_args()
You then get:
$ python parser -h
usage: parser [-h] {a,b} ...
My desc
positional arguments:
{a,b}
a a help
b b help
optional arguments:
-h, --help show this help message and exit
and:
$ python parser b -h
usage: parser b [-h] [-c]
optional arguments:
-h, --help show this help message and exit
-c c help
If you would prefer your arguments as stated in the question, have a look at docopt, it looks lovely, and should do exactly what you want.
Upvotes: 2