28
import argparse

class customAction(argparse.Action):
    def __call__(self, parser, args, values, option_string=None):
       setattr(args, self.dest, values)

parser = argparse.ArgumentParser()
parser.add_argument('-e', '--example', action=customAction)

I want to pass additional arguments to customAction when the option -e is triggered, e.g. a instance of another class. How can I do this? Everything I have tried has errored out.

2 Answers 2

53
def make_action(additional_arg):
    class customAction(argparse.Action):
        def __call__(self, parser, args, values, option_string=None):
            print(additional_arg)
            setattr(args, self.dest, values)
    return customAction
#...
parser.add_argument('-e', '--example', action=make_action('your arg'))
Sign up to request clarification or add additional context in comments.

Comments

26

Another solution is to derive the based class argparse.Action like this:

class CustomAction(argparse.Action):
    def __init__(self,option_strings,
                 additional_arg1,additional_arg2,
                 dest=None,
                 nargs=0,
                 default=None,
                 required=False,
                 type=None,
                 metavar=None,
                 help=None):
        self._a1=additional_arg1
        self._a2=additional_arg2
        super(CustomAction, self).__init__(
            option_strings=option_strings,
            dest=dest,
            nargs=nargs,
            default=default,
            required=required,
            metavar=metavar,
            type=type,
            help=help)
    def __call__(self, parser, namespace, values, option_string=None):
        print(self._a1)
        print(self._a2)
        setattr(namespace, self.dest, values)

#........
parser.add_argument('-e', '--example', action=CustomAction, additional_arg1='your arg', additional_arg2=42)

Alternatively, supply *args and **kwargs to pass through any additional parameters to the parent constructor.

class CustomAction(argparse.Action):
    def __init__(self, option_strings, additional_arg1, additional_arg2,
                 *args, **kwargs):
        self._a1 = additional_arg1
        self._a2 = additional_arg2
        super(CustomAction, self).__init__(option_strings=option_strings,
                                           *args, **kwargs)
    def __call__(self, parser, namespace, values, option_string=None):
        print(self._a1)
        print(self._a2)
        setattr(namespace, self.dest, values)

#........
parser.add_argument('-e', '--example', action=CustomAction, additional_arg1='your arg', additional_arg2=42)

3 Comments

As much as I love closures, this answer strikes me as a cleaner (if more object-oriented) solution. Anyone using this might consider adding *args and **kwargs instead of listing out all of argparse's default Action arguments.
this example I needed to change setattr(args to setattr(namespace to make it work
@kdubs I've made an edit to the answer, correcting that issue.

Your Answer

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