msg182251 - (view) |
Author: Chris Jerdonek (chris.jerdonek) *  |
Date: 2013-02-17 00:38 |
This issue is to add to argparse's add_mutually_exclusive_group() method support for passing a title and description. From the argparse docs: "Note that currently mutually exclusive argument groups do not support the title and description arguments of add_argument_group()." (from http://docs.python.org/dev/library/argparse.html#argparse.add_mutually_exclusive_group ) |
|
|
msg216193 - (view) |
Author: Tatiana Al-Chueyr (tati_alchueyr) * |
Date: 2014-04-14 20:03 |
My proposal is that both: - add_mutually_exclusive_group() - add_argument_group() print optional arguments in the same way when title and/or description are provided. I've attached a test case of the proposed behavior. Please, let me know if you have any objections or suggestions! :) I'm working on the implementation right now. Note: it is outside the existing Lib/test/test_argparse.py for clarifying the idea. BTW: thanks to r.david.murray for mentoring and discussing use cases! |
|
|
msg216203 - (view) |
Author: Tatiana Al-Chueyr (tati_alchueyr) * |
Date: 2014-04-14 20:28 |
uploading test file |
|
|
msg216505 - (view) |
Author: paul j3 (paul.j3) *  |
Date: 2014-04-16 17:24 |
While mutually exclusive groups are a subclass of argument groups, they have very different uses. Argument groups are used solely to organize the help section. Groups are not used at all during parsing. 'parse_args' doesn't even pay attention to those 2 default groups (positionals and optionals). 'parse_args' just uses the master list of actions ('parser._actions'). Mutually exclusive groups are not used at all while formatting the help lines. They are used to format the usage line. They also implement argument tests during parsing. Groups are not set up for nesting. However it is possible to define a mutually exclusive group within an argument group, and effectively give it a title and description. p=argparse.ArgumentParser() g=p.add_argument_group('title') g1=g.add_mutually_exclusive_group() g1.add_argument('--foo') p.print_help() producing: usage: ipython [-h] [--foo FOO] optional arguments: -h, --help show this help message and exit title: --foo FOO Both kinds of groups are a superficial addition to argparse. I argue in http://bugs.python.org/issue11588 that they aren't adequate for handling more complicated groupings (inclusive, nesting, etc). While I'm not convinced the change proposed in this issue is necessary, if we are going implement it, I'd suggest a simple addition to 'add_mutually_exclusive_group()'. If there's a title argument, add this group to '_action_groups' as well as '_mutually_exclusive_groups'. def add_mutually_exclusive_group(self, **kwargs): group = _MutuallyExclusiveGroup(self, **kwargs) self._mutually_exclusive_groups.append(group) try: kwargs.title self._action_groups.append(group) except AttributeError: pass return group This should do the job without adding much complexity. |
|
|
msg216559 - (view) |
Author: paul j3 (paul.j3) *  |
Date: 2014-04-16 19:15 |
Using a mutually_exclusive_group is a little more complicated than I implied in the previous post. p=argparse.ArgumentParser() g=p.add_mutually_exclusive_group() # currently the code objects to 'title' and 'description' keywords g.add_argument('--foo') g.add_argument('--bar') # but a title can be added after creation g.title='test' g.description='description' # now add the group to the list that is used for help formatting p._action_groups.append(g) p.print_help() producing: usage: ipython [-h] [--foo FOO | --bar BAR] optional arguments: -h, --help show this help message and exit --foo FOO --bar BAR test: description --foo FOO --bar BAR Now the arguments appear in both the 'optional arguments' group (a default one), and the new group. That's not what we want. So the mutually_exclusive_group has to be changed so it accepts title and description. And it also has to block the addition of arguments to one of the existing groups. A key difference is in how _add_action is implemented for the 2 group classes: For argument_group: def _add_action(self, action): action = super(_ArgumentGroup, self)._add_action(action) self._group_actions.append(action) return action for mutually exclusive group def _add_action(self, action): ... action = self._container._add_action(action) self._group_actions.append(action) return action The first uses 'super' to add the action to itself. The second adds the action to its 'container'. That difference allows you to add a mutually_exclusive_group to an argument_group (or to another mutually_exclusive_group), but you can't add an argument_group to another argument_group (no nesting). I don't like the idea of using a different _add_action method depending on whether group has a 'title' or not. That's too kludgy. Another possibility is to have 'parser.add_mutually_exclusive_group()' do what I first demonstrated - first create an 'argument_group' with the title, and add the mutually_exclusive_group to that. This is still kludgy, but the change is limited to one function. For demonstration purposes it probably could be implemented in a new function (add_titled_mutually_exclusive_group). |
|
|
msg216574 - (view) |
Author: paul j3 (paul.j3) *  |
Date: 2014-04-16 20:03 |
The attached file implements a solution using a subclassed ArgumentParser and a .add_titled_mutually_exclusive_group method (two versions). I changed the test conditions a bit, removing a blank line, and making the usage 'exclusive'. |
|
|
msg216761 - (view) |
Author: paul j3 (paul.j3) *  |
Date: 2014-04-17 22:27 |
The idea of nesting a mutually_exclusive_group in a titled argument_group is already present in `test_argparse.py`. class TestMutuallyExclusiveInGroup(MEMixin, TestCase): def get_parser(self, required=None): parser = ErrorRaisingArgumentParser(prog='PROG') titled_group = parser.add_argument_group( title='Titled group', description='Group description') mutex_group = \ titled_group.add_mutually_exclusive_group(required=required) mutex_group.add_argument('--bar', help='bar help') mutex_group.add_argument('--baz', help='baz help') return parser failures = ['--bar X --baz Y', '--baz X --bar Y'] successes = [ ('--bar X', NS(bar='X', baz=None)), ('--baz Y', NS(bar=None, baz='Y')), ] successes_when_not_required = [ ('', NS(bar=None, baz=None)), ] usage_when_not_required = '''\ usage: PROG [-h] [--bar BAR | --baz BAZ] ''' usage_when_required = '''\ usage: PROG [-h] (--bar BAR |
--baz BAZ) ''' help = '''\ optional arguments: -h, --help show this help message and exit Titled group: Group description --bar BAR bar help --baz BAZ baz help ''' So now the question is - do we to modify `add_mutually_exclusive_group` to streamline this task? An alternative is to add a note to the documentation, eg. Note that currently mutually exclusive argument groups do not support the title and description arguments of add_argument_group(). However a such a group can be added to a titled argument group. (and then add an example) |
|
msg216763 - (view) |
Author: paul j3 (paul.j3) *  |
Date: 2014-04-17 23:22 |
oops - one more glitch (revealed by TestMutuallyExclusiveInGroup): 'add_mutually_exclusive_group' accepts a 'required' argument, but 'add_argument_group' does not. So 'add_titled_mutually_exclusive_group' needs to be changed to temporarily remove that argument (if given). |
|
|