Reputation: 357
I'm somewhat new to using argparse and have run into a problem stemming from using an optional argument (list of files arbitrarily long) along with a positional argument (a single file). Here is a simple program that demonstrates this problem:
parser = argparse.ArgumentParser()
parser.add_argument("pos_file", help="Input file")
parser.add_argument("-v", "--verbose", action="store_true")
parser.add_argument("-l", "--optional_list", help="file list", nargs="+")
args = parser.parse_args()
When I call this program using the command:
python test_arg_parse.py -l file1.txt file2.txt pos_file.txt
Argparse fails, mentioning that there are too few arguments. I understand why this is happening - argparse assumes that pos_file.txt is part of the optional list and therefore doesn't find a positional argument - but I don't understand why argparse doesn't always consider the last argument to be positional. This can be solved by placing the verbose argument between the optional list and the positional argument:
python test_arg_parse.py -l file1.txt file2.txt -v pos_file.txt
Which argparse happily processes. However, I don't want to enforce this strict ordering of arguments and I would like to keep the list optional and the single file positional. I have looked into using the append
functionality, but it doesn't seem reasonable considering the list can be arbitrarily long.
Is there a nice way of accomplishing this?
Upvotes: 3
Views: 1022
Reputation: 10723
As users noted, once you pass in a flag (optional) argument argparse will not know how to handle positional arguments that come afterwards. One solution I found is to use the pseudo-argument --
which tells argparse that the next parameters are positional. From the python argparse docs
If you have positional arguments that must begin with - and don’t look like negative numbers, you can insert the pseudo-argument '--' which tells parse_args() that everything after that is a positional argument
You can use the updated command:
python test_arg_parse.py -l file1.txt file2.txt -- pos_file.txt
Upvotes: 1
Reputation: 231665
Parsing is driven by the order of values in the command line, having first identified which strings look like flags (optionals) and which are just arguments.
python test_arg_parse.py -l file1.txt file2.txt pos_file.txt
It first checks the start of the list for positional arguments - none. Then for flags - it finds '-l'. That takes '+', so it's given everything up to the next flag (or the end). Now there's nothing left on the list for 'pos_file'.
There is a bug/issue about this, and I proposed a patch that would check the positionals, and hold back on giving the optional everything. But that requires too much fiddling with the core parsing code, and hasn't gotten very far in approval process.
So for now, using a positional like this after an open ended argument (optionals or positionals) doesn't work
python test_arg_parse.py pos_file.txt -l file1.txt file2.txt
should work. But if you want more control, define pos_file
as a flagged argument, not a positional.
Upvotes: 3