scipion-pyworkflow 3.11.0__py3-none-any.whl → 3.11.1__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 (98) hide show
  1. pyworkflow/apps/__init__.py +29 -0
  2. pyworkflow/apps/pw_manager.py +37 -0
  3. pyworkflow/apps/pw_plot.py +51 -0
  4. pyworkflow/apps/pw_project.py +113 -0
  5. pyworkflow/apps/pw_protocol_list.py +143 -0
  6. pyworkflow/apps/pw_protocol_run.py +51 -0
  7. pyworkflow/apps/pw_run_tests.py +267 -0
  8. pyworkflow/apps/pw_schedule_run.py +322 -0
  9. pyworkflow/apps/pw_sleep.py +37 -0
  10. pyworkflow/apps/pw_sync_data.py +439 -0
  11. pyworkflow/apps/pw_viewer.py +78 -0
  12. pyworkflow/constants.py +1 -1
  13. pyworkflow/gui/__init__.py +36 -0
  14. pyworkflow/gui/browser.py +760 -0
  15. pyworkflow/gui/canvas.py +1190 -0
  16. pyworkflow/gui/dialog.py +979 -0
  17. pyworkflow/gui/form.py +2726 -0
  18. pyworkflow/gui/graph.py +247 -0
  19. pyworkflow/gui/graph_layout.py +271 -0
  20. pyworkflow/gui/gui.py +566 -0
  21. pyworkflow/gui/matplotlib_image.py +233 -0
  22. pyworkflow/gui/plotter.py +247 -0
  23. pyworkflow/gui/project/__init__.py +25 -0
  24. pyworkflow/gui/project/base.py +192 -0
  25. pyworkflow/gui/project/constants.py +139 -0
  26. pyworkflow/gui/project/labels.py +205 -0
  27. pyworkflow/gui/project/project.py +491 -0
  28. pyworkflow/gui/project/searchprotocol.py +238 -0
  29. pyworkflow/gui/project/searchrun.py +181 -0
  30. pyworkflow/gui/project/steps.py +171 -0
  31. pyworkflow/gui/project/utils.py +332 -0
  32. pyworkflow/gui/project/variables.py +179 -0
  33. pyworkflow/gui/project/viewdata.py +472 -0
  34. pyworkflow/gui/project/viewprojects.py +510 -0
  35. pyworkflow/gui/project/viewprotocols.py +2116 -0
  36. pyworkflow/gui/project/viewprotocols_extra.py +562 -0
  37. pyworkflow/gui/text.py +771 -0
  38. pyworkflow/gui/tooltip.py +185 -0
  39. pyworkflow/gui/tree.py +684 -0
  40. pyworkflow/gui/widgets.py +307 -0
  41. pyworkflow/mapper/__init__.py +26 -0
  42. pyworkflow/mapper/mapper.py +222 -0
  43. pyworkflow/mapper/sqlite.py +1581 -0
  44. pyworkflow/mapper/sqlite_db.py +145 -0
  45. pyworkflow/project/__init__.py +31 -0
  46. pyworkflow/project/config.py +454 -0
  47. pyworkflow/project/manager.py +180 -0
  48. pyworkflow/project/project.py +2095 -0
  49. pyworkflow/project/usage.py +165 -0
  50. pyworkflow/protocol/__init__.py +38 -0
  51. pyworkflow/protocol/bibtex.py +48 -0
  52. pyworkflow/protocol/constants.py +87 -0
  53. pyworkflow/protocol/executor.py +483 -0
  54. pyworkflow/protocol/hosts.py +317 -0
  55. pyworkflow/protocol/launch.py +277 -0
  56. pyworkflow/protocol/package.py +42 -0
  57. pyworkflow/protocol/params.py +781 -0
  58. pyworkflow/protocol/protocol.py +2707 -0
  59. pyworkflow/tests/__init__.py +29 -0
  60. pyworkflow/tests/test_utils.py +25 -0
  61. pyworkflow/tests/tests.py +341 -0
  62. pyworkflow/utils/__init__.py +38 -0
  63. pyworkflow/utils/dataset.py +414 -0
  64. pyworkflow/utils/echo.py +104 -0
  65. pyworkflow/utils/graph.py +169 -0
  66. pyworkflow/utils/log.py +293 -0
  67. pyworkflow/utils/path.py +528 -0
  68. pyworkflow/utils/process.py +153 -0
  69. pyworkflow/utils/profiler.py +92 -0
  70. pyworkflow/utils/progressbar.py +154 -0
  71. pyworkflow/utils/properties.py +617 -0
  72. pyworkflow/utils/reflection.py +129 -0
  73. pyworkflow/utils/utils.py +880 -0
  74. pyworkflow/utils/which.py +229 -0
  75. pyworkflow/webservices/__init__.py +8 -0
  76. pyworkflow/webservices/config.py +8 -0
  77. pyworkflow/webservices/notifier.py +152 -0
  78. pyworkflow/webservices/repository.py +59 -0
  79. pyworkflow/webservices/workflowhub.py +74 -0
  80. pyworkflowtests/tests/__init__.py +0 -0
  81. pyworkflowtests/tests/test_canvas.py +72 -0
  82. pyworkflowtests/tests/test_domain.py +45 -0
  83. pyworkflowtests/tests/test_logs.py +74 -0
  84. pyworkflowtests/tests/test_mappers.py +392 -0
  85. pyworkflowtests/tests/test_object.py +507 -0
  86. pyworkflowtests/tests/test_project.py +42 -0
  87. pyworkflowtests/tests/test_protocol_execution.py +146 -0
  88. pyworkflowtests/tests/test_protocol_export.py +78 -0
  89. pyworkflowtests/tests/test_protocol_output.py +158 -0
  90. pyworkflowtests/tests/test_streaming.py +47 -0
  91. pyworkflowtests/tests/test_utils.py +210 -0
  92. {scipion_pyworkflow-3.11.0.dist-info → scipion_pyworkflow-3.11.1.dist-info}/METADATA +2 -2
  93. scipion_pyworkflow-3.11.1.dist-info/RECORD +161 -0
  94. scipion_pyworkflow-3.11.0.dist-info/RECORD +0 -71
  95. {scipion_pyworkflow-3.11.0.dist-info → scipion_pyworkflow-3.11.1.dist-info}/WHEEL +0 -0
  96. {scipion_pyworkflow-3.11.0.dist-info → scipion_pyworkflow-3.11.1.dist-info}/entry_points.txt +0 -0
  97. {scipion_pyworkflow-3.11.0.dist-info → scipion_pyworkflow-3.11.1.dist-info}/licenses/LICENSE.txt +0 -0
  98. {scipion_pyworkflow-3.11.0.dist-info → scipion_pyworkflow-3.11.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,332 @@
1
+ # **************************************************************************
2
+ # *
3
+ # * Authors: Pablo Conesa (pconesa@cnb.csic.es)
4
+ # *
5
+ # * Unidad de Bioinformatica of Centro Nacional de Biotecnologia , CSIC
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, write to the Free Software
19
+ # * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20
+ # * 02111-1307 USA
21
+ # *
22
+ # * All comments concerning this program package may be sent to the
23
+ # * e-mail address 'scipion@cnb.csic.es'
24
+ # *
25
+ # **************************************************************************
26
+ import datetime
27
+ import platform
28
+ import abc
29
+ from abc import ABC
30
+
31
+ from pyworkflow.gui.project.constants import STATUS_COLORS, WARNING_COLOR
32
+ from pyworkflow.protocol import STATUS_FAILED
33
+ from pyworkflow.viewer import ProtocolViewer
34
+
35
+
36
+ def getStatusColorFromNode(node):
37
+ # If it is a run node (not PROJECT)
38
+ return getStatusColorFromRun(node.run)
39
+
40
+
41
+ def getStatusColorFromRun(prot):
42
+ """ Returns the color associated with the status. """
43
+ if prot:
44
+ if prot.hasSummaryWarnings():
45
+ return WARNING_COLOR
46
+ else:
47
+ return getStatusColor(prot.status.get(STATUS_FAILED))
48
+ else:
49
+ return getStatusColor()
50
+
51
+
52
+ def getStatusColor(status=None, default='#ADD8E6'):
53
+ """
54
+ Parameters
55
+ ----------
56
+ status status of the protocol
57
+
58
+ Returns the color associated with he status
59
+ -------
60
+
61
+ """
62
+ return STATUS_COLORS[status] if status else default
63
+
64
+ # OS dependent behaviour. Add any OS dependent method here and later we might move
65
+ # or refactor this to a class or something else
66
+
67
+
68
+ class OSHandler(abc.ABC):
69
+ """ Abstract class: Handler for OS specific actions"""
70
+ def maximizeWindow(root):
71
+ pass
72
+
73
+
74
+ class LinuxHandler(OSHandler, ABC):
75
+
76
+ def maximizeWindow(root):
77
+ root.attributes("-zoomed", True)
78
+
79
+
80
+ class MacHandler(OSHandler, ABC):
81
+
82
+ def maximizeWindow(root):
83
+ root.state("zoomed")
84
+
85
+
86
+ class WindowsHandler(OSHandler, ABC):
87
+
88
+ def maximizeWindow(root):
89
+ root.state("zoomed")
90
+
91
+
92
+ class OS:
93
+ _handler = None
94
+
95
+ _handlers = {"Linux": LinuxHandler,
96
+ "Darwin": MacHandler,
97
+ "Windows": WindowsHandler} # Until testing this on windows
98
+
99
+ @staticmethod
100
+ def getPlatform():
101
+ return platform.system()
102
+
103
+ @classmethod
104
+ def handler(cls):
105
+ if cls._handler is None:
106
+ cls._handler = cls._handlers[cls.getPlatform()]
107
+
108
+ return cls._handler
109
+
110
+
111
+ def isAFinalProtocol(v, k):
112
+ if (issubclass(v, ProtocolViewer) or
113
+ v.isBase() or v.isDisabled()):
114
+ return False
115
+
116
+ return v.__name__ == k
117
+
118
+
119
+ def inspectObj(object, filename, prefix='', maxDeep=5, inspectDetail=2, memoryDict=None):
120
+ """ Creates a .CSV file in the filename path with
121
+ all its members and recursively with a certain maxDeep,
122
+ if maxDeep=0 means no maxDeep (until all members are inspected).
123
+
124
+ inspectDetail can be:
125
+ - 1: All attributes are shown
126
+ - 2: All attributes are shown and iterable values are also inspected
127
+
128
+ prefix and memoryDict will be updated in the recursive entries:
129
+ - prefix is a compound of the two first columns (DEEP and Tree)
130
+ - memoryDict is a dictionary with the memory address and an identifier
131
+ """
132
+ END_LINE = '\n' # end of line char
133
+ COL_DELIM = '\t' # column delimiter
134
+ INDENT_COUNTER = '/' # character append in each indention (it's not written)
135
+
136
+ NEW_CHILD = ' |------> ' # new item indention
137
+ BAR_CHILD = ' | ' + INDENT_COUNTER # bar indention
138
+ END_CHILD = (' -- ' + COL_DELIM) * 4 + END_LINE # Child ending
139
+ column1 = ' - Name - ' + COL_DELIM
140
+ column2 = ' - Type - ' + COL_DELIM
141
+ column3 = ' - Value - ' + COL_DELIM
142
+ column4 = ' - Memory Address -'
143
+
144
+ # Constants to distinguish the first, last and middle rows
145
+ IS_FIRST = 1
146
+ IS_LAST = -1
147
+ IS_MIDDLE = 0
148
+
149
+ memoryDict = memoryDict or {}
150
+
151
+ def writeRow(name, value, prefix, posList=False):
152
+ """ Writes a row item. """
153
+ # we will avoid to recursively print the items wrote before
154
+ # (ie. with the same memory address), thus we store a dict with the
155
+ # addresses and the flag isNew is properly set
156
+ if str(hex(id(value))) in memoryDict:
157
+ memorySTR = memoryDict[str(hex(id(value)))]
158
+ isNew = False
159
+ else:
160
+ # if the item is new, we save its memory address in the memoryDict
161
+ # and we pass the name and the line on the file as a reference.
162
+ memorySTR = str(hex(id(value)))
163
+ file = open(filename, 'r')
164
+ lineNum = str(len(file.readlines()) + 1)
165
+ file.close()
166
+ nameDict = str(name)[0:15] + ' ...' if len(str(name)) > 25 else str(name)
167
+ memoryDict[str(hex(id(value)))] = '>>> ' + nameDict + ' - L:' + lineNum
168
+ isNew = True
169
+
170
+ if posList:
171
+ # if we have a List, the third column is 'pos/lenght'
172
+ thirdCol = posList
173
+ else:
174
+ # else, we print the value avoiding the EndOfLine char (// instead)
175
+ thirdCol = str(value).replace(END_LINE, ' // ')
176
+
177
+ # we will print the indentation deep number in the first row
178
+ indentionDeep = prefix.count(INDENT_COUNTER)
179
+ deepStr = str(indentionDeep) + COL_DELIM
180
+
181
+ # the prefix without the indentCounters is
182
+ # the tree to be printed in the 2nd row
183
+ prefixToWrite = prefix.replace(INDENT_COUNTER, '')
184
+
185
+ file = open(filename, 'a')
186
+ file.write(deepStr + prefixToWrite + COL_DELIM +
187
+ str(name) + COL_DELIM +
188
+ str(type(value)) + COL_DELIM +
189
+ thirdCol + COL_DELIM +
190
+ memorySTR + END_LINE)
191
+ file.close()
192
+
193
+ return isNew
194
+
195
+ def recursivePrint(value, prefix, isFirstOrLast):
196
+ """ We print the childs items of tuples, lists, dicts and classes. """
197
+
198
+ # if it's the last item, its childs has not the bar indention
199
+ if isFirstOrLast == IS_LAST: # void indention when no more items
200
+ prefixList = prefix.split(INDENT_COUNTER)
201
+ prefixList[-2] = prefixList[-2].replace('|', ' ')
202
+ prefix = INDENT_COUNTER.join(prefixList)
203
+
204
+ # recursive step with the new prefix and memory dict.
205
+ inspectObj(value, filename, prefix + BAR_CHILD, maxDeep, inspectDetail,
206
+ memoryDict)
207
+
208
+ if isFirstOrLast == IS_FIRST:
209
+ deepStr = str(indentionDeep) + COL_DELIM
210
+ else:
211
+ # When it was not the first item, the deep is increased
212
+ # to improve the readability when filter
213
+ deepStr = str(indentionDeep + 1) + COL_DELIM
214
+
215
+ prefix = prefix.replace(INDENT_COUNTER, '') + COL_DELIM
216
+
217
+ # We introduce the end of the child and
218
+ # also the next header while it is not the last
219
+ file = open(filename, 'a')
220
+ file.write(deepStr + prefix + END_CHILD)
221
+ if isFirstOrLast != IS_LAST:
222
+ # header
223
+ file.write(deepStr + prefix +
224
+ column1 + column2 + column3 + column4 + END_LINE)
225
+ file.close()
226
+
227
+ def isIterable(obj):
228
+ """ Returns true if obj is a tuple, list, dict or calls. """
229
+ isTupleListDict = (isinstance(obj, tuple) or
230
+ isinstance(obj, dict) or
231
+ isinstance(obj, list)) and len(value) > 1
232
+
233
+ # FIX ME: I don't know how to assert if is a class or not...
234
+ isClass = str(type(obj))[1] == 'c'
235
+
236
+ return isClass or (isTupleListDict and inspectDetail < 2)
237
+
238
+ indentionDeep = prefix.count(INDENT_COUNTER)
239
+ if indentionDeep == 0:
240
+ prefix = ' - Root - '
241
+
242
+ # dict with name and value pairs of the members
243
+ if len(object) == 1:
244
+ # if only one obj is passed in the input list,
245
+ # we directly inspect that obj.
246
+ obj_dict = object[0].__dict__
247
+ object = object[0]
248
+
249
+ # setting the header row
250
+ treeHeader = ' - Print on ' + str(datetime.datetime.now())
251
+ prefixHeader = '-DEEP-' + COL_DELIM + treeHeader + COL_DELIM
252
+ col1 = ' - Name - (value for Lists and Tuples)' + COL_DELIM
253
+ col3 = ' - Value - (Pos./Len for Lists and Tuples) ' + COL_DELIM
254
+
255
+ # writing the header row
256
+ file = open(filename, 'w')
257
+ file.write(prefixHeader + col1 + column2 + col3 + column4 + END_LINE)
258
+ file.close()
259
+
260
+ # writing the root object
261
+ writeRow(object.__class__.__name__, object, prefix)
262
+ # adding the child bar to the prefix
263
+ prefix = ' ' + BAR_CHILD
264
+ else:
265
+ # firsts settings depending on the type of the obj
266
+ if str(type(object))[1] == 'c':
267
+ obj_dict = object.__dict__
268
+ elif (isinstance(object, tuple) or
269
+ isinstance(object, list)):
270
+ column1 = ' - Value - ' + COL_DELIM
271
+ column3 = ' - Pos./Len. - ' + COL_DELIM
272
+ elif isinstance(object, dict):
273
+ column1 = ' - Key - ' + COL_DELIM
274
+ obj_dict = object
275
+ else: # if is not of the type above it not make sense to continue
276
+ return
277
+
278
+ indentionDeep = prefix.count(INDENT_COUNTER)
279
+ deepStr = str(indentionDeep) + COL_DELIM
280
+ isBelowMaxDeep = indentionDeep < maxDeep if maxDeep > 0 else True
281
+
282
+ prefixToWrite = prefix.replace(INDENT_COUNTER, '') + COL_DELIM
283
+ file = open(filename, 'a')
284
+ file.write(deepStr + prefixToWrite +
285
+ column1 + column2 + column3 + column4 + END_LINE)
286
+ file.close()
287
+
288
+ # we update the prefix to put the NEW_CHILD string ( |----> )
289
+ prefixList = prefix.split(INDENT_COUNTER)
290
+ prefixList[-2] = NEW_CHILD
291
+ # we return to the string structure
292
+ # with a certain indention if it's the root
293
+ prefixToWrite = ' ' + INDENT_COUNTER.join(prefixList) if indentionDeep == 1 \
294
+ else INDENT_COUNTER.join(prefixList)
295
+
296
+ isNew = True
297
+ if str(type(object))[1] == 'c' or isinstance(object, dict):
298
+ counter = 0
299
+ for key, value in obj_dict.items():
300
+ counter += 1
301
+ # write the variable
302
+ isNew = writeRow(key, value, prefixToWrite)
303
+
304
+ # managing the extremes of the loop
305
+ if counter == 1:
306
+ isFirstOrLast = IS_FIRST
307
+ elif counter == len(obj_dict):
308
+ isFirstOrLast = IS_LAST
309
+ else:
310
+ isFirstOrLast = IS_MIDDLE
311
+
312
+ # show attributes for objects and items for lists and tuples
313
+ if isBelowMaxDeep and isNew and isIterable(value):
314
+ recursivePrint(value, prefix, isFirstOrLast)
315
+ else:
316
+ for i in range(0, len(object)):
317
+ # write the variable
318
+ isNew = writeRow(object[i], object[i], prefixToWrite,
319
+ str(i + 1) + '/' + str(len(object)))
320
+
321
+ # managing the extremes of the loop
322
+ if i == 0:
323
+ isFirstOrLast = IS_FIRST
324
+ elif len(object) == i + 1:
325
+ isFirstOrLast = IS_LAST
326
+ else:
327
+ isFirstOrLast = IS_MIDDLE
328
+
329
+ # show attributes for objects and items for lists and tuples
330
+ if isBelowMaxDeep and isNew and isIterable(object[i]):
331
+ recursivePrint(object[i], prefix, isFirstOrLast)
332
+
@@ -0,0 +1,179 @@
1
+ # **************************************************************************
2
+ # *
3
+ # * Authors: Pablo Conesa (scipion@cnb.csic.es)
4
+ # *
5
+ # * Unidad de Bioinformatica of Centro Nacional de Biotecnologia , CSIC
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, write to the Free Software
19
+ # * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20
+ # * 02111-1307 USA
21
+ # *
22
+ # * All comments concerning this program package may be sent to the
23
+ # * e-mail address 'scipion@cnb.csic.es'
24
+ # *
25
+ # **************************************************************************
26
+ """
27
+ Module for editing variables
28
+ """
29
+
30
+ import tkinter as tk
31
+
32
+ from pyworkflow import Config, Variable, VariablesRegistry, VarTypes
33
+ from pyworkflow.gui import Icon, configureWeigths, getDefaultFont, askPath
34
+ from pyworkflow.gui.tree import TreeProvider
35
+ import pyworkflow.gui.dialog as dialog
36
+
37
+
38
+ class VariablesTreeProvider(TreeProvider):
39
+ """ Populate Tree from Labels. """
40
+ def __init__(self):
41
+ TreeProvider.__init__(self)
42
+ self._parentDict = {}
43
+
44
+ def getColumns(self):
45
+ return [('Name', 300), ('Value', 500), ('Default?', 60), ('DefaultV',200),('Description', 400), ('Source', 150)]
46
+
47
+ def getObjectInfo(self, variable: Variable):
48
+
49
+ return {'key': variable.name, 'parent': None,
50
+ 'text': variable.name, 'values': (variable.value, "is default" if variable.isDefault else "Declared",
51
+ variable.default, variable.description, variable.source),
52
+ }
53
+
54
+
55
+ def getObjects(self):
56
+ return VariablesRegistry.__iter__()
57
+
58
+
59
+ class VariablesDialog(dialog.ToolbarListDialog):
60
+ """
61
+ This dialog will allow editing variables coming either from pyworkflow or the plugins
62
+ """
63
+ def __init__(self, parent, **kwargs):
64
+ """ From kwargs:
65
+ message: message tooltip to show when browsing.
66
+ selected: the item that should be selected.
67
+ validateSelectionCallback:
68
+ a callback function to validate selected items.
69
+ allowSelect: if set to False, the 'Select' button will not
70
+ be shown.
71
+ """
72
+ toolbarButtons = [
73
+ # dialog.ToolbarButton('Add', self._addLabel, Icon.ACTION_NEW),
74
+ dialog.ToolbarButton('Edit', self._editVariable, Icon.ACTION_EDIT),
75
+ dialog.ToolbarButton('Set to default', self._setToDefault, Icon.ACTION_DELETE)
76
+ ]
77
+
78
+ helpMsg =("Use this form to change core and plugin's variables. If \"Default\" is true, it currently is the default value and is not present in the config file. All changes here "
79
+ "will be persisted in the general %s config file. \"Source\" field tells you where the variable is defined."% Config.SCIPION_CONFIG)
80
+
81
+ dialog.ToolbarListDialog.__init__(self, parent,
82
+ "Edit config variables",
83
+ VariablesTreeProvider(),
84
+ helpMsg,
85
+ toolbarButtons,
86
+ allowsEmptySelection=True,
87
+ itemDoubleClick=self._editVariable,
88
+ cancelButton=False,
89
+ buttons=[('Save', dialog.RESULT_YES),
90
+ ('Cancel', dialog.RESULT_CANCEL)],
91
+ **kwargs)
92
+
93
+
94
+ def apply(self):
95
+ VariablesRegistry.save(Config.SCIPION_CONFIG)
96
+ def _editVariable(self, e=None):
97
+ selection = self.tree.getSelectedObjects()
98
+ if selection:
99
+ variable = selection[0]
100
+ dlg = EditVariableDialog(self, "Edit variable", variable)
101
+ if dlg.resultYes():
102
+ self.refresh()
103
+
104
+ def _setToDefault(self, e=None):
105
+ selection = self.tree.getSelectedObjects()
106
+ if selection:
107
+ varsStr = '\n'.join('- %s' % v.name for v in selection)
108
+ if dialog.askYesNo(" The variables will be set it to its default value.",
109
+ "Are you sure to reset the %s"
110
+ "value?\n" % varsStr, self):
111
+ for variable in selection:
112
+ variable.setToDefault()
113
+ self.tree.update()
114
+
115
+
116
+ class EditVariableDialog(dialog.Dialog):
117
+ """ Dialog to edit a variable """
118
+ def __init__(self, parent, title, variable:Variable, **kwargs):
119
+ self.variable = variable
120
+ dialog.Dialog.__init__(self, parent, title)
121
+
122
+ def body(self, bodyFrame):
123
+ bodyFrame.config(bg=Config.SCIPION_BG_COLOR)
124
+ configureWeigths(bodyFrame, 1, 1)
125
+
126
+ # Name
127
+ label_text = tk.Label(bodyFrame, text=self.variable.name, bg=Config.SCIPION_BG_COLOR, bd=0)
128
+ label_text.grid(row=0, column=0, sticky='nw', padx=(15, 10), pady=15)
129
+
130
+ # Description
131
+ label_text = tk.Label(bodyFrame, text=self.variable.description, bg=Config.SCIPION_BG_COLOR, bd=0)
132
+ label_text.grid(row=0, column=1, sticky='nw', padx=(15, 10), pady=15)
133
+
134
+ # Value
135
+ label_text = tk.Label(bodyFrame, text="Value", bg=Config.SCIPION_BG_COLOR, bd=0)
136
+ label_text.grid(row=2, column=0, sticky='nw', padx=(15, 10), pady=15)
137
+
138
+ # Value Entry
139
+ if self.variable.var_type == VarTypes.INTEGER:
140
+ var=tk.IntVar()
141
+ else:
142
+ var = tk.StringVar()
143
+
144
+ var.set(self.variable.value)
145
+ self.valueVar = var
146
+ self.valueLabel = tk.Entry(bodyFrame, width=30, textvariable=var, font=getDefaultFont())
147
+ self.valueLabel.grid(row=2, column=1, sticky='news', padx=5, pady=5)
148
+
149
+ if self.variable.var_type in [VarTypes.PATH, VarTypes.FOLDER, VarTypes.FILENAME]:
150
+ self._addButton(bodyFrame, self.buttonClicked, icon=Icon.ACTION_BROWSE, row=2, col=2,tooltip="Click to browse file system for a file or folder")
151
+
152
+ def buttonClicked(self, e):
153
+ """ Callback for when the wizard button has been clicked"""
154
+
155
+ var_type = self.variable.var_type
156
+
157
+ if var_type in [VarTypes.PATH, VarTypes.FOLDER, VarTypes.FILENAME]:
158
+
159
+ onlyFolders = (var_type == VarTypes.FOLDER)
160
+ returnBaseName = (var_type ==var_type.FILENAME)
161
+ path = self.valueVar.get() if not returnBaseName else "."
162
+
163
+ value =askPath(path=path, master=self, onlyFolders=onlyFolders, returnBaseName=returnBaseName)
164
+ self.valueVar.set(value)
165
+ def apply(self):
166
+ self.variable.setValue(self.valueVar.get())
167
+
168
+ def validate(self):
169
+
170
+ validationMsg = None
171
+
172
+ if len(self.valueVar.get().strip()) == 0:
173
+ validationMsg = "Value name can't be empty.\n"
174
+
175
+ if validationMsg is not None:
176
+ dialog.showError("Validation error", validationMsg, self)
177
+ return False
178
+
179
+ return True