Search code examples
pythonstdoutstdinargparse

Argparse and ArgumentDefaultsHelpFormatter. Formatting of default values when sys.stdin/stdout are selected as default


I am interested in using the ArgumentDefaultsHelpFormatter class formatter of argparse (my program has several sub-commands). By default, the input and output arguments are set to sys.stdin and sys.stdout respectively. However, the formatting for these two arguments may be a little bit confusing for users (e.g (default: ', mode 'r' at 0x10028e0c0>). Is there a way to specifically and easily change the output format for these two arguments to get something like 'default: STDIN' or 'default: STDOUT'?

Thank you

import sys
import argparse

parser = argparse.ArgumentParser(prog='PROG', 
                                 formatter_class=argparse.ArgumentDefaultsHelpFormatter)

parser.add_argument('--infile',
                '-i',
                metavar='File',
                help='The input file/stream.',
                default=sys.stdin,
                type=argparse.FileType('r'),
                required=False)

parser.add_argument('--outfile',
                '-o',
                metavar='File',
                help='The output file/stream.',
                default=sys.stdout,
                type=argparse.FileType('r'),
                required=False)

parser.add_argument('--whatever-arg',
                '-w',
                type=str,
                default='any',
                help='Change something',
                required=False)


args = parser.parse_args()
parser.print_help()

Which gives:

usage: PROG [-h] [--infile File] [--outfile File]
            [--whatever-arg WHATEVER_ARG]

optional arguments:
  -h, --help            show this help message and exit
  --infile File, -i File
                        The input file/stream. (default: <open file '<stdin>',
                        mode 'r' at 0x10028e0c0>)
  --outfile File, -o File
                        The output file/stream. (default: <open file
                        '<stdout>', mode 'w' at 0x10028e150>)
  --whatever-arg WHATEVER_ARG, -w WHATEVER_ARG
                        Change something (default: any)

Solution

  • You can subclass ArgumentDefaultsHelpFormatter to do what you want.

    from argparse import ArgumentDefaultsHelpFormatter,RawDescriptionHelpFormatter
    
    class CustomFormatter(argparse.ArgumentDefaultsHelpFormatter, argparse.RawDescriptionHelpFormatter):
        def _get_help_string(self, action):
            help = action.help
            if '%(default)' not in action.help:
                if action.default is not argparse.SUPPRESS:
                    defaulting_nargs = [argparse.OPTIONAL, argparse.ZERO_OR_MORE]
                    if action.option_strings or action.nargs in defaulting_nargs:
                        if type(action.default) == type(sys.stdin):
                            print action.default.name
                            help += ' (default: ' + str(action.default.name) + ')'
                        else:
                            help += ' (default: %(default)s)'
            return help
    
    parser = argparse.ArgumentParser(prog='PROG', formatter_class=CustomFormatter)
    

    result for me is:

    optional arguments:
      -h, --help            show this help message and exit
      --infile File, -i File
                            The input file/stream. (default: <stdin>)
      --outfile File, -o File
                            The output file/stream. (default: <stdout>)
      --whatever-arg WHATEVER_ARG, -w WHATEVER_ARG
                            Change something (default: any)