Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

argparse metavar for nargs='+' to get numbered arguments in help info?

In the argparse document, there is an example using nargs='+':

parser.add_argument('integers', metavar='N', type=int, nargs='+')

The corresponding help information is

usage: prog.py [-h] [--sum] N [N ...]

Is it possible to set the metavar such that the help info looks like this?

usage: prog.py [-h] [--sum] N1 [N2 ...]
like image 851
nos Avatar asked Jan 24 '18 18:01

nos


People also ask

What does Metavar do in Argparse?

Python argparse metavar The metavar option gives a name to the expected value in error and help outputs. The example names the expected value value . The default name is V . The given name is shown in the help output.

What does Nargs do in Argparse?

Using the nargs parameter in add_argument() , you can specify the number (or arbitrary number) of inputs the argument should expect. In this example named sum.py , the --value argument takes in 3 integers and will print the sum.

What does Metavar mean in Python?

Metavar: It provides a different name for optional argument in help messages.

How do you pass arguments to Argparse?

First, we need the argparse package, so we go ahead and import it on Line 2. On Line 5 we instantiate the ArgumentParser object as ap . Then on Lines 6 and 7 we add our only argument, --name . We must specify both shorthand ( -n ) and longhand versions ( --name ) where either flag could be used in the command line.


2 Answers

metavar can be tuple, as in

In [26]: parser = argparse.ArgumentParser()
In [27]: a=parser.add_argument('--integers', metavar=('N1','N2'), type=int, nargs='+');
In [28]: parser.print_help()
usage: ipython3 [-h] [--integers N1 [N2 ...]]

optional arguments:
  -h, --help            show this help message and exit
  --integers N1 [N2 ...]

But that only works for optionals (flagged arguments), not positionals. I'm not exactly sure why, though I may have dug into this issue before.

https://docs.python.org/3/library/argparse.html#metavar


With the positional, the error stack includes:

/usr/lib/python3.5/argparse.py in _format_action_invocation(self, action)
    542         if not action.option_strings:
    543             default = self._get_default_metavar_for_positional(action)
--> 544             metavar, = self._metavar_formatter(action, default)(1)
    545             return metavar
    546 

A positional doesn't have option_strings (or its empty), so it's using the metavar, = ... unpacking idiom to ask for just one string. Hence the error: ValueError: too many values to unpack (expected 1).

So expecting only one metavar variable is quite intentional, but I'm not sure about the rational. Maybe it's because it would be harder to tell where one positional ends and the next starts in the usage:

In [34]: parser = argparse.ArgumentParser()
In [35]: parser.add_argument('foo', type=int, nargs=2);
In [36]: parser.add_argument('bar', type=int, nargs='+');
In [38]: parser.print_usage()
usage: ipython3 [-h] foo foo bar [bar ...]

I looked at this a couple of years ago, https://bugs.python.org/issue14074. Looks like there can be problems with the usage, help-lines and error message.


Actually the problem isn't in the usage, it's in formatting the help lines:

In [39]: parser = argparse.ArgumentParser()
In [40]: a=parser.add_argument('integers', metavar=('N1','N2'), type=int, nargs='+')
In [41]: parser.print_usage()
usage: ipython3 [-h] N1 [N2 ...]

The normal help line for a positional just shows one symbol, not the N [N ...] of the usage:

In [43]: parser.print_help()
usage: ipython3 [-h] N [N ...]

positional arguments:
  N
like image 149
hpaulj Avatar answered Sep 21 '22 09:09

hpaulj


I would make a custom HelpFormatter and use that. Below is a quick hack.

from argparse import HelpFormatter, ZERO_OR_MORE, ONE_OR_MORE


class CustomHelpFormatter(HelpFormatter):
    def _format_args(self, action, default_metavar):
        get_metavar = self._metavar_formatter(action, default_metavar)
        if action.nargs == ZERO_OR_MORE:
            return '[%s1 [%s2 ...]]' % get_metavar(2)
        elif action.nargs == ONE_OR_MORE:
            return '%s1 [%s2 ...]' % get_metavar(2)
        else:
            return super()._format_args(action, default_metavar)


>>> parser = argparse.ArgumentParser(formatter_class=CustomHelpFormatter)
>>> parser.add_argument('integers', metavar='N', type=int, nargs='+')
>>> parser.parse_args(['--help'])
like image 29
d125q Avatar answered Sep 22 '22 09:09

d125q