1
votes

I'm struggling to cleanly combine an API function in Python that has defaulted arguments, with a command-line script using optparse that wraps it. Let's suppose the API function looks like this:

def api(foo, bar, opt1 = 2, opt2 = 3):
    pass

And the OptionParser for the command line tool looks as follows

parser = OptionParser(usage=usage, description=desc, version=version)
parser.add_option("-a", "--opt1", type="int", action="store", help="opt1")
parser.add_option("-b", "--opt2", type="int", action="store", help="opt2")
parser.add_option("-v", "--verbose", action="store", help="verbosity")
(opt, args) = parser.parse_args()

At this point I want the CLI to call api(), providing a value for foo and bar and propagating the opt1/opt2 options if they were specified, otherwise omitting those arguments which will result in the default values of 2 and 3 being used. What is the best way to do this? Bear in mind that the command line option "verbose" is not applicable to api().

I want the defaults in the API instead of the OptionParser because sometimes the API is called in a library fashion and the same defaults should apply as in the CLI case. Above all, I don't want a None value in opts to be propagated in the event that opt1 or opt2 was not specified.

I need to use OptionParser but argparse answers would be interesting as well.

Thanks for your time.

Edit:

Here's the best I've come up with, using the inspect module:

kws = {}
param_names = inspect.getargspec(api)[0]
kws.update((k, v) for k, v in opt.__dict__.items() if v is not None and k in param_names)

api(foo, bar, **kws)
1

1 Answers

0
votes
parser = OptionParser(usage=usage, description=desc,
        version=version)
parser.add_option("-a", "--opt1", type="int", action="store",
        help="opt1")
parser.add_option("-b", "--opt2", type="int", action="store",
        help="opt2")
parser.add_option("-v", "--verbose", action="store",
        help="verbosity")
(opt, args) = parser.parse_args()

optional_arguments = dict((k, v) for k, v in vars(opt).items() \
    if v and k in ['op1', 'op2'])
api('the foo', 'the bar', **optional_arguments)

Discussion

  • vars(opt) returns a dictionary, e.g. {'opt1': None, 'opt2': None, 'verbose': None}
  • The whole dict( ... ) expression filters out those options with values that are not None and return a dictionary object. I can also use filter() for this purpose.
  • This dictionary object can be fed into api()

Update

I added and k in ['op1', 'op2'] in the creation of optional_arguments to prevent other parameters from making their way into the argument list.