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

Source Code for Module user_functions.objects

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