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.
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:
(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:
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:
bare --, if not the argument to some option,
causes command-line processing to halt and the --
itself is lost.
bare - similarly causes command-line processing to
halt, but the - itself is kept.
either -- or - can be option
arguments.
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.