Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add argparse arguments from external modules

I'm trying to write a Python program that could be extended by third parties. The program will be run from the command line with whatever arguments are supplied.

In order to allow third parties to create their own modules, I've created the following (simplified) base class:

class MyBaseClass(object):
    def __init__(self):
        self.description = ''
        self.command = ''

    def get_args(self):
        # code that I can't figure out to specify argparse arguments here
        # args = []
        # arg.append(.....)
        return args

Any arguments that they supply via get_args() will be added to a subparser for that particular module. I want them to be able to specify any type of argument.

I'm not sure of the best way to declare and then get the arguments from the subclassed modules into my main program. I successfully find all subclasses of MyBaseClass and loop through them to create the subparsers, but I cannot find a clean way to add the individual arguments to the subparser.

Here is the current code from the main program:

for module in find_modules():
    m = module()
    subparser_dict[module.__name__] = subparsers.add_parser(m.command, help=m.help)
    for arg in m.get_args():
            subparser_dict[module.__name__].add_argument(...)

How can I best specify the arguments in the external modules via get_args() or similar and then add them to the subparser? One of my failed attempts looked like the following, which doesn't work because it tries to pass every possible option to add_argument() whether it has a value or is None:

            subparser_dict[module.__name__].add_argument(arg['long-arg'],
                action=arg['action'],
                nargs=arg['nargs'],
                const=arg['const'],
                default=arg['default'],
                type=arg['type'],
                choices=arg['choices'],
                required=arg['required'],
                help=arg['help'],
                metavar=arg['metavar'],
                dest=arg['dest'],
                )
like image 819
doza Avatar asked May 25 '14 01:05

doza


1 Answers

Without trying to fully understand your module structure, I think you want to be able to provide the arguments to a add_argument call as objects that you can import.

You could, for example, provide a list of positional arguments, and dictionary of keyword arguments:

args=['-f','--foo']
kwargs={'type':int, 'nargs':'*', 'help':'this is a help line'}

parser=argparse.ArgumentParser()
parser.add_argument(*args, **kwargs)
parser.print_help()

producing

usage: ipython [-h] [-f [FOO [FOO ...]]]

optional arguments:
  -h, --help            show this help message and exit
  -f [FOO [FOO ...]], --foo [FOO [FOO ...]]
                        this is a help line

In argparse.py, the add_argument method (of a super class of ArgumentParser), has this general signature

def add_argument(self, *args, **kwargs):

The code of this method manipulates these arguments, adds the args to the kwargs, adds default values, and eventually passes kwargs to the appropriate Action class, returning the new action. (It also 'registers' the action with the parser or subparser). It's the __init__ of the Action subclasses that lists the arguments and their default values.

like image 114
hpaulj Avatar answered Sep 18 '22 20:09

hpaulj