scipion-pyworkflow 3.10.6__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 (123) hide show
  1. pyworkflow/config.py +131 -67
  2. pyworkflow/constants.py +2 -1
  3. pyworkflow/plugin.py +93 -44
  4. pyworkflow/resources/showj/arrowDown.png +0 -0
  5. pyworkflow/resources/showj/arrowUp.png +0 -0
  6. pyworkflow/resources/showj/background_section.png +0 -0
  7. pyworkflow/resources/showj/colRowModeOff.png +0 -0
  8. pyworkflow/resources/showj/colRowModeOn.png +0 -0
  9. pyworkflow/resources/showj/delete.png +0 -0
  10. pyworkflow/resources/showj/doc_icon.png +0 -0
  11. pyworkflow/resources/showj/download_icon.png +0 -0
  12. pyworkflow/resources/showj/enabled_gallery.png +0 -0
  13. pyworkflow/resources/showj/galleryViewOff.png +0 -0
  14. pyworkflow/resources/showj/galleryViewOn.png +0 -0
  15. pyworkflow/resources/showj/goto.png +0 -0
  16. pyworkflow/resources/showj/menu.png +0 -0
  17. pyworkflow/resources/showj/separator.png +0 -0
  18. pyworkflow/resources/showj/tableViewOff.png +0 -0
  19. pyworkflow/resources/showj/tableViewOn.png +0 -0
  20. pyworkflow/resources/showj/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  21. pyworkflow/resources/showj/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  22. pyworkflow/resources/showj/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  23. pyworkflow/resources/showj/volumeOff.png +0 -0
  24. pyworkflow/resources/showj/volumeOn.png +0 -0
  25. pyworkflow/viewer.py +23 -1
  26. pyworkflowtests/protocols.py +1 -3
  27. {scipion_pyworkflow-3.10.6.dist-info → scipion_pyworkflow-3.11.0.dist-info}/METADATA +13 -27
  28. scipion_pyworkflow-3.11.0.dist-info/RECORD +71 -0
  29. {scipion_pyworkflow-3.10.6.dist-info → scipion_pyworkflow-3.11.0.dist-info}/WHEEL +1 -1
  30. pyworkflow/apps/__init__.py +0 -29
  31. pyworkflow/apps/pw_manager.py +0 -37
  32. pyworkflow/apps/pw_plot.py +0 -51
  33. pyworkflow/apps/pw_project.py +0 -113
  34. pyworkflow/apps/pw_protocol_list.py +0 -143
  35. pyworkflow/apps/pw_protocol_run.py +0 -51
  36. pyworkflow/apps/pw_run_tests.py +0 -267
  37. pyworkflow/apps/pw_schedule_run.py +0 -322
  38. pyworkflow/apps/pw_sleep.py +0 -37
  39. pyworkflow/apps/pw_sync_data.py +0 -439
  40. pyworkflow/apps/pw_viewer.py +0 -78
  41. pyworkflow/gui/__init__.py +0 -36
  42. pyworkflow/gui/browser.py +0 -726
  43. pyworkflow/gui/canvas.py +0 -1190
  44. pyworkflow/gui/dialog.py +0 -977
  45. pyworkflow/gui/form.py +0 -2637
  46. pyworkflow/gui/graph.py +0 -247
  47. pyworkflow/gui/graph_layout.py +0 -271
  48. pyworkflow/gui/gui.py +0 -566
  49. pyworkflow/gui/matplotlib_image.py +0 -233
  50. pyworkflow/gui/plotter.py +0 -247
  51. pyworkflow/gui/project/__init__.py +0 -25
  52. pyworkflow/gui/project/base.py +0 -192
  53. pyworkflow/gui/project/constants.py +0 -139
  54. pyworkflow/gui/project/labels.py +0 -205
  55. pyworkflow/gui/project/project.py +0 -492
  56. pyworkflow/gui/project/searchprotocol.py +0 -154
  57. pyworkflow/gui/project/searchrun.py +0 -181
  58. pyworkflow/gui/project/steps.py +0 -171
  59. pyworkflow/gui/project/utils.py +0 -332
  60. pyworkflow/gui/project/variables.py +0 -179
  61. pyworkflow/gui/project/viewdata.py +0 -472
  62. pyworkflow/gui/project/viewprojects.py +0 -510
  63. pyworkflow/gui/project/viewprotocols.py +0 -2093
  64. pyworkflow/gui/project/viewprotocols_extra.py +0 -559
  65. pyworkflow/gui/text.py +0 -771
  66. pyworkflow/gui/tooltip.py +0 -185
  67. pyworkflow/gui/tree.py +0 -684
  68. pyworkflow/gui/widgets.py +0 -307
  69. pyworkflow/mapper/__init__.py +0 -26
  70. pyworkflow/mapper/mapper.py +0 -222
  71. pyworkflow/mapper/sqlite.py +0 -1581
  72. pyworkflow/mapper/sqlite_db.py +0 -145
  73. pyworkflow/project/__init__.py +0 -31
  74. pyworkflow/project/config.py +0 -454
  75. pyworkflow/project/manager.py +0 -180
  76. pyworkflow/project/project.py +0 -2007
  77. pyworkflow/protocol/__init__.py +0 -38
  78. pyworkflow/protocol/bibtex.py +0 -48
  79. pyworkflow/protocol/constants.py +0 -87
  80. pyworkflow/protocol/executor.py +0 -471
  81. pyworkflow/protocol/hosts.py +0 -314
  82. pyworkflow/protocol/launch.py +0 -270
  83. pyworkflow/protocol/package.py +0 -42
  84. pyworkflow/protocol/params.py +0 -741
  85. pyworkflow/protocol/protocol.py +0 -2641
  86. pyworkflow/tests/__init__.py +0 -29
  87. pyworkflow/tests/test_utils.py +0 -25
  88. pyworkflow/tests/tests.py +0 -341
  89. pyworkflow/utils/__init__.py +0 -38
  90. pyworkflow/utils/dataset.py +0 -414
  91. pyworkflow/utils/echo.py +0 -104
  92. pyworkflow/utils/graph.py +0 -169
  93. pyworkflow/utils/log.py +0 -284
  94. pyworkflow/utils/path.py +0 -528
  95. pyworkflow/utils/process.py +0 -153
  96. pyworkflow/utils/profiler.py +0 -92
  97. pyworkflow/utils/progressbar.py +0 -154
  98. pyworkflow/utils/properties.py +0 -631
  99. pyworkflow/utils/reflection.py +0 -129
  100. pyworkflow/utils/utils.py +0 -879
  101. pyworkflow/utils/which.py +0 -229
  102. pyworkflow/webservices/__init__.py +0 -8
  103. pyworkflow/webservices/config.py +0 -11
  104. pyworkflow/webservices/notifier.py +0 -162
  105. pyworkflow/webservices/repository.py +0 -59
  106. pyworkflow/webservices/workflowhub.py +0 -74
  107. pyworkflowtests/tests/__init__.py +0 -0
  108. pyworkflowtests/tests/test_canvas.py +0 -72
  109. pyworkflowtests/tests/test_domain.py +0 -45
  110. pyworkflowtests/tests/test_logs.py +0 -74
  111. pyworkflowtests/tests/test_mappers.py +0 -392
  112. pyworkflowtests/tests/test_object.py +0 -507
  113. pyworkflowtests/tests/test_project.py +0 -42
  114. pyworkflowtests/tests/test_protocol_execution.py +0 -142
  115. pyworkflowtests/tests/test_protocol_export.py +0 -78
  116. pyworkflowtests/tests/test_protocol_output.py +0 -158
  117. pyworkflowtests/tests/test_streaming.py +0 -47
  118. pyworkflowtests/tests/test_utils.py +0 -210
  119. scipion_pyworkflow-3.10.6.dist-info/RECORD +0 -140
  120. scipion_pyworkflow-3.10.6.dist-info/dependency_links.txt +0 -1
  121. {scipion_pyworkflow-3.10.6.dist-info → scipion_pyworkflow-3.11.0.dist-info}/entry_points.txt +0 -0
  122. {scipion_pyworkflow-3.10.6.dist-info → scipion_pyworkflow-3.11.0.dist-info}/licenses/LICENSE.txt +0 -0
  123. {scipion_pyworkflow-3.10.6.dist-info → scipion_pyworkflow-3.11.0.dist-info}/top_level.txt +0 -0
@@ -1,559 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- # **************************************************************************
3
- # *
4
- # * Authors: Pablo Conesa [1]
5
- # *
6
- # * [1] Unidad de Bioinformatica of Centro Nacional de Biotecnologia , CSIC
7
- # *
8
- # * This program is free software: you can redistribute it and/or modify
9
- # * it under the terms of the GNU General Public License as published by
10
- # * the Free Software Foundation, either version 3 of the License, or
11
- # * (at your option) any later version.
12
- # *
13
- # * This program is distributed in the hope that it will be useful,
14
- # * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
- # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
- # * GNU General Public License for more details.
17
- # *
18
- # * You should have received a copy of the GNU General Public License
19
- # * along with this program. If not, see <https://www.gnu.org/licenses/>.
20
- # *
21
- # * All comments concerning this program package may be sent to the
22
- # * e-mail address 'scipion@cnb.csic.es'
23
- # *
24
- # **************************************************************************
25
- """ This modules hosts most of the accessory code that is used in view protocols"""
26
- import json
27
- import os
28
- from configparser import ConfigParser
29
-
30
- from pyworkflow import Config
31
- import pyworkflow.gui as pwgui
32
- import pyworkflow.object as pwobj
33
- import pyworkflow.utils as pwutils
34
- from pyworkflow.gui.project.utils import isAFinalProtocol
35
- from pyworkflow.project import MenuConfig
36
- from pyworkflow.utils import Message, Icon
37
- from pyworkflow.viewer import DESKTOP_TKINTER
38
-
39
-
40
-
41
- class RunIOTreeProvider(pwgui.tree.TreeProvider):
42
- """Create the tree elements from a Protocol Run input/output children"""
43
-
44
- def __init__(self, parent, protocol, mapper, loggerCallback):
45
- """
46
-
47
- :param parent:
48
- :param protocol:
49
- :param mapper:
50
- :param loggerCallback: method to call to log events in the gui.
51
- """
52
-
53
- self.parent = parent
54
- self.protocol = protocol
55
- self.mapper = mapper
56
- self._loggerCallback = loggerCallback
57
-
58
- @staticmethod
59
- def getColumns():
60
- return [('Attribute', 200), ('Info', 100)]
61
-
62
- def getObjects(self):
63
- objs = []
64
- if self.protocol is not None:
65
- # Store a dict with input parents (input, PointerList)
66
- self.inputParentDict = pwobj.OrderedDict()
67
- inputs = []
68
- inputObj = pwobj.String(Message.LABEL_INPUT)
69
- inputObj._icon = Icon.ACTION_IN
70
- self.inputParentDict['_input'] = inputObj
71
- inputParents = [inputObj]
72
-
73
- for key, attr in self.protocol.iterInputAttributes():
74
- attr._parentKey = key
75
- # Repeated keys means there are inside a pointerList
76
- # since the same key is yielded for all items inside
77
- # so update the parent dict with a new object
78
- if key in self.inputParentDict:
79
- if self.inputParentDict[key] == inputObj:
80
- parentObj = pwobj.String(key)
81
- parentObj._icon = Icon.ACTION_IN
82
- parentObj._parentKey = '_input'
83
- inputParents.append(parentObj)
84
- self.inputParentDict[key] = parentObj
85
- else:
86
- self.inputParentDict[key] = inputObj
87
- inputs.append(attr)
88
-
89
- outputs = [attr for _, attr in
90
- self.protocol.iterOutputAttributes()]
91
- self.outputStr = pwobj.String(Message.LABEL_OUTPUT)
92
- objs = inputParents + inputs + [self.outputStr] + outputs
93
- return objs
94
-
95
- def _visualizeObject(self, ViewerClass, obj):
96
- viewer = ViewerClass(project=self.protocol.getProject(),
97
- protocol=self.protocol,
98
- parent=self.parent.window)
99
- viewer.visualize(obj, windows=self.parent.window)
100
-
101
- def _editObject(self, obj):
102
- """Open the Edit GUI Form given an instance"""
103
- pwgui.dialog.EditObjectDialog(self.parent, Message.TITLE_EDIT_OBJECT,
104
- obj, self.mapper)
105
-
106
- def _deleteObject(self, obj):
107
- """ Remove unnecessary output, specially for Coordinates. """
108
- prot = self.protocol
109
- try:
110
- objLabel = self.getObjectLabel(obj, prot)
111
- if self.parent.window.askYesNo("Delete object",
112
- "Are you sure to delete *%s* object?"
113
- % objLabel):
114
- prot.getProject().deleteProtocolOutput(prot, obj)
115
- self.parent._fillSummary()
116
- self.parent.window.showInfo("Object *%s* successfully deleted."
117
- % objLabel)
118
- except Exception as ex:
119
- self.parent.window.showError(str(ex))
120
-
121
- @staticmethod
122
- def getObjectPreview(obj):
123
- desc = "<name>: " + obj.getName()
124
- return None, desc
125
-
126
- def getObjectActions(self, obj):
127
- if isinstance(obj, pwobj.Pointer):
128
- obj = obj.get()
129
- isPointer = True
130
- else:
131
- isPointer = False
132
- actions = []
133
-
134
- # If viewers not loaded yet (firstime)
135
- domain = Config.getDomain()
136
-
137
- if not domain.viewersLoaded():
138
- self._loggerCallback("Discovering viewers for the first time across all the plugins.")
139
-
140
-
141
- viewers = Config.getDomain().findViewers(obj.getClassName(), DESKTOP_TKINTER)
142
-
143
- def viewerCallback(viewer):
144
- return lambda: self._visualizeObject(viewer, obj)
145
-
146
- for v in viewers:
147
- actions.append((v.getName(),
148
- viewerCallback(v),
149
- Icon.ACTION_VISUALIZE))
150
- # EDIT
151
- actions.append((Message.LABEL_EDIT,
152
- lambda: self._editObject(obj),
153
- Icon.ACTION_EDIT))
154
- # DELETE
155
- # Special case to allow delete outputCoordinates
156
- # since we can end up with several outputs and
157
- # we may want to clean up
158
- if self.protocol.allowsDelete(obj) and not isPointer:
159
- actions.append((Message.LABEL_DELETE,
160
- lambda: self._deleteObject(obj),
161
- Icon.ACTION_DELETE))
162
- return actions
163
-
164
- @staticmethod
165
- def getObjectLabel(obj, parent):
166
- """ We will try to show in the list the string representation
167
- that is more readable for the user to pick the desired object.
168
- """
169
- label = 'None'
170
- if obj is not None:
171
- label = obj.getObjLabel()
172
- if not len(label.strip()):
173
- parentLabel = parent.getObjLabel() if parent else 'None'
174
- label = "%s -> %s" % (parentLabel, obj.getLastName())
175
- return label
176
-
177
- def getObjectInfo(self, obj):
178
-
179
- def stringToInfo():
180
- """ String objects converted to info dictionary for the tree"""
181
-
182
- value = obj.get()
183
- infoStr = {'key': value, 'text': value, 'values': '', 'open': True}
184
- if hasattr(obj, '_parentKey'):
185
- infoStr['parent'] = self.inputParentDict[obj._parentKey]
186
- return infoStr
187
-
188
- def labelToValue(label, key, name):
189
- """ To tolerate str(labelObj) in case xmippLib is missing, but
190
- still being able to open a project."""
191
- try:
192
- value = str(label)
193
- except Exception as e:
194
- print("Can not convert object %s - %s to string." % (key, name))
195
- value = str(e)
196
-
197
- return value
198
-
199
- def pointerToInfo():
200
- """ Converts a Pointer into an info dictionary for the tree"""
201
-
202
- namePtr = obj.getLastName()
203
- # Remove ugly item notations inside lists
204
- namePtr = namePtr.replace('__item__000', '')
205
- # Consider Pointer as inputs
206
- imagePtr = getattr(obj, '_icon', '')
207
- parentPtr = self.inputParentDict[obj._parentKey]
208
-
209
- suffix = ''
210
- if obj.hasExtended():
211
- # getExtended method remove old attributes conventions.
212
- extendedValue = obj.getExtended()
213
- if obj.hasExtended():
214
- suffix = '[%s]' % extendedValue
215
- # else:
216
- # suffix = '[Item %s]' % extendedValue
217
-
218
- # Tolerate loading projects:
219
- # When having only the project sqlite..an obj.get() will
220
- # the load of the set...and if it is missing this whole
221
- # "thread" fails.
222
- try:
223
- labelObjPtr = obj.get()
224
- if labelObjPtr is None:
225
- labelObjPtr = obj.getObjValue()
226
- suffix = ''
227
-
228
- except Exception:
229
- return {'parent': parentPtr, 'image': imagePtr, 'text': namePtr,
230
- 'values': ("Couldn't read object attributes.",)}
231
- else:
232
- labelObjPtr = obj.get()
233
-
234
- objKeyPtr = obj._parentKey + str(labelObjPtr.getObjId())
235
- labelPtr = self.getObjectLabel(labelObjPtr,
236
- self.mapper.getParent(labelObjPtr))
237
- namePtr += ' (from %s %s)' % (labelPtr, suffix)
238
- valuePtr = labelToValue(labelObjPtr, objKeyPtr, namePtr)
239
- infoPtr = {'key': objKeyPtr, 'parent': parentPtr, 'image': imagePtr,
240
- 'text': namePtr, 'values': (valuePtr,)}
241
-
242
- return infoPtr
243
-
244
- if obj is None or not obj.hasValue():
245
- return None
246
-
247
- if isinstance(obj, pwobj.String) and not obj.getName():
248
- info = stringToInfo()
249
- else:
250
- # All attributes are considered output, unless they are pointers
251
- image = Icon.ACTION_OUT
252
- parent = self.outputStr
253
-
254
- if isinstance(obj, pwobj.Pointer):
255
- info = pointerToInfo()
256
- else:
257
- name = self.getObjectLabel(obj, self.protocol)
258
- objKey = str(obj.getObjId())
259
- labelObj = obj
260
- value = labelToValue(labelObj, objKey, name)
261
- info = {'key': objKey, 'parent': parent, 'image': image,
262
- 'text': name, 'values': (value,)}
263
- return info
264
-
265
- class ProtocolTreeConfig:
266
- """ Handler class that groups functions and constants
267
- related to the protocols tree configuration.
268
- """
269
- ALL_PROTOCOLS = "All"
270
- TAG_PROTOCOL_DISABLED = 'protocol-disabled'
271
- TAG_PROTOCOL = 'protocol'
272
- TAG_SECTION = 'section'
273
- TAG_PROTOCOL_GROUP = 'protocol_group'
274
- TAG_PROTOCOL_BETA = 'protocol_beta'
275
- TAG_PROTOCOL_NEW = 'protocol_new'
276
- TAG_PROTOCOL_UPDATED = 'protocol_updated'
277
- PLUGIN_CONFIG_PROTOCOLS = 'protocols.conf'
278
-
279
- @classmethod
280
- def getProtocolTag(cls, isInstalled, isBeta=False, isNew=False, isUpdated=False):
281
- """ Return the proper tag depending if the protocol is installed or not.
282
- """
283
- if isInstalled:
284
- if isBeta:
285
- return cls.TAG_PROTOCOL_BETA
286
- elif isNew:
287
- return cls.TAG_PROTOCOL_NEW
288
- elif isUpdated:
289
- return cls.TAG_PROTOCOL_UPDATED
290
- return cls.TAG_PROTOCOL
291
- else:
292
- return cls.TAG_PROTOCOL_DISABLED
293
-
294
- @classmethod
295
- def __addToTree(cls, menu, item, checkFunction=None):
296
- """ Helper function to recursively add items to a menu.
297
- Add item (a dictionary that can contain more dictionaries) to menu
298
- If check function is added will use it to check if the value must be added.
299
- """
300
- children = item.pop('children', [])
301
-
302
- if checkFunction is not None:
303
- add = checkFunction(item)
304
- if not add:
305
- return
306
- subMenu = menu.addSubMenu(**item) # we expect item={'text': ...}
307
- for child in children:
308
- cls.__addToTree(subMenu, child, checkFunction) # add recursively to sub-menu
309
-
310
- return subMenu
311
-
312
- @classmethod
313
- def __inSubMenu(cls, child, subMenu):
314
- """
315
- Return True if child belongs to subMenu
316
- """
317
- for ch in subMenu:
318
- if cls.__isProtocol(child):
319
- if ch.value is not None and ch.value == child['value']:
320
- return ch
321
- elif ch.text == child['text']:
322
- return ch
323
- return None
324
-
325
- @classmethod
326
- def _orderSubMenu(cls, session):
327
- """
328
- Sort all children of a given section:
329
- The protocols first, then the sections (the 'more' section at the end)
330
- """
331
-
332
- def sortWhenLastIsAProtocol():
333
- """ Sorts children when the last is a protocol"""
334
- for i in range(lastChildPos - 1, -1, -1):
335
- if childs[i].tag == cls.TAG_PROTOCOL:
336
- break
337
- else:
338
- tmp = childs[i + 1]
339
- childs[i + 1] = childs[i]
340
- childs[i] = tmp
341
-
342
- def sortWhenLastIsNotAProtocol():
343
- """ Sorts children when the last is NOT a protocol"""
344
- for i in range(lastChildPos - 1, -1, -1):
345
- if childs[i].tag == cls.TAG_PROTOCOL:
346
- break
347
- elif 'more' in str(childs[i].text).lower():
348
- tmp = childs[i + 1]
349
- childs[i + 1] = childs[i]
350
- childs[i] = tmp
351
-
352
- lengthSession = len(session.childs)
353
- if lengthSession > 1:
354
- childs = session.childs
355
- lastChildPos = lengthSession - 1
356
- if childs[lastChildPos].tag == cls.TAG_PROTOCOL:
357
- sortWhenLastIsAProtocol()
358
- else:
359
- sortWhenLastIsNotAProtocol()
360
-
361
- @classmethod
362
- def __findTreeLocation(cls, subMenu, children, parent):
363
- """
364
- Locate the protocol position in the given view
365
- """
366
- for child in children:
367
- sm = cls.__inSubMenu(child, subMenu)
368
- if sm is None:
369
- cls.__addToTree(parent, child, cls.__checkItem)
370
- cls._orderSubMenu(parent)
371
- elif child['tag'] == cls.TAG_PROTOCOL_GROUP or child['tag'] == cls.TAG_SECTION:
372
- cls.__findTreeLocation(sm.childs, child['children'], sm)
373
- @classmethod
374
- def __isProtocol(cls, dict):
375
- """ True inf the item has a key named tag with protocol as value"""
376
- return dict["tag"] == cls.TAG_PROTOCOL
377
-
378
- @classmethod
379
- def __isProtocolNode(cls, node):
380
- """ True if tag attribute is protocol"""
381
- return node.tag == cls.TAG_PROTOCOL
382
-
383
-
384
- @classmethod
385
- def __checkItem(cls, item):
386
- """ Function to check if the protocol has to be added or not.
387
- Params:
388
- item: {"tag": "protocol", "value": "ProtImportMovies",
389
- "text": "import movies"}
390
- """
391
- if not cls.__isProtocol(item):
392
- return True
393
-
394
- # It is a protocol as this point, get the class name and
395
- # check if it is disabled
396
- protClassName = item["value"]
397
- protClass = Config.getDomain().getProtocols().get(protClassName)
398
- icon = Icon.PRODUCTION
399
- if protClass is not None:
400
- if protClass.isBeta():
401
- icon = Icon.BETA
402
- elif protClass.isNewDev():
403
- icon = Icon.NEW
404
- elif protClass.isUpdated():
405
- icon = Icon.UPDATED
406
- item['icon'] = icon
407
- return False if protClass is None else not protClass.isDisabled()
408
-
409
- @classmethod
410
- def __addAllProtocols(cls, domain, protocols):
411
- # Add all protocols
412
- allProts = domain.getProtocols()
413
-
414
- # Sort the list
415
- allProtsSorted = sorted(allProts.items(), key=lambda e: e[1].getClassLabel())
416
-
417
- allProtMenu = ProtocolConfig(cls.ALL_PROTOCOLS)
418
- packages = {}
419
-
420
- # Group protocols by package name
421
- for k, v in allProtsSorted:
422
- if isAFinalProtocol(v, k):
423
- packageName = v.getPlugin().getName()
424
-
425
- # Get the package submenu
426
- packageMenu = packages.get(packageName)
427
-
428
- # If no package menu available
429
- if packageMenu is None:
430
- # Add it to the menu ...
431
- packageLine = {"tag": "package", "value": packageName,
432
- "text": packageName}
433
- packageMenu = cls.__addToTree(allProtMenu, packageLine)
434
-
435
- # Store it in the dict
436
- packages[packageName] = packageMenu
437
-
438
- # Add the protocol
439
- tag = cls.getProtocolTag(v.isInstalled(), v.isBeta(), v.isNewDev(), v.isUpdated())
440
-
441
- protLine = {"tag": tag, "value": k,
442
- "text": v.getClassLabel(prependPackageName=False)}
443
-
444
- cls.__addToTree(packageMenu, protLine)
445
-
446
- protocols[cls.ALL_PROTOCOLS] = allProtMenu
447
-
448
- @classmethod
449
- def __addProtocolsFromConf(cls, protocols, protocolsConfPath):
450
- """
451
- Load the protocols in the tree from a given protocols.conf file,
452
- either the global one in Scipion or defined in a plugin.
453
- """
454
-
455
- def addProtocols():
456
- """ Adds protocols defined in the "PROTOCOLS" section of the config file. """
457
- for menuName in cp.options('PROTOCOLS'):
458
- if menuName not in protocols: # The view has not been inserted
459
- menu = ProtocolConfig(menuName)
460
- children = json.loads(cp.get('PROTOCOLS', menuName))
461
- for child in children:
462
- cls.__addToTree(menu, child, cls.__checkItem)
463
- protocols[menuName] = menu
464
- else: # The view has been inserted
465
- menu = protocols.get(menuName)
466
- children = json.loads(cp.get('PROTOCOLS',
467
- menuName))
468
- cls.__findTreeLocation(menu.childs, children, menu)
469
-
470
- # Populate the protocols menu from the plugin config file.
471
- if os.path.exists(protocolsConfPath):
472
- cp = ConfigParser()
473
- cp.optionxform = str # keep case
474
- cp.read(protocolsConfPath)
475
- # Ensure that the protocols section exists
476
- if cp.has_section('PROTOCOLS'):
477
- addProtocols()
478
-
479
- @classmethod
480
- def load(cls, domain, protocolsConf):
481
- """ Read the protocol configuration from a .conf file similar to the
482
- one in scipion/config/protocols.conf,
483
- which is the default one when no file is passed.
484
- """
485
- protocols = dict()
486
- # Read the protocols.conf from Scipion (base) and create an initial
487
- # tree view
488
- cls.__addProtocolsFromConf(protocols, protocolsConf)
489
-
490
- # Read the protocols.conf of any installed plugin
491
- pluginDict = domain.getPlugins()
492
-
493
- for pluginName in pluginDict.keys():
494
- try:
495
-
496
- # if the plugin has a path
497
- if pwutils.isModuleLoaded(pluginName) and pwutils.isModuleAFolder(pluginName):
498
- # Locate the plugin protocols.conf file
499
- protocolsConfPath = os.path.join(
500
- pluginDict[pluginName].__path__[0],
501
- cls.PLUGIN_CONFIG_PROTOCOLS)
502
- cls.__addProtocolsFromConf(protocols, protocolsConfPath)
503
-
504
- except Exception as e:
505
- print('Failed to read settings. The reported error was:\n %s\n'
506
- 'To solve it, fix %s and run again.' % (e, pluginName))
507
-
508
- # Clean empty sections
509
- cls._hideEmptySections(protocols)
510
-
511
- # Add all protocols to All view
512
- cls.__addAllProtocols(domain, protocols)
513
-
514
- return protocols
515
-
516
- @classmethod
517
- def _hideEmptySections(cls, protocols):
518
- """ Cleans all empty sections in the tree"""
519
-
520
- for protConf in protocols.values():
521
- cls._setVisibility(protConf)
522
-
523
- @classmethod
524
- def _setVisibility(cls, node):
525
- """ Sets the visibility of a node based on the presence of a leaf hanging form it"""
526
- if cls.__isProtocolNode(node):
527
- # Default visibility value is true. No need to set it again
528
- return True
529
-
530
- anyLeaf = False
531
-
532
- for child in node.childs:
533
- # NOTE: since python short circuits this, _setVisibility must be called always. So not swap!!
534
- anyLeaf = cls._setVisibility(child) or anyLeaf
535
-
536
- node.visible = anyLeaf
537
-
538
- return anyLeaf
539
-
540
-
541
- class ProtocolConfig(MenuConfig):
542
- """Store protocols configuration """
543
-
544
- def __init__(self, text=None, value=None, **args):
545
- MenuConfig.__init__(self, text, value, **args)
546
- if 'openItem' not in args:
547
- self.openItem = self.tag != 'protocol_base'
548
-
549
- def addSubMenu(self, text, value=None, shortCut=None, **args):
550
- if 'icon' not in args:
551
- tag = args.get('tag', None)
552
- if tag == 'protocol_base':
553
- args['icon'] = Icon.GROUP
554
-
555
- args['shortCut'] = shortCut
556
- return MenuConfig.addSubMenu(self, text, value, **args)
557
-
558
- def __str__(self):
559
- return self.text