Mutual exclusion between argument groups

2019-07-16 12:32发布

问题:

I'm trying to implement the following argument dependency using the argparse module: ./prog [-h | [-v schema] file] meaning the user must pass either -h or a file, if a file is passed the user can optionally pass -v schema.

That's what I have now but that doesn't seem to be working:

import argparse

parser = argparse.ArgumentParser()
mtx = parser.add_mutually_exclusive_group()
mtx.add_argument('-h', ...)  
grp = mtx.add_argument_group()
grp.add_argument('-v', ...)
grp.add_argument('file', ...)   
args = parser.parse_args()

It looks like you can't add an arg group to a mutex group or am I missing something?

回答1:

If -h means the default help, then this is all you need (this help is already exclusive)

import argparse
parser = argparse.ArgumentParser()
parser.add_argument('file')
parser.add_argument('-s','--schema')
parser.parse_args('-h'.split())  # parser.print_help()

producing

usage: stack23951543.py [-h] [-s SCHEMA] file
...

If by -h you mean some other action, lets rename it -x. This would come close to what you describe

parser = argparse.ArgumentParser()
parser.add_argument('-s','--schema', default='meaningful default value')
mxg = parser.add_mutually_exclusive_group(required=True)
mxg.add_argument('-x','--xxx', action='store_true')
mxg.add_argument('file', nargs='?')
parser.parse_args('-h'.split())

usage is:

usage: stack23951543.py [-h] [-s SCHEMA] (-x | file)

Now -x or file is required (but not both). -s is optional in either case, but with a meaningful default, it doesn't matter if it is omitted. And if -x is given, you can just ignore the -s value.

If necessary you could test args after parsing, to confirm that if args.file is not None, then args.schema can't be either.


Earlier I wrote (maybe over thinking the question):

An argument_group cannot be added to a mutually_exclusive_group. The two kinds of groups have different purposes and functions. There are previous SO discussions of this (see 'related'), as well as a couple of relevant Python bug issues. If you want tests that go beyond a simple mutually exclusive group, you probably should do your own testing after parse_args. That may also require your own usage line.

An argument_group is just a means of grouping and labeling arguments in the help section.

A mutually_exclusive_group affects the usage formatting (if it can), and also runs tests during parse_args. The use of 'group' for both implies that they are more connected than they really are.

http://bugs.python.org/issue11588 asks for nested groups, and the ability to test for 'inclusivity' as well. I tried to make the case that 'groups' aren't general enough to express all the kinds of testing that users want. But it's one thing to generalize the testing mechanism, and quite another to come up with an intuitive API. Questions like this suggest that argparse does need some sort of 'nested group' syntax.