scipion-pyworkflow 3.10.5__py3-none-any.whl → 3.11.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (127) hide show
  1. pyworkflow/config.py +131 -67
  2. pyworkflow/constants.py +12 -2
  3. pyworkflow/object.py +3 -2
  4. pyworkflow/plugin.py +93 -44
  5. pyworkflow/project/scripts/fix_links.py +4 -1
  6. pyworkflow/resources/showj/arrowDown.png +0 -0
  7. pyworkflow/resources/showj/arrowUp.png +0 -0
  8. pyworkflow/resources/showj/background_section.png +0 -0
  9. pyworkflow/resources/showj/colRowModeOff.png +0 -0
  10. pyworkflow/resources/showj/colRowModeOn.png +0 -0
  11. pyworkflow/resources/showj/delete.png +0 -0
  12. pyworkflow/resources/showj/doc_icon.png +0 -0
  13. pyworkflow/resources/showj/download_icon.png +0 -0
  14. pyworkflow/resources/showj/enabled_gallery.png +0 -0
  15. pyworkflow/resources/showj/galleryViewOff.png +0 -0
  16. pyworkflow/resources/showj/galleryViewOn.png +0 -0
  17. pyworkflow/resources/showj/goto.png +0 -0
  18. pyworkflow/resources/showj/menu.png +0 -0
  19. pyworkflow/resources/showj/separator.png +0 -0
  20. pyworkflow/resources/showj/tableViewOff.png +0 -0
  21. pyworkflow/resources/showj/tableViewOn.png +0 -0
  22. pyworkflow/resources/showj/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  23. pyworkflow/resources/showj/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  24. pyworkflow/resources/showj/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  25. pyworkflow/resources/showj/volumeOff.png +0 -0
  26. pyworkflow/resources/showj/volumeOn.png +0 -0
  27. pyworkflow/viewer.py +23 -1
  28. pyworkflowtests/objects.py +2 -2
  29. pyworkflowtests/protocols.py +1 -3
  30. {scipion_pyworkflow-3.10.5.dist-info → scipion_pyworkflow-3.11.0.dist-info}/METADATA +21 -25
  31. scipion_pyworkflow-3.11.0.dist-info/RECORD +71 -0
  32. {scipion_pyworkflow-3.10.5.dist-info → scipion_pyworkflow-3.11.0.dist-info}/WHEEL +1 -1
  33. scipion_pyworkflow-3.11.0.dist-info/entry_points.txt +2 -0
  34. pyworkflow/apps/__init__.py +0 -29
  35. pyworkflow/apps/pw_manager.py +0 -37
  36. pyworkflow/apps/pw_plot.py +0 -51
  37. pyworkflow/apps/pw_project.py +0 -113
  38. pyworkflow/apps/pw_protocol_list.py +0 -143
  39. pyworkflow/apps/pw_protocol_run.py +0 -51
  40. pyworkflow/apps/pw_run_tests.py +0 -267
  41. pyworkflow/apps/pw_schedule_run.py +0 -322
  42. pyworkflow/apps/pw_sleep.py +0 -37
  43. pyworkflow/apps/pw_sync_data.py +0 -439
  44. pyworkflow/apps/pw_viewer.py +0 -78
  45. pyworkflow/gui/__init__.py +0 -36
  46. pyworkflow/gui/browser.py +0 -726
  47. pyworkflow/gui/canvas.py +0 -1190
  48. pyworkflow/gui/dialog.py +0 -977
  49. pyworkflow/gui/form.py +0 -2637
  50. pyworkflow/gui/graph.py +0 -247
  51. pyworkflow/gui/graph_layout.py +0 -271
  52. pyworkflow/gui/gui.py +0 -566
  53. pyworkflow/gui/matplotlib_image.py +0 -233
  54. pyworkflow/gui/plotter.py +0 -247
  55. pyworkflow/gui/project/__init__.py +0 -25
  56. pyworkflow/gui/project/base.py +0 -192
  57. pyworkflow/gui/project/constants.py +0 -139
  58. pyworkflow/gui/project/labels.py +0 -205
  59. pyworkflow/gui/project/project.py +0 -492
  60. pyworkflow/gui/project/searchprotocol.py +0 -154
  61. pyworkflow/gui/project/searchrun.py +0 -181
  62. pyworkflow/gui/project/steps.py +0 -171
  63. pyworkflow/gui/project/utils.py +0 -332
  64. pyworkflow/gui/project/variables.py +0 -179
  65. pyworkflow/gui/project/viewdata.py +0 -472
  66. pyworkflow/gui/project/viewprojects.py +0 -510
  67. pyworkflow/gui/project/viewprotocols.py +0 -2093
  68. pyworkflow/gui/project/viewprotocols_extra.py +0 -560
  69. pyworkflow/gui/text.py +0 -771
  70. pyworkflow/gui/tooltip.py +0 -185
  71. pyworkflow/gui/tree.py +0 -684
  72. pyworkflow/gui/widgets.py +0 -307
  73. pyworkflow/mapper/__init__.py +0 -26
  74. pyworkflow/mapper/mapper.py +0 -222
  75. pyworkflow/mapper/sqlite.py +0 -1578
  76. pyworkflow/mapper/sqlite_db.py +0 -145
  77. pyworkflow/project/__init__.py +0 -31
  78. pyworkflow/project/config.py +0 -454
  79. pyworkflow/project/manager.py +0 -180
  80. pyworkflow/project/project.py +0 -2010
  81. pyworkflow/protocol/__init__.py +0 -38
  82. pyworkflow/protocol/bibtex.py +0 -48
  83. pyworkflow/protocol/constants.py +0 -87
  84. pyworkflow/protocol/executor.py +0 -455
  85. pyworkflow/protocol/hosts.py +0 -313
  86. pyworkflow/protocol/launch.py +0 -270
  87. pyworkflow/protocol/package.py +0 -42
  88. pyworkflow/protocol/params.py +0 -741
  89. pyworkflow/protocol/protocol.py +0 -2582
  90. pyworkflow/tests/__init__.py +0 -29
  91. pyworkflow/tests/test_utils.py +0 -25
  92. pyworkflow/tests/tests.py +0 -341
  93. pyworkflow/utils/__init__.py +0 -38
  94. pyworkflow/utils/dataset.py +0 -414
  95. pyworkflow/utils/echo.py +0 -104
  96. pyworkflow/utils/graph.py +0 -169
  97. pyworkflow/utils/log.py +0 -284
  98. pyworkflow/utils/path.py +0 -528
  99. pyworkflow/utils/process.py +0 -132
  100. pyworkflow/utils/profiler.py +0 -92
  101. pyworkflow/utils/progressbar.py +0 -154
  102. pyworkflow/utils/properties.py +0 -631
  103. pyworkflow/utils/reflection.py +0 -129
  104. pyworkflow/utils/utils.py +0 -879
  105. pyworkflow/utils/which.py +0 -229
  106. pyworkflow/webservices/__init__.py +0 -8
  107. pyworkflow/webservices/config.py +0 -11
  108. pyworkflow/webservices/notifier.py +0 -162
  109. pyworkflow/webservices/repository.py +0 -59
  110. pyworkflow/webservices/workflowhub.py +0 -74
  111. pyworkflowtests/tests/__init__.py +0 -0
  112. pyworkflowtests/tests/test_canvas.py +0 -72
  113. pyworkflowtests/tests/test_domain.py +0 -45
  114. pyworkflowtests/tests/test_logs.py +0 -74
  115. pyworkflowtests/tests/test_mappers.py +0 -392
  116. pyworkflowtests/tests/test_object.py +0 -507
  117. pyworkflowtests/tests/test_project.py +0 -42
  118. pyworkflowtests/tests/test_protocol_execution.py +0 -135
  119. pyworkflowtests/tests/test_protocol_export.py +0 -78
  120. pyworkflowtests/tests/test_protocol_output.py +0 -158
  121. pyworkflowtests/tests/test_streaming.py +0 -47
  122. pyworkflowtests/tests/test_utils.py +0 -210
  123. scipion_pyworkflow-3.10.5.dist-info/RECORD +0 -140
  124. scipion_pyworkflow-3.10.5.dist-info/dependency_links.txt +0 -1
  125. scipion_pyworkflow-3.10.5.dist-info/entry_points.txt +0 -5
  126. {scipion_pyworkflow-3.10.5.dist-info → scipion_pyworkflow-3.11.0.dist-info/licenses}/LICENSE.txt +0 -0
  127. {scipion_pyworkflow-3.10.5.dist-info → scipion_pyworkflow-3.11.0.dist-info}/top_level.txt +0 -0
@@ -1,741 +0,0 @@
1
- # **************************************************************************
2
- # *
3
- # * Authors: J.M. De la Rosa Trevin (delarosatrevin@scilifelab.se) [1]
4
- # *
5
- # * [1] SciLifeLab, Stockholm University
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 <https://www.gnu.org/licenses/>.
19
- # *
20
- # * All comments concerning this program package may be sent to the
21
- # * e-mail address 'scipion@cnb.csic.es'
22
- # *
23
- # **************************************************************************
24
-
25
-
26
- import re
27
- import collections
28
-
29
- from pyworkflow.object import *
30
- from .constants import *
31
-
32
-
33
- class FormElement(Object):
34
- """Base for any element on the form"""
35
- ATTRIBUTES = ['label', 'expertLevel', 'condition', 'important', 'help',
36
- 'default', 'paramClass']
37
-
38
- def __init__(self, **args):
39
- super().__init__(**args)
40
- self.label = String(args.get('label', None))
41
- self.expertLevel = Integer(args.get('expertLevel', LEVEL_NORMAL))
42
- self.condition = String(args.get('condition', None))
43
- self._isImportant = Boolean(args.get('important', False))
44
- self.help = String(args.get('help', None))
45
- # This two list will be filled by the Form
46
- # which have a global-view of all parameters
47
- # All param names in which condition appears this param
48
- self._dependants = []
49
- # All param names that appears in the condition
50
- self._conditionParams = []
51
-
52
- def isExpert(self):
53
- return self.expertLevel > LEVEL_NORMAL
54
-
55
- def setExpert(self):
56
- self.expertLevel.set(LEVEL_ADVANCED)
57
-
58
- def isImportant(self):
59
- return self._isImportant.get()
60
-
61
- def setImportant(self, value):
62
- self._isImportant.set(value)
63
-
64
- def hasCondition(self):
65
- return self.condition.hasValue()
66
-
67
- def getLabel(self):
68
- return self.label.get()
69
-
70
- def getHelp(self):
71
- return self.help.get()
72
-
73
- def config(self, **kwargs):
74
- """ Configure the object and set attributes
75
- coming in the keyword-arguments, the
76
- same as in the __init__
77
- """
78
- for key in self.ATTRIBUTES:
79
- if key in kwargs:
80
- self.setAttributeValue(key, kwargs.get(key))
81
-
82
-
83
- class Param(FormElement):
84
- """Definition of a protocol parameter"""
85
- def __init__(self, **args):
86
- FormElement.__init__(self, **args)
87
- # This should be defined in subclasses
88
- self.paramClass = args.get('paramClass', None)
89
- self.default = String(args.get('default', None))
90
-
91
- # Allow pointers (used for scalars)
92
- self.allowsPointers = args.get('allowsPointers', False)
93
- self.validators = args.get('validators', [])
94
- self.readOnly = args.get("readOnly", False)
95
-
96
- def __str__(self):
97
- return " label: %s" % self.label.get()
98
-
99
- def addValidator(self, validator):
100
- """ Validators should be callables that
101
- receive a value and return a list of errors if so.
102
- If everything is ok, the result should be an empty list.
103
- """
104
- self.validators.append(validator)
105
-
106
- def validate(self, value):
107
- errors = []
108
- for val in self.validators:
109
- errors += val(value)
110
- return errors
111
-
112
- def getDefault(self):
113
- return self.default.get()
114
-
115
- def setDefault(self, newDefault):
116
- self.default.set(newDefault)
117
-
118
-
119
- class ElementGroup(FormElement):
120
- """ Class to group some params in the form.
121
- Such as: Labeled group or params in the same line.
122
- """
123
- def __init__(self, form=None, **args):
124
- FormElement.__init__(self, **args)
125
- self._form = form
126
- self._paramList = []
127
-
128
- def iterParams(self):
129
- """ Return key and param for every child param. """
130
- for name in self._paramList:
131
- yield name, self._form.getParam(name)
132
-
133
- def addParam(self, paramName, ParamClass, **kwargs):
134
- """Add a new param to the group"""
135
- param = ParamClass(**kwargs)
136
- self._paramList.append(paramName)
137
- self._form.registerParam(paramName, param)
138
- return param
139
-
140
- def addHidden(self, paramName, ParamClass, **kwargs):
141
- """Add a hidden parameter to be used in conditions. """
142
- kwargs.update({'label': '', 'condition': 'False'})
143
- self.addParam(paramName, ParamClass, **kwargs)
144
-
145
- def addLine(self, lineName, **kwargs):
146
-
147
- labelName = lineName
148
- for symbol in ' ()':
149
- labelName = labelName.replace(symbol, '_')
150
-
151
- return self.addParam(labelName, Line, form=self._form,
152
- label=lineName, **kwargs)
153
-
154
-
155
- # ----------- Some type of ElementGroup --------------------------
156
-
157
- class Line(ElementGroup):
158
- """ Group to put some parameters in the same line. """
159
- pass
160
-
161
-
162
- class Group(ElementGroup):
163
- """ Group some parameters with a labeled frame. """
164
- pass
165
-
166
-
167
- class Section(ElementGroup):
168
- """Definition of a section to hold other params"""
169
- def __init__(self, form, **args):
170
- ElementGroup.__init__(self, form, **args)
171
- self.questionParam = String(args.get('questionParam', ''))
172
-
173
- def hasQuestion(self):
174
- """Return True if a question param was set"""
175
- return self.questionParam.get() in self._paramList
176
-
177
- def getQuestionName(self):
178
- """ Return the name of the question param. """
179
- return self.questionParam.get()
180
-
181
- def getQuestion(self):
182
- """ Return the question param"""
183
- return self._form.getParam(self.questionParam.get())
184
-
185
- def addGroup(self, groupName, **kwargs):
186
- labelName = groupName
187
- for symbol in ' ()':
188
- labelName = labelName.replace(symbol, '_')
189
-
190
- return self.addParam(labelName, Group, form=self._form,
191
- label=groupName, **kwargs)
192
-
193
-
194
- class Form(object):
195
- """Store all sections and parameters"""
196
- def __init__(self, protocol):
197
- """ Build a Form from a given protocol. """
198
- object.__init__(self)
199
- self._sectionList = [] # Store list of sections
200
- # Dictionary to store all params, grouped by sections
201
- self._paramsDict = collections.OrderedDict()
202
- self._lastSection = None
203
- self._protocol = protocol
204
- self.addGeneralSection()
205
-
206
- def getClass(self):
207
- return type(self)
208
-
209
- def addSection(self, label='', **kwargs):
210
- """Add a new section"""
211
- self.lastSection = Section(self, label=label, **kwargs)
212
- self._sectionList.append(self.lastSection)
213
- return self.lastSection
214
-
215
- def getSection(self, label):
216
- """ get section by label from _sectionList"""
217
- for s in self._sectionList:
218
- if s.label == label:
219
- return s
220
- return
221
-
222
- def addGroup(self, *args, **kwargs):
223
- return self.lastSection.addGroup(*args, **kwargs)
224
-
225
- def addLine(self, *args, **kwargs):
226
- return self.lastSection.addLine(*args, **kwargs)
227
-
228
- def registerParam(self, paramName, param):
229
- """ Register a given param in the form. """
230
- self._paramsDict[paramName] = param
231
- self._analizeCondition(paramName, param)
232
-
233
- def addParam(self, *args, **kwargs):
234
- """Add a new param to last section"""
235
- return self.lastSection.addParam(*args, **kwargs)
236
-
237
- # Adhoc method for specific params
238
- def addBooleanParam(self, name, label, help, default=True, **kwargs):
239
- return self.addParam(name, BooleanParam, label=label, help=help, default=default, **kwargs)
240
-
241
- def addHidden(self, *args, **kwargs):
242
- return self.lastSection.addHidden(*args, **kwargs)
243
-
244
- def _analizeCondition(self, paramName, param):
245
- if param.hasCondition():
246
- param._conditionParams = []
247
- tokens = re.split(r'\W+', param.condition.get())
248
- for t in tokens:
249
- if self.hasParam(t):
250
- self.getParam(t)._dependants.append(paramName)
251
- param._conditionParams.append(t)
252
- if self._protocol.hasAttribute(t):
253
- param._conditionParams.append(t)
254
-
255
- def evalParamCondition(self, paramName):
256
- """Evaluate if a condition is True for a give param
257
- with the values of a particular Protocol"""
258
- param = self.getParam(paramName)
259
-
260
- if not param.hasCondition():
261
- return True
262
- condStr = param.condition.get()
263
- localDict = {}
264
- globalDict = dict(globals())
265
- # FIXME: Check why this import is here
266
- from pyworkflow import Config
267
- globalDict.update(Config.getDomain().getObjects())
268
-
269
- for t in param._conditionParams:
270
- if self.hasParam(t) or self._protocol.hasAttribute(t):
271
- localDict[t] = self._protocol.getAttributeValue(t)
272
-
273
- return eval(condStr, globalDict, localDict)
274
-
275
- def validateParams(self, protocol):
276
- """ Check that all validations of the params in the form
277
- are met for the protocol param values.
278
- It will return a list with errors, just in the same
279
- way of the Protocol.validate function
280
- """
281
- errors = []
282
-
283
- for name, param in self.iterParams():
284
- value = protocol.getAttributeValue(name)
285
- errors += param.validate(value)
286
-
287
- return errors
288
-
289
- def getParam(self, paramName):
290
- """Retrieve a param given a the param name
291
- None is returned if not found
292
- """
293
- return self._paramsDict.get(paramName, None)
294
-
295
- def hasParam(self, paramName):
296
- return paramName in self._paramsDict
297
-
298
- def __str__(self):
299
- s = "Form: \n"
300
- for section in self.iterSections():
301
- s += str(section)
302
- return s
303
-
304
- def iterSections(self):
305
- return self._sectionList
306
-
307
- def iterAllParams(self):
308
- """ Iter all parameters, including ElementGroups. """
309
- return self._paramsDict.items()
310
-
311
- def iterParams(self):
312
- """ Iter parameters disregarding the ElementGroups. """
313
- for k, v in self._paramsDict.items():
314
- if not isinstance(v, ElementGroup):
315
- yield k, v
316
-
317
- def iterPointerParams(self):
318
- for paramName, param in self._paramsDict.items():
319
- if isinstance(param, PointerParam):
320
- yield paramName, param
321
-
322
- def addGeneralSection(self):
323
- self.addSection(label='General')
324
- self.addParam('runName', StringParam, label="Run name:", important=True,
325
- help='Select run name label to identify this run.')
326
- self.addParam('runMode', EnumParam, choices=['resume', 'restart'],
327
- label="Run mode", display=EnumParam.DISPLAY_COMBO, default=0,
328
- help='The <resume> mode will try to start the execution'
329
- 'from the last successfully finished step if possible.'
330
- 'On the contrary, <restart> will delete all previous results'
331
- 'of this particular run and start from the beginning. This option'
332
- 'should be used carefully.'
333
- )
334
-
335
- def addParallelSection(self, threads=1, mpi=8, condition="",
336
- hours=72, jobsize=0):
337
-
338
- """ Adds the parallelization section to the form
339
- pass threads=0 to disable threads parameter and mpi=0 to disable mpi params
340
-
341
- :param threads: default value for of threads, defaults to 1
342
- :param mpi: default value for mpi, defaults to 8"""
343
-
344
- self.addSection(label='Parallelization')
345
- self.addParam('hostName', StringParam, default="localhost",
346
- label='Execution host',
347
- help='Select in which of the available do you want to launch this protocol.')
348
-
349
- # NOTE: help messages for these parameters is defined at HELP_MPI_THREADS and used in form.py.
350
-
351
- if threads > 0:
352
- self.addParam('numberOfThreads', IntParam, default=threads,
353
- label='Threads')
354
- if mpi > 0:
355
- self.addParam('numberOfMpi', IntParam, default=mpi,
356
- label='MPI processes')
357
- if jobsize > 0:
358
- self.addParam('mpiJobSize', IntParam, default=jobsize,
359
- label='MPI job size', condition="numberOfMpi>1",
360
- help='Minimum size of jobs in mpi processes.'
361
- 'Set to 1 for large images (e.g. 500x500)'
362
- 'and to 10 for small images (e.g. 100x100)')
363
-
364
-
365
- class StringParam(Param):
366
- """Param with underlying String value"""
367
- def __init__(self, **args):
368
- Param.__init__(self, paramClass=String, **args)
369
-
370
-
371
- class TextParam(StringParam):
372
- """Long string params"""
373
- def __init__(self, **args):
374
- StringParam.__init__(self, **args)
375
- self.height = args.get('height', 5)
376
- self.width = args.get('width', 30)
377
-
378
-
379
- class RegexParam(StringParam):
380
- """Regex based string param"""
381
- pass
382
-
383
-
384
- class PathParam(StringParam):
385
- """Param for path strings"""
386
- pass
387
-
388
-
389
- # TODO: Handle filter pattern
390
- class FileParam(PathParam):
391
- """Filename path"""
392
- pass
393
-
394
-
395
- class FolderParam(PathParam):
396
- """Folder path"""
397
- pass
398
-
399
-
400
- class LabelParam(StringParam):
401
- """ Just the same as StringParam, but to be rendered
402
- as a label and can not be directly edited by the user
403
- in the Protocol Form.
404
- """
405
- pass
406
-
407
-
408
- class IntParam(Param):
409
- def __init__(self, **args):
410
- Param.__init__(self, paramClass=Integer, **args)
411
- self.addValidator(Format(int, error="should be an integer",
412
- allowsNull=args.get('allowsNull', False)))
413
-
414
-
415
- class EnumParam(IntParam):
416
- """Select from a list of values, separated by comma"""
417
- # Possible values for display
418
- DISPLAY_LIST = 0
419
- DISPLAY_COMBO = 1
420
- DISPLAY_HLIST = 2 # horizontal list, save space
421
-
422
- def __init__(self, **args):
423
- IntParam.__init__(self, **args)
424
- self.choices = args.get('choices', [])
425
- self.display = Integer(args.get('display', EnumParam.DISPLAY_COMBO))
426
-
427
-
428
- class FloatParam(Param):
429
- def __init__(self, **args):
430
- Param.__init__(self, paramClass=Float, **args)
431
- self.addValidator(Format(float, error="should be a float",
432
- allowsNull=args.get('allowsNull', False)))
433
-
434
-
435
- class BooleanParam(Param):
436
- """ Param to store boolean values. By default it will be displayed as 2 radio buttons with Yes/no labels.
437
- Alternatively, if you pass checkbox it will be displayed as a checkbox.
438
-
439
- :param display: (Optional) default DISPLAY_YES_NO. (Yes /no)
440
- Alternatively use BooleanParam.DISPLAY_CHECKBOX to use checkboxes """
441
- DISPLAY_YES_NO = 1
442
- DISPLAY_CHECKBOX = 2
443
-
444
- def __init__(self, display=DISPLAY_YES_NO, **args):
445
- Param.__init__(self, paramClass=Boolean, **args)
446
- self.display = display
447
- self.addValidator(NonEmptyBool)
448
-
449
-
450
- class HiddenBooleanParam(BooleanParam):
451
- def __init__(self, **args):
452
- Param.__init__(self, paramClass=Boolean, **args)
453
-
454
-
455
- class PointerParam(Param):
456
- """ This type of Param will serve to select existing objects
457
- in the database that will be input for some protocol.
458
- """
459
- def __init__(self, paramClass=Pointer, **args):
460
- Param.__init__(self, paramClass=paramClass, **args)
461
- # This will be the class to be pointed
462
- self.setPointerClass(args['pointerClass'])
463
- # Some conditions on the pointed candidates
464
- self.pointerCondition = String(args.get('pointerCondition', None))
465
- self.allowsNull = Boolean(args.get('allowsNull', False))
466
-
467
- def setPointerClass(self, newPointerClass):
468
-
469
- # Tolerate passing classes instead of their names
470
- if isinstance(newPointerClass, list):
471
- self.pointerClass = CsvList()
472
- self.pointerClass.set(",". join([clazz.__name__ for clazz in newPointerClass]))
473
-
474
- elif(isinstance(newPointerClass, str)):
475
- if ',' in newPointerClass:
476
- self.pointerClass = CsvList()
477
- self.pointerClass.set(newPointerClass)
478
- else:
479
- self.pointerClass = String(newPointerClass)
480
-
481
- # Single class item, not the string
482
- else:
483
- self.pointerClass = String(newPointerClass.__name__)
484
-
485
-
486
- class MultiPointerParam(PointerParam):
487
- """ This type of Param will serve to select objects
488
- with DIFFERENT types from the database to be input for some protocol.
489
- """
490
- def __init__(self, **args):
491
- PointerParam.__init__(self, paramClass=PointerList, **args)
492
- self.maxNumObjects = Integer(args.get('maxNumObjects', 100))
493
- self.minNumObjects = Integer(args.get('minNumObjects', 2))
494
-
495
-
496
- class RelationParam(Param):
497
- """ This type of Param is very similar to PointerParam, since it will
498
- hold a pointer to another object. But, in the PointerParam, we search
499
- for objects of some Class (maybe with some conditions).
500
- Here, we search for objects related to a given attribute of a protocol
501
- by a given relation.
502
- """
503
- def __init__(self, **args):
504
- Param.__init__(self, paramClass=Pointer, **args)
505
- # This will be the name of the relation
506
- self._relationName = String(args.get('relationName'))
507
- # We will store the attribute name in the protocol to be
508
- # used as the object for which relations will be search
509
- self._attributeName = String(args.get('attributeName'))
510
- # This specify if we want to search for childs or parents
511
- # of the given attribute of the protocol
512
- self._direction = Integer(args.get('direction', RELATION_CHILDS))
513
- self.allowsNull = Boolean(args.get('allowsNull', False))
514
-
515
- def getName(self):
516
- return self._relationName.get()
517
-
518
- def getAttributeName(self):
519
- return self._attributeName.get()
520
-
521
- def getDirection(self):
522
- return self._direction.get()
523
-
524
-
525
- class ProtocolClassParam(StringParam):
526
- def __init__(self, **args):
527
- StringParam.__init__(self, **args)
528
- self.protocolClassName = String(args.get('protocolClassName'))
529
- self.allowSubclasses = Boolean(args.get('allowSubclasses', False))
530
-
531
-
532
- class DigFreqParam(FloatParam):
533
- """ Digital frequency param. """
534
- def __init__(self, **args):
535
- FloatParam.__init__(self, **args)
536
- self.addValidator(FreqValidator)
537
-
538
-
539
- class NumericListParam(StringParam):
540
- """ This class will serve to have list representations as strings.
541
- Possible notation are:
542
- 1000 10 1 1 -> to define a list with 4 values [1000, 10, 1, 1], or
543
- 10x2 5x3 -> to define a list with 5 values [10, 10, 5, 5, 5]
544
- If you ask for more elements than in the list, the last one is repeated
545
- """
546
- def __init__(self, **args):
547
- StringParam.__init__(self, **args)
548
- self.addValidator(NumericListValidator())
549
-
550
-
551
- class NumericRangeParam(StringParam):
552
- """ This class will serve to specify range of numbers with a string representation.
553
- Possible notation are::
554
-
555
- "1,5-8,10" -> [1,5,6,7,8,10]
556
- "2,6,9-11" -> [2,6,9,10,11]
557
- "2 5, 6-8" -> [2,5,6,7,8]
558
-
559
- """
560
- def __init__(self, **args):
561
- StringParam.__init__(self, **args)
562
- self.addValidator(NumericRangeValidator())
563
-
564
-
565
- class TupleParam(Param):
566
- """ This class will condense a tuple of several
567
- other params of the same type and related concept.
568
- For example: min and max, low and high.
569
- """
570
- def __init__(self, **args):
571
- Param.__init__(self, **args)
572
-
573
-
574
- class DeprecatedParam:
575
- """ Deprecated param. To be used when you want to rename an existing param
576
- and still be able to recover old param value. It acts like a redirector, passing the
577
- value received when its value is set to the new renamed parameter
578
-
579
- usage: In defineParams method, before the renamed param definition line add the following:
580
-
581
- self.oldName = DeprecatedParam("newName", self)
582
- form.addParam('newName', ...)
583
-
584
- """
585
- def __init__(self, newParamName, prot):
586
- """
587
-
588
- :param newParamName: Name of the renamed param
589
- :param prot: Protocol hosting this and the renamed param
590
-
591
- """
592
- self._newParamName = newParamName
593
- self.prot = prot
594
- # Need to fake being a Object at loading time
595
- self._objId = None
596
- self._objIsPointer = False
597
-
598
- def set(self, value, cleanExtended=False):
599
- if hasattr(self.prot, self._newParamName):
600
- newParam = self._getNewParam()
601
- if newParam.isPointer():
602
- newParam.set(value, cleanExtended)
603
- self._extended = newParam._extended
604
- else:
605
- newParam.set(value)
606
-
607
- def isPointer(self):
608
- return self._getNewParam().isPointer()
609
-
610
- def getObjValue(self):
611
- return None
612
-
613
- def _getNewParam(self):
614
- return getattr(self.prot, self._newParamName)
615
-
616
- # -----------------------------------------------------------------------------
617
- # Validators
618
- # -----------------------------------------------------------------------------
619
- class Validator(object):
620
- pass
621
-
622
-
623
- class Conditional(Validator):
624
- """ Simple validation based on a condition.
625
- If the value doesn't meet the condition,
626
- the error will be returned.
627
- """
628
- def __init__(self, error, allowsNull=False):
629
- self.error = error
630
- self._allowsNull = allowsNull
631
-
632
- def __call__(self, value):
633
- errors = []
634
- if value is not None or not self._allowsNull:
635
- if not self._condition(value):
636
- errors.append(self.error)
637
- return errors
638
-
639
-
640
- class Format(Conditional):
641
- """ Check if the format is right. """
642
- def __init__(self, valueType, error='Value have not a correct format',
643
- allowsNull=False):
644
- Conditional.__init__(self, error, allowsNull)
645
- self.valueType = valueType
646
-
647
- def _condition(self, value):
648
- try:
649
- self.valueType(value)
650
- return True
651
- except Exception:
652
- return False
653
-
654
-
655
- class NonEmptyCondition(Conditional):
656
- def __init__(self, error='Value cannot be empty'):
657
- Conditional.__init__(self, error)
658
- self._condition = lambda value: len(value) > 0
659
-
660
-
661
- class LT(Conditional):
662
- def __init__(self, threshold,
663
- error='Value should be less than the threshold'):
664
- Conditional.__init__(self, error)
665
- self._condition = lambda value: value < threshold
666
-
667
-
668
- class LE(Conditional):
669
- def __init__(self, threshold,
670
- error='Value should be less or equal than the threshold'):
671
- Conditional.__init__(self, error)
672
- self._condition = lambda value: value <= threshold
673
-
674
-
675
- class GT(Conditional):
676
- def __init__(self, threshold,
677
- error='Value should be greater than the threshold'):
678
- Conditional.__init__(self, error)
679
- self._condition = lambda value: value > threshold
680
-
681
-
682
- class GE(Conditional):
683
- def __init__(self, thresold, error='Value should be greater or equal than the threshold'):
684
- Conditional.__init__(self, error)
685
- self._condition = lambda value: value is not None and value >= thresold
686
-
687
-
688
- class Range(Conditional):
689
- def __init__(self, minValue, maxValue, error='Value is outside range'):
690
- Conditional.__init__(self, error)
691
- self._condition = lambda value: minValue <= value <= maxValue
692
-
693
-
694
- class NumericListValidator(Conditional):
695
- """ Validator for ListParam. See ListParam. """
696
- def __init__(self, error='Incorrect format for numeric list param'):
697
- Conditional.__init__(self, error)
698
-
699
- def _condition(self, value):
700
- try:
701
- parts = re.split(r"[x\s]", value)
702
- parts = list(filter(None, parts))
703
- for p in parts:
704
- float(p)
705
- return True
706
- except Exception:
707
- return False
708
-
709
-
710
- class NumericRangeValidator(Conditional):
711
- """ Validator for RangeParam. See RangeParam. """
712
-
713
- def __init__(self, error='Incorrect format for numeric range param'):
714
- Conditional.__init__(self, error)
715
-
716
- def _condition(self, value):
717
- try:
718
- parts = re.split(r"[-,\s]", value)
719
- parts = list(filter(None, parts))
720
- for p in parts:
721
- float(p)
722
- return True
723
- except Exception:
724
- return False
725
-
726
-
727
- class NonEmptyBoolCondition(Conditional):
728
- def __init__(self, error='Boolean param needs to be set.'):
729
- Conditional.__init__(self, error)
730
- self._condition = lambda value: value is not None
731
-
732
-
733
- # --------- Some constants validators ---------------------
734
-
735
- Positive = GT(0.0, error='Value should be greater than zero')
736
-
737
- FreqValidator = Range(0.001, 0.5,
738
- error="Digital frequencies should be between 0.001 and 0.5")
739
-
740
- NonEmpty = NonEmptyCondition()
741
- NonEmptyBool = NonEmptyBoolCondition()