20

I would like to implement logic like this in argparse:

If argument A is selected, the user cannot select arguments B or C.
B and C can both be selected

It looks like add_mutually_exclusive_group is what I would want for this, but it looks like you can only choose one option from a mutually exclusive group, so I cannot put all three in a mutually exclusive group.

Is there a way to do this in argparse?

Kevin Burke
  • 61,194
  • 76
  • 188
  • 305
  • Did you consider simply checking after argparse with an if? – erikbstack Dec 17 '12 at 17:51
  • 2
    I could, the nice thing about argparse is it handles the error message for you. – Kevin Burke Dec 17 '12 at 17:52
  • I though you could add a normal group of options using `add_argument_group` to the mutually exclusive group, but this does not work at all(it's like not having a mutually exclusive group at all). Probably the better choice you have is to write a custom action that implements this kind of logic. It should be too hard to do. – Bakuriu Dec 17 '12 at 19:24
  • I meant "should **not**" be too hard to do. – Bakuriu Dec 17 '12 at 19:34
  • Possible duplicate of [Does argparse (python) support mutually exclusive groups of arguments?](http://stackoverflow.com/questions/4770576/does-argparse-python-support-mutually-exclusive-groups-of-arguments) – Ciro Santilli OurBigBook.com Aug 19 '16 at 16:18

3 Answers3

5

You could not really do it with argparse, however you can do it after argparse has run.

Here is an example:

parser = argparse.ArgumentParser()

# group 1 
parser.add_argument("-q", "--query", help="query", required=False)
parser.add_argument("-f", "--fields", help="field names", required=False)

# group 2 
parser.add_argument("-a", "--aggregation", help="aggregation",
                    required=False)

I am using here options given to a command line wrapper for querying a mongodb. The collection instance can either call the method aggregate or the method find with to optional arguments query and fields, hence you see why the first two arguments are compatible and the last one isn't.

So now I run parser.parse_args() and check it's content:

args = parser().parse_args()

print args.aggregation
if args.aggregation and (args.query or args.fields):
    print "-a and -q|-f are mutually exclusive ..."
    sys.exit(2)

Of course, this little hack is only working for simple cases and it would become a nightmare to check all the possible options if you have many mutually exclusive options and groups. In that case you should break your options in to command groups. For that, you should follow the suggestion here Python argparse mutual exclusive group.

Community
  • 1
  • 1
oz123
  • 27,559
  • 27
  • 125
  • 187
1

Docopt could work in this instance.

It uses pipes for mutually exclusive elements.

my_program (aggregate | find [-q | -f])
Patrick
  • 171
  • 1
  • 7
  • 1
    If you don't have to use argparse for consistency with your team, use Docopt. If you have to use argparse, then talk to the person who can decide differently, and show them Docopt. Docopt makes it quick, and super easy to set up up complicated requirements and behaviours, because argparse and it's ilk, are basically the tail wagging the dog. I haven't found a single instance where I couldn't do something I actually needed in Docopt, that I could do (and would work) in argparse. – TinBane Jan 20 '15 at 22:34
-1

You could negate the meaning of A and then use an subparser. The subparsers allows you to specify that "If and only if A is selected, user can select B or C."

http://docs.python.org/2/library/argparse.html

jary
  • 1,161
  • 6
  • 9