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