1   
  2   
  3   
  4   
  5   
  6   
  7   
  8   
  9   
 10   
 11   
 12   
 13   
 14   
 15   
 16   
 17   
 18   
 19   
 20   
 21   
 22   
 23  """The module of all the objects used to hold the user function details.""" 
 24   
 25   
 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   
 34  from graphics import IMAGE_PATH 
 35  from lib.errors import RelaxError 
 36   
 37   
 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       
 50      __mod_attr__ = [ 
 51              'title', 
 52              'menu_text', 
 53              'gui_icon' 
 54      ] 
 55   
 57          """Initialise all the data.""" 
 58   
 59           
 60          self.title = None 
 61          self.menu_text = None 
 62          self.gui_icon = None 
  63   
 64   
 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           
 75          if not name in self.__mod_attr__: 
 76              raise RelaxError("The object '%s' is not a modifiable attribute." % name) 
 77   
 78           
 79          self.__dict__[name] = value 
   80   
 81   
 82   
 84      """An empty container object.""" 
  85   
 86   
 87   
 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           
 99          self._title = title 
100   
101           
102          self._data = [] 
103          self._types = [] 
 104   
105   
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           
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           
121          else: 
122              self._data[-1].append([item, text]) 
 123   
124   
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           
133          if not len(self._types) or self._types[-1] != 'list': 
134              self._data.append([text]) 
135              self._types.append('list') 
136   
137           
138          else: 
139              self._data[-1].append(text) 
 140   
141   
143          """Add a paragraph of text to the description. 
144   
145          @param text:    The paragraph text. 
146          @type text:     str 
147          """ 
148   
149           
150          self._data.append(text) 
151          self._types.append('paragraph') 
 152   
153   
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           
162          if not len(self._types) or self._types[-1] != 'prompt': 
163              self._data.append([text]) 
164              self._types.append('prompt') 
165   
166           
167          else: 
168              self._data[-1].append(text) 
 169   
170   
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           
179          if not isinstance(label, str): 
180              raise RelaxError("The table label '%s' is not a valid string.") 
181   
182           
183          self._data.append(label) 
184          self._types.append('table') 
 185   
186   
188          """Add a section of verbatim text to the description. 
189   
190          @param text:    The verbatim text. 
191          @type text:     str 
192          """ 
193   
194           
195          self._data.append(text) 
196          self._types.append('verbatim') 
 197   
198   
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           
209          if title: 
210              yield 'title', self._title 
211   
212           
213          for i in range(len(self._data)): 
214              yield self._types[i], self._data[i] 
 215   
216   
218          """Return the title of the section. 
219   
220          @return:    The section title. 
221          @rtype:     str 
222          """ 
223   
224           
225          return self._title 
  226   
227   
228   
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           
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           
258          self.headings = None 
259          self.cells = [] 
260          self.num_cols = 0 
 261   
262   
264          """Add a row of table headings. 
265   
266          @param headings:    The table headings. 
267          @type headings:     list of str 
268          """ 
269   
270           
271          self.headings = headings 
272   
273           
274          self.num_cols = len(self.headings) 
 275   
276   
278          """Add a table row. 
279   
280          @param row: The table row. 
281          @type row:  list of str 
282          """ 
283   
284           
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           
291          self.cells.append(row) 
  292   
293   
294   
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       
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   
345          """Initialise all the data.""" 
346   
347           
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   
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           
373          if not name in self.__mod_attr__: 
374              raise RelaxError("The object '%s' is not a modifiable attribute." % name) 
375   
376           
377          if name in ['title', 'title_short', 'backend', 'gui_icon']: 
378               
379              if not hasattr(self, name): 
380                  obj = None 
381   
382               
383              else: 
384                  obj = getattr(self, name) 
385   
386               
387              if obj != None: 
388                  raise RelaxError("The variable '%s' is already set to %s." % (name, repr(obj))) 
389   
390           
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           
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           
459          if arg_type == "file sel" and wiz_filesel_style == None: 
460              raise RelaxError("The file selection style must always be provided.") 
461   
462           
463          self.kargs.append({}) 
464          arg = self.kargs[-1] 
465   
466           
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