Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python argparse mutual exclusive group

What I need is:

pro [-a xxx | [-b yyy -c zzz]] 

I tried this but does not work. Could someone help me out?

group= parser.add_argument_group('Model 2') group_ex = group.add_mutually_exclusive_group() group_ex.add_argument("-a", type=str, action = "store", default = "", help="test") group_ex_2 = group_ex.add_argument_group("option 2") group_ex_2.add_argument("-b", type=str, action = "store", default = "", help="test") group_ex_2.add_argument("-c", type=str, action = "store", default = "", help="test") 

Thanks!

like image 503
Sean Avatar asked Jul 28 '13 14:07

Sean


2 Answers

add_mutually_exclusive_group doesn't make an entire group mutually exclusive. It makes options within the group mutually exclusive.

What you're looking for is subcommands. Instead of prog [ -a xxxx | [-b yyy -c zzz]], you'd have:

prog    command 1      -a: ...   command 2     -b: ...     -c: ... 

To invoke with the first set of arguments:

prog command_1 -a xxxx 

To invoke with the second set of arguments:

prog command_2 -b yyyy -c zzzz 

You can also set the sub command arguments as positional.

prog command_1 xxxx 

Kind of like git or svn:

git commit -am git merge develop 

Working Example

# create the top-level parser parser = argparse.ArgumentParser(prog='PROG') parser.add_argument('--foo', action='store_true', help='help for foo arg.') subparsers = parser.add_subparsers(help='help for subcommand', dest="subcommand")  # create the parser for the "command_1" command parser_a = subparsers.add_parser('command_1', help='command_1 help') parser_a.add_argument('a', type=str, help='help for bar, positional')  # create the parser for the "command_2" command parser_b = subparsers.add_parser('command_2', help='help for command_2') parser_b.add_argument('-b', type=str, help='help for b') parser_b.add_argument('-c', type=str, action='store', default='', help='test') 

Test it

>>> parser.print_help() usage: PROG [-h] [--foo] {command_1,command_2} ...  positional arguments:   {command_1,command_2}                         help for subcommand     command_1           command_1 help     command_2           help for command_2  optional arguments:   -h, --help            show this help message and exit   --foo                 help for foo arg. >>>  >>> parser.parse_args(['command_1', 'working']) Namespace(subcommand='command_1', a='working', foo=False) >>> parser.parse_args(['command_1', 'wellness', '-b x']) usage: PROG [-h] [--foo] {command_1,command_2} ... PROG: error: unrecognized arguments: -b x 

Good luck.

like image 94
Jonathan Avatar answered Sep 23 '22 23:09

Jonathan


While Jonathan's answer is perfectly fine for complex options, there is a very simple solution which will work for the simple cases, e.g. 1 option excludes 2 other options like in

command [- a xxx | [ -b yyy | -c zzz ]]  

or even as in the original question:

pro [-a xxx | [-b yyy -c zzz]] 

Here is how I would do it:

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 like Jonathan suggested.

like image 21
oz123 Avatar answered Sep 23 '22 23:09

oz123