Package user_functions :: Module objects
[hide private]
[frames] | no frames]

Source Code for Module user_functions.objects

  1  ############################################################################### 
  2  #                                                                             # 
  3  # Copyright (C) 2012-2014 Edward d'Auvergne                                   # 
  4  # Copyright (C) 2014 Troels E. Linnet                                         # 
  5  #                                                                             # 
  6  # This file is part of the program relax (http://www.nmr-relax.com).          # 
  7  #                                                                             # 
  8  # This program is free software: you can redistribute it and/or modify        # 
  9  # it under the terms of the GNU General Public License as published by        # 
 10  # the Free Software Foundation, either version 3 of the License, or           # 
 11  # (at your option) any later version.                                         # 
 12  #                                                                             # 
 13  # This program is distributed in the hope that it will be useful,             # 
 14  # but WITHOUT ANY WARRANTY; without even the implied warranty of              # 
 15  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               # 
 16  # GNU General Public License for more details.                                # 
 17  #                                                                             # 
 18  # You should have received a copy of the GNU General Public License           # 
 19  # along with this program.  If not, see <http://www.gnu.org/licenses/>.       # 
 20  #                                                                             # 
 21  ############################################################################### 
 22   
 23  # Module docstring. 
 24  """The module of all the objects used to hold the user function details.""" 
 25   
 26  # Python module imports. 
 27  import dep_check 
 28  if dep_check.wx_module: 
 29      from wx import DD_DEFAULT_STYLE, FileSelectorDefaultWildcardStr 
 30  else: 
 31      DD_DEFAULT_STYLE = -1 
 32      FileSelectorDefaultWildcardStr = -1 
 33   
 34  # relax module imports. 
 35  from graphics import IMAGE_PATH 
 36  from lib.errors import RelaxError 
 37   
 38   
39 -class Class_container:
40 """This class is used to process and store all of the user function class information. 41 42 @ivar title: The user function class description. 43 @type title: str 44 @ivar menu_text: The text to use for the GUI menu entry. 45 @type menu_text: str 46 @ivar gui_icon: The code for the icon to use in the GUI. 47 @type gui_icon: str or None 48 """ 49 50 # The list of modifiable objects (anything else will be rejected to prevent coding errors). 51 __mod_attr__ = [ 52 'title', 53 'menu_text', 54 'gui_icon' 55 ] 56
57 - def __init__(self):
58 """Initialise all the data.""" 59 60 # Initialise the variables for all user function classes. 61 self.title = None 62 self.menu_text = None 63 self.gui_icon = None
64 65
66 - def __setattr__(self, name, value):
67 """Override the class __setattr__ method. 68 69 @param name: The name of the attribute to modify. 70 @type name: str 71 @param value: The new value of the attribute. 72 @type value: anything 73 """ 74 75 # Test if the attribute that is trying to be set is modifiable. 76 if not name in self.__mod_attr__: 77 raise RelaxError("The object '%s' is not a modifiable attribute." % name) 78 79 # Set the attribute normally. 80 self.__dict__[name] = value
81 82 83
84 -class Container:
85 """An empty container object."""
86 87 88
89 -class Desc_container(object):
90 """A special object for holding and processing user function description information.""" 91
92 - def __init__(self, title="Description"):
93 """Set up the container. 94 95 @keyword section: The section title. 96 @type section: str 97 """ 98 99 # Store the title. 100 self._title = title 101 102 # Initialise internal storage objects. 103 self._data = [] 104 self._types = []
105 106
107 - def add_item_list_element(self, item, text):
108 """Add the element of an itemised list to the description. 109 110 @param item: The item text. 111 @type item: str 112 @param text: The itemised list element text. 113 @type text: str 114 """ 115 116 # Create a new block if needed. 117 if not len(self._types) or self._types[-1] != 'item list': 118 self._data.append([[item, text]]) 119 self._types.append('item list') 120 121 # Append the element to an existing itemised list structure. 122 else: 123 self._data[-1].append([item, text])
124 125
126 - def add_list_element(self, text):
127 """Add the element of a list to the description. 128 129 @param text: The list element text. 130 @type text: str 131 """ 132 133 # Create a new block if needed. 134 if not len(self._types) or self._types[-1] != 'list': 135 self._data.append([text]) 136 self._types.append('list') 137 138 # Append the element to an existing list structure. 139 else: 140 self._data[-1].append(text)
141 142
143 - def add_paragraph(self, text):
144 """Add a paragraph of text to the description. 145 146 @param text: The paragraph text. 147 @type text: str 148 """ 149 150 # Store the text. 151 self._data.append(text) 152 self._types.append('paragraph')
153 154
155 - def add_prompt(self, text):
156 """Add the text of a relax prompt example to the description. 157 158 @param text: The relax prompt text. 159 @type text: str 160 """ 161 162 # Create a new block if needed. 163 if not len(self._types) or self._types[-1] != 'prompt': 164 self._data.append([text]) 165 self._types.append('prompt') 166 167 # Append the example to an existing example block. 168 else: 169 self._data[-1].append(text)
170 171
172 - def add_table(self, label):
173 """Add a table to the description. 174 175 @param label: The unique label corresponding to a user_functions.objects.Table instance. 176 @type label: str 177 """ 178 179 # Check. 180 if not isinstance(label, str): 181 raise RelaxError("The table label '%s' is not a valid string.") 182 183 # Add the table. 184 self._data.append(label) 185 self._types.append('table')
186 187
188 - def add_verbatim(self, text):
189 """Add a section of verbatim text to the description. 190 191 @param text: The verbatim text. 192 @type text: str 193 """ 194 195 # Store the text. 196 self._data.append(text) 197 self._types.append('verbatim')
198 199
200 - def element_loop(self, title=False):
201 """Iterator method yielding the description elements. 202 203 @keyword title: A flag which if True will cause the title to be yielded first. 204 @type title: bool 205 @return: The element type and corresponding data. 206 @rtype: str and anything 207 """ 208 209 # The title. 210 if title: 211 yield 'title', self._title 212 213 # Loop over the elements. 214 for i in range(len(self._data)): 215 yield self._types[i], self._data[i]
216 217
218 - def get_title(self):
219 """Return the title of the section. 220 221 @return: The section title. 222 @rtype: str 223 """ 224 225 # The title. 226 return self._title
227 228 229
230 -class Table(object):
231 """A special class defining the tables used in the user function descriptions.""" 232
233 - def __init__(self, label=None, caption=None, caption_short=None, spacing=True, longtable=False):
234 """Set up the table container. 235 236 @keyword label: The unique label of the table. This is used to identify tables, and is also used in the table referencing in the LaTeX compilation of the user manual. 237 @type label: str 238 @keyword caption: The caption for the table. 239 @type caption: str 240 @keyword caption_short: The optional short caption for the table, used in the LaTeX user manual list of tables section for example. 241 @type caption_short: str 242 @keyword spacing: A flag which if True will cause empty rows to be placed between elements. 243 @type spacing: bool 244 @keyword longtable: A special LaTeX flag which if True will cause the longtables package to be used to spread a table across multiple pages. This should only be used for tables that do not fit on a single page. 245 @type longtable: bool 246 """ 247 248 # Store the args. 249 self.label = label 250 self.caption = caption 251 if caption_short: 252 self.caption_short = caption_short 253 else: 254 self.caption_short = caption 255 self.spacing = spacing 256 self.longtable = longtable 257 258 # Initialise some objects. 259 self.headings = None 260 self.cells = [] 261 self.num_cols = 0
262 263
264 - def add_headings(self, headings):
265 """Add a row of table headings. 266 267 @param headings: The table headings. 268 @type headings: list of str 269 """ 270 271 # Store the headings. 272 self.headings = headings 273 274 # The number of columns. 275 self.num_cols = len(self.headings)
276 277
278 - def add_row(self, row):
279 """Add a table row. 280 281 @param row: The table row. 282 @type row: list of str 283 """ 284 285 # Checks. 286 if self.headings == None: 287 raise RelaxError("A row cannot be added as the headings have not been set up.") 288 if len(row) != self.num_cols: 289 raise RelaxError("The number of columns in %s does not match the %s columns of the headings." % (row, self.num_cols)) 290 291 # Append the row. 292 self.cells.append(row)
293 294 295
296 -class Uf_container(object):
297 """This class is used to process and store all of the user function specific information. 298 299 @ivar title: The long title of the user function. 300 @type title: str 301 @ivar title_short: The optional short title. 302 @type title_short: str or None 303 @ivar kargs: The list of keyword argument details. 304 @type kargs: list of dict 305 @ivar backend: The user function back end. This should be a string version with full module path of the function which executes the back end. For example 'pipe_control.pipes.create'. Note, this should be importable as __import__(backend)! 306 @type backend: executable object 307 @ivar display: A flag specifying if the user function displays output to STDOUT. This is used for certain UIs to display that output. 308 @type display: str 309 @ivar desc: The multi-paragraph description defined via the Desc_container class. 310 @type desc: list of Desc_container instances 311 @ivar menu_text: The text to use for the GUI menu entry. 312 @type menu_text: str 313 @ivar gui_icon: The code for the icon to use in the GUI. 314 @type gui_icon: str or None 315 @ivar wizard_size: The size for the GUI user function wizard. This defaults to (700, 500) if not supplied. 316 @type wizard_size: tuple of int or None 317 @ivar wizard_image: The 200 pixel wide image to use for the user function wizard. This should be the path to the bitmap image. This defaults to the relax Ulysses butterfly image. 318 @type wizard_image: str 319 @ivar wizard_height_desc: The height in pixels of the description part of the wizard. 320 @type wizard_height_desc: int 321 @ivar wizard_apply_button: A flag specifying if the apply button should be shown or not. This defaults to True. 322 @type wizard_apply_button: bool 323 @ivar gui_sync: A GUI flag which if left on the default of False will cause user functions to be called in asynchronous mode. If changed to True, then synchronous operation of the user functions will occur. 324 @type gui_sync: bool 325 """ 326 327 # The list of modifiable objects (anything else will be rejected to prevent coding errors). 328 __mod_attr__ = [ 329 'title', 330 'title_short', 331 'kargs', 332 'backend', 333 'display', 334 'desc', 335 'menu_text', 336 'gui_icon', 337 'wizard_size', 338 'wizard_image', 339 'wizard_height_desc', 340 'wizard_apply_button', 341 'gui_sync', 342 ] 343 344
345 - def __init__(self):
346 """Initialise all the data.""" 347 348 # Initialise the variables for all user functions. 349 self.title = None 350 self.title_short = None 351 self.kargs = [] 352 self.backend = None 353 self.display = False 354 self.desc = [] 355 self.menu_text = '' 356 self.gui_icon = None 357 self.wizard_size = (700, 500) 358 self.wizard_image = IMAGE_PATH + "relax.gif" 359 self.wizard_height_desc = 300 360 self.wizard_apply_button = True 361 self.gui_sync = False
362 363
364 - def __setattr__(self, name, value):
365 """Override the class __setattr__ method. 366 367 @param name: The name of the attribute to modify. 368 @type name: str 369 @param value: The new value of the attribute. 370 @type value: anything 371 """ 372 373 # Test if the attribute that is trying to be set is modifiable. 374 if not name in self.__mod_attr__: 375 raise RelaxError("The object '%s' is not a modifiable attribute." % name) 376 377 # Check for duplicative modifications (to catch typo coding errors). 378 if name in ['title', 'title_short', 'backend', 'gui_icon']: 379 # No object set yet. 380 if not hasattr(self, name): 381 obj = None 382 383 # Get the current object. 384 else: 385 obj = getattr(self, name) 386 387 # Not None! 388 if obj != None: 389 raise RelaxError("The variable '%s' is already set to %s." % (name, repr(obj))) 390 391 # Set the attribute normally. 392 self.__dict__[name] = value
393 394
395 - def add_keyarg(self, name=None, default=None, py_type=None, arg_type=None, dim=None, min=0, max=1000, desc_short=None, desc=None, list_titles=None, wiz_element_type='default', wiz_combo_choices=None, wiz_combo_data=None, wiz_combo_iter=None, wiz_combo_list_min=None, wiz_filesel_wildcard=FileSelectorDefaultWildcardStr, wiz_filesel_style=None, wiz_dirsel_style=DD_DEFAULT_STYLE, wiz_read_only=None, wiz_filesel_preview=True, can_be_none=False, can_be_empty=False, none_elements=False):
396 """Wrapper method for adding keyword argument information to the container. 397 398 @keyword name: The name of the argument. 399 @type name: str 400 @keyword default: The default value of the argument. 401 @type default: anything 402 @keyword py_type: The Python object type that the argument must match (taking the can_be_none flag into account). 403 @type py_type: str 404 @keyword arg_type: The type of argument. This is reserved for special UI elements: 405 - 'file sel' will indicate to certain UIs that a file selection dialog is required. 406 - 'dir' will cause the argument to not be shown in certain UIs, as this indicates that the user function already has a 'file sel' type argument and hence a directory is not required. 407 - 'dir sel' will indicate to certain UIs that a dir selection dialog is required. 408 @type arg_type: str 409 @keyword dim: The fixed dimensions that a list or tuple must conform to. For a 1D sequence, this can be a single value or a tuple of possible sizes. For a 2D sequence (a numpy matrix or list of lists), this must be a tuple of the fixed dimension sizes, e.g. a 3x5 matrix should be specified as (3, 5). 410 @type dim: int, tuple of int or None 411 @keyword min: The minimum value allowed for integer types. This is used in the wx.SpinCtrl for example. 412 @type min: int 413 @keyword max: The maximum value allowed for integer types. This is used in the wx.SpinCtrl for example. 414 @type max: int 415 @keyword desc_short: The short human-readable description of the argument. This is used in the RelaxError messages to refer to the argument, as well as in the GUI user function page elements. 416 @type desc_short: str 417 @keyword desc: The long human-readable description of the argument. 418 @type desc: str 419 @keyword list_titles: The titles of each of the elements of the fixed length lists. This only applies to lists or list of lists. 420 @type list_titles: list of str 421 @keyword wiz_element_type: The type of GUI element to create. If left to 'default', then the currently set default element will be used. If set to 'text', a wx.TextCtrl element will be used. If set to 'combo', a wx.ComboBox element will be used. 422 @type wiz_element_type: str 423 @keyword wiz_combo_choices: The list of choices to present to the user. This is only used if the element_type is set to 'combo'. 424 @type wiz_combo_choices: list of str 425 @keyword wiz_combo_data: The data returned by a call to GetValue(). This is only used if the element_type is set to 'combo'. If supplied, it should be the same length at the combo_choices list. If not supplied, the combo_choices list will be used for the returned data. 426 @type wiz_combo_data: list 427 @keyword wiz_combo_iter: An iterator method for regenerating the ComboBox choices. 428 @type wiz_combo_iter: iterator or None 429 @keyword wiz_combo_list_min: The minimum length of the Combo_list element. 430 @type wiz_combo_list_min: int or None 431 @keyword wiz_filesel_wildcard: The file selection dialog wildcard string. For example for opening PDB files, this could be "PDB files (*.pdb)|*.pdb;*.PDB". 432 @type wiz_filesel_wildcard: str or None 433 @keyword wiz_filesel_style: The file selection dialog style. 434 @type wiz_filesel_style: int 435 @keyword wiz_dirsel_style: The directory selection dialog style. 436 @type wiz_dirsel_style: int 437 @keyword wiz_read_only: A flag which if True means that the text of the GUI wizard page element cannot be edited. If the default of None is given, then each UI element will decide for itself what to do. 438 @type wiz_read_only: bool or None 439 @keyword wiz_filesel_preview: A flag which if True will enable the preview button in the file selection GUI wizard page element. 440 @type wiz_filesel_preview: bool 441 @keyword can_be_none: A flag which specifies if the argument is allowed to have the None value. 442 @type can_be_none: bool 443 @keyword can_be_empty: A flag which if True allows the sequence type object to be empty. 444 @type can_be_empty: bool 445 @keyword none_elements: A flag which if True allows the sequence type object to contain None elements. 446 @type none_elements: bool 447 """ 448 449 # Check that the args have been properly supplied. 450 if name == None: 451 raise RelaxError("The 'name' argument must be supplied.") 452 if py_type == None: 453 raise RelaxError("The 'py_type' argument must be supplied.") 454 if desc_short == None: 455 raise RelaxError("The 'desc_short' argument must be supplied.") 456 if desc == None: 457 raise RelaxError("The 'desc' argument must be supplied.") 458 459 # Check the file selection dialog. 460 if arg_type == "file sel" and wiz_filesel_style == None: 461 raise RelaxError("The file selection style must always be provided.") 462 463 # Append a new argument dictionary to the list, and alias it. 464 self.kargs.append({}) 465 arg = self.kargs[-1] 466 467 # Add the data. 468 arg['name'] = name 469 arg['default'] = default 470 arg['py_type'] = py_type 471 arg['arg_type'] = arg_type 472 arg['dim'] = dim 473 arg['min'] = min 474 arg['max'] = max 475 arg['desc_short'] = desc_short 476 arg['desc'] = desc 477 arg['list_titles'] = list_titles 478 arg['wiz_element_type'] = wiz_element_type 479 if wiz_combo_choices == None: 480 arg['wiz_combo_choices'] = [] 481 else: 482 arg['wiz_combo_choices'] = wiz_combo_choices 483 arg['wiz_combo_data'] = wiz_combo_data 484 arg['wiz_combo_iter'] = wiz_combo_iter 485 arg['wiz_combo_list_min'] = wiz_combo_list_min 486 arg['wiz_filesel_wildcard'] = wiz_filesel_wildcard 487 arg['wiz_filesel_style'] = wiz_filesel_style 488 arg['wiz_dirsel_style'] = wiz_dirsel_style 489 arg['wiz_read_only'] = wiz_read_only 490 arg['wiz_filesel_preview'] = wiz_filesel_preview 491 arg['can_be_none'] = can_be_none 492 arg['can_be_empty'] = can_be_empty 493 arg['none_elements'] = none_elements
494