1

from the advice by the accepted answer of my previous question, and from this question, I tried to do:

parser = argparse.ArgumentParser(description="output parser")
line_parser = argparse.ArgumentParser(add_help=False)
line_parser.add_argument("-N", help="Showing first N line",
                    metavar='integer', type=int)
line_parser.add_argument("-n", help="Showing last n line",
                    metavar='integer', type=int)
parser.add_argument("opt", help="grep string from file",
                    nargs=2, metavar=("str", "file"))
subp = parser.add_subparsers()
pscf = subp.add_parser("scf", help="show convergence", parents=[line_parser])#,
pkp = subp.add_parser("kpoint", help="show kpoints")
pnb = subp.add_parser("nband", help="show number of bands")
pmd = subp.add_parser("md", help="Create xyz file for each ionic step for"
                    " visualization")#, action='store_true')
pfrc = subp.add_parser("force", help="See which atom has maximum force")
# parser.add_argument("--xsf", help="Create xsf file for md(default is xyz)"
                    # " visualization", action='store_true')
args = parser.parse_args()

This is giving error:

python3 vasp.py --help
Traceback (most recent call last):
  File "vasp.py", line 27, in <module>
    args = parser.parse_args()
  File "/usr/lib64/python3.4/argparse.py", line 1728, in parse_args
    args, argv = self.parse_known_args(args, namespace)
  File "/usr/lib64/python3.4/argparse.py", line 1760, in parse_known_args
    namespace, args = self._parse_known_args(args, namespace)
  File "/usr/lib64/python3.4/argparse.py", line 1966, in _parse_known_args
    start_index = consume_optional(start_index)
  File "/usr/lib64/python3.4/argparse.py", line 1906, in consume_optional
    take_action(action, args, option_string)
  File "/usr/lib64/python3.4/argparse.py", line 1834, in take_action
    action(self, namespace, argument_values, option_string)
  File "/usr/lib64/python3.4/argparse.py", line 1016, in __call__
    parser.print_help()
  File "/usr/lib64/python3.4/argparse.py", line 2359, in print_help
    self._print_message(self.format_help(), file)
  File "/usr/lib64/python3.4/argparse.py", line 2336, in format_help
    formatter.add_arguments(action_group._group_actions)
  File "/usr/lib64/python3.4/argparse.py", line 272, in add_arguments
    self.add_argument(action)
  File "/usr/lib64/python3.4/argparse.py", line 257, in add_argument
    invocations = [get_invocation(action)]
  File "/usr/lib64/python3.4/argparse.py", line 535, in _format_action_invocation
    metavar, = self._metavar_formatter(action, default)(1)
ValueError: too many values to unpack (expected 1)

If I remove all of line_parser, then it works fine. But I need them, as -N and -n will be used in multiple options, though not shown here.

I have read this but haven't managed to assimilate.

Community
  • 1
  • 1
BaRud
  • 3,055
  • 7
  • 41
  • 89

2 Answers2

0

The exception is not related to line_parser, but parameter 'metavar' in line 8. Change tuple to list will make your code work.

parser.add_argument("opt", help="grep string from file",
                    nargs=2, metavar=["str", "file"])
Li Feng
  • 931
  • 6
  • 14
  • Changing to a list does let it run. The help line looks right, but the usage line has `['str', 'file'] ['str', 'file']`, which isn't what BaRud intends. Something looks buggy. I'll have to dig into the code. – hpaulj Mar 19 '16 at 02:49
0

I agree, it isn't a parents or subparser issue, but a nargs and metavar issue. There is a relevant Python bug/issue

http://bugs.python.org/issue14074; argparse allows nargs>1 for positional arguments but doesn't allow metavar to be a tuple

I suggested a patch a couple of years ago, but there's a big backlog of argparse issues, so no action has been taken.


If opt is changed to --opt:

parser.add_argument("--opt", help="grep string from file",
                nargs=2, metavar=("str", "file"))

then the help is:

1949:~/mypy$ python stack36095543.py -h
usage: stack36095543.py [-h] [--opt str file] {scf,kpoint,nband,md,force} ...

output parser

positional arguments:
  {scf,kpoint,nband,md,force}
    scf                 show convergence
  ...

optional arguments:
  -h, --help            show this help message and exit
  --opt str file        grep string from file

I think that's what is intended.

Changing the metavar to a list produces

usage: stack36095543.py [-h] [--opt ['str', 'file'] ['str', 'file']]
                    {scf,kpoint,nband,md,force} ...

which I don't think is the intended usage.

According to the docs:

Providing a tuple to metavar specifies a different display for each of the arguments:

I would suggest going with the --opt argument. One, it gets this metavar display right. Two, positionals don't play that nicely with subparsers. A subparser is a positional argument as well (in disguise). I think it is safer to define the other main parser arguments as 'optionals'

Note, if I make --opt required=True, the usage like is:

usage: stack36095543.py [-h] --opt str file {scf,kpoint,nband,md,force} ...

In that case it's a bit hard to distinguish between flag and argument. argparse uses upper case for the default optionals metavars. It is clear if get use:

 usage: stack36095543.py [-h] --opt STR FILE {scf,kpoint,nband,md,force} ...

Another possibility is to replace the nargs=2 argument with 2 positionals

parser.add_argument("grep",metavar='STR')
parser.add_argument("file",metavar='FILE')

producing:

usage: stack36095543.py [-h] STR FILE {scf,kpoint,nband,md,force} ...

A positional with nargs=2 (or *,+) is best reserved for cases where all values are the same kind of thing - values in a list. Where they represent different things, it makes more sense to use separate arguments.


On further testing I find that your code handles the usage just fine. parser.print_usage() produces:

usage: stack36095543.py [-h] str file {scf,kpoint,nband,md,force} ...

the error is produced when formatting the help line. A line that should look like:

str file        grep string from file

And according to my posts on the bug/issue, a metavar like this also has problems when displaying an error message.

hpaulj
  • 221,503
  • 14
  • 230
  • 353