Group in a group ArgParse
Solution 1
The mutually exclusive group mechanism is just for a simple (flat) exclusive or group. There's no mechanism for nesting one group in another, or for applying other logic (and
, any
etc).
You need to do your own testing after parsing. As long as the defaults are reasonable (e.g. the default default None
) that isn't hard.
Subparsers provide another kind of grouping logic, which may work for you.
This has been raised in other SO questions, and a Python bug/issue, if you need to explore it in more detail.
===============
argument groups
, despite the name, do not work with mutually exclusive groups. Their intended purpose is entirely different (grouping of help lines). You can nest one mutually exclusive group within another, but the net effect is to put everything in one group.
argparse: some mutually exclusive arguments in required group
============================
import argparse
usage = '%(prog)s [A | [B ? C]]'
parser = argparse.ArgumentParser(usage=usage)
parser.add_argument('-a')
parser.add_argument('-b')
parser.add_argument('-c')
args=parser.parse_args()
print(args)
if args.a is not None:
if not(args.b is None and args.c is None):
parser.error('Cannot use b or c with a')
with resulting runs
1722:~/mypy$ python3 stack37311550.py -a 1
Namespace(a='1', b=None, c=None)
1726:~/mypy$ python3 stack37311550.py -a 1 -b2
Namespace(a='1', b='2', c=None)
usage: stack37311550.py [A | [B ? C]]
stack37311550.py: error: Cannot use b or c with a
1726:~/mypy$ python3 stack37311550.py -c3 -b2
Namespace(a=None, b='2', c='3')
1726:~/mypy$ python3 stack37311550.py -c3 -b2 -a1
Namespace(a='1', b='2', c='3')
usage: stack37311550.py [A | [B ? C]]
stack37311550.py: error: Cannot use b or c with a
Solution 2
import argparse
parser = argparse.ArgumentParser(description='test group')
subparsers = parser.add_subparsers(help='sub-commands help')
sp = subparsers.add_parser('A', help='A command')
sp.set_defaults(cmd = 'A')
sp = subparsers.add_parser('B', help='B command')
sp.set_defaults(cmd = 'B')
sp.add_argument('C', help='C option')
args = parser.parse_args()
if (args.cmd == 'A'):
print("running A mode")
else:
print("running B mode with C=%s" % args.C)
Here's execution log:
$ python test.py A
running A mode
$ python test.py B
usage: test.py B [-h] C
$ python test.py B some
running B mode with C=some
Mutually exclusive groups are intended for cases when user have to select at least one option out of a given set, or if required=True
exactly one option.
Harbus
Updated on June 04, 2022Comments
-
Harbus about 2 years
So I'm using argparse and I'm trying to create something that I can't seem to find the solution anywhere.
I'm trying to do
[A | [B C]]
. So either I haveA
or(B and C)
.EDIT So some example of code would be
parser = argparse.ArgumentParser() group = parser.add_mutually_exclusive_group(required=False) group.add_argument("-a") more = group.add_mutually_exclusive_group() more.add_argument("-b") more.add_argument("c")
This however ends up giving me
[A | [B | C]]
-
tuexss almost 5 yearsThe last sentence is a bit misleading, as the mutex group can still be optional. So it's rather "when users have to select a maximum of one option out of a given set". Your sentence applies when required=True is set.
-
user3159253 almost 5 yearsI agree with this change. Can you edit the answer (I mean, you have enough reputation and all other prerequisites are fulfilled)? If yes, I will approve your change.