Using argparse (or something else?) I would like each positional argument to have an optional argument with default value.
The arguments would be as so:
script.py arg1 arg2 -o 1 arg3 -o 2 arg4 arg5
and I want it to parse this into something usable, like a list of the positional arguments and a list of the optional arguments with defaults filled in. e.g. if the default for the optional is 0 in the example above:
positional = [arg1, arg2, arg3, arg4, arg5]
optional = [0, 1, 2, 0, 0]
in other words, parser.add_argument('-o', action='append') is not what I want because I lose the positional argument, each optional argument is associated to.
Here’s a simple hack that I put together that might be a reasonable place to start:
And here it is in action:
This problem has a few challenges. First, You want to accept an arbitrary number of positional arguments — argparse doesn’t like that. argparse wants to know up front what to expect. The solution is to build a parser and parse the commandline, but to tell argparse to only parse the known arguments only (in this case, the non-positional
-oarguments are all parsed silently but the “positional” arguments aren’t parsed.).parse_known_argsis perfect for this as it returns a tuple in the form(namespace_of_parsed_stuff, uknown_args). So now we know the unknown arguments — We just need to add a positional argument to the parser for each one to make parse_args happy.Now, what are the custom actions actually doing? When a positional argument is found (on the second pass), we get the default (which is a list) and add the value to that list (hereafter I’ll call it the “value” list). We then modify the parser with a reference to the “value” list. We also get the “all_positional” list from the namespace. If it doesn’t have that attribute, we just get an empty list. We add the “value” list to the “all_positional” list and put it back on the namespace.
Now, when we hit a
-oflag, we look at the parser to get the “value” list and we add the additional value to that list. We could do the same thing without touching the parser at all … (we could look atnamespace.all_positional[-1]— It’s the same list asparser.last_positional_values).