Title: max_help_position is not works in argparse library
Type: Stage:
Components: Library (Lib) Versions: Python 2.7
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: morden2k, paul.j3
Priority: normal Keywords:

Created on 2015-10-02 08:55 by morden2k, last changed 2015-10-03 21:30 by paul.j3.

File name Uploaded Description Edit paul.j3, 2015-10-02 21:27
Messages (5)
msg252093 - (view) Author: Alexander (morden2k) Date: 2015-10-02 08:55
Hi colleagues I have the code (max_help_position is 2000):

formatter_class=lambda prog: argparse.HelpFormatter(prog, max_help_position=2000)
parser = argparse.ArgumentParser(formatter_class=formatter_class)

subparsers = parser.add_subparsers(title="Commands", metavar="<command>")

cmd_parser = subparsers.add_parser('long_long_long_long_long_long_long',
                                   help='- jksljdalkjda',

args = parser.parse_args(['-h'])
print args


we have

optional arguments:
  -h, --help                          show this help message and exit

                                      - jksljdalkjda
    small                             - descr


optional arguments:
  -h, --help  show this help message and exit

    long_long_long_long_long_long_long - jksljdalkjda
    small                              - descr

The code:

class MyFormatter(argparse.HelpFormatter):
    def __init__(self, prog):
        super(MyFormatter, self).__init__(prog, max_help_position=2000, width=2000)
        self._max_help_position = 2000
        self._action_max_length += 4

got same result.

The strings like:

formatter_class = lambda prog: argparse.HelpFormatter(prog,
                  max_help_position=2000, width=2000)

formatter_class = lambda prog: argparse.HelpFormatter(prog,
                  max_help_position=1000, width=2000)

formatter_class = lambda prog: argparse.HelpFormatter(prog,
                  max_help_position=2000, width=1000)

got same result: we always have new line after command.
msg252095 - (view) Author: Alexander (morden2k) Date: 2015-10-02 09:03
Problem also described on
msg252144 - (view) Author: paul j3 (paul.j3) * (Python triager) Date: 2015-10-02 16:40
My testing shows that it's a problem with the subparsers listing.  When regular arguments are long, 'max_help_position' works (within limits allowed by 'width').
msg252164 - (view) Author: paul j3 (paul.j3) * (Python triager) Date: 2015-10-02 21:27
There's a bug in the HelpFormatter.add_argument method.  It does not take into account the extra indentation of subactions (sub parsers) when calculating self._action_max_length.

The corrected method and a test case is in the attached file.

class MyFormatter(argparse.HelpFormatter):
    Corrected _max_action_length for the indenting of subactions
    def add_argument(self, action):
        if is not argparse.SUPPRESS:

            # find all invocations
            get_invocation = self._format_action_invocation
            invocations = [get_invocation(action)]
            current_indent = self._current_indent
            for subaction in self._iter_indented_subactions(action):
                # compensate for the indent that will be added
                indent_chg = self._current_indent - current_indent
                added_indent = 'x'*indent_chg
                invocations.append(added_indent + get_invocation( subaction) )
            # print('inv', invocations)

            # update the maximum item length
            invocation_length = max([len(s) for s in invocations])
            action_length = invocation_length + self._current_indent
            self._action_max_length = max(self._action_max_length,

            # add the item to the list
            self._add_item(self._format_action, [action])

Without this correction self._action_max_length is off by 2 if a subparser has the longest invocation.  Normally that wouldn't be an issue since normally subparser names are short and easy to use.  But with the 'aliases' that newer argparse allows, the invocation could be longer, and possibly longer than regular arguments.

I haven't passed this correction through  It also would need a test case or two.  I don't think it need a documentation change.

I don't know if this correction will work with the subparser grouping proposed in
msg252242 - (view) Author: paul j3 (paul.j3) * (Python triager) Date: 2015-10-03 21:30
The unittest has one related test

class TestAddSubparsers
   def test_alias_help

has a long enough subparser invocation (with aliases) to produce wrapping with the default 24 max position:

                1 (1alias1, 1alias2)
                                    1 help
                2                   2 help

I don't see anything in the test file that tries to vary the max_help_position parameter.
Date User Action Args
2015-10-03 21:30:55paul.j3setmessages: + msg252242
2015-10-02 21:27:09paul.j3setfiles: +

messages: + msg252164
2015-10-02 16:40:17paul.j3setmessages: + msg252144
2015-10-02 15:58:16paul.j3setnosy: + paul.j3
2015-10-02 09:03:33morden2ksetmessages: + msg252095
2015-10-02 08:55:13morden2kcreate