Here's an example of a callback option that takes no arguments, and simply records that the option was seen:
def record_foo_seen (option, opt, value, parser): parser.saw_foo = 1 parser.add_option("--foo", action="callback", callback=record_foo_seen)
Of course, you could do that with the ``store_true'' action. Here's a slightly more interesting example: record the fact that -a is seen, but blow up if it comes after -b in the command-line.
def check_order (option, opt, value, parser): if parser.values.b: raise OptionValueError("can't use -a after -b") parser.values.a = 1 ... parser.add_option("-a", action="callback", callback=check_order) parser.add_option("-b", action="store_true", dest="b")
If you want to reuse this callback for several similar options (set a flag, but blow up if -b has already been seen), it needs a bit of work: the error message and the flag that it sets must be generalized.
def check_order (option, opt, value, parser): if parser.values.b: raise OptionValueError("can't use %s after -b" % opt) setattr(parser.values, option.dest, 1) ... parser.add_option("-a", action="callback", callback=check_order, dest='a') parser.add_option("-b", action="store_true", dest="b") parser.add_option("-c", action="callback", callback=check_order, dest='c')
Of course, you could put any condition in there--you're not limited to checking the values of already-defined options. For example, if you have options that should not be called when the moon is full, all you have to do is this:
def check_moon (option, opt, value, parser): if is_full_moon(): raise OptionValueError("%s option invalid when moon full" % opt) setattr(parser.values, option.dest, 1) ... parser.add_option("--foo", action="callback", callback=check_moon, dest="foo")
(The definition of is_full_moon()
is left as an exercise for the
reader.)
Fixed arguments
Things get slightly more interesting when you define callback options that take a fixed number of arguments. Specifying that a callback option takes arguments is similar to defining a ``store'' or ``append'' option: if you define type, then the option takes one argument that must be convertible to that type; if you further define nargs, then the option takes that many arguments.
Here's an example that just emulates the standard ``store'' action:
def store_value (option, opt, value, parser): setattr(parser.values, option.dest, value) ... parser.add_option("--foo", action="callback", callback=store_value, type="int", nargs=3, dest="foo")
Note that optparse takes care of consuming 3 arguments and converting them to integers for you; all you have to do is store them. (Or whatever: obviously you don't need a callback for this example. Use your imagination!)
Variable arguments
Things get hairy when you want an option to take a variable number of arguments. For this case, you have to write a callback; optparse doesn't provide any built-in capabilities for it. You have to deal with the full-blown syntax for conventional Unix command-line parsing. (Previously, optparse took care of this for you, but I got it wrong. It was fixed at the cost of making this kind of callback more complex.) In particular, callbacks have to worry about bare -- and - arguments; the convention is:
If you want an option that takes a variable number of arguments, there are several subtle, tricky issues to worry about. The exact implementation you choose will be based on which trade-offs you're willing to make for your application (which is why optparse doesn't support this sort of thing directly).
Nevertheless, here's a stab at a callback for an option with variable arguments:
def varargs (option, opt, value, parser): assert value is None done = 0 value = [] rargs = parser.rargs while rargs: arg = rargs[0] # Stop if we hit an arg like "--foo", "-a", "-fx", "--file=f", # etc. Note that this also stops on "-3" or "-3.0", so if # your option takes numeric values, you will need to handle # this. if ((arg[:2] == "--" and len(arg) > 2) or (arg[:1] == "-" and len(arg) > 1 and arg[1] != "-")): break else: value.append(arg) del rargs[0] setattr(parser.values, option.dest, value) ... parser.add_option("-c", "--callback", action="callback", callback=varargs)
The main weakness with this particular implementation is that negative numbers in the arguments following -c will be interpreted as further options, rather than as arguments to -c. Fixing this is left as an exercise for the reader.
See About this document... for information on suggesting changes.