Repository navigation
argparse drops '|'s when the arguments are too long #75949
Copy link
Copy link
Closed
Labels
3.10 (EOL)end of lifeend of life3.11only security fixesonly security fixes3.12only security fixesonly security fixes3.13only security fixesonly security fixes3.14bugs and security fixesbugs and security fixes3.15bugs and security fixesbugs and security fixesstdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directorytype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
Description
| BPO | 31768 |
|---|---|
| Nosy | @ericvsmith, @mlouielu, @al-caveman, @iritkatriel |
| Files |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
assignee = None
closed_at = None
created_at = <Date 2017-10-11.21:49:25.596>
labels = ['type-bug', 'library', '3.9', '3.10', '3.11']
title = "argparse drops '|'s when the arguments are too long"
updated_at = <Date 2021-12-10.16:33:55.067>
user = 'https://github.com/al-caveman'bugs.python.org fields:
activity = <Date 2021-12-10.16:33:55.067>
actor = 'iritkatriel'
assignee = 'none'
closed = False
closed_date = None
closer = None
components = ['Library (Lib)']
creation = <Date 2017-10-11.21:49:25.596>
creator = 'caveman'
dependencies = []
files = ['47214']
hgrepos = []
issue_num = 31768
keywords = []
message_count = 9.0
messages = ['304184', '304186', '304187', '304188', '304189', '304202', '304284', '304287', '408221']
nosy_count = 5.0
nosy_names = ['eric.smith', 'paul.j3', 'louielu', 'caveman', 'iritkatriel']
pr_nums = []
priority = 'normal'
resolution = None
stage = None
status = 'open'
superseder = None
type = 'behavior'
url = 'https://bugs.python.org/issue31768'
versions = ['Python 3.9', 'Python 3.10', 'Python 3.11']Linked PRs
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
3.10 (EOL)end of lifeend of life3.11only security fixesonly security fixes3.12only security fixesonly security fixes3.13only security fixesonly security fixes3.14bugs and security fixesbugs and security fixes3.15bugs and security fixesbugs and security fixesstdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directorytype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
Projects
- StatusShow more project fieldsDoc issues
Activity
al-caveman commentedon Oct 11, 2017
if you execute the code below, mutually exclusive agrs are separated by '|' as expected. but if you uncomment the 1 line down there, then the args list will be too long, and as argparse tries to wrap the args around, it drops all '|'s which semantically destroys the intended syntax of the arguments.
al-caveman commentedon Oct 11, 2017
forgot to add: when you execute the code, pass the argument '-h' in order to have the script generate the help menu text.
ericvsmith commentedon Oct 11, 2017
Removing versions 3.4 and 3.8.
Attaching a reproducing script. Run it with a parameter of the number of arguments to add. The behavior changes between 7 and 8, although I'm not sure either is wrong, just different. This is from Windows:
al-caveman commentedon Oct 11, 2017
When | is dropped, it means that the arguments/options are no longer mutually exclusive, which renders the resultant help menu incorrect.
ericvsmith commentedon Oct 11, 2017
Good point.
mlouielu commentedon Oct 12, 2017
the format of usage is do at argparse.py:296.
So how do we format this kind of situation,
to be like this, if the group also too long?
Also, another bug I think is, given two mutul group,
it will not show out the correct grouping:
--- 2 mutul group ---
paulj3 commentedon Oct 12, 2017
As documented in many other issues, the usage formatter is brittle. It formats the individual usages, joins them into a string. Then if too long to fit on one line it tries t split into actions, etc. This split produces an assertion error if there are 'wierd' characters in the names (e.g. #[]).
With mutually exclusive groups it gets even worse. The brackets and | are spliced into the original string, and then excess [] and spaces are removed. Once recent issue complained about its handling of nested groups (which are borderline wrong).
So I"m not surprised that a long group that spans a couple of lines gets messed up. It requires a major rewrite, and even then I there will be formats involving groups that fall through the cracks.
paulj3 commentedon Oct 12, 2017
I've changed your example a bit to clarify some points.
With
n=0, usage is:Notice that the positional is placed last. That is, regardless of the definition order, 'usage' shows optionals first, positionals last.
With 2 'z':
All the mutually exclusive markings have been dropped. That's because the component actions are not consecutive, having been split up by the reordering of positionals. Marking the group is done only if it can do so in a simple minded way. The group testing is not dependent on being able to format it. That's done by a different part of the code.
For 7 'z' it splits the line. Positionals are printed on a new line.
I noticed this problem with formating group positional in multiline usage some time ago, https://bugs.python.org/issue10984#msg192954
Another thing to watch out for - multiple positionals in a group don't make sense. Only the first one can ever be filled. I don't see a formal check, but it doesn't make logical sense.
If I change the code so it produces multiple optionals:
the group markings are preserved across lines. Note again that the positional (n) is on its own line.
---
Here's another weird behavior, with just one positional in the group:
It complains about not recognizing the '3', rather than complaining about 'z0' not allow with '-v'. That's because the '?' has already been satisfied with [] when parsing the 'n' (see https://bugs.python.org/issue15112).
---
In sum, I think this is pathological case that doesn't need to be fixed.
Usage is ok if there's a long list of optionals. Usage (and parsing) with just one positional in the group is brittle. We shouldn't expect it work with many positionals in the group.
---
@louie, you 2nd example interweaves the definitions of two groups. Except for the optionals/positions reordering that I mentioned above, usage does not reorder arguments. Mutually exclusive groups are marked only if they are contiguous.
https://bugs.python.org/issue10984 has a patch that can format groups even if the actions don't occur in the right order. It isn't a trivial fix.
iritkatriel commentedon Dec 10, 2021
In 3.11 the problem is still there, but the cutoff to make Eric's script show it is now 26 rather than 8:
7 remaining items
serhiy-storchaka commentedon Oct 10, 2024
See also #86020 (comment) which may describe the same or related bug.
GH-75949: Fix argparse dropping '|' in mutually exclusive groups on l…
pythonGH-75949: Fix argparse dropping '|' in mutually exclusive group…
pythonGH-75949: Fix argparse dropping '|' in mutually exclusive group…
[3.13] GH-75949: Fix argparse dropping '|' in mutually exclusive grou…
[3.14] GH-75949: Fix argparse dropping '|' in mutually exclusive grou…