1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
119 import copy, pydoc, sys
120
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
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
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):
164 self._default_dict = {}
165 self._min_dict = {}
166 self._max_dict = {}
167 self._strlen_dict = {}
168 self._help_string = ''
169 return
170
172 """Display help for this task."""
173
174 if self._help_string:
175 pydoc.pager(self._help_string)
176 pass
177
178 return
179
181 """Check whether VALUE is a valid valid for attribute ATTR."""
182
183
184 if attr.startswith('_'):
185 return value
186
187
188 if value == None and default == None:
189 return value
190
191
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
203 if type(value) == int and type(default) == float:
204 value = float(value)
205 pass
206
207
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
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
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
240 attr = self._findattr(name)
241
242
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
251 if __name__ == '__main__':
252 import doctest, sys
253 results = doctest.testmod(sys.modules[__name__])
254 sys.exit(results[0])
255