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,491 @@
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
+
140
+ def createHeaderFrame(self, parent):
141
+ """Create the header and add the view selection frame at the right."""
142
+ header = ProjectBaseWindow.createHeaderFrame(self, parent)
143
+ self.addViewList(header)
144
+ return header
145
+
146
+ def customizeheader(self, headerFrame):
147
+ """ Adds the Project name in the header frame"""
148
+ # Create the Project Name label
149
+
150
+ projLabel = Label(headerFrame, text=self.projName, font=getBigFont(),
151
+ borderwidth=0, anchor='nw', bg=pw.Config.SCIPION_BG_COLOR,
152
+ fg=pw.Color.ALT_COLOR_DARK)
153
+ projLabel.bind("<Button-1>", self.setComment)
154
+ projLabel.grid(row=0, column=2, sticky='sw', padx=(20, 5), pady=10)
155
+
156
+ self.commentTT = ToolTip(projLabel, self.project.getComment(), 200)
157
+ def setComment(self, e):
158
+
159
+ newComment = askString("Change project description", "Description", self.root, entryWidth=100, defaultValue=self.project.getComment())
160
+ self.commentTT.configure(text=newComment)
161
+ self.project.setComment(newComment)
162
+ self.project._storeCreationTime() # Comment is stored as creation time comment for now
163
+ def getSettings(self):
164
+ return self.settings
165
+
166
+ def saveSettings(self):
167
+
168
+ try:
169
+ self.settings.write()
170
+ except Exception as ex:
171
+ logger.error(Message.NO_SAVE_SETTINGS, exc_info=ex)
172
+
173
+ def _onClosing(self):
174
+ if not self.project.openedAsReadOnly():
175
+ self.saveSettings()
176
+ # Send usage stats when closing scipion.
177
+ ProjectWorkflowNotifier(self.project).notifyWorkflow()
178
+
179
+
180
+ ProjectBaseWindow._onClosing(self)
181
+
182
+ def loadProject(self):
183
+ proj = pw.project.Project(pw.Config.getDomain(), self.projPath)
184
+ proj.configureLogging()
185
+ proj.load()
186
+
187
+ # Check if we have settings.sqlite, generate if not
188
+ settingsPath = os.path.join(proj.path, proj.settingsPath)
189
+ if os.path.exists(settingsPath):
190
+ self.settings = proj.getSettings()
191
+ else:
192
+ logger.info('Warning: settings.sqlite not found! '
193
+ 'Creating default settings..')
194
+ self.settings = proj.createSettings()
195
+
196
+ return proj
197
+
198
+ # The next functions are callbacks from the menu options.
199
+ # See how it is done in pyworkflow/gui/gui.py:Window._addMenuChilds()
200
+ #
201
+ def onBrowseFiles(self):
202
+ # Project -> Browse files
203
+ FileBrowserWindow("Browse Project files",
204
+ self, self.project.getPath(''),
205
+ selectButton=None # we will select nothing
206
+ ).show()
207
+
208
+ def onDebugMode(self):
209
+ pw.Config.toggleDebug()
210
+
211
+ def onNotes(self):
212
+ notes_program = pw.Config.SCIPION_NOTES_PROGRAM
213
+ notes_args = pw.Config.SCIPION_NOTES_ARGS
214
+ args = []
215
+ notes_file = self.project.getPath('Logs', pw.Config.SCIPION_NOTES_FILE)
216
+
217
+ # If notesFile does not exist, it is created and an explanation/documentation comment is added at the top.
218
+ if not os.path.exists(notes_file):
219
+ f = open(notes_file, 'a')
220
+ f.write(pw.genNotesHeading())
221
+ f.close()
222
+
223
+ # Then, it will be opened as specified in the conf
224
+ if notes_program:
225
+ args.append(notes_program)
226
+ # Custom arguments
227
+ if notes_args:
228
+ args.append(notes_args)
229
+ args.append(notes_file)
230
+ subprocess.Popen(args) # nonblocking
231
+ else:
232
+ # if no program has been selected
233
+ # xdg-open will try to guess but
234
+ # if the file does not exist it
235
+ # will return an error so If the file does
236
+ # not exist I will create an empty one
237
+ # 'a' will avoid accidental truncation
238
+ openTextFileEditor(notes_file)
239
+
240
+ def onRemoveTemporaryFiles(self):
241
+ # Project -> Remove temporary files
242
+ tmpPath = os.path.join(self.project.path, self.project.tmpPath)
243
+ n = 0
244
+ try:
245
+ for fname in os.listdir(tmpPath):
246
+ fpath = "%s/%s" % (tmpPath, fname)
247
+ pwutils.cleanPath(fpath)
248
+ n += 1
249
+ self.showInfo("Deleted content of %s -- %d files or folders." % (tmpPath, n))
250
+ except Exception as e:
251
+ self.showError(str(e))
252
+
253
+ def _loadWorkflow(self, obj):
254
+ try:
255
+ self.getViewWidget().info('Importing workflow %s' % obj.getPath())
256
+ self.project.loadProtocols(obj.getPath())
257
+ self.getViewWidget().updateRunsGraph(True)
258
+ self.getViewWidget().cleanInfo()
259
+ except Exception as ex:
260
+ self.showError(str(ex), exception=ex)
261
+
262
+ def onImportWorkflow(self):
263
+ FileBrowserWindow("Select workflow .json file",
264
+ self, self.project.getPath(''),
265
+ onSelect=self._loadWorkflow,
266
+ selectButton='Import'
267
+ ).show()
268
+
269
+ def onSearchWorkflow(self):
270
+ WorkflowRepository().search()
271
+
272
+ def onToggleColorMode(self):
273
+ self.getViewWidget()._toggleColorScheme(None)
274
+
275
+ def onSelectAllProtocols(self):
276
+ self.getViewWidget()._selectAllProtocols(None)
277
+
278
+ def onLocateAProtocol(self):
279
+ self.getViewWidget()._locateProtocol(None)
280
+
281
+ def manageLabels(self):
282
+
283
+ labels = self.project.settings.getLabels()
284
+ dialog = LabelsDialog(self.root,
285
+ labels,
286
+ allowSelect=True)
287
+
288
+ # Scan for renamed labels to update node info...
289
+ labelsRenamed = dict()
290
+ for label in labels:
291
+ if label.hasOldName():
292
+ oldName = label.getOldName()
293
+ newName = label.getName()
294
+ logger.info("Label %s renamed to %s" % (oldName, newName))
295
+ labelsRenamed[oldName] = newName
296
+ label.clearOldName()
297
+
298
+ # If there are labels renamed
299
+ if labelsRenamed:
300
+ logger.info("Updating labels of protocols after renaming.")
301
+ labels.updateDict()
302
+
303
+ for node in self.project.settings.getNodes():
304
+ nodeLabels = node.getLabels()
305
+ for index, nodeLabel in enumerate(nodeLabels):
306
+
307
+ newLabel = labelsRenamed.get(nodeLabel, None)
308
+ if newLabel is not None:
309
+ logger.info("Label %s found in %s. Updating it to %s" % (nodeLabel,node, newLabel))
310
+ nodeLabels[index] = newLabel
311
+
312
+ return dialog
313
+
314
+ def initProjectTCPServer(self):
315
+ server = ProjectTCPServer((self.project.address, self.project.port),
316
+ ProjectTCPRequestHandler)
317
+ server.project = self.project
318
+ server.window = self
319
+ server_thread = threading.Thread(name="projectTCPserver", target=server.serve_forever)
320
+ # Exit the server thread when the main thread terminates
321
+ server_thread.daemon = True
322
+ server_thread.start()
323
+
324
+ # Seems it is not used and should be in scipion-em
325
+ # Not within scipion but used from ShowJ
326
+ def schedulePlot(self, path, *args):
327
+ # FIXME: This import should not be here
328
+ from pwem.viewers import EmPlotter
329
+ self.enqueue(lambda: EmPlotter.createFromFile(path, *args).show())
330
+
331
+ @classmethod
332
+ def registerObjectCommand(cls, cmd, func):
333
+ """ Register an object command to be handled when receiving the
334
+ action from showj. """
335
+ cls._OBJECT_COMMANDS[cmd] = func
336
+
337
+ def runObjectCommand(self, cmd, inputStrId, objStrId):
338
+ try:
339
+ objId = int(objStrId)
340
+ project = self.project
341
+
342
+ if os.path.isfile(inputStrId) and os.path.exists(inputStrId):
343
+ from pwem.utils import loadSetFromDb
344
+ inputObj = loadSetFromDb(inputStrId)
345
+ else:
346
+ inputId = int(inputStrId)
347
+ inputObj = project.mapper.selectById(inputId)
348
+
349
+ func = self._OBJECT_COMMANDS.get(cmd, None)
350
+
351
+ if func is None:
352
+ logger.info("Error, command '%s' not found. " % cmd)
353
+ else:
354
+ def myfunc():
355
+ func(inputObj, objId)
356
+ inputObj.close()
357
+ self.enqueue(myfunc)
358
+
359
+ except Exception as ex:
360
+ logger.error("There was an error executing object command !!!:", exc_info=ex)
361
+
362
+ class ProjectManagerWindow(ProjectBaseWindow):
363
+ """ Windows to manage all projects. """
364
+ # To allow plugins to add their own menus
365
+ _pluginMenus = dict()
366
+
367
+ def __init__(self, **kwargs):
368
+
369
+ # TODO: put the menu part more nicely. From here:
370
+ menu = MenuConfig()
371
+
372
+ fileMenu = menu.addSubMenu('File')
373
+ fileMenu.addSubMenu('Browse files', 'browse', icon=Icon.FOLDER_OPEN)
374
+ fileMenu.addSubMenu('Exit', 'exit', icon=Icon.ACTION_OUT)
375
+
376
+ confMenu = menu.addSubMenu('Configuration')
377
+ if os.path.exists(pw.Config.SCIPION_CONFIG):
378
+ confMenu.addSubMenu('General', 'general')
379
+ confMenu.addSubMenu('Hosts', 'hosts')
380
+ if os.path.exists(pw.Config.SCIPION_PROTOCOLS):
381
+ confMenu.addSubMenu('Protocols', 'protocols')
382
+ if os.path.exists(pw.Config.SCIPION_LOCAL_CONFIG):
383
+ confMenu.addSubMenu('User', 'user')
384
+
385
+ helpMenu = menu.addSubMenu('Help')
386
+ helpMenu.addSubMenu('Online help', 'online_help', icon=Icon.ACTION_EXPORT)
387
+ helpMenu.addSubMenu('About', 'about', icon=Icon.ACTION_HELP)
388
+
389
+ self.menuCfg = menu
390
+
391
+ try:
392
+ title = '%s (%s on %s)' % (Message.LABEL_PROJECTS,
393
+ pwutils.getLocalUserName(),
394
+ pwutils.getLocalHostName())
395
+ except Exception:
396
+ title = Message.LABEL_PROJECTS
397
+
398
+ ProjectBaseWindow.__init__(self, title, minsize=(750, 500),
399
+ icon=Icon.SCIPION_ICON_PROJS, **kwargs)
400
+ self.manager = pw.project.Manager()
401
+ self.switchView(VIEW_PROJECTS)
402
+
403
+ #
404
+ # The next functions are callbacks from the menu options.
405
+ # See how it is done in pyworkflow/gui/gui.py:Window._addMenuChilds()
406
+ #
407
+ def onBrowseFiles(self):
408
+ # File -> Browse files
409
+ FileBrowserWindow("Browse files", self,
410
+ pw.Config.SCIPION_USER_DATA,
411
+ selectButton=None).show()
412
+
413
+ def onGeneral(self):
414
+ # Config -> General
415
+ self._openConfigFile(pw.Config.SCIPION_CONFIG)
416
+
417
+ @staticmethod
418
+ def _openConfigFile(configFile):
419
+ """ Open an Scipion configuration file, if the user have one defined,
420
+ also open that one with the defined text editor.
421
+ """
422
+ _open_cmd(configFile)
423
+
424
+ @staticmethod
425
+ def onHosts():
426
+ # Config -> Hosts
427
+ ProjectManagerWindow._openConfigFile(pw.Config.SCIPION_HOSTS)
428
+
429
+ @staticmethod
430
+ def onProtocols():
431
+ ProjectManagerWindow._openConfigFile(pw.Config.SCIPION_PROTOCOLS)
432
+
433
+ @staticmethod
434
+ def onUser():
435
+ ProjectManagerWindow._openConfigFile(pw.Config.SCIPION_LOCAL_CONFIG)
436
+
437
+
438
+ class ProjectTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
439
+ pass
440
+
441
+
442
+ class ProjectTCPRequestHandler(socketserver.BaseRequestHandler):
443
+
444
+ def handle(self):
445
+ try:
446
+ project = self.server.project
447
+ window = self.server.window
448
+ msg = self.request.recv(1024)
449
+ msg = msg.decode()
450
+ tokens = shlex.split(msg)
451
+ if msg.startswith('run protocol'):
452
+
453
+ logger.debug("run protocol messaged arrived: %s" % msg)
454
+ protocolName = tokens[2]
455
+ protocolClass = pw.Config.getDomain().getProtocols()[protocolName]
456
+ # Create the new protocol instance and set the input values
457
+ protocol = project.newProtocol(protocolClass)
458
+
459
+ for token in tokens[3:]:
460
+ param, value = token.split('=')
461
+ attr = getattr(protocol, param, None)
462
+ if param == 'label':
463
+ protocol.setObjLabel(value)
464
+ elif attr.isPointer():
465
+ obj = project.getObject(int(value))
466
+ attr.set(obj)
467
+ elif value:
468
+ attr.set(value)
469
+
470
+ if protocol.useQueue():
471
+ # Do not use the queue in this case otherwise we need to ask for queue parameters.
472
+ # Maybe something to do in the future. But now this logic is in form.py.
473
+ logger.warning('Cancelling launching protocol "%s" to the queue.' % protocol)
474
+ protocol._useQueue.set(False)
475
+
476
+ # project.launchProtocol(protocol)
477
+ # We need to enqueue the action of execute a new protocol
478
+ # to be run in the same GUI thread and avoid concurrent
479
+ # access to the project sqlite database
480
+ window.getViewWidget().executeProtocol(protocol)
481
+ elif msg.startswith('run function'):
482
+ functionName = tokens[2]
483
+ functionPointer = getattr(window, functionName)
484
+ functionPointer(*tokens[3:])
485
+ else:
486
+ answer = b'no answer available\n'
487
+ self.request.sendall(answer)
488
+ except Exception as e:
489
+ print(e)
490
+ import traceback
491
+ traceback.print_stack()