Skip to content

argparse AssertionError with add_mutually_exclusive_group and help=SUPPRESS #66559

Closed

Description

@mZarjk
mannequin
BPO 22363
Nosy @vadmium
Superseder
  • bpo-17890: argparse: mutually exclusive groups full of help-suppressed args can cause AssertionErrors
  • Files
  • bug.py: Minimal program to reproduce bug.
  • bugfix.patch: Patch for the bug
  • 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 = <Date 2016-01-29.03:30:00.386>
    created_at = <Date 2014-09-08.11:46:27.076>
    labels = ['type-bug']
    title = 'argparse AssertionError with add_mutually_exclusive_group and help=SUPPRESS'
    updated_at = <Date 2016-01-29.03:30:00.384>
    user = 'https://bugs.python.org/mZarjk'

    bugs.python.org fields:

    activity = <Date 2016-01-29.03:30:00.384>
    actor = 'martin.panter'
    assignee = 'none'
    closed = True
    closed_date = <Date 2016-01-29.03:30:00.386>
    closer = 'martin.panter'
    components = []
    creation = <Date 2014-09-08.11:46:27.076>
    creator = 'mZarjk'
    dependencies = []
    files = ['36572', '36579']
    hgrepos = []
    issue_num = 22363
    keywords = ['patch']
    message_count = 5.0
    messages = ['226572', '226618', '226624', '226627', '259188']
    nosy_count = 4.0
    nosy_names = ['bethard', 'martin.panter', 'paul.j3', 'mZarjk']
    pr_nums = []
    priority = 'normal'
    resolution = 'duplicate'
    stage = 'patch review'
    status = 'closed'
    superseder = '17890'
    type = 'behavior'
    url = 'https://bugs.python.org/issue22363'
    versions = ['Python 3.1', 'Python 2.7', 'Python 3.2', 'Python 3.3', 'Python 3.4', 'Python 3.5']

    Activity

    1. mZarjk commented on Sep 8, 2014

      mZarjkmannequin
      MannequinAuthor

      Executing the attached script causes an AssertionError.

      Traceback (most recent call last):
        File "bug.py", line 18, in <module>
          parser.format_usage()
        File "/usr/lib/python3.4/argparse.py", line 2318, in format_usage
          return formatter.format_help()
        File "/usr/lib/python3.4/argparse.py", line 287, in format_help
          help = self._root_section.format_help()
        File "/usr/lib/python3.4/argparse.py", line 217, in format_help
          func(*args)
        File "/usr/lib/python3.4/argparse.py", line 338, in _format_usage
          assert ' '.join(opt_parts) == opt_usage
      AssertionError

      The script was tested in a clean Python installation.

      If any of the arguments are removed, there is no AssertionError exception.
      If "help=SUPPRESS" is removed, there is no AssertionError exception.

      This bug appears to have existed since Python 3.2, the first version that included argparse.

    2. added
      type-bugAn unexpected behavior, bug, or error
      on Sep 8, 2014
    3. mZarjk commented on Sep 9, 2014

      mZarjkmannequin
      MannequinAuthor

      This assert statement is only reached when the usage line is long enough that it needs to be wrapped. Which is why the assertion does not happen when an argument is removed.

      opt_usage is being compared to this string:
      "[-h] [--arg2 ARG2] [--arg3 ARG3] [--arg4 ARG4] [--arg5 ARG5] [--arg6 ARG6]"

      opt_usage in this case has the value:
      "[-h] [--arg2 ARG2] [--arg3 ARG3] [--arg4 ARG4] [--arg5 ARG5] [--arg6 ARG6]"

      There is an extra space after "[-h]". The value of opt_usage comes from _format_actions_usage. And that is where the bug is.

      Just before _format_actions_usage returns, the usage string is:
      "[-h] [ ] [--arg2 ARG2] [--arg3 ARG3] [--arg4 ARG4] [--arg5 ARG5] [--arg6 ARG6]"

      The method uses this regexp:
      "[ *]"

      To remove the extra brackets. But that leaves the extra space after the brackets.

      The attached patch changes the regexp to:
      "[ *] ?"

      So that the extra space is also removed.

      The patch also adds a testcase based on the script that reproduces the

    4. paulj3 commented on Sep 9, 2014

      paulj3mannequin
      Mannequin

      This assertion has triggered several bug issues, either due to an empty group like this, or certain characters in the metavars.

      http://bugs.python.org/issue17890
      'argparse: mutually exclusive groups full of suppressed args can cause AssertionErrors'

      http://bugs.python.org/issue11874
      'argparse assertion failure with brackets in metavars'

      http://bugs.python.org/issue16360
      'argparse: comma in metavar causes assertion failure when formatting long usage message'

      I think this is a duplicate of 17890, though I'll have to look more closely at your patch to see what it adds.

      For 11874 I proposed a major rewrite of the usage formatting. There I format each group and/or action separately, and keep the pieces in a list. That way it's easier to filter out empty pieces, and avoids the complex split that gives headaches when the usage is long enough to wrap.

    5. mZarjk commented on Sep 9, 2014

      mZarjkmannequin
      MannequinAuthor

      I've confirmed that this is a duplicate of bpo-17890.

      In case anyone needs it, a workaround is to move the mutually exclusive group to the end of the arguments.

    6. vadmium commented on Jan 29, 2016

      @vadmium
      Member

      I left one review comment, but it seems there is more discussion at bpo-17890, which also originally proposed a very similar fix.

    7. transferred this issue fromon Apr 10, 2022
    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

      type-bugAn unexpected behavior, bug, or error

      Projects

      No projects

        Milestone

        No milestone

        Relationships

        None yet

        Development

        No branches or pull requests

        Issue actions