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