Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

argparse help formatter raises IndexError #71139

Closed
Endre mannequin opened this issue May 4, 2016 · 13 comments
Closed

argparse help formatter raises IndexError #71139

Endre mannequin opened this issue May 4, 2016 · 13 comments
Labels
3.9 only security fixes 3.10 only security fixes 3.11 only security fixes stdlib Python modules in the Lib dir type-bug An unexpected behavior, bug, or error

Comments

@Endre
Copy link
Mannequin

Endre mannequin commented May 4, 2016

BPO 26952
Nosy @berkerpeksag, @zhangyangyu, @miss-islington, @iritkatriel
PRs
  • bpo-26952: [argparse] clearer error when formatting an empty mutually… #30099
  • [3.10] bpo-26952: [argparse] clearer error when formatting an empty mutually… (GH-30099) #30114
  • [3.9] bpo-26952: [argparse] clearer error when formatting an empty mutually… (GH-30099) #30115
  • 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 2021-12-15.12:25:22.995>
    created_at = <Date 2016-05-04.15:14:47.647>
    labels = ['type-bug', 'library', '3.9', '3.10', '3.11']
    title = 'argparse help formatter raises IndexError'
    updated_at = <Date 2021-12-15.12:25:22.994>
    user = 'https://bugs.python.org/Endre'

    bugs.python.org fields:

    activity = <Date 2021-12-15.12:25:22.994>
    actor = 'iritkatriel'
    assignee = 'none'
    closed = True
    closed_date = <Date 2021-12-15.12:25:22.995>
    closer = 'iritkatriel'
    components = ['Library (Lib)']
    creation = <Date 2016-05-04.15:14:47.647>
    creator = 'Endre'
    dependencies = []
    files = []
    hgrepos = []
    issue_num = 26952
    keywords = ['patch']
    message_count = 13.0
    messages = ['264823', '264834', '264835', '264837', '264839', '265164', '326127', '326129', '347469', '347477', '408592', '408597', '408598']
    nosy_count = 8.0
    nosy_names = ['bethard', 'berker.peksag', 'paul.j3', 'xiang.zhang', 'Endre', 'miss-islington', 'kapsh', 'iritkatriel']
    pr_nums = ['30099', '30114', '30115']
    priority = 'normal'
    resolution = 'fixed'
    stage = 'resolved'
    status = 'closed'
    superseder = None
    type = 'behavior'
    url = 'https://bugs.python.org/issue26952'
    versions = ['Python 3.9', 'Python 3.10', 'Python 3.11']

    @Endre
    Copy link
    Mannequin Author

    Endre mannequin commented May 4, 2016

    I am using argparse-1.4.0.

    For this code exception is thrown when the script is started with the -h option:
    http://pastebin.com/dFF1paFA

    This exception is thrown:
    Traceback (most recent call last):
      File "C:\Users\ebak\Picea\tools\buildsystem\python\kw_set_checkers.py", line 129, in <module>
        args = parser.parse_args()
      File "C:\Python27\lib\argparse.py", line 1688, in parse_args
        args, argv = self.parse_known_args(args, namespace)
      File "C:\Python27\lib\argparse.py", line 1720, in parse_known_args
        namespace, args = self._parse_known_args(args, namespace)
      File "C:\Python27\lib\argparse.py", line 1926, in _parse_known_args
        start_index = consume_optional(start_index)
      File "C:\Python27\lib\argparse.py", line 1866, in consume_optional
        take_action(action, args, option_string)
      File "C:\Python27\lib\argparse.py", line 1794, in take_action
        action(self, namespace, argument_values, option_string)
      File "C:\Python27\lib\argparse.py", line 994, in __call__
        parser.print_help()
      File "C:\Python27\lib\argparse.py", line 2327, in print_help
        self._print_message(self.format_help(), file)
      File "C:\Python27\lib\argparse.py", line 2301, in format_help
        return formatter.format_help()
      File "C:\Python27\lib\argparse.py", line 279, in format_help
        help = self._root_section.format_help()
      File "C:\Python27\lib\argparse.py", line 209, in format_help
        func(*args)
      File "C:\Python27\lib\argparse.py", line 317, in _format_usage
        action_usage = format(optionals + positionals, groups)
      File "C:\Python27\lib\argparse.py", line 388, in _format_actions_usage
        start = actions.index(group._group_actions[0])
    IndexError: list index out of range

    @Endre Endre mannequin added type-crash A hard crash of the interpreter, possibly with a core dump stdlib Python modules in the Lib dir labels May 4, 2016
    @berkerpeksag
    Copy link
    Member

    I don't think add_mutually_exclusive_group and add_argument_group are designed to work together. Did this worked with argparse 1.3.0 or stdlib version of argparse before? I'm getting the same traceback in 2.7 and 3.4+.

    @zhangyangyu
    Copy link
    Member

    This error occurs due to there is no action belong to the mutexGroup, the code requires at least one. You can simply add

        mutexGroup.add_argument('--foo', action='store_true')

    and you'll see the error disappears. I have no idea that this behaviour is intended or not.

    @zhangyangyu
    Copy link
    Member

    I agree with Berker. Even without any exceptions, the help message given is not what add_argument_group and add_mutually_exclusive_group intend.

    You can see

    usage: argparse_test.py [-h] [--foo] -u URL -p PROJECT [--dump] --mergeInput
    MERGEINPUT [--removeDisabled] -c CHECKERS

    Sets the checkers of a klocwork project

    optional arguments:
    -h, --help show this help message and exit
    --foo
    -c CHECKERS, --checkers CHECKERS
    File which lists the checkers to be enabled.

    There is not group name and still optional arguments. And the command line does not show exclusive. I believe they are not designed to work like this.

    @Endre
    Copy link
    Mannequin Author

    Endre mannequin commented May 4, 2016

    Hi,

    Thanks for taking a look at it.
    I have only tried it with argparse-1.4.0.

    "I don't think add_mutually_exclusive_group and add_argument_group are designed to work together."

    Yes, it really works strange in this case. I guess the framework should raise an exception which states that this use case is not supported, e.g. at the "serverGroup = mutexGroup.add_argument_group('serverGroup')
    " line.

    @paulj3
    Copy link
    Mannequin

    paulj3 mannequin commented May 8, 2016

    Argument Groups are not designed for nesting, and despite their names and subclassing, Mutually exclusive groups and Argument Groups are not meant to be used together (with one exception).

    I agree that the error is obscure, but it occurs in a particularly fragile function in the formatter, '_format_actions_usage'. That function needs a major rewrite (that's in another bug/issue).

    Argument Groups serve only as a way of grouping help lines. Mutually exclusive groups test arguments during parsing, and add some markings to the usage line. So they have very different purposes.

    I have seen questions on Stackoverflow where people try to use Argument Groups as a way of adding some sort of subgroup to the Mutually Exclusive one, one for example that implements a 'allow any of this group' logic. There is a bug/issue asking for 'inclusive' nesting groups, but production patch of that sort is long ways off. http://bugs.python.org/issue11588

    This usage line

    (--url URL --project Prj [--dump]) | (--mergeInput input.txt [--removeDisabled])
    

    suggests that this what you are trying do - allow any of -u,-p,-d, but disallow one of these with -m or -r. That logic is beyond the current group testing mechanism, and beyond the usage formatting code. You'll have to do your own tests, and write a custom usage line.

    Mutually exclusive groups can be nested in other mutual groups, but the effect isn't what you might hope. It just forms a larger mutually exclusive group; there's no subgrouping.

    It is possible to nest a mutually exclusive group in an Argument group; the effect is to give the mutually exclusive group a title.

    @serhiy-storchaka serhiy-storchaka added type-bug An unexpected behavior, bug, or error and removed type-crash A hard crash of the interpreter, possibly with a core dump labels Jul 11, 2018
    @paulj3
    Copy link
    Mannequin

    paulj3 mannequin commented Sep 23, 2018

    If I add an argument to the mutexGroup as suggested by xiang

    In [7]: mutexGroup.add_argument('--foo', action='store_true')
    Out[7]: _StoreTrueAction(option_strings=['--foo'], dest='foo', nargs=0, const=True, default=False, type=None, choices=None, help=None, metavar=None)
    In [8]: parser.print_usage()
    usage: ipython3 [-h] -u URL -p PROJECT [--dump] --mergeInput MERGEINPUT
    [--removeDisabled] -c CHECKERS --foo
    In [9]: parser.print_help()
    usage: ipython3 [-h] -u URL -p PROJECT [--dump] --mergeInput MERGEINPUT
    [--removeDisabled] -c CHECKERS --foo

    Sets the checkers of a klocwork project

    optional arguments:
    -h, --help show this help message and exit
    -c CHECKERS, --checkers CHECKERS
    File which lists the checkers to be enabled.

    the argument_group arguments show up in the usage, but without mutually_exclusive markings. But they don't show up in the help lines. I suspect all those group arguments will be tested as one mutually exclusive group, not two subgroups.

    If I put the argument groups in the main parser, and omit the mutually_exclusive group I get this help:

    In [11]: parser.print_help()
    usage: ipython3 [-h] -u URL -p PROJECT [--dump] --mergeInput MERGEINPUT
    [--removeDisabled] -c CHECKERS

    Sets the checkers of a klocwork project

    optional arguments:
    -h, --help show this help message and exit
    -c CHECKERS, --checkers CHECKERS
    File which lists the checkers to be enabled.

    serverGroup:
    -u URL, --url URL klocwork server URL.
    -p PROJECT, --project PROJECT
    klocwork project name.
    --dump Dump the current checkers config.

    mergeGroup:
    --mergeInput MERGEINPUT
    Input file to merge for the '--checkers' file. Format:
    checkerName Enabled|Disabled
    --removeDisabled Disabled checkers will be removed from the '--
    checkers' file.

    The argument groups appear as intended in the help lines.

    add_argument_group is inherited from _ActionsContainer. The parser ArgumentParser also inherits this method. A possible fix is to override this method in the _MutuallyExclusiveGroup class to raise some sort of not-implemented error.

    The documentation, as written, does not suggest or hint that an argument_group can be added to anything but a parser. But a stronger disclaimer could be added.

    @paulj3
    Copy link
    Mannequin

    paulj3 mannequin commented Sep 23, 2018

    https://bugs.python.org/issue29553 deals with a similar problem, the usage display when one mutually exclusive group is embedded in another mutually exclusive group. In that case, usage is displayed, but with some missing brackets.

    As here there are two issues - the usage formatter is brittle, and groups are not designed for nesting.

    @kapsh
    Copy link
    Mannequin

    kapsh mannequin commented Jul 7, 2019

    I have a feeling that nesting groups has nothing to do with it. Got same traceback when I forgot to fill my mutually exclusive groups with arguments.

    import argparse
    
    parser = argparse.ArgumentParser()
    group = parser.add_mutually_exclusive_group()
    parser.parse_args(['-h'])

    # Result:

    Traceback (most recent call last):
      File "/home/kapsh/.PyCharmCE2019.1/config/scratches/scratch_12.py", line 5, in <module>
        parser.parse_args(['-h'])
      File "/usr/lib/python3.7/argparse.py", line 1749, in parse_args
        args, argv = self.parse_known_args(args, namespace)
      File "/usr/lib/python3.7/argparse.py", line 1781, in parse_known_args
        namespace, args = self._parse_known_args(args, namespace)
      File "/usr/lib/python3.7/argparse.py", line 1987, in _parse_known_args
        start_index = consume_optional(start_index)
      File "/usr/lib/python3.7/argparse.py", line 1927, in consume_optional
        take_action(action, args, option_string)
      File "/usr/lib/python3.7/argparse.py", line 1855, in take_action
        action(self, namespace, argument_values, option_string)
      File "/usr/lib/python3.7/argparse.py", line 1037, in __call__
        parser.print_help()
      File "/usr/lib/python3.7/argparse.py", line 2474, in print_help
        self._print_message(self.format_help(), file)
      File "/usr/lib/python3.7/argparse.py", line 2458, in format_help
        return formatter.format_help()
      File "/usr/lib/python3.7/argparse.py", line 284, in format_help
        help = self._root_section.format_help()
      File "/usr/lib/python3.7/argparse.py", line 215, in format_help
        item_help = join([func(*args) for func, args in self.items])
      File "/usr/lib/python3.7/argparse.py", line 215, in <listcomp>
        item_help = join([func(*args) for func, args in self.items])
      File "/usr/lib/python3.7/argparse.py", line 322, in _format_usage
        action_usage = format(optionals + positionals, groups)
      File "/usr/lib/python3.7/argparse.py", line 397, in _format_actions_usage
        start = actions.index(group._group_actions[0])
    IndexError: list index out of range

    @paulj3
    Copy link
    Mannequin

    paulj3 mannequin commented Jul 7, 2019

    Xiang Zhang pointed out that the immediate error in this case was caused by the empty mutually exclusive group:

    https://bugs.python.org/issue26952#msg264835

    The nesting fails because adding actions to the argument_group does not enroll them in the mutually exclusive group. So the group._group_actions list remains empty, just as it is in your case.

    As I pointed out earlier, the usage formatter is brittle. The addition of mutually exclusive group markings is particularly clunky.

    @iritkatriel iritkatriel added 3.9 only security fixes 3.10 only security fixes 3.11 only security fixes labels May 28, 2021
    @iritkatriel iritkatriel changed the title argparse help formatter crashes argparse help formatter raises IndexError May 28, 2021
    @iritkatriel
    Copy link
    Member

    New changeset 86de995 by Irit Katriel in branch 'main':
    bpo-26952: [argparse] clearer error when formatting an empty mutually… (GH-30099)
    86de995

    @iritkatriel
    Copy link
    Member

    New changeset 8e4c962 by Miss Islington (bot) in branch '3.10':
    bpo-26952: [argparse] clearer error when formatting an empty mutually… (GH-30099) (GH-30114)
    8e4c962

    @iritkatriel
    Copy link
    Member

    New changeset f0b274d by Miss Islington (bot) in branch '3.9':
    bpo-26952: [argparse] clearer error when formatting an empty mutually… (GH-30099) (GH-30115)
    f0b274d

    @ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    3.9 only security fixes 3.10 only security fixes 3.11 only security fixes stdlib Python modules in the Lib dir type-bug An unexpected behavior, bug, or error
    Projects
    None yet
    Development

    No branches or pull requests

    4 participants