Without argparse.REMAINDER
, optional arguments can be in front of or after positional arguments:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-a')
parser.add_argument('b')
print(parser.parse_args('-a 1 2'.split())) # Namespace(a='1', b='2')
print(parser.parse_args('2 -a 1'.split())) # Namespace(a='1', b='2')
But with argparse.REMAINDER
, optional arguments must be in front:
parser.add_argument('c', nargs=argparse.REMAINDER)
print(parser.parse_args('-a 1 2 3'.split())) # Namespace(a='1', b='2', c=['3'])
print(parser.parse_args('2 -a 1 3'.split())) # Namespace(a=None, b='2', c=['-a', '1', '3'])
How can I parse the last line correctly, while argparse.REMAINDER
is used?
To add to kabanus's answer, it may help to know a bit about how arguments are parsed.
It iterates over the arguments, first looking for positionals, then optionals, then positionals, ...,
At the positionals step it tries to match as many as it can, using the
nargs
as a primary factor. The default is one string (your 'b'); '*' will match up to the next optional (the-a
); but a REMAINDER ignores that constraint and matches to the end. So a 'positionals' evaluation is greedy, and one with REMAINDER is especially greedy.So in the
'2 -a 1 3'
case, the initial '2' can match 'b', and the rest can match 'c'. Just one 'positionals' evaluation consumes the whole list, including the '-a', and it is done.The documentation example shows this:
The '--foo' is handled as optional, but the '--arg1' is part of the REMAINDER. 'args' is filled immediately after 'command'.
If you want to retain control over when the REMAINDER is used, make it an optional,
add_argument('-c',nargs='...')
. Otherwise you are at the mercy of this positionals/optionals loop.By the way, subparsers are implemented with a
narg=argarse.PARSER
, which is the name for '+...'. It's like REMAINDER but requires at least one string (the subparser name). It too consumes everything in its path.Instead of REMAINDER you might want to use '*' and use '--' to trigger the 'consume everything else' action.
From the documentation:
this means using remainder by definition cannot have (any) other arguments after the argument accepting this, as they are part of the remainder, and would go into this argument.