The python optparse package is really handy for parsing command line arguments. When combining this with an extra main function idiom (to allow interactive usage or use as a module), I ran into a small problem – the following code does not run:
1 2 3 4 5 6 7 8 9 | def main(foo, bar): print("foo: %s, bar: %s\n" % (foo, bar)) if __name__ == "__main__": from optparse import OptionParser parser = OptionParser() parser.add_option("--foo", dest="foo") parser.add_option("--bar", dest="bar") (options, args) = parser.parse_args() main(**options) |
This is the error message:
Traceback (most recent call last): File "foobar.py", line 9, inmain(**options) TypeError: main() argument after ** must be a dictionary
The problem here is that the options result from OptionParser is instead of type optparse.Values, which is not derived from dict (huh?!). Quoting the Python language reference:
If the syntax **expression appears in the function call, expression must evaluate to a mapping, the contents of which are treated as additional keyword arguments.
Here are two ways to fix the problem:
1 2 3 4 | # ... (options, args) = parser.parse_args() main(foo=options.foo, bar=options.bar) # Fix (a) main(**options.__dict__) # Fix (b) |
I know I prefer (b), especially if there are many options to pass on. Another work around is used by the pylit project (extending the optparse.Values class).