Search code examples
pythondryoptparse

Python optparse defaults vs function defaults


I'm writing a python script which I would like to be able to both call from the command line and import as a library function. Ideally the command line options and the function should use the same set of default values. What is the best way to allow me to reuse a single set of defaults in both places?

Here's the current code with duplicate defaults.

from optparse import OptionParser

def do_stuff(opt1="a", opt2="b", opt3="c"):
    print opt1, opt2, opt3

if __name__ == "__main__":
    parser = OptionParser()
    parser.add_option("--opt1", default="a")
    parser.add_option("--opt2", default="b")
    parser.add_option("--opt3", default="c")
    #parser.set_defaults(opt1="a")

    options, args = parser.parse_args()

    do_stuff(*args, **vars(options))

Solution

  • I'd handle it by introspecting the function of interest to set options and defaults appropriately. For example:

    import inspect
    from optparse import OptionParser
    import sys
    
    def do_stuff(opt0, opt1="a", opt2="b", opt3="c"):
        print opt0, opt1, opt2, opt3
    
    if __name__ == "__main__":
        parser = OptionParser()
        args, varargs, varkw, defaults = inspect.getargspec(do_stuff)
        if varargs or varkw:
          sys.exit("Sorry, can't make opts from a function with *a and/or **k!")
        lend = len(defaults)
        nodef = args[:-lend]
        for a in nodef:
          parser.add_option("--%s" % a)
        for a, d in zip(args[-lend:], defaults):
          parser.add_option("--%s" % a, default=d)
    
        options, args = parser.parse_args()
        d = vars(options)
        for n, v in zip(nodef, args):
          d[n] = v
    
        do_stuff(**d)