This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author paul.j3
Recipients andrewnester, berker.peksag, bethard, brian.curtin, christofsteel, paul.j3
Date 2017-02-26.18:15:35
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <>
The PR117 patch adds an apparent symmetry.  There's a if/else for 'start', so shouldn't there also be one for 'end'?

    if start in inserts:
        inserts[start] += ' ['
        inserts[start] = '['

But why the '+=' case?  It's needed for cases like this:

    usage: prog [-h] [-A | -B] [-C | -D]

It ensures that the insert between B and C is '] [', as opposed to just '['. 

Without any groups usage for the 4 Actions is

    usage: prog [-h] [-A] [-B] [-C] [-D]

Adding the first group adds a '[','|', and ']' (the inner [] will be deleted later).  The second group also wants to add '[','|',']', but its '[' has to be concatenated to the existing ']', rather than replace it.


To understand what's happening when we nest groups, we have to look at the resulting groups.  

Usage is created with

    formatter.add_usage(self.usage, self._actions,

In christofsteel's original example, the parser._mutually_exclusive_groups is a len 3 list.  Each group has a list of '_group_actions'.  

    In [13]: [len(g._group_actions) for g in parser._mutually_exclusive_groups]
    Out[13]: [6, 4, 2]

The first, outermost group, contains all the defined Actions, including the ones defined in the nested groups.  It doesn't contain 2 actions and a group. The link between child and parent group is one way.  The child knows its 'container', but the parent has not information about 'children'. 

Usage using just the 1st group produces:

    usage: ipython3 [-h] [-a A | -b B | -c C | -d D | -e E | -f F]

With 2 groups:

    usage: ipython3 [-h] [-a A | -b B | [-c C | -d D | -e E | -f F]

The second group has added it's '[ | | | ]' on top of the first group's inserts.  The '[' was appended, the others over write.

That's more apparent if I change the 2nd group to be 'required':

    usage: ipython3 [-h] [-a A | -b B | (-c C | -d D | -e E | -f F)

The final ']' (from the 1st group) has been replaced with a ')'.

The patch ensures that the new ']' is appended to the existing ']'. But if the 2nd group is required, the patch will produce:

     | -f F])


     | -f F)]

as would be expected if the groups were really nested.

In sum, patching brittle code to do something it wasn't designed to do in the first place isn't the solution.

Disabling nesting as recommended in, is, I think a better solution.


An old (2011) issue tries to put an action in 2 or more groups: 'argparse add_mutually_exclusive_group should accept existing arguments to register conflicts'

Adding an existing action to a new group is relatively easy.  But usage display runs into the same issues.  I had to recommend a total rewrite that ditches the 'inserts' approach entirely.
Date User Action Args
2017-02-26 18:15:36paul.j3setrecipients: + paul.j3, bethard, brian.curtin, berker.peksag, andrewnester, christofsteel
2017-02-26 18:15:36paul.j3setmessageid: <>
2017-02-26 18:15:36paul.j3linkissue29553 messages
2017-02-26 18:15:35paul.j3create