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