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 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
35 from graphics import IMAGE_PATH
36 from lib.errors import RelaxError
37
38
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
51 __mod_attr__ = [
52 'title',
53 'menu_text',
54 'gui_icon'
55 ]
56
58 """Initialise all the data."""
59
60
61 self.title = None
62 self.menu_text = None
63 self.gui_icon = None
64
65
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
76 if not name in self.__mod_attr__:
77 raise RelaxError("The object '%s' is not a modifiable attribute." % name)
78
79
80 self.__dict__[name] = value
81
82
83
85 """An empty container object."""
86
87
88
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
100 self._title = title
101
102
103 self._data = []
104 self._types = []
105
106
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
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
122 else:
123 self._data[-1].append([item, text])
124
125
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
134 if not len(self._types) or self._types[-1] != 'list':
135 self._data.append([text])
136 self._types.append('list')
137
138
139 else:
140 self._data[-1].append(text)
141
142
144 """Add a paragraph of text to the description.
145
146 @param text: The paragraph text.
147 @type text: str
148 """
149
150
151 self._data.append(text)
152 self._types.append('paragraph')
153
154
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
163 if not len(self._types) or self._types[-1] != 'prompt':
164 self._data.append([text])
165 self._types.append('prompt')
166
167
168 else:
169 self._data[-1].append(text)
170
171
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
180 if not isinstance(label, str):
181 raise RelaxError("The table label '%s' is not a valid string.")
182
183
184 self._data.append(label)
185 self._types.append('table')
186
187
189 """Add a section of verbatim text to the description.
190
191 @param text: The verbatim text.
192 @type text: str
193 """
194
195
196 self._data.append(text)
197 self._types.append('verbatim')
198
199
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
210 if title:
211 yield 'title', self._title
212
213
214 for i in range(len(self._data)):
215 yield self._types[i], self._data[i]
216
217
219 """Return the title of the section.
220
221 @return: The section title.
222 @rtype: str
223 """
224
225
226 return self._title
227
228
229
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
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
259 self.headings = None
260 self.cells = []
261 self.num_cols = 0
262
263
265 """Add a row of table headings.
266
267 @param headings: The table headings.
268 @type headings: list of str
269 """
270
271
272 self.headings = headings
273
274
275 self.num_cols = len(self.headings)
276
277
279 """Add a table row.
280
281 @param row: The table row.
282 @type row: list of str
283 """
284
285
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
292 self.cells.append(row)
293
294
295
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
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
346 """Initialise all the data."""
347
348
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
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
374 if not name in self.__mod_attr__:
375 raise RelaxError("The object '%s' is not a modifiable attribute." % name)
376
377
378 if name in ['title', 'title_short', 'backend', 'gui_icon']:
379
380 if not hasattr(self, name):
381 obj = None
382
383
384 else:
385 obj = getattr(self, name)
386
387
388 if obj != None:
389 raise RelaxError("The variable '%s' is already set to %s." % (name, repr(obj)))
390
391
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
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
460 if arg_type == "file sel" and wiz_filesel_style == None:
461 raise RelaxError("The file selection style must always be provided.")
462
463
464 self.kargs.append({})
465 arg = self.kargs[-1]
466
467
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