0

I got a script with a list of arguments defined with argparse. Because I want to have bullet points and line breaks in the help text, I added a custom formatter. That works like a charm but the problem now is that the default 'usage' text in the help, now shows the formatter object:

usage: <__main__.MyFormatter object at 0x7f30cc163c70> [-h] {list,add,remove} ...

If I remove the custom formatter, then the 'usage' is as expected:

usage: test.py [-h] {list,add,remove} ...

And I can't understand why and how to fix it.

Here's a stripped down version of my script (test.py):

import argparse
class MyFormatter(argparse.ArgumentDefaultsHelpFormatter):
    def __init__(self,
            prog,
            indent_increment=2,
            max_help_position=30,
            width=None):
        super().__init__(self,
                        indent_increment=indent_increment,
                        max_help_position=max_help_position,
                        width=width)
    def _split_lines(self, text, width):
        """
        If the text starts with 'S|', remove the prefix, split the text into lines at the new line '\n'
        and maintain spaces. Otherwise, uses the default splitting behavior of ArgumentDefaultsHelpFormatter.
        """
        if text.startswith('S|'):
            text = text[2:].strip().splitlines()
            import textwrap
            out = []
            for line in text:
                out.extend(textwrap.wrap(line, width))
            return out
        return argparse.ArgumentDefaultsHelpFormatter._split_lines(self, text, width)

parser = argparse.ArgumentParser(description="This script will do a bunch of stuff",
                                formatter_class=MyFormatter)
parser.set_defaults(func=lambda args: parser.print_help())
subparsers = parser.add_subparsers()

parser_list = subparsers.add_parser("list", help="Show a list of things", formatter_class=MyFormatter)

parser_add = subparsers.add_parser("add", help="Add item to the list", formatter_class=MyFormatter)
parser_add.add_argument("item", type=str, help="Item to add to the list")

parser_remove = subparsers.add_parser("remove", help="Remove item from the list", formatter_class=MyFormatter)
parser_remove.add_argument("item", type=str, help="Item to remove from the list")

args = parser.parse_args()

I know I can add my own usage message with the 'usage=' argument, but I'm more trying to understand why using the custom formatter breaks the usage text?

PS. using Python 3.12

2
  • 3
    You passed self instead of prog to the superclass constructor. Commented Mar 13 at 23:26
  • Holy ****! You are right! I completely missed that! Thank you, it was driving me crazy! Commented Mar 14 at 6:17

1 Answer 1

0

As mentioned, you passed self in place of prog. There are two fixes:

  1. Replace self with prog
    def __init__(self, prog, indent_increment=2, max_help_position=30, width=None):
        super().__init__(
            prog,
            indent_increment=indent_increment,
            max_help_position=max_help_position,
            width=width,
        )
  1. Since the __init__ function does not add customization, go ahead and delete it.
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.