Using argparse with argument values that begin with a dash ("-")

Viewed 675

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?

0 Answers
Related