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_argssolution does not work in this case. - The
nargs=argparse.PARSERsolution does not work either. - Removing
nargsdid not help either.
How can I get argparse to deal with argument values starting with - in this case?