Skip to content Skip to sidebar Skip to footer

Access "implicit" Metavar Value In Argument Help String

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

Solution 1:

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


Solution 2:

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

Post a Comment for "Access "implicit" Metavar Value In Argument Help String"