Package npsgd :: Module model_parameters
[hide private]
[frames] | no frames]

Source Code for Module npsgd.model_parameters

  1  # Author: Thomas Dimson [tdimson@gmail.com] 
  2  # Date:   January 2011 
  3  # For distribution details, see LICENSE 
  4  """Module holding all types of model parameters.""" 
  5  import copy 
  6  import logging 
  7   
8 -class ValidationError(RuntimeError): pass
9 -class MissingError(RuntimeError): pass
10
11 -class ModelParameter(object):
12 """Model parameter - keeps track of arguments to a model. 13 14 This object has a dual purpose, first to declare the parameters 15 that are actually needed by a module and secondly to keep track 16 of the values of that parameter. To switch between the two, a 17 call to "withValue" creates a copy of the parameter, this time 18 with a given value. 19 20 Note: this is a lot less screwy than it sounds. 21 """
22 - def __init__(self, name):
23 self.name = name
24
25 - def withValue(self, value):
26 """Instantiates a copy of the model parameter with a given value. 27 28 The setValue method will return a ValidationError if validation fails, so 29 this method implicitly performs parameter verification. 30 """ 31 32 ret = copy.copy(self) 33 ret.setValue(value) 34 return ret
35
36 - def asDict(self):
37 return { 38 "name" : self.name, 39 "value": self.value 40 }
41
42 - def fromDict(self, d):
43 if d["name"] != self.name: 44 raise ValidationError("Trying to instantiate the wrong parameter (called '%s' for '%s')",\ 45 self.name, d["name"]) 46 47 return self.withValue(d["value"])
48
49 - def asMatlabCode(self):
50 """Converts an instance of this parameter (with value) into matlab code. 51 52 This is used to inject copies of the parameters __directly__ into the Matlab 53 namespace. 54 """ 55 56 logging.warning("Unable to convert parameter '%s' to matlab code", self.name) 57 return "%s='UNABLE TO CONVERT TO MATLAB';" % self.value
58
59 - def asHTML(self):
60 """Returns this parameter as HTML.""" 61 62 return "No HTML for this parameter type"
63
64 - def hiddenHTML(self):
65 """Returns this parameter as hidden HTML.""" 66 67 return "No hidden HTML for this parameter type"
68
69 - def helpHTML(self):
70 """Returns HTML helptext for this parameter (directly for inclusion)""" 71 72 if self.helpText: 73 img = "<img src='/static/images/question_mark_icon.gif' />" 74 return "<a href='#' class='modelParameterHelp' data-helpText='%s'>%s</a>" \ 75 % (htmlAttributeEscape(self.helpText), img) 76 else: 77 return ""
78
79 - def nonExistValue(self):
80 """Gives a value of this parameter does not exist (i.e. in a post request). 81 82 This is mostly useful for the screwy way browsers handle "checkbox" parameters, 83 by simply not sending the key when the checkbox is unchecked. 84 """ 85 86 raise MissingError("Missing value")
87 88
89 -class SelectParameter(ModelParameter):
90 """Parameter type for selecting from a fixed set of string options (like a combo box).""" 91
92 - def __init__(self, name, options=[], description="", default=None, hidden=False, helpText=""):
93 self.name = name 94 95 if len(options) == 0: 96 raise ValidationError("Select parameter '%s' specified with no options" % name) 97 98 self.options = options 99 self.description = description 100 self.units = "" 101 102 if default == None: 103 default = self.options[0] 104 105 self.default = default 106 self.hidden = hidden 107 self.helpText = helpText 108 109 self.setValue(self.default)
110
111 - def setValue(self, value):
112 checkVal = str(value) 113 if checkVal not in self.options: 114 raise ValidationError("Attempted to set ComboParameter with invalid value '%s'" % value) 115 116 self.value = value
117
118 - def asMatlabCode(self):
119 if self.value: 120 return "%s='%s'" % (self.name, self.value) 121 else: 122 return "%s='%s'" % (self.name, self.value)
123
124 - def asTextRow(self):
125 return "%s: %s %s" % (self.description, self.value, self.units)
126
127 - def asLatexRow(self):
128 return "%s & %s %s" % (self.description, latexEscape(self.valueString()), latexEscape(self.units))
129
130 - def valueString(self):
131 return str(self.value)
132
133 - def hiddenHTML(self):
134 return "<tr><td></td><td><input type='hidden' name='%s' value='%s' /></td></tr>" % (self.name, self.valueString())
135
136 - def asHTML(self):
137 if self.hidden: 138 return self.hiddenHTML() 139 140 optionSelections = [] 141 for option in self.options: 142 if option == self.default: 143 optionSelections.append("<option value='%s' selected='selected'>%s</option>" % (option, option)) 144 else: 145 optionSelections.append("<option value='%s'>%s</option>" % (option, option)) 146 147 return "<tr><td><label for='%s'>%s</label></td><td><select name='%s'/>%s</select> %s</td></tr>" %\ 148 (self.name, self.description, self.name, "".join(optionSelections), self.helpHTML())
149
150 -class BooleanParameter(ModelParameter):
151 """Parameter type for selecting true/false values.""" 152
153 - def __init__(self, name, description="", default=False, hidden=False, helpText=""):
154 self.name = name 155 self.description = description 156 self.units = "" 157 self.default = default 158 self.hidden = hidden 159 self.helpText = helpText 160 161 self.setValue(self.default)
162
163 - def setValue(self, value):
164 self.value = bool(value)
165
166 - def asMatlabCode(self):
167 if self.value: 168 return "%s=1" % (self.name) 169 else: 170 return "%s=0" % (self.name)
171
172 - def asTextRow(self):
173 return "%s: %s %s" % (self.description, self.value, self.units)
174
175 - def asLatexRow(self):
176 return "%s & %s %s" % (self.description, latexEscape(self.valueString()), latexEscape(self.units))
177
178 - def valueString(self):
179 return str(self.value)
180
181 - def hiddenHTML(self):
182 return "<tr><td></td><td><input type='hidden' name='%s' value='%s' /></td></tr>" % (self.name, self.valueString())
183
184 - def asHTML(self):
185 if self.hidden: 186 return self.hiddenHTML() 187 188 if self.value: 189 checkedString = "checked='checked'" 190 else: 191 checkedString = "" 192 193 return "<tr><td><label for='%s'>%s</label></td><td><input type='checkbox' name='%s' value='%s' %s/> %s</td></tr>" %\ 194 (self.name, self.description, self.name, self.valueString(), checkedString, self.helpHTML())
195
196 - def nonExistValue(self):
197 return False
198
199 -class StringParameter(ModelParameter):
200 """Parameter type for selecting string values.""" 201
202 - def __init__(self, name, description="", units="", default=None, hidden=False, helpText=""):
203 self.name = name 204 self.description = description 205 self.units = units 206 self.default = default 207 self.value = None 208 self.hidden = hidden 209 self.helpText = helpText 210 if default != None: 211 self.setValue(self.default)
212
213 - def setValue(self, value):
214 self.value = str(value)
215
216 - def asMatlabCode(self):
217 return "%s='%s';" % (self.name, matlabEscape(self.value))
218
219 - def asTextRow(self):
220 return "%s: %s %s" % (self.description, self.value, self.units)
221
222 - def asLatexRow(self):
223 return "%s & %s %s" % (self.description, latexEscape(self.valueString()), latexEscape(self.units))
224
225 - def valueString(self):
226 if self.value == None: 227 valueString = "" 228 else: 229 valueString = str(self.value) 230 231 return valueString
232
233 - def hiddenHTML(self):
234 return "<tr><td></td><td><input type='hidden' name='%s' value='%s' /></td></tr>" % (self.name, self.valueString())
235
236 - def asHTML(self):
237 if self.hidden: 238 return self.hiddenHTML() 239 240 return "<tr><td><label for='%s'>%s</label></td><td><input type='text' name='%s' value='%s'/> %s</td></tr>" %\ 241 (self.name, self.description, self.name, self.valueString(), self.helpHTML())
242 243
244 -class RangeParameter(ModelParameter):
245 """Parameter type for selecting a range of floats (e.g. 420.4nm-500nm) at a fixed step.""" 246
247 - def __init__(self, name, description="", rangeStart=1.0, rangeEnd=10.0, \ 248 step=1.0, units="", default=None, hidden=False, helpText=""):
249 self.name = name 250 self.description = description 251 self.rangeStart = rangeStart 252 self.rangeEnd = rangeEnd 253 self.step = step 254 self.default = None 255 self.units = units 256 self.hidden = hidden 257 self.helpText = helpText 258 self.value = None 259 260 if default != None: 261 self.setValue(self.default)
262
263 - def setValue(self, value):
264 if isinstance(value, basestring): 265 start, end = [float(e.strip()) for e in value.split("-")] 266 else: 267 start, end = map(float, value) 268 269 if start > end: 270 raise ValidationError("%s starts after it ends (%s-%s)" % 271 (self.name, start, end)) 272 273 if start < self.rangeStart: 274 raise ValidationError("%s start value of '%s' less than minimum '%s'" % 275 (self.name, start, self.rangeStart)) 276 277 if end > self.rangeEnd: 278 raise ValidationError("%s end value of '%s' greater than maximum '%s'" % 279 (self.name, end, self.rangeEnd)) 280 281 282 self.value = (start, end)
283
284 - def asMatlabCode(self):
285 start, end = self.value 286 return "%sStart=%s;\n%sEnd=%s;\n%s=%s:%s:%s;" % (self.name, start, self.name, end, self.name, start, self.step, end)
287
288 - def asTextRow(self):
289 return "%s: %s-%s %s" % (self.description, self.value[0], self.value[1], self.units)
290
291 - def asLatexRow(self):
292 return "%s & %s-%s %s" % (latexEscape(self.description), self.value[0], self.value[1], latexEscape(self.units))
293
294 - def valueString(self):
295 if self.value == None: 296 valueString = "" 297 else: 298 valueString = "%s-%s" % (self.value[0], self.value[1]) 299 300 return valueString
301 302
303 - def hiddenHTML(self):
304 return """ 305 <tr> 306 <td></td> 307 <td> 308 <input type='hidden' name='%s' value='%s' /> %s 309 </td> 310 </tr> 311 """ % (self.name, self.valueString())
312 313
314 - def asHTML(self):
315 if self.hidden: 316 return self.hiddenHTML() 317 318 return """ 319 <tr class="rangeParameter"> 320 <td> 321 <label for='%s'>%s</label> 322 </td> 323 <td> 324 <input type='text' class="npsgdRange" name='%s' value='%s' data-rangeStart='%s' data-rangeEnd='%s' data-step='%s' /> %s %s 325 <div class="slider"></div> 326 </td> 327 </tr> 328 """ % (self.name, self.description, self.name, self.valueString(), self.rangeStart, self.rangeEnd, self.step, self.units, self.helpHTML())
329
330 -class FloatParameter(ModelParameter):
331 """Parameter type for selecting a single float value.""" 332
333 - def __init__(self, name, description="", rangeStart=None, rangeEnd=None, \ 334 step=None, units="", default=None, hidden=False, helpText=""):
335 self.name = name 336 self.description = description 337 self.rangeStart = rangeStart 338 self.rangeEnd = rangeEnd 339 self.step = step 340 self.default = default 341 self.units = units 342 self.value = None 343 self.hidden = hidden 344 self.helpText = helpText 345 self.htmlClassBase = "npsgdFloat" 346 if default != None: 347 self.setValue(self.default)
348
349 - def setValue(self, inVal):
350 value = float(inVal) 351 352 if self.rangeStart != None and value < self.rangeStart: 353 raise ValidationError("%s value (%s) out of range" % 354 (self.name, value)) 355 356 if self.rangeEnd != None and value > self.rangeEnd: 357 raise ValidationError("%s value (%s) out of range" % 358 (self.name, value)) 359 360 self.value = value
361
362 - def asMatlabCode(self):
363 return "%s=%s;" % (self.name, self.value)
364
365 - def asTextRow(self):
366 return "%s: %s %s" % (self.description, self.value, self.units)
367
368 - def asLatexRow(self):
369 return "%s & %s %s" % (latexEscape(self.description), self.valueString(), latexEscape(self.units))
370
371 - def valueString(self):
372 if self.value == None: 373 valueString = "" 374 else: 375 valueString = str(self.value) 376 377 return valueString
378
379 - def hiddenHTML(self):
380 return "<tr><td></td><td><input type='hidden' name='%s' value='%s'/></td></tr>" \ 381 % (self.name, self.valueString())
382
383 - def asHTML(self):
384 if self.hidden: 385 return self.hiddenHTML() 386 387 if self.rangeStart != None and self.rangeEnd != None and self.step != None: 388 return """ 389 <tr class="floatSliderParameter"> 390 <td> 391 <label for='%s'>%s</label> 392 </td> 393 <td> 394 <input type='text' class='%sRange' name='%s' value='%s' 395 data-rangeStart='%s' data-rangeEnd='%s' data-step='%s' /> %s %s 396 <div class="slider"></div> 397 </td> 398 </tr> 399 """ % (self.name, self.description, self.htmlClassBase, self.name, self.valueString(), self.rangeStart, self.rangeEnd, self.step, self.units, self.helpHTML()) 400 else: 401 return "<tr><td><label for='%s'>%s</label></td><td><input type='text' class='%s' name='%s' value='%s' data-rangeStart='%s' data-rangeEnd='%s' data-step='%s'/> %s %s</td></tr>" \ 402 % (self.name, self.description, self.htmlClassBase, self.name, self.valueString(), self.rangeStart, self.rangeEnd, self.step, self.units, self.helpHTML())
403
404 -class IntegerParameter(FloatParameter):
405 """Parameter type for selecting a single integer value.""" 406
407 - def __init__(self, *args, **kwargs):
408 FloatParameter.__init__(self, *args, **kwargs) 409 self.htmlClassBase = "npsgdInteger"
410
411 - def setValue(self, value):
412 self.value = int(value)
413 414
415 -def replaceAll(replacee, replaceList):
416 for find, replace in replaceList: 417 replacee = replacee.replace(find, replace) 418 419 return replacee
420
421 -def matlabEscape(string):
422 """Escapes parameter values (strings usually) for inclusion in a Matlab script.""" 423 return string.replace("'", "\\'")\ 424 .replace("%", "%%")\ 425 .replace("\\", "\\\\")
426
427 -def htmlAttributeEscape(string):
428 return string.replace("'", "\\'")
429
430 -def latexEscape(string):
431 """Escapes parameter values for inclusion in LaTeX.""" 432 433 return replaceAll(string, 434 [("\\",r"\textbackslash "), 435 ("<", r"\textless "), 436 (">", r"\textgreater "), 437 ("~", r"\texasciitilde "), 438 ("^", r"\textasciicircum "), 439 ("|", r"\docbooktolatexpipe "), 440 ("&", r"\&"), 441 ("#", r"\#"), 442 ("_", r"\_"), 443 ("$", r"\$"), 444 ("%", r"\%"), 445 ("{", r"\{"), 446 ("}", r"\}")])
447