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)
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)
If you give default='-'
instead of sys.stdin
, the help display would be
the input file/stream. (default: -)
That is, help shows the default string, but FileType
converts '-'
to stdin/out.
As A.H
shows you can customize the _get_help_string
method. It doesn't matter which class you inherit from, since modifying that method is all that ADHF does:
class ArgumentDefaultsHelpFormatter(HelpFormatter):
"""...
"""
def _get_help_string(self, action):
help = action.help
if '%(default)' not in action.help:
if action.default is not SUPPRESS:
defaulting_nargs = [OPTIONAL, ZERO_OR_MORE]
if action.option_strings or action.nargs in defaulting_nargs:
help += ' (default: %(default)s)'
return help
And note that all this modification does is add a string to the help
parameter - just the (default: %(default)s)
That means you could get a similar effect by adjusting your own help
lines, e.g.
parser.add_argument('--infile',
'-i',
metavar='File',
help='The input file/stream, (default: stdin).',
default='-',
type=argparse.FileType('r'))
parser.add_argument('--whatever-arg',
'-w',
default='any',
help='Change something, (default: %(default)s)')
In other words it saves you typing (default: %(default)s)
for 28 of your arguments.
If you are uncomfortable customizing the HelpFormatter class (though that is what developers recommend - with suitable cautions), you could tweak your own setup. For example, make simple helper function that adds the extra string to each help line:
def foohelp(astr):
return astr + ' (default: %(default)s)'
arg1 = parser.add_argument('-f','--fooarg', help=foohelp('help string'))
Speaking of changing the setup programmatically, it's worth noting that add_argument
creates an Action
object. You can save a link to that, as I did here, and tweak parameters.
arg1 = parser.add_argument('-f','--fooarg', help='help string')
print arg1.help
arg1.help = foohelp(arg1.help) # modify help after creation
print arg1.help
With 30 arguments you probably have done a lot of copy-n-paste to define them, or writen various helper functions to streamline the setup. Adding the default display is just another of those tasks. You can do it during setup, or you can do it via a custom Formatter.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With