python – Argparse: Way to include default values in ‘–help’?

The Question :

333 people think this question is useful

Suppose I have the following argparse snippet:

diags.cmdln_parser.add_argument( '--scan-time',
                     action  = 'store',
                     nargs   = '?',
                     type    = int,
                     default = 5,
                     help    = "Wait SCAN-TIME seconds between status checks.")

Currently, --help returns:

usage: connection_check.py [-h]
                             [--version] [--scan-time [SCAN_TIME]]

          Test the reliability/uptime of a connection.



optional arguments:
-h, --help            show this help message and exit
--version             show program's version number and exit
--scan-time [SCAN_TIME]
                    Wait SCAN-TIME seconds between status checks.

I would prefer something like:

--scan-time [SCAN_TIME]
                    Wait SCAN-TIME seconds between status checks.
                    (Default = 5)

Peeking at the help formatter code revealed limited options. Is there a clever way to get argparse to print the default value for --scan-time in a similar fashion, or should I just subclass the help formatter?

The Question Comments :
  • You may be interested in docopt. I’ve never looked at argparse again.
  • @PauloScardine – Being built in to the language is a major benefit for argparse.
  • @PauloScardine: Pulling a non-standard library into my current project will indeed be a pain, but I sure like the look of docopt’s output. Thanks for the tip!
  • @JS. you say “Pulling a non-standard library into my current project will indeed be a pain” Really? There are plenty of very useful libraries at pypi. In my context it is easy to pull in a non-standard library. It is sad, if it is hard in your context.
  • @guettli: That project was for a commercial embedded project. You’re right installation was easy. Getting approval from corporate legal was a nightmare.

The Answer 1

483 people think this answer is useful

Use the argparse.ArgumentDefaultsHelpFormatter formatter:

parser = argparse.ArgumentParser(
    # ... other options ...
    formatter_class=argparse.ArgumentDefaultsHelpFormatter)

To quote the documentation:

The other formatter class available, ArgumentDefaultsHelpFormatter, will add information about the default value of each of the arguments.

Note that this only applies to arguments that have help text defined; with no help value for an argument, there is no help message to add information about the default value to.

The exact output for your scan-time option then becomes:

  --scan-time [SCAN_TIME]
                        Wait SCAN-TIME seconds between status checks.
                        (default: 5)

The Answer 2

213 people think this answer is useful

Add '%(default)s' to the help parameter to control what is displayed.

parser.add_argument("--type", default="toto", choices=["toto","titi"],
                              help = "type (default: %(default)s)")

The Answer 3

11 people think this answer is useful

Wrapper class

This is the most reliable and DRY approach I’ve found so far to both show defaults and use another formatter such as argparse.RawTextHelpFormatter at the same time:

#!/usr/bin/env python3

import argparse

class ArgumentParserWithDefaults(argparse.ArgumentParser):
    def add_argument(self, *args, help=None, default=None, **kwargs):
        if help is not None:
            kwargs['help'] = help
        if default is not None and args[0] != '-h':
            kwargs['default'] = default
            if help is not None:
                kwargs['help'] += ' Default: {}'.format(default)
        super().add_argument(*args, **kwargs)

parser = ArgumentParserWithDefaults(
    formatter_class=argparse.RawTextHelpFormatter
)
parser.add_argument('-a', default=13, help='''my help
for a''')
parser.add_argument('-b', default=42, help='''my help
for b''')
parser.add_argument('--no-default', help='''my help
for no-default''')
parser.add_argument('--no-help', default=101)

parser.print_help()
print()
print(parser.parse_args())

Output:

usage: main.py [-h] [-a A] [-b B] [--no-default NO_DEFAULT]
               [--no-help NO_HELP]

optional arguments:
  -h, --help            show this help message and exit
  -a A                  my help
                        for a Default: 13
  -b B                  my help
                        for b Default: 42
  --no-default NO_DEFAULT
                        my help
                        for no-default
  --no-help NO_HELP

Namespace(a=13, b=42, no_default=None, no_help=101)

ArgumentDefaultsHelpFormatter + RawTextHelpFormatter multiple inheritance

Multiple inheritance just works, but it does not seem to be public API:

#!/usr/bin/env python3

import argparse

class RawTextArgumentDefaultsHelpFormatter(
        argparse.ArgumentDefaultsHelpFormatter,
        argparse.RawTextHelpFormatter
    ):
        pass

parser = argparse.ArgumentParser(
    formatter_class=RawTextArgumentDefaultsHelpFormatter
)
parser.add_argument('-a', default=13, help='''my help
for a''')
parser.add_argument('-b', default=42, help='''my help
for b''')
parser.print_help()

Output:

usage: a.py [-h] [-a A] [-b B]

optional arguments:
  -h, --help  show this help message and exit
  -a A        my help
              for a (default: 13)
  -b B        my help
              for b (default: 42)

It just works works because as we can see trivially from the sources https://github.com/python/cpython/blob/v3.6.5/Lib/argparse.py#L648 that:

  • RawTextHelpFormatter implements _split_lines
  • ArgumentDefaultsHelpFormatter implements _get_help_string

so we can guess that they will work together just fine.

However, this does not seem to be public API, and neither are the methods of formatter_class, so I don’t think there is a public API way to do it currently. argparse docstring says:

All other classes in this module are considered implementation details. (Also note that HelpFormatter and RawDescriptionHelpFormatter are only considered public as object names — the API of the formatter objects is still considered an implementation detail.)

See also: Customize argparse help message

Tested on Python 3.6.5.

Add a Comment