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.

classification
Title: Deprecate unsupported nesting of argparse groups
Type: behavior Stage: resolved
Components: Library (Lib) Versions: Python 3.11
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: Nosy List: Laszlo.Attila.Toth, Sam.Kerr, iritkatriel, paul.j3, rhettinger, serhiy.storchaka
Priority: normal Keywords: patch

Created on 2014-07-23 16:03 by Sam.Kerr, last changed 2022-04-11 14:58 by admin. This issue is now closed.

Files
File name Uploaded Description Edit
issue22047_1.patch paul.j3, 2014-07-25 21:37 review
issue22047.py paul.j3, 2014-07-25 22:52
issue22047_2.patch paul.j3, 2014-07-26 06:05 review
Pull Requests
URL Status Linked Edit
PR 30098 merged iritkatriel, 2021-12-14 11:57
Messages (16)
msg223744 - (view) Author: Sam Kerr (Sam.Kerr) Date: 2014-07-23 16:03
The following code:

   import argparse
   parser = argparse.ArgumentParser()
   group1 = parser.add_mutually_exclusive_group()
   group2 = group1.add_mutually_exclusive_group()
   group2.add_argument('-hello',action='store_true', help="A flag")
   args = parser.parse_args()

produces this output:

   skerr@gravel:~$ python bug.py -h
   usage: bug.py [-h] [[-hello]

   optional arguments:
        -h, --help  show this help message and exit
        -hello      A flag
   skerr@gravel:~$ 

Note the double [[ around hello, but there is no double ]] to close it. This is the error.
msg223917 - (view) Author: paul j3 (paul.j3) * (Python triager) Date: 2014-07-25 03:50
That's an artifact of how the group usage is formatted (which isn't very robust).  It's not designed to handle nested groups.  

Mutually exclusive groups aren't meant to nest inside other mutually exclusive groups.  While it possible, it doesn't help you.  Effectively the arguments combined into one larger group.

See http://bugs.python.org/issue11588 for discussion on how nested groups might be implemented, and the difficulties in properly formatting their usage.

http://bugs.python.org/issue10984 has a more robust mutually exclusive group formatter, but even that is not designed for nesting.
msg223972 - (view) Author: paul j3 (paul.j3) * (Python triager) Date: 2014-07-25 17:24
On further thought, I think

   group2 = group1.add_mutually_exclusive_group()

should have raised an error, stating that a group (argument or mutually exclusive) cannot be added to a mutually exclusive group.

Also an argument group should not be added to another argument group.

However, adding a mutually exclusive group to an argument group is ok, though only for the undocumented (though tested) purpose of giving it a title.
msg223974 - (view) Author: Sam Kerr (Sam.Kerr) Date: 2014-07-25 17:28
What I was going for was the ability to have a group contain a mutually exclusive group and a non-exclusive group, but using the mutually exclusive group meant you could not use the non-exclusive group.

Such as:

[ [ -opt1 | -opt2 | -opt3   ] [ [-opt4] [-opt5] [-opt6] ] ]
msg223978 - (view) Author: Sam Kerr (Sam.Kerr) Date: 2014-07-25 17:37
I fat fingered the example, sorry:

[ [ -opt1 | -opt2 | -opt3   ] | [ [-opt4] [-opt5] [-opt6] ] ]

Note the new pipe between the 2 subgroups
msg224004 - (view) Author: paul j3 (paul.j3) * (Python triager) Date: 2014-07-25 21:37
Here's a preliminary patch that raises an error if there's an attempt to nest a mutually exclusive group in another, or there's an attempt to add an argument group to either kind of group.

It still needs test_argparse.py and argparse.rst changes

I'm raising a ValueError, since that is what most of the other add_argument errors do.  An alternative is a NotImplementedError, since that is, in effect, what I am doing, blocking the implementation of particular 'add' methods.

An alternative to adding this patch as high priority bug issue, is to include it in the UsageGroup patch (11588) which will implement nestable groups.
msg224010 - (view) Author: paul j3 (paul.j3) * (Python triager) Date: 2014-07-25 22:52
ArgumentGroups and MutuallyExclusiveGroups, as currently defined, won't give you that kind of usage.  I have appended a script that uses UsageGroups, which I am developing for http://bugs.python.org/issue11588, 
to solve this.

It defines 2 'mxg' groups (groups with the xor logic of mutually exclusive groups), and 1 'any' group.  They can be nested.

The resulting usage line is:

    usage: PROG [-h] [[--opt1 | --opt2 | --opt3] | [--opt4 --opt5 --opt6]]

Normally '|' is used for simple logical 'or'.  But in mutually exclusive groups it denotes 'xor'.  So what should join 'any' lists?  You chose ' ', I was using ','.  Defining a usage notation that is simple, intuitive, and also flexible, is not easy.
msg224020 - (view) Author: paul j3 (paul.j3) * (Python triager) Date: 2014-07-26 06:05
This patch adds a 

    class TestMutuallyExclusiveGroupErrors
        test_invalid_add_group() test,

closely modeled on

        test_invalid_add_argument()

I'm using ValueError in group add methods (maintaining the similarity with add_argument errors).

I haven't changed the documentation.  add_argument_group and add_mutually_exclusive_group methods are described as belonging to an ArgumentParser, and the examples are consistent with that. An admonition against nesting groups would not fit with the current flow.

However to be accurate, these methods belong to _ActionsContainer, the parent class for both the parser and groups.  The documentation glosses over this detail.  So an alternative way of addressing this issue is to move these 2 methods to the ArgumentParser class.
msg286584 - (view) Author: paul j3 (paul.j3) * (Python triager) Date: 2017-02-01 02:34
A similar issue about nesting an Argument Group inside a Mutually Exclusive Group.

http://bugs.python.org/issue24736
msg408220 - (view) Author: Irit Katriel (iritkatriel) * (Python committer) Date: 2021-12-10 16:26
I am unable to reproduce this on 3.11:

% ./python.exe tt.py -h
usage: tt.py [-h] [[-hello]]

options:
  -h, --help  show this help message and exit
  -hello      A flag
msg408412 - (view) Author: Irit Katriel (iritkatriel) * (Python committer) Date: 2021-12-12 23:28
While I was unable to reproduce this rendering error, there are other issues due to nesting of argument groups, and I wonder if we should deprecate those operations, along the lines of Paul's patch on this issue (but with deprecation rather than raising an exception).

Other related issues:  issue46057 (from today), issue16807, issue45690, issue43259, (there are probably more).
msg408524 - (view) Author: Irit Katriel (iritkatriel) * (Python committer) Date: 2021-12-14 11:56
I am repurposing this issue for the deprecation of nesting. It is pretty clear that the functions exist by accident through inheritance. They are not documented and from the number of open issues about them they clearly are not working as people expect them to.
msg408637 - (view) Author: Irit Katriel (iritkatriel) * (Python committer) Date: 2021-12-15 19:17
Another issue due to nesting: issue38590.
msg408712 - (view) Author: Irit Katriel (iritkatriel) * (Python committer) Date: 2021-12-16 15:31
New changeset 30322c497e0b8d978f7a0de95985aac9c5daf1ac by Irit Katriel in branch 'main':
bpo-22047: [argparse] deprecate nested argument groups and mutually exclusive groups (GH-30098)
https://github.com/python/cpython/commit/30322c497e0b8d978f7a0de95985aac9c5daf1ac
msg408765 - (view) Author: László Attila Tóth (Laszlo.Attila.Toth) * Date: 2021-12-17 09:53
Hi, according to the group update the _MutuallyExclusiveGroup should have an add_argument_group() call with the deprecation warning, but that method is missing in commit 30322c497e0b8d978f7a0de95985aac9c5daf1ac.
msg408782 - (view) Author: Irit Katriel (iritkatriel) * (Python committer) Date: 2021-12-17 14:29
_MutuallyExclusiveGroup inherits add_argument_group from _ArgumentGroup.
History
Date User Action Args
2022-04-11 14:58:06adminsetgithub: 66246
2021-12-17 14:29:50iritkatrielsetmessages: + msg408782
2021-12-17 09:53:10Laszlo.Attila.Tothsetnosy: + Laszlo.Attila.Toth
messages: + msg408765
2021-12-16 15:45:51iritkatriellinkissue46058 superseder
2021-12-16 15:39:12iritkatriellinkissue38590 superseder
2021-12-16 15:38:30iritkatriellinkissue45690 superseder
2021-12-16 15:34:57iritkatrielsetstatus: open -> closed
resolution: fixed
stage: patch review -> resolved
2021-12-16 15:31:21iritkatrielsetmessages: + msg408712
2021-12-15 19:17:18iritkatrielsetmessages: + msg408637
2021-12-14 11:57:42iritkatrielsetstage: patch review
pull_requests: + pull_request28320
2021-12-14 11:56:41iritkatrielsettitle: argparse improperly prints mutually exclusive options when they are in a group -> Deprecate unsupported nesting of argparse groups
messages: + msg408524
versions: + Python 3.11, - Python 2.7, Python 3.5
2021-12-14 07:11:28iritkatriellinkissue46057 superseder
2021-12-12 23:28:33iritkatrielsetstatus: pending -> open
nosy: + rhettinger, serhiy.storchaka
messages: + msg408412

2021-12-10 16:26:16iritkatrielsetstatus: open -> pending
nosy: + iritkatriel
messages: + msg408220

2017-02-01 02:34:00paul.j3setmessages: + msg286584
2014-07-26 06:05:38paul.j3setfiles: + issue22047_2.patch

messages: + msg224020
2014-07-25 22:52:22paul.j3setfiles: + issue22047.py

messages: + msg224010
2014-07-25 21:37:22paul.j3setfiles: + issue22047_1.patch
keywords: + patch
messages: + msg224004
2014-07-25 17:37:52Sam.Kerrsetmessages: + msg223978
2014-07-25 17:28:34Sam.Kerrsetmessages: + msg223974
2014-07-25 17:24:55paul.j3setmessages: + msg223972
versions: + Python 3.5
2014-07-25 03:50:46paul.j3setnosy: + paul.j3
messages: + msg223917
2014-07-23 16:03:44Sam.Kerrcreate