Initial Commit
[Projects.git] / pkgbuilds / pytivo / pkg / usr / share / pyTivo / Cheetah / Utils / optik / option.py
blobac85c3d2df21d850b6b00c077a61f01ffcfd01fe
1 """optik.option
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.
7 """
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)
16 import sys
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]
27 try:
28 return cvt(value)
29 except ValueError:
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"
39 class Option:
40 """
41 Instance attributes:
42 _short_opts : [string]
43 _long_opts : [string]
45 action : string
46 type : string
47 dest : string
48 default : any
49 nargs : int
50 const : any
51 callback : function
52 callback_args : (any*)
53 callback_kwargs : { string : any }
54 help : string
55 metavar : string
56 """
58 # The list of instance attributes that may be set through
59 # keyword args to the constructor.
60 ATTRS = ['action',
61 'type',
62 'dest',
63 'default',
64 'nargs',
65 'const',
66 'callback',
67 'callback_args',
68 'callback_kwargs',
69 'help',
70 'metavar']
72 # The set of actions allowed by option parsers. Explicitly listed
73 # here so the constructor can validate its arguments.
74 ACTIONS = ("store",
75 "store_const",
76 "store_true",
77 "store_false",
78 "append",
79 "count",
80 "callback",
81 "help",
82 "version")
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",
88 "store_const",
89 "store_true",
90 "store_false",
91 "append",
92 "count")
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",
97 "append",
98 "callback")
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
109 # where
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.
135 CHECK_METHODS = None
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:
154 checker(self)
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
159 # could be None.
160 opts = filter(None, opts)
161 if not opts:
162 raise OptionError("at least one option string must be supplied",
163 self)
164 return opts
166 def _set_opt_strings (self, opts):
167 self._short_opts = []
168 self._long_opts = []
169 for opt in opts:
170 if len(opt) < 2:
171 raise OptionError(
172 "invalid option string %r: "
173 "must be at least two characters long" % opt, self)
174 elif len(opt) == 2:
175 if not (opt[0] == "-" and opt[1] != "-"):
176 raise OptionError(
177 "invalid short option string %r: "
178 "must be of the form -x, (x any non-dash char)" % opt,
179 self)
180 self._short_opts.append(opt)
181 else:
182 if not (opt[0:2] == "--" and opt[2] != "-"):
183 raise OptionError(
184 "invalid long option string %r: "
185 "must start with --, followed by non-dash" % opt,
186 self)
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])
193 del attrs[attr]
194 else:
195 if attr == 'default':
196 setattr(self, attr, NO_DEFAULT)
197 else:
198 setattr(self, attr, None)
199 if attrs:
200 raise OptionError(
201 "invalid keyword arguments: %s" % ", ".join(attrs.keys()),
202 self)
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.
219 self.type = "string"
220 else:
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:
224 raise OptionError(
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.
232 if self._long_opts:
233 # eg. "--foo-bar" -> "foo_bar"
234 self.dest = self._long_opts[0][2:].replace('-', '_')
235 else:
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:
240 raise OptionError(
241 "'const' must not be supplied for action %r" % self.action,
242 self)
244 def _check_nargs (self):
245 if self.action in self.TYPED_ACTIONS:
246 if self.nargs is None:
247 self.nargs = 1
248 elif self.nargs is not None:
249 raise OptionError(
250 "'nargs' must not be supplied for action %r" % self.action,
251 self)
253 def _check_callback (self):
254 if self.action == "callback":
255 if not callable(self.callback):
256 raise OptionError(
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):
260 raise OptionError(
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):
265 raise OptionError(
266 "callback_kwargs, if supplied, must be a dict: not %r"
267 % self.callback_kwargs, self)
268 else:
269 if self.callback is not None:
270 raise OptionError(
271 "callback supplied (%r) for non-callback option"
272 % self.callback, self)
273 if self.callback_args is not None:
274 raise OptionError(
275 "callback_args supplied for non-callback option", self)
276 if self.callback_kwargs is not None:
277 raise OptionError(
278 "callback_kwargs supplied for non-callback option", self)
281 CHECK_METHODS = [_check_action,
282 _check_type,
283 _check_dest,
284 _check_const,
285 _check_nargs,
286 _check_callback]
289 # -- Miscellaneous methods -----------------------------------------
291 def __str__ (self):
292 if self._short_opts or self._long_opts:
293 return "/".join(self._short_opts + self._long_opts)
294 else:
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)
305 if checker is None:
306 return value
307 else:
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:
315 if self.nargs == 1:
316 value = self.check_value(opt, value)
317 else:
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":
344 parser.print_help()
345 sys.exit(0)
346 elif action == "version":
347 parser.print_version()
348 sys.exit(0)
349 else:
350 raise RuntimeError, "unknown action %r" % self.action
352 return 1
354 # class Option