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,492 +0,0 @@
1
- #!/usr/bin/env python
2
- # **************************************************************************
3
- # *
4
- # * Authors: J.M. De la Rosa Trevin (delarosatrevin@scilifelab.se) [1]
5
- # *
6
- # * [1] SciLifeLab, Stockholm University
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
- """
26
- Main Project window implementation.
27
- It is composed by three panels:
28
- 1. Left: protocol tree.
29
- 2. Right upper: VIEWS (Data/Protocols)
30
- 3. Summary/Details
31
- """
32
-
33
- import logging
34
- from tkinter import Label
35
-
36
- from .. import askString
37
-
38
- logger = logging.getLogger(__name__)
39
-
40
- import os
41
- import threading
42
- import shlex
43
- import subprocess
44
- import socketserver
45
-
46
- import pyworkflow as pw
47
- import pyworkflow.utils as pwutils
48
- from pyworkflow.gui.project.utils import OS
49
- from pyworkflow.project import MenuConfig
50
- from pyworkflow.gui import Message, Icon, getBigFont, ToolTip
51
- from pyworkflow.gui.browser import FileBrowserWindow
52
-
53
- from pyworkflow.gui.plotter import Plotter
54
- from pyworkflow.gui.text import _open_cmd, openTextFileEditor
55
- from pyworkflow.webservices import ProjectWorkflowNotifier, WorkflowRepository
56
-
57
- from .labels import LabelsDialog
58
- # Import possible Object commands to be handled
59
- from .base import ProjectBaseWindow, VIEW_PROTOCOLS, VIEW_PROJECTS
60
-
61
-
62
- class ProjectWindow(ProjectBaseWindow):
63
- """ Main window for working in a Project. """
64
- _OBJECT_COMMANDS = {}
65
-
66
- def __init__(self, path, master=None):
67
- # Load global configuration
68
- self.projPath = path
69
- self.project = self.loadProject()
70
- self.projName = self.project.getShortName()
71
-
72
- try:
73
- projTitle = '%s (%s on %s)' % (self.projName,
74
- pwutils.getLocalUserName(),
75
- pwutils.getLocalHostName())
76
- except Exception:
77
- projTitle = self.projName
78
-
79
-
80
- # TODO: put the menu part more nicely. From here:
81
- menu = MenuConfig()
82
-
83
- projMenu = menu.addSubMenu('Project')
84
- projMenu.addSubMenu('Browse files', 'browse',
85
- icon=Icon.FOLDER_OPEN)
86
- projMenu.addSubMenu('Remove temporary files', 'delete',
87
- icon=Icon.ACTION_DELETE)
88
- projMenu.addSubMenu('Toggle color mode', 'color_mode',
89
- shortCut="Ctrl+t", icon=Icon.ACTION_VISUALIZE)
90
- projMenu.addSubMenu('Select all protocols', 'select all',
91
- shortCut="Ctrl+a", icon=Icon.SELECT_ALL)
92
- projMenu.addSubMenu('Locate a protocol', 'locate protocol',
93
- shortCut="Ctrl+l")
94
- projMenu.addSubMenu('', '') # add separator
95
- projMenu.addSubMenu('Import workflow', 'load_workflow',
96
- icon=Icon.DOWNLOAD)
97
- projMenu.addSubMenu('Search workflow', 'search_workflow',
98
- icon=Icon.ACTION_SEARCH)
99
-
100
- projMenu.addSubMenu('Configuration', 'configuration',
101
- icon=Icon.SETTINGS)
102
-
103
- projMenu.addSubMenu('', '') # add separator
104
- projMenu.addSubMenu('Debug Mode', 'debug mode',
105
- shortCut="Ctrl+D", icon=Icon.DEBUG)
106
- projMenu.addSubMenu('', '') # add separator
107
- projMenu.addSubMenu('Notes', 'notes', icon=Icon.ACTION_EDIT)
108
- projMenu.addSubMenu('', '') # add separator
109
- projMenu.addSubMenu('Exit', 'exit', icon=Icon.ACTION_OUT)
110
-
111
- helpMenu = menu.addSubMenu('Help')
112
- helpMenu.addSubMenu('Online help', 'online_help',
113
- icon=Icon.ACTION_EXPORT)
114
- helpMenu.addSubMenu('About', 'about',
115
- icon=Icon.ACTION_HELP)
116
- helpMenu.addSubMenu('Contact support', 'contact_us',
117
- icon=Icon.ACTION_HELP)
118
-
119
- self.menuCfg = menu
120
-
121
- if self.project.openedAsReadOnly():
122
- self.projName += "<READ ONLY>"
123
-
124
- # Notify about the workflow in this project
125
- self.selectedProtocol = None
126
- self.showGraph = False
127
- self.commentTT = None # Tooltip to store the project description
128
-
129
- Plotter.setBackend('TkAgg')
130
- ProjectBaseWindow.__init__(self, projTitle, master,
131
- minsize=(90, 50), icon=Icon.SCIPION_ICON_PROJ, _class=self.projName)
132
-
133
- OS.handler().maximizeWindow(self.root)
134
-
135
- self.switchView(VIEW_PROTOCOLS)
136
-
137
- self.initProjectTCPServer() # Socket thread to communicate with clients
138
-
139
- ProjectWorkflowNotifier(self.project).notifyWorkflow()
140
-
141
-
142
- def createHeaderFrame(self, parent):
143
- """Create the header and add the view selection frame at the right."""
144
- header = ProjectBaseWindow.createHeaderFrame(self, parent)
145
- self.addViewList(header)
146
- return header
147
-
148
- def customizeheader(self, headerFrame):
149
- """ Adds the Project name in the header frame"""
150
- # Create the Project Name label
151
-
152
- projLabel = Label(headerFrame, text=self.projName, font=getBigFont(),
153
- borderwidth=0, anchor='nw', bg=pw.Config.SCIPION_BG_COLOR,
154
- fg=pw.Color.ALT_COLOR_DARK)
155
- projLabel.bind("<Button-1>", self.setComment)
156
- projLabel.grid(row=0, column=2, sticky='sw', padx=(20, 5), pady=10)
157
-
158
- self.commentTT = ToolTip(projLabel, self.project.getComment(), 200)
159
- def setComment(self, e):
160
-
161
- newComment = askString("Change project description", "Description", self.root, entryWidth=100, defaultValue=self.project.getComment())
162
- self.commentTT.configure(text=newComment)
163
- self.project.setComment(newComment)
164
- self.project._storeCreationTime() # Comment is stored as creation time comment for now
165
- def getSettings(self):
166
- return self.settings
167
-
168
- def saveSettings(self):
169
-
170
- try:
171
- self.settings.write()
172
- except Exception as ex:
173
- logger.error(Message.NO_SAVE_SETTINGS, exc_info=ex)
174
-
175
- def _onClosing(self):
176
- if not self.project.openedAsReadOnly():
177
- self.saveSettings()
178
-
179
- ProjectBaseWindow._onClosing(self)
180
-
181
- def loadProject(self):
182
- proj = pw.project.Project(pw.Config.getDomain(), self.projPath)
183
- proj.configureLogging()
184
- proj.load()
185
-
186
- # Check if we have settings.sqlite, generate if not
187
- settingsPath = os.path.join(proj.path, proj.settingsPath)
188
- if os.path.exists(settingsPath):
189
- self.settings = proj.getSettings()
190
- else:
191
- logger.info('Warning: settings.sqlite not found! '
192
- 'Creating default settings..')
193
- self.settings = proj.createSettings()
194
-
195
- return proj
196
-
197
- # The next functions are callbacks from the menu options.
198
- # See how it is done in pyworkflow/gui/gui.py:Window._addMenuChilds()
199
- #
200
- def onBrowseFiles(self):
201
- # Project -> Browse files
202
- FileBrowserWindow("Browse Project files",
203
- self, self.project.getPath(''),
204
- selectButton=None # we will select nothing
205
- ).show()
206
-
207
- def onDebugMode(self):
208
- pw.Config.toggleDebug()
209
-
210
- def onNotes(self):
211
- notes_program = pw.Config.SCIPION_NOTES_PROGRAM
212
- notes_args = pw.Config.SCIPION_NOTES_ARGS
213
- args = []
214
- notes_file = self.project.getPath('Logs', pw.Config.SCIPION_NOTES_FILE)
215
-
216
- # If notesFile does not exist, it is created and an explanation/documentation comment is added at the top.
217
- if not os.path.exists(notes_file):
218
- f = open(notes_file, 'a')
219
- f.write(pw.genNotesHeading())
220
- f.close()
221
-
222
- # Then, it will be opened as specified in the conf
223
- if notes_program:
224
- args.append(notes_program)
225
- # Custom arguments
226
- if notes_args:
227
- args.append(notes_args)
228
- args.append(notes_file)
229
- subprocess.Popen(args) # nonblocking
230
- else:
231
- # if no program has been selected
232
- # xdg-open will try to guess but
233
- # if the file does not exist it
234
- # will return an error so If the file does
235
- # not exist I will create an empty one
236
- # 'a' will avoid accidental truncation
237
- openTextFileEditor(notes_file)
238
-
239
- def onRemoveTemporaryFiles(self):
240
- # Project -> Remove temporary files
241
- tmpPath = os.path.join(self.project.path, self.project.tmpPath)
242
- n = 0
243
- try:
244
- for fname in os.listdir(tmpPath):
245
- fpath = "%s/%s" % (tmpPath, fname)
246
- if os.path.isfile(fpath):
247
- os.remove(fpath)
248
- n += 1
249
- # TODO: think what to do with directories. Delete? Report?
250
- self.showInfo("Deleted content of %s -- %d file(s)." % (tmpPath, n))
251
- except Exception as e:
252
- self.showError(str(e))
253
-
254
- def _loadWorkflow(self, obj):
255
- try:
256
- self.getViewWidget().info('Importing workflow %s' % obj.getPath())
257
- self.project.loadProtocols(obj.getPath())
258
- self.getViewWidget().updateRunsGraph(True)
259
- self.getViewWidget().cleanInfo()
260
- except Exception as ex:
261
- self.showError(str(ex), exception=ex)
262
-
263
- def onImportWorkflow(self):
264
- FileBrowserWindow("Select workflow .json file",
265
- self, self.project.getPath(''),
266
- onSelect=self._loadWorkflow,
267
- selectButton='Import'
268
- ).show()
269
-
270
- def onSearchWorkflow(self):
271
- WorkflowRepository().search()
272
-
273
- def onToggleColorMode(self):
274
- self.getViewWidget()._toggleColorScheme(None)
275
-
276
- def onSelectAllProtocols(self):
277
- self.getViewWidget()._selectAllProtocols(None)
278
-
279
- def onLocateAProtocol(self):
280
- self.getViewWidget()._locateProtocol(None)
281
-
282
- def manageLabels(self):
283
-
284
- labels = self.project.settings.getLabels()
285
- dialog = LabelsDialog(self.root,
286
- labels,
287
- allowSelect=True)
288
-
289
- # Scan for renamed labels to update node info...
290
- labelsRenamed = dict()
291
- for label in labels:
292
- if label.hasOldName():
293
- oldName = label.getOldName()
294
- newName = label.getName()
295
- logger.info("Label %s renamed to %s" % (oldName, newName))
296
- labelsRenamed[oldName] = newName
297
- label.clearOldName()
298
-
299
- # If there are labels renamed
300
- if labelsRenamed:
301
- logger.info("Updating labels of protocols after renaming.")
302
- labels.updateDict()
303
-
304
- for node in self.project.settings.getNodes():
305
- nodeLabels = node.getLabels()
306
- for index, nodeLabel in enumerate(nodeLabels):
307
-
308
- newLabel = labelsRenamed.get(nodeLabel, None)
309
- if newLabel is not None:
310
- logger.info("Label %s found in %s. Updating it to %s" % (nodeLabel,node, newLabel))
311
- nodeLabels[index] = newLabel
312
-
313
- return dialog
314
-
315
- def initProjectTCPServer(self):
316
- server = ProjectTCPServer((self.project.address, self.project.port),
317
- ProjectTCPRequestHandler)
318
- server.project = self.project
319
- server.window = self
320
- server_thread = threading.Thread(name="projectTCPserver", target=server.serve_forever)
321
- # Exit the server thread when the main thread terminates
322
- server_thread.daemon = True
323
- server_thread.start()
324
-
325
- # Seems it is not used and should be in scipion-em
326
- # Not within scipion but used from ShowJ
327
- def schedulePlot(self, path, *args):
328
- # FIXME: This import should not be here
329
- from pwem.viewers import EmPlotter
330
- self.enqueue(lambda: EmPlotter.createFromFile(path, *args).show())
331
-
332
- @classmethod
333
- def registerObjectCommand(cls, cmd, func):
334
- """ Register an object command to be handled when receiving the
335
- action from showj. """
336
- cls._OBJECT_COMMANDS[cmd] = func
337
-
338
- def runObjectCommand(self, cmd, inputStrId, objStrId):
339
- try:
340
- objId = int(objStrId)
341
- project = self.project
342
-
343
- if os.path.isfile(inputStrId) and os.path.exists(inputStrId):
344
- from pwem.utils import loadSetFromDb
345
- inputObj = loadSetFromDb(inputStrId)
346
- else:
347
- inputId = int(inputStrId)
348
- inputObj = project.mapper.selectById(inputId)
349
-
350
- func = self._OBJECT_COMMANDS.get(cmd, None)
351
-
352
- if func is None:
353
- logger.info("Error, command '%s' not found. " % cmd)
354
- else:
355
- def myfunc():
356
- func(inputObj, objId)
357
- inputObj.close()
358
- self.enqueue(myfunc)
359
-
360
- except Exception as ex:
361
- logger.error("There was an error executing object command !!!:", exc_info=ex)
362
-
363
- class ProjectManagerWindow(ProjectBaseWindow):
364
- """ Windows to manage all projects. """
365
- # To allow plugins to add their own menus
366
- _pluginMenus = dict()
367
-
368
- def __init__(self, **kwargs):
369
-
370
- # TODO: put the menu part more nicely. From here:
371
- menu = MenuConfig()
372
-
373
- fileMenu = menu.addSubMenu('File')
374
- fileMenu.addSubMenu('Browse files', 'browse', icon=Icon.FOLDER_OPEN)
375
- fileMenu.addSubMenu('Exit', 'exit', icon=Icon.ACTION_OUT)
376
-
377
- confMenu = menu.addSubMenu('Configuration')
378
- if os.path.exists(pw.Config.SCIPION_CONFIG):
379
- confMenu.addSubMenu('General', 'general')
380
- confMenu.addSubMenu('Hosts', 'hosts')
381
- if os.path.exists(pw.Config.SCIPION_PROTOCOLS):
382
- confMenu.addSubMenu('Protocols', 'protocols')
383
- if os.path.exists(pw.Config.SCIPION_LOCAL_CONFIG):
384
- confMenu.addSubMenu('User', 'user')
385
-
386
- helpMenu = menu.addSubMenu('Help')
387
- helpMenu.addSubMenu('Online help', 'online_help', icon=Icon.ACTION_EXPORT)
388
- helpMenu.addSubMenu('About', 'about', icon=Icon.ACTION_HELP)
389
-
390
- self.menuCfg = menu
391
-
392
- try:
393
- title = '%s (%s on %s)' % (Message.LABEL_PROJECTS,
394
- pwutils.getLocalUserName(),
395
- pwutils.getLocalHostName())
396
- except Exception:
397
- title = Message.LABEL_PROJECTS
398
-
399
- ProjectBaseWindow.__init__(self, title, minsize=(750, 500),
400
- icon=Icon.SCIPION_ICON_PROJS, **kwargs)
401
- self.manager = pw.project.Manager()
402
- self.switchView(VIEW_PROJECTS)
403
-
404
- #
405
- # The next functions are callbacks from the menu options.
406
- # See how it is done in pyworkflow/gui/gui.py:Window._addMenuChilds()
407
- #
408
- def onBrowseFiles(self):
409
- # File -> Browse files
410
- FileBrowserWindow("Browse files", self,
411
- pw.Config.SCIPION_USER_DATA,
412
- selectButton=None).show()
413
-
414
- def onGeneral(self):
415
- # Config -> General
416
- self._openConfigFile(pw.Config.SCIPION_CONFIG)
417
-
418
- @staticmethod
419
- def _openConfigFile(configFile):
420
- """ Open an Scipion configuration file, if the user have one defined,
421
- also open that one with the defined text editor.
422
- """
423
- _open_cmd(configFile)
424
-
425
- @staticmethod
426
- def onHosts():
427
- # Config -> Hosts
428
- ProjectManagerWindow._openConfigFile(pw.Config.SCIPION_HOSTS)
429
-
430
- @staticmethod
431
- def onProtocols():
432
- ProjectManagerWindow._openConfigFile(pw.Config.SCIPION_PROTOCOLS)
433
-
434
- @staticmethod
435
- def onUser():
436
- ProjectManagerWindow._openConfigFile(pw.Config.SCIPION_LOCAL_CONFIG)
437
-
438
-
439
- class ProjectTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
440
- pass
441
-
442
-
443
- class ProjectTCPRequestHandler(socketserver.BaseRequestHandler):
444
-
445
- def handle(self):
446
- try:
447
- project = self.server.project
448
- window = self.server.window
449
- msg = self.request.recv(1024)
450
- msg = msg.decode()
451
- tokens = shlex.split(msg)
452
- if msg.startswith('run protocol'):
453
-
454
- logger.debug("run protocol messaged arrived: %s" % msg)
455
- protocolName = tokens[2]
456
- protocolClass = pw.Config.getDomain().getProtocols()[protocolName]
457
- # Create the new protocol instance and set the input values
458
- protocol = project.newProtocol(protocolClass)
459
-
460
- for token in tokens[3:]:
461
- param, value = token.split('=')
462
- attr = getattr(protocol, param, None)
463
- if param == 'label':
464
- protocol.setObjLabel(value)
465
- elif attr.isPointer():
466
- obj = project.getObject(int(value))
467
- attr.set(obj)
468
- elif value:
469
- attr.set(value)
470
-
471
- if protocol.useQueue():
472
- # Do not use the queue in this case otherwise we need to ask for queue parameters.
473
- # Maybe something to do in the future. But now this logic is in form.py.
474
- logger.warning('Cancelling launching protocol "%s" to the queue.' % protocol)
475
- protocol._useQueue.set(False)
476
-
477
- # project.launchProtocol(protocol)
478
- # We need to enqueue the action of execute a new protocol
479
- # to be run in the same GUI thread and avoid concurrent
480
- # access to the project sqlite database
481
- window.getViewWidget().executeProtocol(protocol)
482
- elif msg.startswith('run function'):
483
- functionName = tokens[2]
484
- functionPointer = getattr(window, functionName)
485
- functionPointer(*tokens[3:])
486
- else:
487
- answer = b'no answer available\n'
488
- self.request.sendall(answer)
489
- except Exception as e:
490
- print(e)
491
- import traceback
492
- traceback.print_stack()
@@ -1,154 +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 protocol"""
26
- import tkinter as tk
27
-
28
- from pyworkflow import Config
29
- import pyworkflow.gui as pwgui
30
- import pyworkflow.object as pwobj
31
- from pyworkflow.gui.dialog import SearchBaseWindow
32
-
33
- from pyworkflow.gui.project.utils import isAFinalProtocol
34
- from pyworkflow.gui.project.viewprotocols_extra import ProtocolTreeConfig
35
-
36
- UPDATED = "updated"
37
-
38
- NEW = "new"
39
-
40
- BETA = "beta"
41
-
42
-
43
- class ProtocolTreeProvider(pwgui.tree.ObjectTreeProvider):
44
- """Create the tree elements for a Protocol run"""
45
-
46
- def __init__(self, protocol):
47
- self.protocol = protocol
48
- # This list is create to group the protocol parameters
49
- # in the tree display
50
- self.status = pwobj.List(objName='_status')
51
- self.params = pwobj.List(objName='_params')
52
- self.statusList = ['status', 'initTime', 'endTime', 'error',
53
- 'interactive', 'mode']
54
-
55
- objList = [] if protocol is None else [protocol]
56
- pwgui.tree.ObjectTreeProvider.__init__(self, objList)
57
-
58
-
59
-
60
- class SearchProtocolWindow(SearchBaseWindow):
61
-
62
- columnConfig = {
63
- '#0': ('Status', {'width': 50, 'minwidth': 50, 'stretch': tk.NO}, 5),
64
- # Heading, tree column kwargs, casting for sorting
65
- 'protocol': ('Protocol', {'width': 300, 'stretch': tk.FALSE}, 10),
66
- 'streaming': ('Streamified', {'width': 100, 'stretch': tk.FALSE}, 5),
67
- 'installed': ('Installation', {'width': 110, 'stretch': tk.FALSE}, 5),
68
- 'help': ('Help', {'minwidth': 300, 'stretch': tk.YES}, 5),
69
- 'score': ('Score', {'width': 50, 'stretch': tk.FALSE}, 5, int)
70
- }
71
-
72
- def __init__(self, parentWindow, position=None):
73
-
74
- posStr = "" if position is None else " at (%s,%s)" % position
75
- self.position = position
76
- super().__init__(parentWindow,
77
- title="Add a protocol" + posStr)
78
-
79
- def _createResultsTree(self, frame, show, columns):
80
- return self.master.getViewWidget()._createProtocolsTree(frame, show=show, columns=columns, position=self.position)
81
-
82
- def _onSearchClick(self, e=None):
83
-
84
- self._resultsTree.clear()
85
-
86
- protList = self.scoreProtocols()
87
-
88
- # Sort by weight
89
- protList.sort(reverse=True, key=lambda x: x[8])
90
-
91
- self._addProtocolToTree(protList)
92
-
93
- def scoreProtocols(self):
94
-
95
- keyword = self._searchVar.get().lower().strip()
96
- emProtocolsDict = Config.getDomain().getProtocols()
97
- protList = []
98
-
99
- for key, prot in emProtocolsDict.items():
100
- if isAFinalProtocol(prot, key):
101
- label = prot.getClassLabel().lower()
102
- line = (key, label,
103
- "installed" if prot.isInstalled() else "missing installation",
104
- prot.getHelpText().strip().replace('\r', '').replace('\n', '').lower(),
105
- "streamified" if prot.worksInStreaming() else "static",
106
- BETA if prot.isBeta() else "",
107
- NEW if prot.isNewDev() else "",
108
- UPDATED if prot.isUpdated() else "")
109
-
110
- line = self._addSearchWeight(line, keyword)
111
- # something was found: weight > 0
112
- if line[8] != 0:
113
- protList.append(line)
114
-
115
- return protList
116
-
117
- @staticmethod
118
- def _addSearchWeight(line2Search, searchtext):
119
- # Adds a weight value for the search
120
- weight = 0
121
-
122
- # prioritize findings in label
123
- if searchtext in line2Search[1]:
124
- weight += 10
125
-
126
- for value in line2Search[2:]:
127
- weight += 5 if searchtext in value else 0
128
-
129
- if " " in searchtext:
130
- for word in searchtext.split():
131
- if word in line2Search[1]:
132
- weight += 3
133
-
134
- for value in line2Search[2:]:
135
- weight += 1 if word in value else 0
136
-
137
- return line2Search + (weight,)
138
-
139
- def _addProtocolToTree(self, protList):
140
- """ Adds the items in protList to the tree
141
-
142
- :param protList: List of tuples with all the values/columns used in the search search to show in the tree"""
143
-
144
- for key, label, installed, help, streamified, beta, new, updated, weight in protList:
145
- tag = ProtocolTreeConfig.getProtocolTag(installed == 'installed',
146
- beta == BETA,
147
- new == NEW,
148
- updated == UPDATED)
149
-
150
- self._resultsTree.insert(
151
- '', 'end', key, text="", tags=tag,
152
- values=(label, streamified, installed, help, weight))
153
-
154
-