pytilities.overloading.parameter

Package pytilities :: Package overloading :: Module parameter |
[hide private]
[frames] | no frames]

# Source Code for Module pytilities.overloading.parameter

      1  # Copyright (C) 2010 Tim Diels <limyreth@users.sourceforge.net>
      2  #
      3  # This file is part of pytilities.
      4  #
      5  # pytilities is free software: you can redistribute it and/or modify
      6  # it under the terms of the GNU General Public License as published by
      7  # the Free Software Foundation, either version 3 of the License, or
      8  # (at your option) any later version.
      9  #
     10  # pytilities is distributed in the hope that it will be useful,
     11  # but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13  # GNU General Public License for more details.
     14  #
     15  # You should have received a copy of the GNU General Public License
     16  # along with pytilities.  If not, see <http://www.gnu.org/licenses/>.
     17  #
     18
     19  __docformat__ = 'reStructuredText'
     20
     21  import logging
     22
     23  from .matchers import matches_everything, matches_type
     24
     25  _logger = logging.getLogger("pytilities.overloading.parameter")
     26
     27 -class Parameter(object):
     28
     29      """
     30      A parameter of an operation.
     31
     32      It can match arguments and provide default values for them.
     33
     34      Note that an argument matches a parameter, if its matcher returns True on
     35      the argument value or the parameter has a default.
     36
     37      Methods:
     38
     39          - `read_arg`: Read/process the given arg.
     40          - `read_kwargs`: Look in a dict for a matching arg and process its value
     41          - `write`: Adds the last read argument value to a dictionary.
     42      """
     43
     44      # support multiple types per param? Wait for a feature request first
     45 -    def __init__(self, name, matcher = matches_everything, *args, **kwargs):
     46          """
     47          Construct a `Parameter`.
     48
     49          Parameters:
     50
     51              `name` :: string
     52                  name of parameter as specified in keyword arguments
     53
     54              `matcher` ::
     55                  Either of:
     56
     57                      - type of the parameter
     58                      - iterable of possible types of param
     59                      - a matcher function :: f(value) -> matched::bool
     60
     61              `default`
     62                  default value for the parameter. Omit if param has no default
     63
     64          Preconditions:
     65              1. `default` must match the specified matcher
     66          """
     67
     68          assert name, "Name param musn't be empty or None"
     69          assert isinstance(name, basestring), "Name must be a string"
     70          assert len(args) <= 1, \
     71              "Unexpected trailing args: %s" % args
     72          assert not (args and "default" in kwargs), (
     73              "Default specified twice: by *args(%s) and **kwargs(%s)" %
     74              (args[0], kwargs["default"]))
     75
     76          self.__name = name
     77
     78          if hasattr(matcher, "__iter__"):
     79              # iter of types
     80              self._matcher = matches_type(*matcher)
     81          elif isinstance(matcher, type):
     82              # a single type
     83              self._matcher = matches_type(matcher)
     84          else:
     85              # it's a matcher function
     86              self._matcher = matcher
     87
     88          self.__has_default = True
     89          if args:
     90              self.__default = args[0]
     91          elif "default" in kwargs:
     92              self.__default = kwargs["default"]
     93          else:
     94              self.__has_default = False
     95
     96          assert not self.__has_default or \
     97                  self._matcher(self.__default), (
     98                  "Default must match the given matcher as well. (Precondition 1) Default: %s" %
     99                      (self.__default))
    100
    101          # whether or not last read was a match
    102          self.__matched = False
    103
    104      # Note: the two step (read all, then write) process is necessary to allow for
    105      # self validating parameters in the future. This allows them to return True at
    106      # read when they match, and throw errors at write when the overload apparantly
    107      # matched and their values will actually be used. (at time of read that is not
    108      # yet certain)
    109 -    def read_arg(self, arg):
    110          """
    111          Read/process the given arg.
    112
    113          Parameters:
    114
    115              `arg`
    116                  the argument value to read
    117
    118          Returns True if parameter matches `arg` :: bool
    119          """
    120          self.__value = arg
    121          self.__matched = self._matcher(self.__value)
    122          return self.__matched
    123
    124 -    def read_kwargs(self, kwargs):
    125          """
    126          Look in a dict for a matching arg and process its value.
    127
    128          Parameters:
    129
    130              `kwargs` :: {name::string : value}
    131                  dictionary of arguments
    132
    133          Returns True if a matching argument was found in `kwargs` :: bool
    134          """
    135
    136          if self.__name in kwargs:
    137              return self.read_arg(kwargs[self.__name])
    138          elif self.__has_default:
    139              self.__matched = True
    140              self.__value = self.__default
    141          else:
    142              self.__matched = False
    143
    144          return self.__matched
    145
    146 -    def write(self, kwargs):
    147          """
    148          Adds the last read argument value to a dictionary.
    149
    150          Parameters:
    151
    152              `kwargs` :: {name::string : value}
    153                  the dictionary to add the last value and the parameter name to
    154
    155          Preconditions:
    156
    157              1. the parameter matched on the last read
    158          """
    159
    160          assert self.__matched, \
    161                 "write() may only be called after a succesful read()"
    162
    163          kwargs[self.__name] = self.__value
    164
    165      @property
    166 -    def _matched(self):
    167          return self.__matched
    168
    169
    170  # a shortcut
    171  Param = Parameter
    172
    173  # TODO: write a validation.py or something like that, add in lots of fun stuff
    174  # like self-validating Parameters that we can then use here! (e.g. check for
    175  # None values etc)
    176  # or add using Strategy pattern: Validator(s)
    177