0
votes

I'm trying to use argparse but I keep having the issue where for some reason my positional parameters are required to be first on the command line. I want the positional to be last since it is a list of file names.

    self.parser = ArgumentParser(description=program_license,
                     formatter_class=RawDescriptionHelpFormatter,
                     conflict_handler='resolve')
    self.parser.add_argument('-V', '--version',
                     action='version',
                     version=program_version_message)
    self.parser.add_argument('--logfile', action='store',
                     dest='logfile', default='daddyvision.log')
    self.parser.add_argument('prog', help=SUPPRESS, nargs=1)
    self.parser.add_argument('library', metavar="library", nargs='*')

    group_loglvl = self.parser.add_mutually_exclusive_group()
    group_loglvl.add_argument("--verbose", dest="loglevel",
                     action="store_const", const="VERBOSE",
                     default='INFO')
    group_loglvl.add_argument("--debug", dest="loglevel",
                     action="store_const", const="DEBUG")
    group_loglvl.add_argument("--trace", dest="loglevel",
                     action="store_const", const="TRACE")
    group_loglvl.add_argument("--quiet", dest="loglevel",
                     action="store_const", const="WARNING")
    group_loglvl.add_argument("--errors", dest="loglevel",
                     action="store_const", const="ERROR")

    args = self.parser.parse_args(arg)

if my command line is: pgm --error filename I get "error: unrecognized arguments: filename"

if my cmd line is pgm filename --error it works without error.

What am I doing wrong. Everything I've read leads me to believe that the positional can come first or last. Python 2.7 environment.

If I make the positional requires (nargs='+') it works but the parm is optional.

1
You may find this helpful: github.com/docopt/docopt - Blender

1 Answers

0
votes

It is easier to test your code if you clean it up, removing things like the self. I like to do import argparse, and then be able to paste the rest, and get a running example.

How are you testing this?

parser.parse_args('pgm --error filename'.split())

or

parser.parse_args('--error filename'.split())

parser.parse_args() parses sys.argv[1:]. If I ran a script named pgm with this argparse, I would expect to parse --error filename.

Help, without the SUPPRESS is:

usage: ipython [-h] [-V] [--logfile LOGFILE]
               [--verbose | --debug | --trace | --quiet | --errors]
               prog [library [library ...]]

positional arguments:
  prog
  library

optional arguments:
  -h, --help         show this help message and exit
  ...
  --errors

Regardless, the key to your error is the prog [library [library ...]] part of usage.

What's happening with pgm --error filename is that the pgm string sets both prog='pgm' and library=[]. With * (or ?), library is satisfied with no string at all. Having done that, it has no place to put the filename string.

pgm filename --error gives library=['filename']. --error pgm filename should also work.

The issue isn't that postionals must be first (or last) but that they must be together (if the 2nd is '?' or '*').

This bug report post tries to explain this interaction of '*' positionals and optionals

http://bugs.python.org/issue14191#msg185517


If pgm is the program name sys.argv[0], then you don't need it in argparse. Remove the prog argument, and your problem goes away (then there is only one positional).