1"""optik.option 2 3Defines the Option class and some standard value-checking functions. 4""" 5 6# Copyright (c) 2001-2006 Gregory P. Ward. All rights reserved. 7# See the README.txt distributed with Optik for licensing terms. 8 9import sys 10import types 11from optik.errors import OptionError, OptionValueError, gettext as _ 12 13__revision__ = "$Id: option.py 522 2006-06-11 16:22:03Z gward $" 14 15__all__ = ['Option'] 16 17# Do the right thing with boolean values for all known Python versions. 18try: 19 True, False 20except NameError: 21 (True, False) = (1, 0) 22 23_idmax = 2L * sys.maxint + 1 24 25def _repr(self): 26 return "<%s at 0x%x: %s>" % (self.__class__.__name__, 27 id(self) & _idmax, 28 self) 29 30def _parse_num(val, type): 31 if val[:2].lower() == "0x": # hexadecimal 32 radix = 16 33 elif val[:2].lower() == "0b": # binary 34 radix = 2 35 val = val[2:] or "0" # have to remove "0b" prefix 36 elif val[:1] == "0": # octal 37 radix = 8 38 else: # decimal 39 radix = 10 40 41 return type(val, radix) 42 43def _parse_int(val): 44 return _parse_num(val, int) 45 46def _parse_long(val): 47 return _parse_num(val, long) 48 49_builtin_cvt = { "int" : (_parse_int, _("integer")), 50 "long" : (_parse_long, _("long integer")), 51 "float" : (float, _("floating-point")), 52 "complex" : (complex, _("complex")) } 53 54def check_builtin(option, opt, value): 55 (cvt, what) = _builtin_cvt[option.type] 56 try: 57 return cvt(value) 58 except ValueError: 59 raise OptionValueError( 60 _("option %s: invalid %s value: %r") % (opt, what, value)) 61 62def check_choice(option, opt, value): 63 if value in option.choices: 64 return value 65 else: 66 choices = ", ".join(map(repr, option.choices)) 67 raise OptionValueError( 68 _("option %s: invalid choice: %r (choose from %s)") 69 % (opt, value, choices)) 70 71# Not supplying a default is different from a default of None, 72# so we need an explicit "not supplied" value. 73NO_DEFAULT = ("NO", "DEFAULT") 74 75 76class Option: 77 """ 78 Instance attributes: 79 _short_opts : [string] 80 _long_opts : [string] 81 82 action : string 83 type : string 84 dest : string 85 default : any 86 nargs : int 87 const : any 88 choices : [string] 89 callback : function 90 callback_args : (any*) 91 callback_kwargs : { string : any } 92 help : string 93 metavar : string 94 """ 95 96 # The list of instance attributes that may be set through 97 # keyword args to the constructor. 98 ATTRS = ['action', 99 'type', 100 'dest', 101 'default', 102 'nargs', 103 'const', 104 'choices', 105 'callback', 106 'callback_args', 107 'callback_kwargs', 108 'help', 109 'metavar'] 110 111 # The set of actions allowed by option parsers. Explicitly listed 112 # here so the constructor can validate its arguments. 113 ACTIONS = ("store", 114 "store_const", 115 "store_true", 116 "store_false", 117 "append", 118 "append_const", 119 "count", 120 "callback", 121 "help", 122 "version") 123 124 # The set of actions that involve storing a value somewhere; 125 # also listed just for constructor argument validation. (If 126 # the action is one of these, there must be a destination.) 127 STORE_ACTIONS = ("store", 128 "store_const", 129 "store_true", 130 "store_false", 131 "append", 132 "append_const", 133 "count") 134 135 # The set of actions for which it makes sense to supply a value 136 # type, ie. which may consume an argument from the command line. 137 TYPED_ACTIONS = ("store", 138 "append", 139 "callback") 140 141 # The set of actions which *require* a value type, ie. that 142 # always consume an argument from the command line. 143 ALWAYS_TYPED_ACTIONS = ("store", 144 "append") 145 146 # The set of actions which take a 'const' attribute. 147 CONST_ACTIONS = ("store_const", 148 "append_const") 149 150 # The set of known types for option parsers. Again, listed here for 151 # constructor argument validation. 152 TYPES = ("string", "int", "long", "float", "complex", "choice") 153 154 # Dictionary of argument checking functions, which convert and 155 # validate option arguments according to the option type. 156 # 157 # Signature of checking functions is: 158 # check(option : Option, opt : string, value : string) -> any 159 # where 160 # option is the Option instance calling the checker 161 # opt is the actual option seen on the command-line 162 # (eg. "-a", "--file") 163 # value is the option argument seen on the command-line 164 # 165 # The return value should be in the appropriate Python type 166 # for option.type -- eg. an integer if option.type == "int". 167 # 168 # If no checker is defined for a type, arguments will be 169 # unchecked and remain strings. 170 TYPE_CHECKER = { "int" : check_builtin, 171 "long" : check_builtin, 172 "float" : check_builtin, 173 "complex": check_builtin, 174 "choice" : check_choice, 175 } 176 177 178 # CHECK_METHODS is a list of unbound method objects; they are called 179 # by the constructor, in order, after all attributes are 180 # initialized. The list is created and filled in later, after all 181 # the methods are actually defined. (I just put it here because I 182 # like to define and document all class attributes in the same 183 # place.) Subclasses that add another _check_*() method should 184 # define their own CHECK_METHODS list that adds their check method 185 # to those from this class. 186 CHECK_METHODS = None 187 188 189 # -- Constructor/initialization methods ---------------------------- 190 191 def __init__(self, *opts, **attrs): 192 # Set _short_opts, _long_opts attrs from 'opts' tuple. 193 # Have to be set now, in case no option strings are supplied. 194 self._short_opts = [] 195 self._long_opts = [] 196 opts = self._check_opt_strings(opts) 197 self._set_opt_strings(opts) 198 199 # Set all other attrs (action, type, etc.) from 'attrs' dict 200 self._set_attrs(attrs) 201 202 # Check all the attributes we just set. There are lots of 203 # complicated interdependencies, but luckily they can be farmed 204 # out to the _check_*() methods listed in CHECK_METHODS -- which 205 # could be handy for subclasses! The one thing these all share 206 # is that they raise OptionError if they discover a problem. 207 for checker in self.CHECK_METHODS: 208 checker(self) 209 210 def _check_opt_strings(self, opts): 211 # Filter out None because early versions of Optik had exactly 212 # one short option and one long option, either of which 213 # could be None. 214 opts = filter(None, opts) 215 if not opts: 216 raise TypeError("at least one option string must be supplied") 217 return opts 218 219 def _set_opt_strings(self, opts): 220 for opt in opts: 221 if len(opt) < 2: 222 raise OptionError( 223 "invalid option string %r: " 224 "must be at least two characters long" % opt, self) 225 elif len(opt) == 2: 226 if not (opt[0] == "-" and opt[1] != "-"): 227 raise OptionError( 228 "invalid short option string %r: " 229 "must be of the form -x, (x any non-dash char)" % opt, 230 self) 231 self._short_opts.append(opt) 232 else: 233 if not (opt[0:2] == "--" and opt[2] != "-"): 234 raise OptionError( 235 "invalid long option string %r: " 236 "must start with --, followed by non-dash" % opt, 237 self) 238 self._long_opts.append(opt) 239 240 def _set_attrs(self, attrs): 241 for attr in self.ATTRS: 242 if attrs.has_key(attr): 243 setattr(self, attr, attrs[attr]) 244 del attrs[attr] 245 else: 246 if attr == 'default': 247 setattr(self, attr, NO_DEFAULT) 248 else: 249 setattr(self, attr, None) 250 if attrs: 251 attrs = attrs.keys() 252 attrs.sort() 253 raise OptionError( 254 "invalid keyword arguments: %s" % ", ".join(attrs), 255 self) 256 257 258 # -- Constructor validation methods -------------------------------- 259 260 def _check_action(self): 261 if self.action is None: 262 self.action = "store" 263 elif self.action not in self.ACTIONS: 264 raise OptionError("invalid action: %r" % self.action, self) 265 266 def _check_type(self): 267 if self.type is None: 268 if self.action in self.ALWAYS_TYPED_ACTIONS: 269 if self.choices is not None: 270 # The "choices" attribute implies "choice" type. 271 self.type = "choice" 272 else: 273 # No type given? "string" is the most sensible default. 274 self.type = "string" 275 else: 276 # Allow type objects or builtin type conversion functions 277 # (int, str, etc.) as an alternative to their names. (The 278 # complicated check of __builtin__ is only necessary for 279 # Python 2.1 and earlier, and is short-circuited by the 280 # first check on modern Pythons.) 281 import __builtin__ 282 if ( type(self.type) is types.TypeType or 283 (hasattr(self.type, "__name__") and 284 getattr(__builtin__, self.type.__name__, None) is self.type) ): 285 self.type = self.type.__name__ 286 287 if self.type == "str": 288 self.type = "string" 289 290 if self.type not in self.TYPES: 291 raise OptionError("invalid option type: %r" % self.type, self) 292 if self.action not in self.TYPED_ACTIONS: 293 raise OptionError( 294 "must not supply a type for action %r" % self.action, self) 295 296 def _check_choice(self): 297 if self.type == "choice": 298 if self.choices is None: 299 raise OptionError( 300 "must supply a list of choices for type 'choice'", self) 301 elif type(self.choices) not in (types.TupleType, types.ListType): 302 raise OptionError( 303 "choices must be a list of strings ('%s' supplied)" 304 % str(type(self.choices)).split("'")[1], self) 305 elif self.choices is not None: 306 raise OptionError( 307 "must not supply choices for type %r" % self.type, self) 308 309 def _check_dest(self): 310 # No destination given, and we need one for this action. The 311 # self.type check is for callbacks that take a value. 312 takes_value = (self.action in self.STORE_ACTIONS or 313 self.type is not None) 314 if self.dest is None and takes_value: 315 316 # Glean a destination from the first long option string, 317 # or from the first short option string if no long options. 318 if self._long_opts: 319 # eg. "--foo-bar" -> "foo_bar" 320 self.dest = self._long_opts[0][2:].replace('-', '_') 321 else: 322 self.dest = self._short_opts[0][1] 323 324 def _check_const(self): 325 if self.action not in self.CONST_ACTIONS and self.const is not None: 326 raise OptionError( 327 "'const' must not be supplied for action %r" % self.action, 328 self) 329 330 def _check_nargs(self): 331 if self.action in self.TYPED_ACTIONS: 332 if self.nargs is None: 333 self.nargs = 1 334 elif self.nargs is not None: 335 raise OptionError( 336 "'nargs' must not be supplied for action %r" % self.action, 337 self) 338 339 def _check_callback(self): 340 if self.action == "callback": 341 if not callable(self.callback): 342 raise OptionError( 343 "callback not callable: %r" % self.callback, self) 344 if (self.callback_args is not None and 345 type(self.callback_args) is not types.TupleType): 346 raise OptionError( 347 "callback_args, if supplied, must be a tuple: not %r" 348 % self.callback_args, self) 349 if (self.callback_kwargs is not None and 350 type(self.callback_kwargs) is not types.DictType): 351 raise OptionError( 352 "callback_kwargs, if supplied, must be a dict: not %r" 353 % self.callback_kwargs, self) 354 else: 355 if self.callback is not None: 356 raise OptionError( 357 "callback supplied (%r) for non-callback option" 358 % self.callback, self) 359 if self.callback_args is not None: 360 raise OptionError( 361 "callback_args supplied for non-callback option", self) 362 if self.callback_kwargs is not None: 363 raise OptionError( 364 "callback_kwargs supplied for non-callback option", self) 365 366 367 CHECK_METHODS = [_check_action, 368 _check_type, 369 _check_choice, 370 _check_dest, 371 _check_const, 372 _check_nargs, 373 _check_callback] 374 375 376 # -- Miscellaneous methods ----------------------------------------- 377 378 def __str__(self): 379 return "/".join(self._short_opts + self._long_opts) 380 381 __repr__ = _repr 382 383 def takes_value(self): 384 return self.type is not None 385 386 def get_opt_string(self): 387 if self._long_opts: 388 return self._long_opts[0] 389 else: 390 return self._short_opts[0] 391 392 393 # -- Processing methods -------------------------------------------- 394 395 def check_value(self, opt, value): 396 checker = self.TYPE_CHECKER.get(self.type) 397 if checker is None: 398 return value 399 else: 400 return checker(self, opt, value) 401 402 def convert_value(self, opt, value): 403 if value is not None: 404 if self.nargs == 1: 405 return self.check_value(opt, value) 406 else: 407 return tuple([self.check_value(opt, v) for v in value]) 408 409 def process(self, opt, value, values, parser): 410 411 # First, convert the value(s) to the right type. Howl if any 412 # value(s) are bogus. 413 value = self.convert_value(opt, value) 414 415 # And then take whatever action is expected of us. 416 # This is a separate method to make life easier for 417 # subclasses to add new actions. 418 return self.take_action( 419 self.action, self.dest, opt, value, values, parser) 420 421 def take_action(self, action, dest, opt, value, values, parser): 422 if action == "store": 423 setattr(values, dest, value) 424 elif action == "store_const": 425 setattr(values, dest, self.const) 426 elif action == "store_true": 427 setattr(values, dest, True) 428 elif action == "store_false": 429 setattr(values, dest, False) 430 elif action == "append": 431 values.ensure_value(dest, []).append(value) 432 elif action == "append_const": 433 values.ensure_value(dest, []).append(self.const) 434 elif action == "count": 435 setattr(values, dest, values.ensure_value(dest, 0) + 1) 436 elif action == "callback": 437 args = self.callback_args or () 438 kwargs = self.callback_kwargs or {} 439 self.callback(self, opt, value, parser, *args, **kwargs) 440 elif action == "help": 441 parser.print_help() 442 parser.exit() 443 elif action == "version": 444 parser.print_version() 445 parser.exit() 446 else: 447 raise RuntimeError, "unknown action %r" % self.action 448 449 return 1 450 451# class Option 452