3 Defines the Option class and some standard value-checking functions.
5 Cheetah modifications: added "Cheetah.Utils.optik." prefix to
6 all intra-Optik imports.
9 __revision__
= "$Id: option.py,v 1.2 2002/09/12 06:56:51 hierro Exp $"
11 # Copyright (c) 2001 Gregory P. Ward. All rights reserved.
12 # See the README.txt distributed with Optik for licensing terms.
14 # created 2001/10/17, GPW (from optik.py)
17 from types
import TupleType
, DictType
18 from Cheetah
.Utils
.optik
.errors
import OptionError
, OptionValueError
20 _builtin_cvt
= { "int" : (int, "integer"),
21 "long" : (long, "long integer"),
22 "float" : (float, "floating-point"),
23 "complex" : (complex, "complex") }
25 def check_builtin (option
, opt
, value
):
26 (cvt
, what
) = _builtin_cvt
[option
.type]
30 raise OptionValueError(
31 #"%s: invalid %s argument %r" % (opt, what, value))
32 "option %s: invalid %s value: %r" % (opt
, what
, value
))
34 # Not supplying a default is different from a default of None,
35 # so we need an explicit "not supplied" value.
36 NO_DEFAULT
= "NO"+"DEFAULT"
42 _short_opts : [string]
52 callback_args : (any*)
53 callback_kwargs : { string : any }
58 # The list of instance attributes that may be set through
59 # keyword args to the constructor.
72 # The set of actions allowed by option parsers. Explicitly listed
73 # here so the constructor can validate its arguments.
84 # The set of actions that involve storing a value somewhere;
85 # also listed just for constructor argument validation. (If
86 # the action is one of these, there must be a destination.)
87 STORE_ACTIONS
= ("store",
94 # The set of actions for which it makes sense to supply a value
95 # type, ie. where we expect an argument to this option.
96 TYPED_ACTIONS
= ("store",
100 # The set of known types for option parsers. Again, listed here for
101 # constructor argument validation.
102 TYPES
= ("string", "int", "long", "float", "complex")
104 # Dictionary of argument checking functions, which convert and
105 # validate option arguments according to the option type.
107 # Signature of checking functions is:
108 # check(option : Option, opt : string, value : string) -> any
110 # option is the Option instance calling the checker
111 # opt is the actual option seen on the command-line
112 # (eg. "-a", "--file")
113 # value is the option argument seen on the command-line
115 # The return value should be in the appropriate Python type
116 # for option.type -- eg. an integer if option.type == "int".
118 # If no checker is defined for a type, arguments will be
119 # unchecked and remain strings.
120 TYPE_CHECKER
= { "int" : check_builtin
,
121 "long" : check_builtin
,
122 "float" : check_builtin
,
123 "complex" : check_builtin
,
127 # CHECK_METHODS is a list of unbound method objects; they are called
128 # by the constructor, in order, after all attributes are
129 # initialized. The list is created and filled in later, after all
130 # the methods are actually defined. (I just put it here because I
131 # like to define and document all class attributes in the same
132 # place.) Subclasses that add another _check_*() method should
133 # define their own CHECK_METHODS list that adds their check method
134 # to those from this class.
138 # -- Constructor/initialization methods ----------------------------
140 def __init__ (self
, *opts
, **attrs
):
141 # Set _short_opts, _long_opts attrs from 'opts' tuple
142 opts
= self
._check
_opt
_strings
(opts
)
143 self
._set
_opt
_strings
(opts
)
145 # Set all other attrs (action, type, etc.) from 'attrs' dict
146 self
._set
_attrs
(attrs
)
148 # Check all the attributes we just set. There are lots of
149 # complicated interdependencies, but luckily they can be farmed
150 # out to the _check_*() methods listed in CHECK_METHODS -- which
151 # could be handy for subclasses! The one thing these all share
152 # is that they raise OptionError if they discover a problem.
153 for checker
in self
.CHECK_METHODS
:
156 def _check_opt_strings (self
, opts
):
157 # Filter out None because early versions of Optik had exactly
158 # one short option and one long option, either of which
160 opts
= filter(None, opts
)
162 raise OptionError("at least one option string must be supplied",
166 def _set_opt_strings (self
, opts
):
167 self
._short
_opts
= []
172 "invalid option string %r: "
173 "must be at least two characters long" % opt
, self
)
175 if not (opt
[0] == "-" and opt
[1] != "-"):
177 "invalid short option string %r: "
178 "must be of the form -x, (x any non-dash char)" % opt
,
180 self
._short
_opts
.append(opt
)
182 if not (opt
[0:2] == "--" and opt
[2] != "-"):
184 "invalid long option string %r: "
185 "must start with --, followed by non-dash" % opt
,
187 self
._long
_opts
.append(opt
)
189 def _set_attrs (self
, attrs
):
190 for attr
in self
.ATTRS
:
191 if attrs
.has_key(attr
):
192 setattr(self
, attr
, attrs
[attr
])
195 if attr
== 'default':
196 setattr(self
, attr
, NO_DEFAULT
)
198 setattr(self
, attr
, None)
201 "invalid keyword arguments: %s" % ", ".join(attrs
.keys()),
205 # -- Constructor validation methods --------------------------------
207 def _check_action (self
):
208 if self
.action
is None:
209 self
.action
= "store"
210 elif self
.action
not in self
.ACTIONS
:
211 raise OptionError("invalid action: %r" % self
.action
, self
)
213 def _check_type (self
):
214 if self
.type is None:
215 # XXX should factor out another class attr here: list of
216 # actions that *require* a type
217 if self
.action
in ("store", "append"):
218 # No type given? "string" is the most sensible default.
221 if self
.type not in self
.TYPES
:
222 raise OptionError("invalid option type: %r" % self
.type, self
)
223 if self
.action
not in self
.TYPED_ACTIONS
:
225 "must not supply a type for action %r" % self
.action
, self
)
227 def _check_dest (self
):
228 if self
.action
in self
.STORE_ACTIONS
and self
.dest
is None:
229 # No destination given, and we need one for this action.
230 # Glean a destination from the first long option string,
231 # or from the first short option string if no long options.
233 # eg. "--foo-bar" -> "foo_bar"
234 self
.dest
= self
._long
_opts
[0][2:].replace('-', '_')
236 self
.dest
= self
._short
_opts
[0][1]
238 def _check_const (self
):
239 if self
.action
!= "store_const" and self
.const
is not None:
241 "'const' must not be supplied for action %r" % self
.action
,
244 def _check_nargs (self
):
245 if self
.action
in self
.TYPED_ACTIONS
:
246 if self
.nargs
is None:
248 elif self
.nargs
is not None:
250 "'nargs' must not be supplied for action %r" % self
.action
,
253 def _check_callback (self
):
254 if self
.action
== "callback":
255 if not callable(self
.callback
):
257 "callback not callable: %r" % self
.callback
, self
)
258 if (self
.callback_args
is not None and
259 type(self
.callback_args
) is not TupleType
):
261 "callback_args, if supplied, must be a tuple: not %r"
262 % self
.callback_args
, self
)
263 if (self
.callback_kwargs
is not None and
264 type(self
.callback_kwargs
) is not DictType
):
266 "callback_kwargs, if supplied, must be a dict: not %r"
267 % self
.callback_kwargs
, self
)
269 if self
.callback
is not None:
271 "callback supplied (%r) for non-callback option"
272 % self
.callback
, self
)
273 if self
.callback_args
is not None:
275 "callback_args supplied for non-callback option", self
)
276 if self
.callback_kwargs
is not None:
278 "callback_kwargs supplied for non-callback option", self
)
281 CHECK_METHODS
= [_check_action
,
289 # -- Miscellaneous methods -----------------------------------------
292 if self
._short
_opts
or self
._long
_opts
:
293 return "/".join(self
._short
_opts
+ self
._long
_opts
)
295 raise RuntimeError, "short_opts and long_opts both empty!"
297 def takes_value (self
):
298 return self
.type is not None
301 # -- Processing methods --------------------------------------------
303 def check_value (self
, opt
, value
):
304 checker
= self
.TYPE_CHECKER
.get(self
.type)
308 return checker(self
, opt
, value
)
310 def process (self
, opt
, value
, values
, parser
):
312 # First, convert the value(s) to the right type. Howl if any
313 # value(s) are bogus.
314 if value
is not None:
316 value
= self
.check_value(opt
, value
)
318 value
= tuple([self
.check_value(opt
, v
) for v
in value
])
320 # And then take whatever action is expected of us.
321 # This is a separate method to make life easier for
322 # subclasses to add new actions.
323 return self
.take_action(
324 self
.action
, self
.dest
, opt
, value
, values
, parser
)
326 def take_action (self
, action
, dest
, opt
, value
, values
, parser
):
327 if action
== "store":
328 setattr(values
, dest
, value
)
329 elif action
== "store_const":
330 setattr(values
, dest
, self
.const
)
331 elif action
== "store_true":
332 setattr(values
, dest
, 1)
333 elif action
== "store_false":
334 setattr(values
, dest
, 0)
335 elif action
== "append":
336 values
.ensure_value(dest
, []).append(value
)
337 elif action
== "count":
338 setattr(values
, dest
, values
.ensure_value(dest
, 0) + 1)
339 elif action
== "callback":
340 args
= self
.callback_args
or ()
341 kwargs
= self
.callback_kwargs
or {}
342 self
.callback(self
, opt
, value
, parser
, *args
, **kwargs
)
343 elif action
== "help":
346 elif action
== "version":
347 parser
.print_version()
350 raise RuntimeError, "unknown action %r" % self
.action