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