classification
Title: argparse group nesting lost on inheritance
Type: behavior Stage:
Components: Library (Lib) Versions: Python 3.4, Python 3.5, Python 2.7
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: bethard, dougalsutherland, paul.j3
Priority: normal Keywords: patch

Created on 2012-12-29 01:39 by dougalsutherland, last changed 2019-04-26 19:42 by BreamoreBoy.

Files
File name Uploaded Description Edit
argparse_mutex_parent.patch dougalsutherland, 2012-12-29 01:39 patch fixing the problem and adding a test review
Messages (4)
msg178459 - (view) Author: Dougal Sutherland (dougalsutherland) * Date: 2012-12-29 01:39
If you wrap a mutually exclusive group inside an argument group in an argparse.ArgumentParser, and then use parents= to inherit from that parser, the non-exclusive argument group is forgotten in the help output, and the arguments move to the default "optional arguments" section. For example:

    # construct the parser with a mutually exclusive group
    >>> import argparse
    >>> parent = argparse.ArgumentParser(add_help=False)
    >>> group = parent.add_argument_group('the group')
    >>> group.add_argument('--foo') and None
    >>> mutex = group.add_mutually_exclusive_group()
    >>> mutex.add_argument('-a', action='store_true') and None
    >>> mutex.add_argument('-b', action='store_true') and None
    >>> parent.print_help()
    usage: [--foo FOO] [-a | -b]

    the group:
      --foo FOO
      -a
      -b

    # now try to inherit from it; "the group" is forgotten for
    # mutex arguments, but remains for others
    >>> argparse.ArgumentParser(add_help=False, parents=[parent]).print_help()
    usage: [--foo FOO] [-a | -b]

    optional arguments:
      -a
      -b

    the group:
      --foo FOO

I see the same behavior on 2.7.3 and 3.3.0.

The problem is that [`argparse._ActionsContainer._add_container_actions`](http://hg.python.org/releasing/2.7.3/file/7bb96963d067/Lib/argparse.py#l1331) always adds mutex groups to the top level, rather than to the equivalent of their `_container` attribute. The attached patch fixes this, and adds a test based on the formatted output (almost identical to the `test_groups_parents` test).

One thing about the patch: it assumes that the `_container` attribute of all the mutex groups will be either the `container` argument to `_add_container_actions` or an argument group that has been processed in `group_map`. If this is not the case, it'll fail with either an `AttributeError` or a `KeyError`. I don't know when this would happen, or if it's common enough that it's worth checking for more explicitly.
msg222934 - (view) Author: Mark Lawrence (BreamoreBoy) * Date: 2014-07-13 14:30
@Dougal sorry about the delay in getting back to you.
msg223047 - (view) Author: paul j3 (paul.j3) * (Python triager) Date: 2014-07-14 18:53
To put this issue in perspective:

- There's nothing in the documentation about nesting a mutually exclusive group in an argument group.

- There are prominent notes in the documentation about MEGs not taking title and description.  The '_add_container_actions' code has a warning that something needs to change if they do acquire such attributes.

- However there is a class in test_argparse.py that does nest an MEG in an argument group, which in effect gives it a title.
TestMutuallyExclusiveInGroup
That's the pattern that Dougal is using.

- http://bugs.python.org/issue17218 support title and description in argparse add_mutually_exclusive_group

proposes adding these attributes to MEG.  There I proposed doing so via this nested group mechanism.  So that patch requires this one to work correctly with parents.

- http://bugs.python.org/issue11588 I am exploring the implementation of UsageGroups, a generalization of MEG that allow other group tests, and nesting.  There too title and description come via nesting in an ArgumentGroup.

- Groups and parents are confusing to beginning users.  In StackOverflow questions 'argparse' users often confuse argument groups and mutually exclusive groups, expecting to be able to nest one inside the other.  Currently that nesting only works one way, and for the limited purpose illustrated here.
msg223158 - (view) Author: paul j3 (paul.j3) * (Python triager) Date: 2014-07-15 23:44
The subcommands grouping mechanism proposed in http://bugs.python.org/issue9341
probably does not work with [parents] either.

This _add_container_actions method is brittle.  It has to know too much about the structure of a parser and its groups.  Any change to that structure could break this [parents] mechanism.  

In a refactoring, each 'add_xxx' method would have a 'copy_xxx' companion method.
History
Date User Action Args
2019-04-26 19:42:34BreamoreBoysetnosy: - BreamoreBoy
2014-07-15 23:44:32paul.j3setmessages: + msg223158
2014-07-14 18:53:52paul.j3setmessages: + msg223047
2014-07-13 14:30:40BreamoreBoysetnosy: + BreamoreBoy, paul.j3

messages: + msg222934
versions: + Python 3.5, - Python 3.2, Python 3.3
2012-12-29 01:39:27dougalsutherlandcreate