athanassis
athanassis

Reputation: 1079

How to define optional argument value before optional positional argument?

Coming back to the question originally set by Python; argparse; how to specify position of positional arguments, I came into a valid use case answering to the question why one would need to do this.

If you have an argument with optional value and an optional positional argument, which is doable with argparse, e.g, from help:

$ myprog.py --help
usage: playargs.py [-h] [-i [I]] [positional [positional ...]]
-----cropped-----

Then the only way of setting '-i' flag without a value 'I' and also get positional values, is to place the '-i' flag at the end. So, if you write

$ myprog.py -i one two three

the 'one' value goes unavoidably to '-i'. If you want all 'one', 'two' and 'three' to be taken as positionals, then only way is to write

$ myprog.py one two three -i

I think there should be a way to restrict the accepted syntax to:

playargs.py [positional [positional ...]] [-i [I]]

The optionality of value 'I' before optional positional arguments makes things unclear.

Is there a way with argparse or other module?

Upvotes: 0

Views: 196

Answers (1)

hpaulj
hpaulj

Reputation: 231665

The linked question is about usage formatting. Positionals are moved to end of the list just as a matter of convention, reflecting a common POSIX command line practice:

prog [optionals] infile outfile

It does not reflect how arguments are accepted or parsed.

argparse, by design, tries to be order agnostic. While positionals are ordered among themselves, optionals can occur in any order, and even between positionals. The basic parsing loop is:

loop:
    handle positionals (up to next optionals flag)
    handle a optional
handle remaining positionals

And the other feature is that nargs are greedy. Your '?' for -i takes 1 argument if available, even though it would be satisfied with none. It actually uses re (regex) pattern matching.

There's no mechanism in argparse to say that -i must occur at the end or after the positionals. That would require altering the basic parsing loop.

Another optional,or '--' are the only tools for terminating a variable length nargs.

prog -i -- 1 2 3
prog -i -f 1 2 3   # -f is another argument
prog 1 2 3 -i 4

optparse has a different parsing strategy. I'm not as familiar with it, but I believe it passes the whole argv to an option, lets it use what it wants, and then continues parsing the remainder. positionals are just the unparsed strings (the extras of argparse parse_known_args).

There are a couple of older parsers, modeled on old UNIX practice. There's a slew of third party parsers. And of course you can handle sys.argv directly.

Upvotes: 1

Related Questions