Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does argparse (python) support mutually exclusive groups of arguments?

Tags:

If I have the arguments '-a', '-b', '-c', '-d', with the add_mutually_exclusive_group() function my program will have to use just one of them. Is there a way to combine that, so that the program will accept only either '-a 999 -b 999' or '-c 999 -d 999'?

Edit: adding a simple program for more clarity:

>>> parser = argparse.ArgumentParser() >>> group = parser.add_mutually_exclusive_group() >>> group.add_argument('-a') >>> group.add_argument('-b') >>> group.add_argument('-c') >>> group.add_argument('-d') 

Then only ./app.py -a | ./app.py -b | ./app.py -c | ./app.py -d can be called. Is it possible to have argparse group the exclusion groups, so that only ./app.py -a .. -b .. | ./app.py -c .. -d .. be called?

like image 721
aeter Avatar asked Jan 22 '11 21:01

aeter


People also ask

What is Argparse in Python used for?

Python's argparse standard library module is a tool that helps you write command-line interfaces (CLI) over your Python code. You may already be familiar with CLIs: programs like git , ls , grep , and find all expose command-line interfaces that allow you to call an underlying program with specific inputs and options.

Is Argparse a standard?

The argparse is a standard module; we do not need to install it. A parser is created with ArgumentParser and a new parameter is added with add_argument . Arguments can be optional, required, or positional.


1 Answers

EDIT: Never mind. Because argparse makes the horrible choice of having to create an option when invoking group.add_argument. That wouldn't be my design choice. If you're desperate for this feature, you can try doing it with ConflictsOptionParser:

# exclusivegroups.py import conflictsparse  parser = conflictsparse.ConflictsOptionParser() a_opt = parser.add_option('-a') b_opt = parser.add_option('-b') c_opt = parser.add_option('-c') d_opt = parser.add_option('-d')  import itertools compatible_opts1 = (a_opt, b_opt) compatible_opts2 = (c_opt, d_opt) exclusives = itertools.product(compatible_opts1, compatible_opts2) for exclusive_grp in exclusives:     parser.register_conflict(exclusive_grp)   opts, args = parser.parse_args() print "opts: ", opts print "args: ", args 

Thus when we invoke it, we can see we get the desired effect.

$ python exclusivegroups.py -a 1 -b 2 opts:  {'a': '1', 'c': None, 'b': '2', 'd': None} args:  [] $ python exclusivegroups.py -c 3 -d 2 opts:  {'a': None, 'c': '3', 'b': None, 'd': '2'} args:  [] $ python exclusivegroups.py -a 1 -b 2 -c 3 Usage: exclusivegroups.py [options]  exclusivegroups.py: error: -b, -c are incompatible options. 

The warning message doesn't inform you that both '-a' and '-b' are incompatible with '-c', however a more appropriate error message could be crafted. Older, wrong answer below.

OLDER EDIT: [This edit is wrong, although wouldn't it be just a perfect world if argparse worked this way?] My previous answer actually was incorrect, you should be able to do this with argparse by specifying one group per mutually exclusive options. We can even use itertools to generalize the process. And make it so we don't have to type out all the combinations explicitly:

import itertools compatible_opts1 = ('-a', '-b') compatible_opts2 = ('-c', '-d') exclusives = itertools.product(compatible_opts1, compatible_opts2) for exclusive_grp in exclusives:     group = parser.add_mutually_exclusive_group()     group.add_argument(exclusive_grp[0])     group.add_argument(exclusive_grp[1]) 
like image 94
gotgenes Avatar answered Sep 20 '22 07:09

gotgenes