6.20.5.2 Adding new actions
Adding new actions is a bit trickier, because you have to understand that optparse has a couple of classifications for actions:
- ``store'' actions
- actions that result in optparse storing a value to an attribute
of the OptionValues instance; these options require a dest attribute to be
supplied to the Option constructor
- ``typed'' actions
- actions that take a value from the command line and expect it to be of a certain type;
or rather, a string that can be converted to a certain type. These options require a type
attribute to the Option constructor.
Some default ``store'' actions are store, store_const, append,
and count. The default ``typed'' actions are store, append,
and callback.
When you add an action, you need to decide if it's a ``store'' action, a ``typed'',
neither, or both. Three class attributes of Option (or your Option subclass) control this:
- ACTIONS
- All actions must be listed as strings in ACTIONS.
- STORE_ACTIONS
- ``store'' actions are additionally listed here.
- TYPED_ACTIONS
- ``typed'' actions are additionally listed here.
In order to actually implement your new action, you must override Option's
take_action() method and add a case that recognizes your action.
For example, let's add an ``extend'' action. This is similar to the standard ``append''
action, but instead of taking a single value from the command-line and appending it to an
existing list, ``extend'' will take multiple values in a single comma-delimited string, and
extend an existing list with them. That is, if --names is an
``extend'' option of type string, the command line:
--names=foo,bar --names blah --names ding,dong
would result in a list:
["foo", "bar", "blah", "ding", "dong"]
Again we define a subclass of Option:
class MyOption (Option):
ACTIONS = Option.ACTIONS + ("extend",)
STORE_ACTIONS = Option.STORE_ACTIONS + ("extend",)
TYPED_ACTIONS = Option.TYPED_ACTIONS + ("extend",)
def take_action (self, action, dest, opt, value, values, parser):
if action == "extend":
lvalue = value.split(",")
values.ensure_value(dest, []).extend(lvalue)
else:
Option.take_action(
self, action, dest, opt, value, values, parser)
Features of note:
- ``extend'' both expects a value on the command-line and stores that value somewhere, so
it goes in both STORE_ACTIONS and TYPED_ACTIONS.
- MyOption.take_action() implements just this one new action, and
passes control back to Option.take_action() for the standard optparse actions.
- values is an instance of the Values class, which
provides the very useful ensure_value() method. ensure_value()
is essentially getattr() with a safety valve; it is called as:
values.ensure_value(attr, value)
If the attr attribute of values doesn't exist or is None,
then ensure_value() first sets it to value, and then
returns value. This is very handy for actions like ``extend'', ``append'', and
``count'', all of which accumulate data in a variable and expect that variable to be of a
certain type (a list for the first two, an integer for the latter). Using ensure_value()
means that scripts using your action don't have to worry about setting a default value for the
option destinations in question; they can just leave the default as None and ensure_value() will take care of getting it right when it's needed.
|