Reputation: 76882
When you call add_argument
on an argparse.ArgumentParser()
without an explicit action, you get the "store"
action. In the auto-generated --help
output you get the uppercase of the long option, unless you set metavar
:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--version', metavar='X.Y.Z')
parser.add_argument('--date'),
parser.parse_args(['--help'])
displays:
usage: try.py [-h] [--version X.Y.Z] [--date DATE]
optional arguments:
-h, --help show this help message and exit
--version X.Y.Z
--date DATE
In this I would call X.Y.Z
an explicit metavar, and DATE
an implicit metavar.
If you want to have more useful help you can do:
parser.add_argument('--version', metavar='X.Y.Z',
help = "set version to % (metavar)s")
which gives (only changed lines shown):
--version X.Y.Z set version to X.Y.Z
and being able to use that %(metavar)s
in the help string is nice because when you change metavar='MAJOR.MINOR'
, the help doesn't need to be updated (which you are bound to forget).
But if you add the help for the --date
argument, with the implicit metavar:
parser.add_argument('--date',
help="use %(metavar)s instead of today's date")
you get:
--date DATE use None instead of today
And that None
is not what I expected, nor what I want.
Of course I can always hard-code 'DATE' in the help, or explicitly provide the metavar (especially when it is used in the help string). But when I do that, I am bound to forget to update the metavar when I change the name of the long option.
Is there an "automatic" way to get DATE
in the help string instead of None
?
Or am I using %(metavar)s
where I should be using something else (and if so, what)?
Upvotes: 3
Views: 548
Reputation: 231665
It's not going to be easy, at least not within argparse
.
When you add_argument
it creates an Action
class object, and assigns attributes:
a1 = parser.add_argument('--version', metavar='X.Y.Z')
a2 = parser.add_argument('--date')
a1.metavar
will be 'X.Y.Z'
, a2.metavar
will be the default None
.
That's the value that is used in the help line, something like:
`'help %(metavar)`%{'metavar':action.metavar}'
That action.metavar
attribute can be modified after creating the Action, as demonstrated in the other answer.
But for the usage
and first part of help
it does something like:
def _metavar_formatter(self, action, default_metavar):
if action.metavar is not None:
result = action.metavar
elif action.choices is not None:
choice_strs = [str(choice) for choice in action.choices]
result = '{%s}' % ','.join(choice_strs)
else:
result = default_metavar
...
default_metavar
is different for positionals
and optionals
, but basically is derived from action.dest
. So the displayed metavar
is generated on the fly, and not stored anywhere.
The %(metavar)s
is handled in:
def _expand_help(self, action):
params = dict(vars(action), prog=self._prog)
for name in list(params):
if params[name] is SUPPRESS:
del params[name]
for name in list(params):
if hasattr(params[name], '__name__'):
params[name] = params[name].__name__
if params.get('choices') is not None:
choices_str = ', '.join([str(c) for c in params['choices']])
params['choices'] = choices_str
return self._get_help_string(action) % params
vars(action)
makes a dictionary from all the attributes of the action
.
I can imagine creating a Formatter subclass that modifies one or more of the methods. The existing subclasses work by modifying just one or two low level methods. But to do that requires studying the code.
In [329]: p = argparse.ArgumentParser()
In [330]: a1 = p.add_argument('--version', metavar='X.Y.Z')
In [331]: a1
Out[331]: _StoreAction(option_strings=['--version'], dest='version', nargs=None, const=None, default=None, type=None, choices=None, help=None, metavar='X.Y.Z')
In [332]: vars(a1)
Out[332]:
{'option_strings': ['--version'],
'dest': 'version',
'nargs': None,
'const': None,
'default': None,
'type': None,
'choices': None,
'required': False,
'help': None,
'metavar': 'X.Y.Z',
'container': <argparse._ArgumentGroup at 0x7f72ecc4b4a8>}
A help with several parameters:
In [333]: a1.help='help %(metavar)s, %(dest)s, %(required)s'
In [334]: p.print_help()
usage: ipython3 [-h] [--version X.Y.Z]
optional arguments:
-h, --help show this help message and exit
--version X.Y.Z help X.Y.Z, version, False
Upvotes: 0
Reputation: 76882
One thing you can do before calling parser.parse_args()
is update those actions added to the parser
that have a metavar
attribute that is None
:
for action in parser._actions:
if not hasattr(action, 'metavar') or not hasattr(action, 'dest'):
continue
metavar = getattr(action, 'metavar')
if metavar is None:
action.metavar = action.dest.upper()
That generates output like:
--version X.Y.Z set version to X.Y.Z
--date DATE use DATE instead of today
But as we say in the BDFL's native language: "mooi is anders" ¹
¹ beautiful looks different
Upvotes: 1