Argument groups simply help organize the display of help. They cannot be nested. Mutually exclusive groups validate arguments and change usage mapping. They can be nested, but the end result is the same as if you made one large group. http://bugs.python.org/issue11588 is trying to create a more general usage group.
At the same time, you can write a custom usage string and check the arguments after parsing if mutually exclusive groups do not give you enough control.
Here's a parser using the code I'm developing for http://bugs.python.org/issue11588
parser = argparse.ArgumentParser(formatter_class=argparse.UsageGroupHelpFormatter) bar = parser.add_usage_group(kind='mxg', dest='s|m') bar.add_argument('-s', action='store_true', default=True) bar.add_argument('-m', action='store_true', default=False) bar = parser.add_usage_group(kind='mxg', dest='year|more') bar.add_argument('-y', metavar='year', type=int,...) baz = bar.add_usage_group(kind='any', dest='', joiner=' ', parens='[]') g_13 = baz.add_usage_group(kind='mxg', dest='1|3') g_13.add_argument('-1', dest='i1',...) g_13.add_argument('-3', dest='i3',...) baz.add_argument(metavar='month', type=int,...) baz.add_argument(metavar='year', type=int,...)
This replaces mutually_exclusive_group with usage_group , which can be nested, and can check for other logical relationships besides "xor". "any" accepts any combination of its arguments, just as you expected "argument_group" to act.
Resulting use:
usage: prog.py [-h] [-s | -m] [-y [year] | [[-1 | -3] month year]] [month] [year]
The main mistake is to display the positioners, โmonthโ and โyearโ. They are in the right place in the โanyโ group, but they also appear in the usual final location for the positions.
It accepts input, such as:
'' '-y 1943 -s '-1 12 1943' '12 1943' '12' '-3' '1943' gives an error, because it it is out of range for a month
As you can see, expanding the concept of groups is not trivial. I think I'm on the right track, but there are still rough edges.