What I want to do
I want to migrate a script from docopt
to argparse
. My script takes a positional argument for input file(s), then calls another command-line tool. It also takes an optional argument option that allows the user to specify additional arguments and options that will be passed to that command-line tool.
So, I allow the user to call:
my_program.py INPUT --extra-options "-foo bar -baz"
These --extra-options
are then added to the other program I'm calling from inside my script, e.g.:
other_program -foo bar -baz INPUT
Problem
Now, having migrated the argument parsing to argparse
, this does not work anymore:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("input", nargs="+")
parser.add_argument("-e", "--extra-options", type=str)
parser.add_argument("-f", "--force", default=False, action="store_true")
args = parser.parse_args()
When I call the same command, it says:
error: argument -e/--extra-options: expected one argument
But -e
was given one argument (-foo bar -baz
, to be precise)! My expectation was that the shell would group the argument based on the double-quotes, and argparse
would understand that.
Now, in the manual, we find:
positional arguments may only begin with - if they look like negative numbers and there are no options in the parser that look like negative numbers … 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
But this does not apply here – I want -e
to just parse the next word from the shell as its argument. The problem in this case is the other option -f/--force
– as soon as I remove it, or give it some other name (e.g., -x
), the arguments are parsed correctly. Apparently the f
from -foo
clashes with the -f/--force
option.
What I've tried
I looked into the answers from this question, but none of them solves the issue.
- I can't force users to specify this option differently (e.g., starting with a space, using
=
, ending with a space, …), as it would break backwards compatibility with existing scripts. - I don't want to use a deprecated module (
optparse
). - The
parse_known_args
solution does not work in this case. - The
nargs=argparse.PARSER
solution does not work either. - Removing
nargs
did not help either.
How can I get argparse
to deal with argument values starting with -
in this case?