Skip to content

argparse sometimes tracebacks when all options in a mutually exclusive group are suppressed #96310

Description

@dmach

Bug report

When a subparser contains a mutually exclusive group and the all options in the group are suppressed,
it sometimes errors out with a traceback. The crash depends on other options (their ordering and length) and terminal size.

Reproducer:

#!/usr/bin/python3

import argparse

parser = argparse.ArgumentParser()
commands = parser.add_subparsers(title="commands", dest="command")
cmd_foo = commands.add_parser("foo")
group = cmd_foo.add_mutually_exclusive_group()
group.add_argument('--verbose', action='store_true', help=argparse.SUPPRESS)
group.add_argument('--quiet', action='store_true', help=argparse.SUPPRESS)
cmd_foo.add_argument("--longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong")

parser.parse_args()
$ python3.11 reproducer.py foo --help
Traceback (most recent call last):
  File ".../reproducer.py", line 13, in <module>
    parser.parse_args()
  File "/usr/lib64/python3.11/argparse.py", line 1862, in parse_args
    args, argv = self.parse_known_args(args, namespace)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.11/argparse.py", line 1895, in parse_known_args
    namespace, args = self._parse_known_args(args, namespace)
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.11/argparse.py", line 2085, in _parse_known_args
    positionals_end_index = consume_positionals(start_index)
                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.11/argparse.py", line 2062, in consume_positionals
    take_action(action, args)
  File "/usr/lib64/python3.11/argparse.py", line 1971, in take_action
    action(self, namespace, argument_values, option_string)
  File "/usr/lib64/python3.11/argparse.py", line 1234, in __call__
    subnamespace, arg_strings = parser.parse_known_args(arg_strings, None)
                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.11/argparse.py", line 1895, in parse_known_args
    namespace, args = self._parse_known_args(args, namespace)
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.11/argparse.py", line 2103, in _parse_known_args
    start_index = consume_optional(start_index)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.11/argparse.py", line 2043, in consume_optional
    take_action(action, args, option_string)
  File "/usr/lib64/python3.11/argparse.py", line 1971, in take_action
    action(self, namespace, argument_values, option_string)
  File "/usr/lib64/python3.11/argparse.py", line 1112, in __call__
    parser.print_help()
  File "/usr/lib64/python3.11/argparse.py", line 2590, in print_help
    self._print_message(self.format_help(), file)
                        ^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.11/argparse.py", line 2574, in format_help
    return formatter.format_help()
           ^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.11/argparse.py", line 286, in format_help
    help = self._root_section.format_help()
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.11/argparse.py", line 217, in format_help
    item_help = join([func(*args) for func, args in self.items])
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.11/argparse.py", line 217, in <listcomp>
    item_help = join([func(*args) for func, args in self.items])
                      ^^^^^^^^^^^
  File "/usr/lib64/python3.11/argparse.py", line 341, in _format_usage
    assert ' '.join(opt_parts) == opt_usage
AssertionError

Please note that setting COLUMNS to a high number doesn't trigger the traceback:

COLUMNS=1000 python3.11 reproducer.py foo --help
usage: reproducer.py foo [-h]  [--longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong LONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONG]

options:
  -h, --help            show this help message and exit
  --longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong LONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONG

Your environment

  • CPython versions tested on: 3.8.13, 3.10.6, 3.11.0b5
  • openSUSE Tumbleweed 20220823

Linked PRs

Activity

  1. added
    type-bugAn unexpected behavior, bug, or error
    on Aug 26, 2022
  2. added a commit that references this issue on Aug 26, 2022
  3. added
    stdlibStandard Library Python modules in the Lib/ directory
    on Aug 26, 2022
  4. added a commit that references this issue on Aug 26, 2022
  5. added a commit that references this issue on May 28, 2023
    4336ac7
  6. added a commit that references this issue on Feb 21, 2024
  7. added 2 commits that reference this issue on Feb 21, 2024
  8. added 2 commits that reference this issue on Feb 21, 2024
  9. moved this from Bugs to Doc issues in Argparse issueson Feb 21, 2024
  10. added a commit that references this issue on Mar 4, 2024
  11. added a commit that references this issue on Apr 17, 2024
  12. added a commit that references this issue on May 7, 2024
  13. added a commit that references this issue on May 8, 2024
  14. tarunsagarpandey commented on Jun 4, 2024

    @tarunsagarpandey

    Traceback (most recent call last):
    File "/usr/bin/weevely", line 104, in
    arguments = parser.parse_args()
    ^^^^^^^^^^^^^^^^^^^
    File "/usr/lib/python3.11/argparse.py", line 1886, in parse_args
    args, argv = self.parse_known_args(args, namespace)
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    File "/usr/lib/python3.11/argparse.py", line 1919, in parse_known_args
    namespace, args = self._parse_known_args(args, namespace)
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    File "/usr/lib/python3.11/argparse.py", line 2143, in _parse_known_args
    stop_index = consume_positionals(start_index)
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    File "/usr/lib/python3.11/argparse.py", line 2099, in consume_positionals
    take_action(action, args)
    File "/usr/lib/python3.11/argparse.py", line 1995, in take_action
    action(self, namespace, argument_values, option_string)
    File "/usr/lib/python3.11/argparse.py", line 1258, in call
    subnamespace, arg_strings = parser.parse_known_args(arg_strings, None)
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    File "/usr/lib/python3.11/argparse.py", line 1919, in parse_known_args
    namespace, args = self._parse_known_args(args, namespace)
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    File "/usr/lib/python3.11/argparse.py", line 2168, in parse_known_args
    self.error(
    ('the following arguments are required: %s') %
    File "/usr/share/weevely/core/argparsers.py", line 56, in error
    raise ArgparseError(message)
    core.weexceptions.ArgparseError: the following arguments are required: url, password

    How to fix this problem ??

  15. added a commit that references this issue on Jan 22, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    stdlibStandard Library Python modules in the Lib/ directorytype-bugAn unexpected behavior, bug, or error

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions