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.
- pyworkflow/config.py +131 -67
- pyworkflow/constants.py +2 -1
- pyworkflow/plugin.py +93 -44
- pyworkflow/resources/showj/arrowDown.png +0 -0
- pyworkflow/resources/showj/arrowUp.png +0 -0
- pyworkflow/resources/showj/background_section.png +0 -0
- pyworkflow/resources/showj/colRowModeOff.png +0 -0
- pyworkflow/resources/showj/colRowModeOn.png +0 -0
- pyworkflow/resources/showj/delete.png +0 -0
- pyworkflow/resources/showj/doc_icon.png +0 -0
- pyworkflow/resources/showj/download_icon.png +0 -0
- pyworkflow/resources/showj/enabled_gallery.png +0 -0
- pyworkflow/resources/showj/galleryViewOff.png +0 -0
- pyworkflow/resources/showj/galleryViewOn.png +0 -0
- pyworkflow/resources/showj/goto.png +0 -0
- pyworkflow/resources/showj/menu.png +0 -0
- pyworkflow/resources/showj/separator.png +0 -0
- pyworkflow/resources/showj/tableViewOff.png +0 -0
- pyworkflow/resources/showj/tableViewOn.png +0 -0
- pyworkflow/resources/showj/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- pyworkflow/resources/showj/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- pyworkflow/resources/showj/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- pyworkflow/resources/showj/volumeOff.png +0 -0
- pyworkflow/resources/showj/volumeOn.png +0 -0
- pyworkflow/viewer.py +23 -1
- pyworkflowtests/protocols.py +1 -3
- {scipion_pyworkflow-3.10.6.dist-info → scipion_pyworkflow-3.11.0.dist-info}/METADATA +13 -27
- scipion_pyworkflow-3.11.0.dist-info/RECORD +71 -0
- {scipion_pyworkflow-3.10.6.dist-info → scipion_pyworkflow-3.11.0.dist-info}/WHEEL +1 -1
- pyworkflow/apps/__init__.py +0 -29
- pyworkflow/apps/pw_manager.py +0 -37
- pyworkflow/apps/pw_plot.py +0 -51
- pyworkflow/apps/pw_project.py +0 -113
- pyworkflow/apps/pw_protocol_list.py +0 -143
- pyworkflow/apps/pw_protocol_run.py +0 -51
- pyworkflow/apps/pw_run_tests.py +0 -267
- pyworkflow/apps/pw_schedule_run.py +0 -322
- pyworkflow/apps/pw_sleep.py +0 -37
- pyworkflow/apps/pw_sync_data.py +0 -439
- pyworkflow/apps/pw_viewer.py +0 -78
- pyworkflow/gui/__init__.py +0 -36
- pyworkflow/gui/browser.py +0 -726
- pyworkflow/gui/canvas.py +0 -1190
- pyworkflow/gui/dialog.py +0 -977
- pyworkflow/gui/form.py +0 -2637
- pyworkflow/gui/graph.py +0 -247
- pyworkflow/gui/graph_layout.py +0 -271
- pyworkflow/gui/gui.py +0 -566
- pyworkflow/gui/matplotlib_image.py +0 -233
- pyworkflow/gui/plotter.py +0 -247
- pyworkflow/gui/project/__init__.py +0 -25
- pyworkflow/gui/project/base.py +0 -192
- pyworkflow/gui/project/constants.py +0 -139
- pyworkflow/gui/project/labels.py +0 -205
- pyworkflow/gui/project/project.py +0 -492
- pyworkflow/gui/project/searchprotocol.py +0 -154
- pyworkflow/gui/project/searchrun.py +0 -181
- pyworkflow/gui/project/steps.py +0 -171
- pyworkflow/gui/project/utils.py +0 -332
- pyworkflow/gui/project/variables.py +0 -179
- pyworkflow/gui/project/viewdata.py +0 -472
- pyworkflow/gui/project/viewprojects.py +0 -510
- pyworkflow/gui/project/viewprotocols.py +0 -2093
- pyworkflow/gui/project/viewprotocols_extra.py +0 -559
- pyworkflow/gui/text.py +0 -771
- pyworkflow/gui/tooltip.py +0 -185
- pyworkflow/gui/tree.py +0 -684
- pyworkflow/gui/widgets.py +0 -307
- pyworkflow/mapper/__init__.py +0 -26
- pyworkflow/mapper/mapper.py +0 -222
- pyworkflow/mapper/sqlite.py +0 -1581
- pyworkflow/mapper/sqlite_db.py +0 -145
- pyworkflow/project/__init__.py +0 -31
- pyworkflow/project/config.py +0 -454
- pyworkflow/project/manager.py +0 -180
- pyworkflow/project/project.py +0 -2007
- pyworkflow/protocol/__init__.py +0 -38
- pyworkflow/protocol/bibtex.py +0 -48
- pyworkflow/protocol/constants.py +0 -87
- pyworkflow/protocol/executor.py +0 -471
- pyworkflow/protocol/hosts.py +0 -314
- pyworkflow/protocol/launch.py +0 -270
- pyworkflow/protocol/package.py +0 -42
- pyworkflow/protocol/params.py +0 -741
- pyworkflow/protocol/protocol.py +0 -2641
- pyworkflow/tests/__init__.py +0 -29
- pyworkflow/tests/test_utils.py +0 -25
- pyworkflow/tests/tests.py +0 -341
- pyworkflow/utils/__init__.py +0 -38
- pyworkflow/utils/dataset.py +0 -414
- pyworkflow/utils/echo.py +0 -104
- pyworkflow/utils/graph.py +0 -169
- pyworkflow/utils/log.py +0 -284
- pyworkflow/utils/path.py +0 -528
- pyworkflow/utils/process.py +0 -153
- pyworkflow/utils/profiler.py +0 -92
- pyworkflow/utils/progressbar.py +0 -154
- pyworkflow/utils/properties.py +0 -631
- pyworkflow/utils/reflection.py +0 -129
- pyworkflow/utils/utils.py +0 -879
- pyworkflow/utils/which.py +0 -229
- pyworkflow/webservices/__init__.py +0 -8
- pyworkflow/webservices/config.py +0 -11
- pyworkflow/webservices/notifier.py +0 -162
- pyworkflow/webservices/repository.py +0 -59
- pyworkflow/webservices/workflowhub.py +0 -74
- pyworkflowtests/tests/__init__.py +0 -0
- pyworkflowtests/tests/test_canvas.py +0 -72
- pyworkflowtests/tests/test_domain.py +0 -45
- pyworkflowtests/tests/test_logs.py +0 -74
- pyworkflowtests/tests/test_mappers.py +0 -392
- pyworkflowtests/tests/test_object.py +0 -507
- pyworkflowtests/tests/test_project.py +0 -42
- pyworkflowtests/tests/test_protocol_execution.py +0 -142
- pyworkflowtests/tests/test_protocol_export.py +0 -78
- pyworkflowtests/tests/test_protocol_output.py +0 -158
- pyworkflowtests/tests/test_streaming.py +0 -47
- pyworkflowtests/tests/test_utils.py +0 -210
- scipion_pyworkflow-3.10.6.dist-info/RECORD +0 -140
- scipion_pyworkflow-3.10.6.dist-info/dependency_links.txt +0 -1
- {scipion_pyworkflow-3.10.6.dist-info → scipion_pyworkflow-3.11.0.dist-info}/entry_points.txt +0 -0
- {scipion_pyworkflow-3.10.6.dist-info → scipion_pyworkflow-3.11.0.dist-info}/licenses/LICENSE.txt +0 -0
- {scipion_pyworkflow-3.10.6.dist-info → scipion_pyworkflow-3.11.0.dist-info}/top_level.txt +0 -0
@@ -1,181 +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 code provider and window to search for a run"""
|
26
|
-
|
27
|
-
import tkinter as tk
|
28
|
-
from pyworkflow import Config
|
29
|
-
import pyworkflow.protocol as pwprot
|
30
|
-
|
31
|
-
from pyworkflow.gui import SearchBaseWindow
|
32
|
-
from pyworkflow.gui.project.constants import *
|
33
|
-
from pyworkflow.gui.tree import ProjectRunsTreeProvider
|
34
|
-
|
35
|
-
class RunsTreeProvider(ProjectRunsTreeProvider):
|
36
|
-
"""Provide runs info to populate tree inside viewprotocols. Is more advanced
|
37
|
-
than ProjectRunsTreeProvider extended, extended with right click actions."""
|
38
|
-
|
39
|
-
def __init__(self, project, actionFunc):
|
40
|
-
super().__init__(project)
|
41
|
-
self.actionFunc = actionFunc # ProtocolsView._runActionClicked
|
42
|
-
self._selection = project.getSettings().runSelection
|
43
|
-
|
44
|
-
def getActionsFromSelection(self):
|
45
|
-
""" Return the list of options available for selection. """
|
46
|
-
n = len(self._selection)
|
47
|
-
single = n == 1
|
48
|
-
anyselected = n > 0
|
49
|
-
if n:
|
50
|
-
prot = self.project.getProtocol(self._selection[0], fromRuns=True)
|
51
|
-
status = prot.getStatus()
|
52
|
-
nodeInfo = self.project.getSettings().getNodeById(prot.getObjId())
|
53
|
-
expanded = nodeInfo.isExpanded() if nodeInfo else True
|
54
|
-
else:
|
55
|
-
status = None
|
56
|
-
|
57
|
-
stoppable = status in [pwprot.STATUS_RUNNING, pwprot.STATUS_SCHEDULED,
|
58
|
-
pwprot.STATUS_LAUNCHED]
|
59
|
-
|
60
|
-
# This list defines the order the icons are shown
|
61
|
-
return [(ACTION_NEW, True),
|
62
|
-
(ACTION_EDIT, single and status and expanded),
|
63
|
-
(ACTION_BROWSE, single and status and expanded),
|
64
|
-
(ACTION_RENAME, single and status and expanded),
|
65
|
-
(ACTION_LABELS, True),
|
66
|
-
|
67
|
-
(ACTION_DUPLICATE, status and expanded),
|
68
|
-
(ACTION_COPY, status and expanded),
|
69
|
-
(ACTION_PASTE, status and expanded),
|
70
|
-
(ACTION_DELETE, status != pwprot.STATUS_RUNNING and status and expanded),
|
71
|
-
|
72
|
-
(ACTION_SELECT_FROM, anyselected),
|
73
|
-
(ACTION_SELECT_TO, anyselected),
|
74
|
-
(ACTION_COLLAPSE, single and status and expanded),
|
75
|
-
(ACTION_EXPAND, single and status and not expanded),
|
76
|
-
|
77
|
-
(ACTION_STOP, stoppable and single),
|
78
|
-
(ACTION_STOP_WORKFLOW, single),
|
79
|
-
(ACTION_RESTART_WORKFLOW, single),
|
80
|
-
(ACTION_CONTINUE_WORKFLOW, single),
|
81
|
-
(ACTION_RESET_WORKFLOW, single),
|
82
|
-
|
83
|
-
(ACTION_EXPORT, anyselected),
|
84
|
-
(ACTION_EXPORT_UPLOAD, anyselected),
|
85
|
-
|
86
|
-
(ACTION_STEPS, single and Config.debugOn() and status and expanded),
|
87
|
-
(ACTION_DB, single and Config.debugOn() and status and expanded),
|
88
|
-
]
|
89
|
-
|
90
|
-
def getObjectActions(self, obj, withEvent=False):
|
91
|
-
""" Get actions available to perform.
|
92
|
-
|
93
|
-
This method is called in 2 cases:
|
94
|
-
1.- Right-click on the tree (list of runs)
|
95
|
-
2.- Right-click on the canvas. When called from the canvas we need the event to get the click's position.
|
96
|
-
|
97
|
-
:param obj: optional, if passed, actions on the object. otherwise generic actions
|
98
|
-
:param withEvent: pass True if callback has to have the event as a parameter (call from canvas but not from tree)
|
99
|
-
|
100
|
-
"""
|
101
|
-
|
102
|
-
def addAction(actionLabel):
|
103
|
-
if actionLabel:
|
104
|
-
text = actionLabel
|
105
|
-
action = actionLabel
|
106
|
-
if withEvent:
|
107
|
-
callback=lambda e: self.actionFunc(action, e)
|
108
|
-
else:
|
109
|
-
callback=lambda: self.actionFunc(action)
|
110
|
-
|
111
|
-
actionLabel = (text, callback,
|
112
|
-
ActionIcons.get(action, None),
|
113
|
-
ActionShortCuts.get(action,None))
|
114
|
-
return actionLabel
|
115
|
-
|
116
|
-
actions = [addAction(a)
|
117
|
-
for a, cond in self.getActionsFromSelection() if cond]
|
118
|
-
|
119
|
-
if obj is not None and hasattr(obj, 'getActions'):
|
120
|
-
for text, action in obj.getActions():
|
121
|
-
actions.append((text, action, None))
|
122
|
-
|
123
|
-
return actions
|
124
|
-
|
125
|
-
|
126
|
-
class SearchRunWindow(SearchBaseWindow):
|
127
|
-
|
128
|
-
columnConfig = {
|
129
|
-
'#0': (ProjectRunsTreeProvider.ID_COLUMN, {'width': 100, 'stretch': tk.NO}, 10),
|
130
|
-
ProjectRunsTreeProvider.RUN_COLUMN: (ProjectRunsTreeProvider.RUN_COLUMN, {'width': 300, 'stretch': tk.TRUE}, 10),
|
131
|
-
ProjectRunsTreeProvider.STATE_COLUMN: (ProjectRunsTreeProvider.STATE_COLUMN, {'width': 150, 'stretch': tk.FALSE}, 5),
|
132
|
-
ProjectRunsTreeProvider.TIME_COLUMN: (ProjectRunsTreeProvider.TIME_COLUMN, {'width': 200, 'stretch': tk.FALSE}, 5),
|
133
|
-
'Comment': ('Comment', {'width': 300, 'stretch': tk.FALSE}, 5),
|
134
|
-
'Expanded': ('Expanded', {'width': 150, 'stretch': tk.FALSE}, 5),
|
135
|
-
}
|
136
|
-
|
137
|
-
def __init__(self, parentWindow, runsGraph, **kwargs):
|
138
|
-
|
139
|
-
|
140
|
-
super().__init__(parentWindow,
|
141
|
-
title="Locate a protocol in the graph",
|
142
|
-
**kwargs)
|
143
|
-
self.runsGraph = runsGraph
|
144
|
-
|
145
|
-
def _onSearchClick(self, e=None):
|
146
|
-
|
147
|
-
self._resultsTree.clear()
|
148
|
-
keyword = self._searchVar.get().lower().strip()
|
149
|
-
|
150
|
-
weightIndex = len(self.columnConfig)
|
151
|
-
nodes = self.runsGraph.getNodes()
|
152
|
-
protList = []
|
153
|
-
|
154
|
-
for node in nodes:
|
155
|
-
if node.run is not None:
|
156
|
-
run = node.run
|
157
|
-
key = run.getObjId()
|
158
|
-
label = run.getRunName()
|
159
|
-
status = run.getStatusMessage(),
|
160
|
-
time = run.getObjCreation()
|
161
|
-
comment = run.getObjComment()
|
162
|
-
expanded = "expanded" if getattr(node, 'expanded', False) else "collapsed"
|
163
|
-
line = (key, label, status, time, comment, expanded)
|
164
|
-
|
165
|
-
line = self.addSearchWeight(line, keyword)
|
166
|
-
# something was found: weight > 0
|
167
|
-
if line[weightIndex] != 0:
|
168
|
-
# Add the run
|
169
|
-
protList.append(line)
|
170
|
-
|
171
|
-
# Sort by weight
|
172
|
-
protList.sort(reverse=True, key=lambda x: x[weightIndex])
|
173
|
-
|
174
|
-
for line in protList:
|
175
|
-
|
176
|
-
self._resultsTree.insert(
|
177
|
-
'', 'end', line[0], text=line[0],
|
178
|
-
values=line[1:])
|
179
|
-
|
180
|
-
|
181
|
-
|
pyworkflow/gui/project/steps.py
DELETED
@@ -1,171 +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 gui code to visualize steps"""
|
26
|
-
import json
|
27
|
-
import tkinter as tk
|
28
|
-
|
29
|
-
import pyworkflow.protocol as pwprot
|
30
|
-
import pyworkflow.gui as pwgui
|
31
|
-
import pyworkflow.utils as pwutils
|
32
|
-
|
33
|
-
from pyworkflow import TK
|
34
|
-
from pyworkflow.utils import Icon
|
35
|
-
|
36
|
-
|
37
|
-
class StepsTreeProvider(pwgui.tree.TreeProvider):
|
38
|
-
"""Create the tree elements for a Protocol run"""
|
39
|
-
|
40
|
-
def __init__(self, stepsList):
|
41
|
-
for i, s in enumerate(stepsList):
|
42
|
-
if not s._index:
|
43
|
-
s._index = i + 1
|
44
|
-
|
45
|
-
self._stepsList = stepsList
|
46
|
-
self.getColumns = lambda: [('Index', 50), ('Step', 200), ('Status', 150),
|
47
|
-
('Time', 150), ('Class', 100)]
|
48
|
-
self._parentDict = {}
|
49
|
-
|
50
|
-
def getObjects(self):
|
51
|
-
return self._stepsList
|
52
|
-
|
53
|
-
@staticmethod
|
54
|
-
def getObjectInfo(obj):
|
55
|
-
info = {'key': obj._index,
|
56
|
-
'values': (str(obj), obj.getStatus(), pwutils.prettyDelta(obj.getElapsedTime()),
|
57
|
-
obj.getClassName())}
|
58
|
-
return info
|
59
|
-
|
60
|
-
@staticmethod
|
61
|
-
def getObjectPreview(obj: pwprot.Step):
|
62
|
-
|
63
|
-
args = json.loads(obj.argsStr.get())
|
64
|
-
msg = "*Prerequisites*: %s \n" % str(obj._prerequisites)
|
65
|
-
|
66
|
-
msg += ("*Arguments*:\n")
|
67
|
-
for arg in args:
|
68
|
-
msg += " %s\n" % arg
|
69
|
-
|
70
|
-
msg += "*Needs GPU*: %s" % obj.needsGPU()
|
71
|
-
|
72
|
-
if hasattr(obj, 'resultFiles'):
|
73
|
-
results = json.loads(obj.resultFiles.get())
|
74
|
-
if len(results):
|
75
|
-
msg += "\n*Result files:* " + '\n '.join(results)
|
76
|
-
|
77
|
-
return None, msg
|
78
|
-
|
79
|
-
class StepsWindow(pwgui.browser.BrowserWindow):
|
80
|
-
def __init__(self, title, parentWindow, protocol, **args):
|
81
|
-
self._protocol = protocol
|
82
|
-
provider = StepsTreeProvider(protocol.loadSteps())
|
83
|
-
pwgui.browser.BrowserWindow.__init__(self, title, parentWindow,
|
84
|
-
weight=False, **args)
|
85
|
-
# Create buttons toolbar
|
86
|
-
self.root.columnconfigure(0, weight=1)
|
87
|
-
self.root.rowconfigure(1, weight=1)
|
88
|
-
|
89
|
-
self.fillToolBar()
|
90
|
-
|
91
|
-
# Create and set browser
|
92
|
-
browser = pwgui.browser.ObjectBrowser(self.root, provider,
|
93
|
-
showPreviewTop=False)
|
94
|
-
self.setBrowser(browser, row=1, column=0)
|
95
|
-
|
96
|
-
def fillToolBar(self):
|
97
|
-
# Tool bar
|
98
|
-
toolbar = tk.Frame(self.root)
|
99
|
-
toolbar.grid(row=0, column=0, sticky='nw', padx=5, pady=5)
|
100
|
-
|
101
|
-
# Tree button
|
102
|
-
btn = tk.Label(toolbar, text="Tree",
|
103
|
-
image=self.getImage(Icon.CODE_BRANCH),
|
104
|
-
compound=tk.LEFT, cursor='hand2')
|
105
|
-
btn.bind(TK.LEFT_CLICK, self._showTree)
|
106
|
-
btn.grid(row=0, column=0, sticky='nw')
|
107
|
-
|
108
|
-
# Reset status
|
109
|
-
btn = tk.Label(toolbar, text="Reset",
|
110
|
-
image=self.getImage(Icon.BROOM),
|
111
|
-
compound=tk.LEFT, cursor='hand2')
|
112
|
-
btn.bind('<Button-1>', self._resetStep)
|
113
|
-
btn.grid(row=0, column=1, sticky='nw')
|
114
|
-
|
115
|
-
# Finish status
|
116
|
-
btn = tk.Label(toolbar, text="Finish",
|
117
|
-
image=self.getImage(Icon.CHECKED),
|
118
|
-
compound=tk.LEFT, cursor='hand2')
|
119
|
-
btn.bind('<Button-1>', self._finishStep)
|
120
|
-
btn.grid(row=0, column=2, sticky='nw')
|
121
|
-
|
122
|
-
def _setStepStatus(self, status):
|
123
|
-
|
124
|
-
item = self.browser._lastSelected
|
125
|
-
if item is not None:
|
126
|
-
objId = item.getObjId()
|
127
|
-
self._protocol._updateSteps(lambda step: step.setStatus(status), where="id='%s'" % objId)
|
128
|
-
item.setStatus(status)
|
129
|
-
self.browser.tree.update()
|
130
|
-
def _resetStep(self, e=None):
|
131
|
-
self._setStepStatus(pwprot.STATUS_NEW)
|
132
|
-
|
133
|
-
def _finishStep(self, e=None):
|
134
|
-
self._setStepStatus(pwprot.STATUS_FINISHED)
|
135
|
-
|
136
|
-
# noinspection PyUnusedLocal
|
137
|
-
def _showTree(self, e=None):
|
138
|
-
g = self._protocol.getStepsGraph()
|
139
|
-
w = pwgui.Window("Protocol steps", self, minsize=(800, 600))
|
140
|
-
root = w.root
|
141
|
-
canvas = pwgui.Canvas(root, width=600, height=500,
|
142
|
-
tooltipCallback=self._stepTooltip,)
|
143
|
-
canvas.grid(row=0, column=0, sticky='nsew')
|
144
|
-
canvas.drawGraph(g, pwgui.LevelTreeLayout())
|
145
|
-
w.show()
|
146
|
-
|
147
|
-
def _stepTooltip(self, tw, item):
|
148
|
-
""" Create the contents of the tooltip to be displayed
|
149
|
-
for the given step.
|
150
|
-
Params:
|
151
|
-
tw: a tk.TopLevel instance (ToolTipWindow)
|
152
|
-
item: the selected step.
|
153
|
-
"""
|
154
|
-
|
155
|
-
if not hasattr(item.node, 'step'):
|
156
|
-
return
|
157
|
-
|
158
|
-
step = item.node.step
|
159
|
-
|
160
|
-
tm = str(step.funcName)
|
161
|
-
|
162
|
-
if not hasattr(tw, 'tooltipText'):
|
163
|
-
frame = tk.Frame(tw)
|
164
|
-
frame.grid(row=0, column=0)
|
165
|
-
tw.tooltipText = pwgui.dialog.createMessageBody(
|
166
|
-
frame, tm, None, textPad=0, textBg=pwutils.Color.ALT_COLOR_2)
|
167
|
-
tw.tooltipText.config(bd=1, relief=tk.RAISED)
|
168
|
-
else:
|
169
|
-
pwgui.dialog.fillMessageText(tw.tooltipText, tm)
|
170
|
-
|
171
|
-
|
pyworkflow/gui/project/utils.py
DELETED
@@ -1,332 +0,0 @@
|
|
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
|
-
|