argparse limitations

Ian Kelly ian.g.kelly at gmail.com
Fri Jul 27 12:26:14 EDT 2012


On Fri, Jul 27, 2012 at 9:19 AM, Benoist Laurent <benoist at ibpc.fr> wrote:
> That's the solution I came to.
> But I'm not very happy with this since I can definitively not make my
> program act as a standard unix tool.
> Any other solution?

I don't understand; that's pretty much the same way that standard unix
tools implement stdin redirection.  What specific behavior are you
looking for that you're missing with Oscar or Peter's suggestions?

> As far as I know it is not the case.
> Let's get into the code.
>
> parser = argparse.ArgumentParser()
> parser.add_argument("-i", help="input files", nargs="+")
>
> subparsers = parser.add_subparsers()
> foo_parser = subparser.add_parser("foo")
> # ... here come some foo parser options
> bar_parser = subparser.add_parser("bar")
> # ... here come some bar parser options
>
> What argparse expects is the "-i" arguments coming before the subparsers.
>
> To summarize, if I adopt your solution to my first question, the I should
> add the "-i" argument to each subparser.
> I don't want to since it's ugly and I'd have to write the help myself (which
> I don't want to).

argparse doesn't really handle well options or arguments with
nargs="+" or "*" that come before other non-option arguments or
subparser commands.  If it sees the input "mytool.py -i one two foo
...", then is the "foo" part of the -i argument (a file to be read),
or is it the subparser command?  At this point in the parsing it can't
really tell the difference, so it tacks it onto the -i list.
Potentially it could figure that out later when it reaches the end of
the command line, but that would require backtracking over an
arbitrarily large part of the command line.  Worse, if the string
"foo" or "bar" appears more than once in the command line, then the
command may really be ambiguous.  Usually for this reason arguments
with indefinite nargs will be the very last argument so they can
simply consume the rest of the command line.

Here's an alternate approach that does more or less what you want:

parser = argparse.ArgumentParser()
parser.add_argument("-i", help="input files", action="append")

subparsers = parser.add_subparsers()
foo_parser = subparser.add_parser("foo")
# ... here come some foo parser options
bar_parser = subparser.add_parser("bar")
# ... here come some bar parser options

>>> parser.parse_args(['-i', 'one', '-i', 'two', 'foo'])
Namespace(i=['one', 'two'])

It may be a bit awkward having to type "-i" once per file in the
command line, but it does clear up the ambiguity.



More information about the Python-list mailing list