Group in a group ArgParse

Question:

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 have A 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]]

Asked By: Harbus

||

Answers:

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 the user has to select at most one option out of a given set, or if required=True is exactly one option.

Answered By: user3159253

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
Answered By: hpaulj
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.