Andreas Matthias
Andreas Matthias

Reputation: 285

Optional positional arguments with Python's argparse

Trying to parse optional positional arguments I ran into following issue:

Example:

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('infile')
parser.add_argument('outfile', nargs='?')
parser.add_argument('-v', action='store_true')

print(parser.parse_args())

Output:

$ ./x.py -v in out
Namespace(infile='in', outfile='out', v=True)

$ ./x.py in out -v
Namespace(infile='in', outfile='out', v=True)

$ ./x.py in -v out
usage: x.py [-h] [-v] infile [outfile]
x.py: error: unrecognized arguments: out

Why is the third program invocation not accepted? Is this a restriction of argparse?

Upvotes: 10

Views: 8550

Answers (1)

abarnert
abarnert

Reputation: 365657

This is a limitation of argparse—but one that's partially lifted in 3.7.

Unix tools generally don't claim to support intermixing of options and arguments, even though they often do. The problem is that combining it with some other features, like subcommands, leads to ambiguity. So, typically, libraries that support any of those features punt on the problem and don't allow intermixing. Or they do something kind of hacky—allowing options at the end, at the start, and in certain hard-to-predict cases but not others in the middle.

That's what argparse originally did. But 3.7 adds Intermixed parsing.

You have to manually call parse_intermixed_args instead of parse_args.

And if you try to use this with any of the features it doesn't go well with, you'll get an exception (even if there's no ambiguity for the particular set of args you pass—which should make it easier to debug).

But otherwise, it'll work as expected: options (together with their values, of course) can be freely mixed with positional arguments anywhere in the command line.


Unfortunately, I don't know of a drop-in backport on PyPI to get 3.7 argparse in earlier versions; the semi-official argparse backport is mainly for pre-2.7/3.2 versions that don't have it at all, and only backports the 3.4 version.

Upvotes: 11

Related Questions