Module Task
[hide private]
[frames] | no frames]

Source Code for Module Task

  1  # Copyright (C) 2005, 2006 Joint Institute for VLBI in Europe 
  2  # 
  3  # This program is free software; you can redistribute it and/or modify 
  4  # it under the terms of the GNU General Public License as published by 
  5  # the Free Software Foundation; either version 2 of the License, or 
  6  # (at your option) any later version. 
  7  # 
  8  # This program is distributed in the hope that it will be useful, 
  9  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 10  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 11  # GNU General Public License for more details. 
 12   
 13  # You should have received a copy of the GNU General Public License 
 14  # along with this program; if not, write to the Free Software 
 15  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
 16   
 17  """ 
 18  This module provides the Task class.  It extends the MinimalMatch 
 19  class from the MinimalMatch module with type and range checking on its 
 20  attributes: 
 21   
 22  >>> class MyTask(Task): 
 23  ...     indisk = 0 
 24  ...     inseq  = 0 
 25  ...     infile = '' 
 26  ...     pixavg = 1.0 
 27  ...     aparms = 10*[0.0] 
 28  ...     def __init__(self): 
 29  ...         Task.__init__(self) 
 30  ...         self._min_dict = {'inseq': 0, 'aparms': 0} 
 31  ...         self._max_dict = {'inseq': 4, 'aparms': 10} 
 32  ...         self._strlen_dict = {'infile': 14} 
 33  ...         self.__dict__['bparms'] = List(self, 'bparms', [None, 1, 2, 3]) 
 34  ... 
 35  >>> my_task = MyTask() 
 36   
 37  It still has the property that attribute names can be abbreviated: 
 38   
 39  >>> print my_task.ind 
 40  0 
 41  >>> my_task.ind = 1 
 42  >>> print my_task.ind 
 43  1 
 44   
 45  But an exception will be thrown if you try to assign a value that is 
 46  out of range: 
 47   
 48  >>> my_task.ins = 5 
 49  Traceback (most recent call last): 
 50    ... 
 51  ValueError: value '5' is out of range for attribute 'inseq' 
 52   
 53  Or if you try to assign a value that has the wrong type, such 
 54  assigning a string to an integer attribute: 
 55   
 56  >>> my_task.ind = 'now' 
 57  Traceback (most recent call last): 
 58    ... 
 59  TypeError: value 'now' has invalid type for attribute 'indisk' 
 60   
 61  Assigning strings to string attributes works fine of course: 
 62   
 63  >>> my_task.infile = 'short' 
 64   
 65  As long as there is no limit on the length of a string: 
 66   
 67  >>> my_task.infile = 'tremendouslylong' 
 68  Traceback (most recent call last): 
 69    ... 
 70  ValueError: string 'tremendouslylong' is too long for attribute 'infile' 
 71   
 72  Assigning an integer value to a floating point attribute is perfectly 
 73  fine of course: 
 74   
 75  >>> my_task.pixavg = 2 
 76  >>> print my_task.pixavg 
 77  2.0 
 78   
 79  The same should happen for lists: 
 80   
 81  >>> my_task.aparms = 10*[1] 
 82  >>> print my_task.aparms 
 83  [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0] 
 84   
 85  For subscripting: 
 86   
 87  >>> my_task.aparms[0] = 0 
 88  >>> print my_task.aparms 
 89  [0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0] 
 90   
 91  And slice assignment: 
 92   
 93  >>> my_task.aparms[1:3] = [1, 2] 
 94  >>> print my_task.aparms 
 95  [0.0, 1.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0] 
 96   
 97  You're not allowed to change the length of the list through slice 
 98  assignment though: 
 99   
100  >>> my_task.aparms[3:6] = [3, 4, 5, 6] 
101  Traceback (most recent call last): 
102    ... 
103  TypeError: slice '3:6' changes the array size of attribute 'aparms' 
104   
105  To provide 1-based indexing used by several packages, you can set the 
106  element at index zero of an array to 'None'.  This prevents setting that 
107  element to anything other than 'None' 
108   
109  >>> my_task.bparms[0] = 0 
110  Traceback (most recent call last): 
111    ... 
112  ValueError: setting element '0' is prohibited 
113   
114  """ 
115   
116  from MinimalMatch import MinimalMatch 
117   
118  # Generic Python stuff 
119  import copy, pydoc, sys 
120   
121 -class List(list):
122 - def __init__(self, task, attr, value):
123 self._task = task 124 self._attr = attr 125 _value = [] 126 for item in value: 127 if isinstance(item, list): 128 _value.append(List(task, attr, item)) 129 else: 130 _value.append(item) 131 pass 132 continue 133 list.extend(self, _value) 134 return
135
136 - def __setitem__(self, key, item):
137 if item != None and self[key] == None: 138 msg = "setting element '%d' is prohibited" % key 139 raise ValueError, msg 140 item = self._task._validateattr(self._attr, item, self[key]) 141 list.__setitem__(self, key, item) 142 return
143
144 - def __setslice__(self, low, high, seq):
145 high = min (high, len(self)) 146 if len(seq) > high - low or \ 147 (len(seq) < high - low and high < len(self)): 148 msg = "slice '%d:%d' changes the array size of" \ 149 " attribute '%s'" % (low, high, self._attr) 150 raise TypeError, msg 151 for key in xrange(low, high): 152 if key - low < len(seq): 153 self[key] = seq[key - low] 154 else: 155 default = self._task._default_dict[self._attr][key] 156 self[key] = copy.copy(default) 157 pass 158 continue 159 return
160 161
162 -class Task(MinimalMatch):
163 - def __init__(self):
164 self._default_dict = {} 165 self._min_dict = {} 166 self._max_dict = {} 167 self._strlen_dict = {} 168 self._help_string = '' 169 return
170
171 - def help(self):
172 """Display help for this task.""" 173 174 if self._help_string: 175 pydoc.pager(self._help_string) 176 pass 177 178 return
179
180 - def _validateattr(self, attr, value, default):
181 """Check whether VALUE is a valid valid for attribute ATTR.""" 182 183 # Do not check private attributes. 184 if attr.startswith('_'): 185 return value 186 187 # Short circuit. 188 if value == None and default == None: 189 return value 190 191 # Handle lists recursively. 192 if isinstance(value, list) and isinstance(default, list): 193 if len(value) > len(default): 194 msg = "array '%s' is too big for attribute '%s'" \ 195 % (value, attr) 196 raise TypeError, msg 197 validated_value = List(self, attr, default) 198 for key in xrange(len(value)): 199 validated_value[key] = value[key] 200 return validated_value 201 202 # Convert integers into floating point numbers if necessary. 203 if type(value) == int and type(default) == float: 204 value = float(value) 205 pass 206 207 # Check attribute type. 208 if type(value) != type(default): 209 msg = "value '%s' has invalid type for attribute '%s'" \ 210 % (value, attr) 211 raise TypeError, msg 212 213 # Check range. 214 if attr in self._min_dict: 215 min = self._min_dict[attr] 216 if not min <= value: 217 msg = "value '%s' is out of range for attribute '%s'" \ 218 % (value, attr) 219 raise ValueError, msg 220 pass 221 if attr in self._max_dict: 222 max = self._max_dict[attr] 223 if not value <= max: 224 msg = "value '%s' is out of range for attribute '%s'" \ 225 % (value, attr) 226 raise ValueError, msg 227 pass 228 229 # Check string length. 230 if attr in self._strlen_dict: 231 if len(value) > self._strlen_dict[attr]: 232 msg = "string '%s' is too long for attribute '%s'" \ 233 % (value, attr) 234 raise ValueError, msg 235 pass 236 237 return value
238
239 - def __setattr__(self, name, value):
240 attr = self._findattr(name) 241 242 # Validate based on the value already present. 243 if hasattr(self, attr): 244 value = self._validateattr(attr, value, getattr(self, attr)) 245 self.__dict__[attr] = value 246 247 return
248 249 250 # Tests. 251 if __name__ == '__main__': 252 import doctest, sys 253 results = doctest.testmod(sys.modules[__name__]) 254 sys.exit(results[0]) 255