Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python argparse: Insert blank line between help entries

When using argparse, passing --help to the program generates help text. Unfortunately, it's hard to read because there are no blank lines between options. Here's an excerpt to illustrate:

optional arguments:
  -h, --help            show this help message and exit
  -u FILENAME, --up-sound FILENAME
                        The sound to play when the network comes up. Default:
                        "/path/to/some/sound/file.wav"
  -d FILENAME, --down-sound FILENAME
                        The sound to play when the network goes down. Default:
                        "/path/to/some/other/sound/file.wav"
  -p EXECUTABLE, --player EXECUTABLE
                        The program to use to play sounds. Default: "play"
  -s, --silent          If specified, network_monitor.py will not play any
                        sounds.
  -c, --no-clear-screen
                        If specified, screen will not be cleared (nor extra
                        blank lines added) before network_monitor.py runs.
  --version             show program's version number and exit

Notice that in some cases, such as between -p and -s or between -c and --version, it is difficult to tell at a glance which help text applies to which option. There should be a blank line between entries. For example:

  -p EXECUTABLE, --player EXECUTABLE
                        The program to use to play sounds. Default: "play"

  -s, --silent          If specified, network_monitor.py will not play any
                        sounds.

How can I accomplish this? Several other questions recommend using argparse.RawTextHelpFormatter. The problem with that is that if I use it, I have to write my own logic to wrap the help text as the raw text help formatter does no formatting. The obvious answer would be to append '\n\n' to the end of the help text and use the default formatter. But inexplicably, newlines get stripped.

What's the way forward here? I'm using Python 3.4.

like image 786
Scott Severance Avatar asked Apr 07 '15 05:04

Scott Severance


People also ask

How do you add an optional argument in Argparse?

Optional arguments are useful if you want to give the user a choice to enable certain features. To add an optional argument, simply omit the required parameter in add_argument() . args = parser. parse_args()if args.


2 Answers

poke's approach is good. Note that RawTextHelpFormatter also modifies this method, simplifying it to:

def _split_lines(self, text, width):
    return text.splitlines()

poke's method could be tweaked to give you more control

class BlankLinesHelpFormatter (argparse.HelpFormatter):
    # add empty line if help ends with \n
    def _split_lines(self, text, width):
        lines = super()._split_lines(text, width)
        if text.endswith('\n'):
            lines += ['']
        return lines

With this:

parser = argparse.ArgumentParser(description='A description',
    formatter_class=BlankLinesHelpFormatter,
    epilog='Epilog line',
    )
parser.add_argument('-u', '--up-sound', metavar='FILENAME',
    help='The sound to play when the network comes up. Default:"%(default)s"\n',
    default="/path/to/some/sound/file.wav")
# note \n in above help
parser.add_argument('-d', '--down-sound', metavar='FILENAME',
    help='The sound to play when the network goes down. Default:"%(default)s"',
    default="/path/to/some/other/sound/file.wav")
parser.add_argument('-s','--silent', action='store_true',
    help='If specified, network_monitor.py will not play any sounds.')
parser.add_argument('positional', nargs='*', help='positional argument')
parser.print_help()

displays:

usage: stack29484443.py [-h] [-u FILENAME] [-d FILENAME] [-s]
                        [positional [positional ...]]

A description

positional arguments:
  positional            positional argument

optional arguments:
  -h, --help            show this help message and exit
  -u FILENAME, --up-sound FILENAME
                        The sound to play when the network comes up.
                        Default:"/path/to/some/sound/file.wav"

  -d FILENAME, --down-sound FILENAME
                        The sound to play when the network goes down.
                        Default:"/path/to/some/other/sound/file.wav"
  -s, --silent          If specified, network_monitor.py will not play any
                        sounds.

Epilog line

For reference, the default _split_lines is:

def _split_lines(self, text, width):
    text = self._whitespace_matcher.sub(' ', text).strip()
    return _textwrap.wrap(text, width)
    # self._whitespace_matcher = _re.compile(r'\s+')

This removes final \n and reduces all interior whitespace to one blank.

like image 80
hpaulj Avatar answered Oct 21 '22 15:10

hpaulj


You can create your own help text formatter that does this. Note that this requires you to be very specific to the implementation detail of the argparse.HelpFormatter. So consider this warning that is included in every help formatter type description:

Only the name of this class is considered a public API. All the methods provided by the class are considered an implementation detail.

Once we ignore that, creating our own help formatter that adds a blank line between the entries is very simple:

class BlankLinesHelpFormatter (argparse.HelpFormatter):
    def _split_lines(self, text, width):
        return super()._split_lines(text, width) + ['']

And that’s it. Now when you create the ArgumentParser object while passing formatter_class=BlankLinesHelpFormatter to the constructor, blank lines will appear between each argument in the help text.

like image 24
poke Avatar answered Oct 21 '22 15:10

poke