jamesdlin
jamesdlin

Reputation: 89946

How can I get argparse to accept "--" as an argument to an option?

I have a command-line option that requires an argument. I would like to be able to supply "--" as the argument, but I can't figure out how to do it.

Sample code: (test-argparse.py)

#!/usr/bin/env python

from __future__ import print_function
import argparse
import sys


def main(argv):
    ap = argparse.ArgumentParser()
    ap.add_argument("-x", "--foo", metavar="VALUE", default="",
                    help="Test option.")
    args = ap.parse_args(argv[1:])

    print(args.foo)

if __name__ == "__main__":
    sys.exit(main(sys.argv))

All my attempts to try to pass "--" as an argument fail:

$ test-argparse.py --foo --
usage: test-argparse.py [-h] [-x VALUE]
test-argparse.py: error: argument -x/--foo: expected one argument

$ test-argparse.py --foo -- --
usage: test-argparse.py [-h] [-x VALUE]
test-argparse.py: error: argument -x/--foo: expected one argument

$ test-argparse.py --foo=--
[]

$ test-argparse.py --foo=-- --
usage: test-argparse.py [-h] [-x VALUE]
test-argparse.py: error: unrecognized arguments: --

$ test-argparse.py --foo="--"
[]

$ test-argparse.py '--foo --'
usage: test-argparse.py [-h] [-x VALUE]
test-argparse.py: error: unrecognized arguments: --foo --

$ test-argparse.py -x--
[]

$ test-argparse.py '-x --'
 --

The last case is the closest, but it includes the space (and I can't just strip whitespace, because what if I want to allow " " as a value?). Is there any way that I can accomplish this?

That argparse forces argument permutation on clients (leading to unnecessary ambiguity) is very frustrating.

(I am using Python 2.7.12.)

Upvotes: 2

Views: 888

Answers (2)

hpaulj
hpaulj

Reputation: 231355

Ideally --foo=-- should work, but the current parser deletes all '--', leaving an empty string in its place, hence the foo=[] result. I proposed a patch a couple of years ago that should have fixed that, but it's caught in the argparse backlog. http://bugs.python.org/issue13922, http://bugs.python.org/issue14364, http://bugs.python.org/issue9571

Python argparse with -- as the value suggests preprocessing sys.argv replacing one or more of the -- with something else.

If you are game for patching your argparse.py file (or subclass the ArgumentParser class), I could revisit my earlier work and suggest a fix. The trick is to accept that =-- but still use the first free -- as the 'rest-are-positionals' flag (and retain any following --). Unfortunately one method that needs to be patched is nested in a much larger one.

Upvotes: 2

John Zwinck
John Zwinck

Reputation: 249123

There is a specific reason that this doesn't work: -- means "Skip this token and consider the rest of the arguments to be positional, even if they start with a dash."

Many, many programs won't accept -- as an argument, but they will accept -. The single dash is even a standard way of specifying "Use standard input or output" in place of a filename.

So the best thing you can do for the users of your program is probably to not design it to require --, because that's not something that's usually done, and not something that most modern command-line parsing libraries are likely able to parse.

You could use -- as a positional option, so you could probably support this:

--foo -- --

If you make --foo have action='store_true' (i.e. it is an option taking no argument), plus one non-mandatory positional argument. That will probably work, because the first -- means "stop processing dashes as options" and the second is a positional argument.

Upvotes: 1

Related Questions