19
class StartAction(argparse.Action):
    def __call__(self, parser, namespace, values, option_string=None):
        print "Hello"

start.add_argument('-s', '--start', action=StartAction)

I know normally having the action be something like 'store_true' would prevent the requirement of an argument, but is there a way to use a custom action and still not require an argument to be passed?

So what I want is:

python example.py -s

Hello

4 Answers 4

22

Try adding nargs=0 to your start.add_argument:

start.add_argument('-s', '--start', action=StartAction, nargs=0)
Sign up to request clarification or add additional context in comments.

6 Comments

ValueError: nargs for store actions must be > 0; if you have nothing to store, actions such as store true or store const may be more appropriate
I don't agree with @Lucina comment. You may want to call a custom action to have a seamless mapping between parsing arguments and complex actions. I prefere to have Action objects that behave as the parameters of the CLI so I have polymorphism between the CLI itnerface and the object that handles it.
@Daniel it's not a question of "agreement". This is an error one can receive when setting nargs=0
@ReinstateMonica I agree the error exists. I don't agree with the actions she suggested.
@Daniel she didn't suggest actions. That is literally the error message.
|
9

As mgilson suggested nargs=0 does the trick. Since it's intrinsic to your action, I'd put it inside the action:

class StartAction(argparse.Action):
    def __init__(self, nargs=0, **kw):
        super().__init__(nargs=nargs, **kw)
    def __call__(self, parser, namespace, values, option_string=None):
        print "Hello"

start.add_argument('-s', '--start', action=StartAction)

And you have your desired behaviour without the redundancy of having to add nargs=0 to every add_argument() call. Neat if you have multiple arguments working in the same way.

However users could still override the default of nargs=0 which is silly for your use case as demonstrated in the question. So I'd enforce it:

class StartAction(argparse.Action):
    def __init__(self, nargs=0, **kw):
        if nargs != 0:
            raise ValueError('nargs for StartAction must be 0; it is '
                             'just a flag.')
        super().__init__(nargs=nargs, **kw)
    def __call__(self, parser, namespace, values, option_string=None):
        print "Hello"

1 Comment

The former (without the enforcing check) is also exactly what action="store_const" does: github.com/python/cpython/blob/…
5

For anyone who finds this in 2020: If you attempt to pass nargs=0 in the latest argparse package for python3, it will error with:

ValueError: nargs for store actions must be != 0; if you have nothing to store, actions such as store true or store const may be more appropriate

The solution you're probably looking for is to pass action="store_const" and const=True

Example:

parser = argparse.ArgumentParser
parser.add_argument('-s', '--start', help='Start script or whatever', action="store_const", const=True)

This will set the value for parser.start equal to "True" when the -s parameter is passed to main/the rest of the script.

Comments

1

I wrote this example after consulting the above and trying out different methods. Here is a class which implements the "Uncount" acount, which is the opposite of the 'count' action.

import argparse
class Uncount(argparse.Action):
    def __init__(self, option_strings, dest, nargs=0, choices=None, const=None, **kwargs):
        if nargs != 0:
            raise ValueError("no arguments to this parameter are allowed")
        if const is not None:
            raise ValueError("this parameter does not permit constants")
        if choices is not None:
            raise ValueError("no choices to this parameter are allowed")
        super(Uncount, self).__init__(option_strings=option_strings, nargs=nargs, dest=dest,**kwargs)
    def __call__(self, parser, namespace, values, option_string=None):
        value = getattr(namespace, self.dest, 0)
        setattr(namespace, self.dest, value-1)

opts={}
argparser = argparse.ArgumentParser(description='Report on other teams')
argparser.add_argument(
    '-v','--verbose',dest='verbose',default=0,action='count',
    help='increase log level',
)
argparser.add_argument(
    '-q','--quiet',dest='verbose',default=0,action=Uncount,
    help='increase log level',
)

Examples:

>>> argparser.parse_args('-q -q'.split())
Namespace(verbose=-2)
>>> argparser.parse_args('-q -v'.split())
Namespace(verbose=0)
>>> argparser.parse_args('-q -v -v'.split())
Namespace(verbose=1)

Comments

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.