0

One nice feature of GCC's command line parsing is that most flags of the form "-fmy-option" have a negative version called "-fno-my-option". The rightmost occurrence takes precedence, so you can just append "-fno-my-option" to your CFLAGS or similar in a Makefile to disable an option without clobbering the other flags.

I'd like to support something similar in a tool whose wrapper script is Python and uses argparse. The obvious hack of just defining both versions of the argument with an action of store_true doesn't work, because that won't let me ask for the rightmost occurrence.

Obviously, it's easy to support a syntax like --my-option=yes / --my-option=no, but it would be nice for the user not to have to pass the parameter.

Is there a way to get argparse to have an on/off switch for a boolean flag like this?

0

1 Answer 1

2

Without any fancy foot work I can setup a pair of arguments that write to the same dest, and take advantage of the fact that the last write is the one that sticks:

In [765]: parser=argparse.ArgumentParser()
In [766]: a1=parser.add_argument('-y',action='store_true')
In [767]: a2=parser.add_argument('-n',action='store_false')

Without a dest parameter these use a name deterived from the option strings. But I can give a dest, or change that value after creation:

In [768]: a1.dest
Out[768]: 'y'
In [769]: a2.dest
Out[769]: 'n'
In [770]: a1.dest='switch'
In [771]: a2.dest='switch'

Now use of either will set the switch attribute.

In [772]: parser.parse_args([])
Out[772]: Namespace(switch=False)

The default comes from the first defined argument. That's a function of how defaults are set at the start of parsing. For all other inputs, it's the last argument that sets the value

In [773]: parser.parse_args(['-y'])
Out[773]: Namespace(switch=True)
In [774]: parser.parse_args(['-n'])
Out[774]: Namespace(switch=False)
In [775]: parser.parse_args(['-n','-y','-n','-y'])
Out[775]: Namespace(switch=True)
In [776]: parser.parse_args(['-n','-y','-n'])
Out[776]: Namespace(switch=False)

The default could also be set with a separate command:

parser.set_defaults(switch='foo')

If you wanted to use this sort of feature a lot you could write a little utility function that creates the pair of arguments with any flags and dest you want. There's even a bug/issues request for such an enhancement, but I doubt if it will be implemented.

Sign up to request clarification or add additional context in comments.

1 Comment

That's great, thank you for explaining. Incidentally, you can also set the dest as part of the add_argument call, so you get something like: p.add_argument('--with-x', action='store_true', dest='x') and p.add_argument('--without-x', action='store_false', dest='x') or whatever.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.