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,267 +0,0 @@
1
- #!/usr/bin/env python
2
- # **************************************************************************
3
- # *
4
- # * Authors: J.M. De la Rosa Trevin (jmdelarosa@cnb.csic.es)
5
- # *
6
- # * 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, write to the Free Software
20
- # * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21
- # * 02111-1307 USA
22
- # *
23
- # * All comments concerning this program package may be sent to the
24
- # * e-mail address 'scipion@cnb.csic.es'
25
- # *
26
- # **************************************************************************
27
-
28
- """
29
- Run or show the selected tests. Tests can be selected by giving
30
- the "case", or by giving the paths and file pattern to use for
31
- searching them.
32
- """
33
- from pyworkflow.utils import LoggingConfigurator
34
- import argparse
35
- from collections import OrderedDict
36
-
37
- import pyworkflow.tests as pwtests
38
- from pyworkflow import getTestsScript, SCIPION_TESTS_CMD, Config
39
-
40
- from pyworkflow.tests import *
41
-
42
- MODULE = 0
43
- CLASS = 1
44
- TEST = 2
45
-
46
-
47
- class Tester:
48
- def main(self, args=None):
49
-
50
- # Trigger plugin's variable definition
51
- Config.getDomain().getPlugins()
52
-
53
- parser = argparse.ArgumentParser(prog=self.getTestsCommand(), description=__doc__)
54
- g = parser.add_mutually_exclusive_group()
55
- g.add_argument('--run', action='store_true', help='run the selected tests')
56
- g.add_argument('--show', action='store_true', help='show available tests',
57
- default=True)
58
-
59
- add = parser.add_argument # shortcut
60
-
61
- add('--pattern', default='test*.py',
62
- help='pattern for the files that will be used in the tests')
63
- add('--grep', default=None, nargs='+',
64
- help='only show/run tests containing the provided words')
65
- add('--skip', default=None, nargs='+',
66
- help='skip tests that contains these words')
67
- add('--log', default=None, nargs='?',
68
- help="Generate logs files with the output of each test.")
69
- add('--mode', default='classes', choices=['modules', 'classes', 'onlyclasses', 'all'],
70
- help='how much detail to give in show mode')
71
- add('tests', metavar='TEST', nargs='*',
72
- help='test case from string identifier (module, class or callable)')
73
- args = parser.parse_args(args)
74
-
75
- if not args.run and not args.show and not args.tests:
76
- sys.exit(parser.format_help())
77
-
78
- # Logging stuff first
79
- self.log = args.log
80
-
81
- if self.log:
82
- LoggingConfigurator.setupLogging(logFile=self.log)
83
- else:
84
- logging.basicConfig(level=Config.SCIPION_LOG_LEVEL, format=Config.SCIPION_LOG_FORMAT)
85
-
86
- self.logger = logging.getLogger(__name__)
87
-
88
- # This goes intentionally to the output. Is not a logging line._S
89
- print("Scanning tests...")
90
-
91
-
92
- testsDict = OrderedDict()
93
- testLoader = unittest.defaultTestLoader
94
-
95
- if args.tests:
96
- print(pwutils.cyanStr("Loading test/s %s" % args.tests))
97
-
98
- # In this case the tests are passed as argument.
99
- # The full name of the test will be used to load it.
100
- testsDict['tests'] = unittest.TestSuite()
101
- for t in args.tests:
102
- try:
103
- testsDict['tests'].addTests(testLoader.loadTestsFromName(t))
104
- except Exception as e:
105
- self.logger.error('Cannot load test %s -- skipping' % t, exc_info=True)
106
- else:
107
- # In this other case, we will load the test available
108
- # from pyworkflow and the other plugins
109
- # self.paths = [('pyworkflow', os.path.dirname(os.path.dirname(pw.__file__)))]
110
- self.paths = []
111
- for name, plugin in pw.Config.getDomain().getPlugins().items():
112
- self.paths.append((name, os.path.dirname(plugin.__path__[0])))
113
- for k, p in self.paths:
114
- testPath = os.path.join(p, k, 'tests')
115
- if os.path.exists(testPath):
116
- self.logger.debug("Discovering tests at %s" % testPath)
117
- testsDict[k] = testLoader.discover(testPath,
118
- pattern=args.pattern,
119
- top_level_dir=p)
120
-
121
- self.grep = [g.lower() for g in args.grep] if args.grep else []
122
- self.skip = [s.lower() for s in args.skip] if args.skip else []
123
- self.mode = args.mode
124
-
125
- if args.tests:
126
- self.runSingleTest(testsDict['tests'])
127
-
128
- elif args.run:
129
- for moduleName, tests in testsDict.items():
130
- self.logger.info(pwutils.cyanStr(">>>> %s" % moduleName))
131
- self.runTests(moduleName, tests)
132
-
133
- elif args.grep:
134
- pattern = args.grep[0]
135
- for moduleName, tests in testsDict.items():
136
- self.printTests(pattern, tests)
137
-
138
- else:
139
- for moduleName, tests in testsDict.items():
140
- if self._match(moduleName):
141
- print(pwutils.cyanStr(">>>> %s" % moduleName))
142
- self.printTests(moduleName, tests)
143
-
144
- def _match(self, itemName):
145
- # Add a space to allow " tomo." as a filter for example to narrow search to tomo and leaving out xmipptomo, emntomo, ...
146
- itemLower = " " + itemName.lower()
147
- grep = (not self.grep or
148
- all(g in itemLower for g in self.grep))
149
- skip = (self.skip and
150
- any(s in itemLower for s in self.skip))
151
-
152
- return grep and not skip
153
-
154
- def __iterTests(self, test):
155
- """ Recursively iterate over a testsuite. """
156
- self.logger.debug("__iterTests: %s, is-suite: %s" % (str(test.__class__),
157
- isinstance(test, unittest.TestSuite)))
158
-
159
- if isinstance(test, unittest.TestSuite):
160
- for t in test:
161
- self.__iterTests(t)
162
- else:
163
- yield test
164
-
165
- def _visitTests(self, moduleName, tests, newItemCallback):
166
- """ Show the list of tests available """
167
- mode = self.mode
168
-
169
- assert mode in ['modules', 'classes', 'onlyclasses', 'all'], 'Unknown mode %s' % mode
170
-
171
- # First flatten the list of tests.
172
- # testsFlat = list(iter(self.__iterTests(tests)))
173
-
174
- testsFlat = []
175
- toCheck = [t for t in tests]
176
-
177
- while toCheck:
178
- test = toCheck.pop()
179
- if isinstance(test, unittest.TestSuite):
180
- toCheck += [t for t in test]
181
- elif test not in testsFlat:
182
- testsFlat.append(test)
183
-
184
- # Follow the flattened list of tests and show the module, class
185
- # and name, in a nice way.
186
- lastClass = None
187
- lastModule = None
188
- if testsFlat:
189
- for t in testsFlat:
190
-
191
- testModuleName, className, testName = t.id().rsplit('.', 2)
192
-
193
- # If there is a failure loading the test, show it
194
- errorStr = 'unittest.loader._FailedTest.'
195
- if testModuleName.startswith(errorStr):
196
- newName = t.id().replace(errorStr, '')
197
- if self._match(newName):
198
- self.logger.error(
199
- pwutils.redStr('Error loading the test. Please, run the test for more information: ' + newName))
200
- continue
201
-
202
- if testModuleName != lastModule:
203
- lastModule = testModuleName
204
- if mode != 'onlyclasses':
205
- newItemCallback(MODULE, "%s" % testModuleName)
206
-
207
- if mode in ['classes', 'onlyclasses', 'all'] and className != lastClass:
208
- lastClass = className
209
- newItemCallback(CLASS, "%s.%s"
210
- % (testModuleName, className))
211
-
212
- if mode == 'all':
213
- newItemCallback(TEST, "%s.%s.%s"
214
- % (testModuleName, className, testName))
215
- else:
216
- if not self.grep:
217
- self.logger.warning(pwutils.greenStr(' The plugin does not have any test'))
218
-
219
- def _printNewItem(self, itemType, itemName):
220
- if self._match(itemName):
221
- spaces = (itemType * 2) * ' '
222
- # Do not use intentionally the logger. This is not a logging output but a GUI output
223
- print("%s %s %s" % (spaces, self.getTestsCommand(), itemName))
224
-
225
- def getTestsCommand(self):
226
- return os.environ.get(SCIPION_TESTS_CMD, getTestsScript())
227
-
228
- def printTests(self, moduleName, tests):
229
- self._visitTests(moduleName, tests, self._printNewItem)
230
-
231
- def _runNewItem(self, itemType, itemName):
232
- if self._match(itemName):
233
- spaces = (itemType * 2) * ' '
234
- script = getTestsScript()
235
- cmd = "%s %s %s %s" % (pw.PYTHON, script, spaces, itemName)
236
- run = ((itemType == MODULE and self.mode == 'modules') or
237
- (itemType == CLASS and self.mode in ('classes', 'onlyclasses')) or
238
- (itemType == TEST and self.mode == 'all'))
239
- if run:
240
- if self.log:
241
- # logFile = join(self.testsDir, '%s.txt' % itemName)
242
- cmdFull = cmd + " >> %s 2>&1" % self.log
243
- else:
244
- logFile = ''
245
- cmdFull = cmd
246
-
247
- self.logger.info(pwutils.greenStr(cmdFull))
248
- t = pwutils.Timer()
249
- t.tic()
250
- self.testCount += 1
251
- os.system(cmdFull)
252
-
253
- def runTests(self, moduleName, tests):
254
-
255
- self.testCount = 0
256
- self._visitTests(moduleName, tests, self._runNewItem)
257
-
258
- def runSingleTest(self, tests):
259
- result = pwtests.GTestResult()
260
- tests.run(result)
261
- result.doReport()
262
- resultPassed = result.numberTests - result.testFailed
263
- sys.exit(1 if result.testFailed > 0 or resultPassed == 0 else 0)
264
-
265
-
266
- if __name__ == '__main__':
267
- Tester().main()
@@ -1,322 +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, write to the Free Software
20
- # * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21
- # * 02111-1307 USA
22
- # *
23
- # * All comments concerning this program package may be sent to the
24
- # * e-mail address 'scipion@cnb.csic.es'
25
- # *
26
- # **************************************************************************
27
-
28
- import logging
29
-
30
- from pyworkflow.utils import LoggingConfigurator
31
-
32
- import os
33
- import sys
34
- import time
35
- import argparse
36
-
37
- from pyworkflow.protocol import (getProtocolFromDb,
38
- STATUS_FINISHED, STATUS_ABORTED, STATUS_FAILED,
39
- STATUS_RUNNING, STATUS_SCHEDULED, STATUS_SAVED,
40
- STATUS_LAUNCHED, Set, Protocol, MAX_SLEEP_TIME)
41
- from pyworkflow.constants import PROTOCOL_UPDATED
42
-
43
- stopStatuses = [STATUS_FINISHED, STATUS_ABORTED, STATUS_FAILED]
44
-
45
-
46
- class RunScheduler:
47
- """ Check that all dependencies are met before launching a run. """
48
-
49
- def __init__(self, args, logger):
50
- self._args = args
51
- # Enter to the project directory and load protocol from db
52
- self.protocol = self._loadProtocol()
53
- self.project = self.protocol.getProject()
54
- self.log = logger
55
- self.protPid = os.getpid()
56
- self.protocol.setPid(self.protPid)
57
- self.protocol._store(self.protocol._pid)
58
- self.prerequisites = list(map(int, self.protocol.getPrerequisites()))
59
- # Keep track of the last time the protocol was checked and
60
- # its modification date to avoid unnecessary db opening
61
- self.updatedProtocols = dict()
62
- self.initial_sleep = self._args.initial_sleep
63
-
64
- def getSleepTime(self):
65
- return self._args.sleepTime
66
-
67
- def getInitialSleepTime(self):
68
- return self.initial_sleep
69
-
70
- def _loadProtocol(self) -> Protocol:
71
- return getProtocolFromDb(self._args.projPath,
72
- self._args.dbPath,
73
- self._args.protId, chdir=True)
74
-
75
- def _log(self, msg):
76
- self.log.info(msg)
77
-
78
- def _updateProtocol(self, protocol):
79
-
80
- protId = protocol.getObjId()
81
-
82
- if protId in self.updatedProtocols:
83
- return self.updatedProtocols[protId]
84
-
85
- protDb = protocol.getDbPath()
86
-
87
- if os.path.exists(protDb):
88
- updateResult = self.project._updateProtocol(protocol)
89
- if updateResult == PROTOCOL_UPDATED:
90
- self._log("Updated protocol: %s (%s)" % (protId, protocol))
91
- else:
92
- self._log("The protocol %s (%s) is up to date" % (protId, protocol))
93
- self.updatedProtocols[protId] = protocol
94
-
95
- return protocol
96
-
97
- def _getProtocolFromPointer(self, pointer):
98
- """
99
- The function return a protocol from an attribute
100
-
101
- A) When the pointer points to a protocol
102
-
103
- B) When the pointer points to another object (INDIRECTLY).
104
- - The pointer has an _extended value (new parameters
105
- configuration in the protocol)
106
-
107
- C) When the pointer points to another object (DIRECTLY).
108
- - The pointer has not an _extended value (old parameters
109
- configuration in the protocol)
110
- """
111
- output = pointer.get()
112
- if isinstance(output, Protocol): # case A
113
- protocol = output
114
- else:
115
- if pointer.hasExtended(): # case B
116
- protocol = pointer.getObjValue()
117
- else: # case C
118
- protocol = self.project.getRunsGraph().getNode(str(output.getObjParentId())).run
119
- return protocol
120
-
121
- def _getSecondsToWait(self, inProt):
122
- """
123
- Assigns a timeout penalty or reward depending on the status of the
124
- input protocol (inProt)
125
- If inProt status is stopped we assign a reward i.o.c a penalty
126
- """
127
- protStatus = inProt.getStatus()
128
- inStreaming = inProt.worksInStreaming()
129
- meStreaming = self.protocol.worksInStreaming()
130
-
131
- penaltyRewardValues = {
132
- STATUS_LAUNCHED: 5 if inStreaming else 10,
133
- STATUS_RUNNING: -2 if inStreaming else 3,
134
- STATUS_SCHEDULED: int(self.getSleepTime()/2),
135
- STATUS_SAVED: self.getSleepTime(),
136
- }
137
-
138
- secondToWait = penaltyRewardValues.get(protStatus, -3)
139
-
140
- if not meStreaming:
141
- secondToWait += 3 * self.getSleepTime()
142
-
143
- return secondToWait
144
-
145
- def _checkPrerequisites(self, prerequisites, project):
146
- # Check if we need to wait for required protocols
147
- wait = False
148
- # For each protocol that is a prerequisite that has not finished,
149
- # we'll penalize with 3 more seconds of waiting
150
- penalize = 0
151
- self._log("Checking prerequisites... %s" % prerequisites)
152
- for protId in prerequisites:
153
- # Check if prerequisites exist. In the case of metaprotocols, it
154
- # may be necessary to load them from the project database.
155
- node = project.getRunsGraph().getNode(str(protId))
156
-
157
- if node is None:
158
- self._log("Updating runs graph. Missing protocol ... %s" % protId)
159
- project.getRunsGraph(refresh=True)
160
-
161
- node = project.getRunsGraph().getNode(str(protId))
162
- # Check if the protocol is within our workflow
163
- if node is None:
164
- self._log("Protocol can't wait for %s. Missing prerequisite " % protId)
165
- break
166
-
167
- prot = project.getRunsGraph().getNode(str(protId)).run
168
- if prot is not None:
169
- prot = self._updateProtocol(prot)
170
- penalize += self._getSecondsToWait(prot)
171
- if prot.getStatus() not in stopStatuses:
172
- wait = True
173
- self._log(" ...waiting for %s" % prot)
174
- return wait, penalize
175
-
176
- def _checkMissingInput(self):
177
- """
178
- Check if there are missing inputs
179
- In case of having them, check if protocol is in streaming
180
- """
181
- inputMissing = False
182
- # For each input that is not ready we'll penalize with 3 more
183
- # seconds of waiting
184
- penalize = 0
185
-
186
- self._log("Checking input data...")
187
- # Updating input protocols
188
- for key, attr in self.protocol.iterInputAttributes():
189
- self.log.debug("Turn for %s" % key)
190
- inputProt = self._getProtocolFromPointer(attr)
191
- inputProt = self._updateProtocol(inputProt)
192
- penalize += self._getSecondsToWait(inputProt)
193
-
194
- validation = self.protocol.validate()
195
- if len(validation) > 0:
196
- inputMissing = True
197
- self._log("%s doesn't validate:\n\t- %s" % (self.protocol.getObjLabel(),
198
- '\n\t- '.join(
199
- validation)))
200
- elif not self.protocol.worksInStreaming():
201
- for key, attr in self.protocol.iterInputAttributes():
202
- inSet = attr.get()
203
- if isinstance(inSet, Set) and inSet.isStreamOpen():
204
- inputMissing = True
205
- self._log("Waiting for closing %s... (does not work in "
206
- "streaming)" % inSet)
207
- break
208
- elif isinstance(inSet, Protocol) and not inSet.isFinished(): # Then is a pointer to a protocol
209
- inputMissing = True
210
- self._log("Waiting for protocol %s to finish... (does not work in "
211
- "streaming)" % inSet)
212
- break
213
-
214
- else:
215
- self._log("%s is not blocking this protocol. All ready." % inSet)
216
-
217
- if not inputMissing:
218
- inputProtocolIds = self.protocol.getProtocolsToUpdate()
219
- for protId in inputProtocolIds:
220
- protocol = self.project.getProtocol(protId)
221
- self.log.debug("Turn from inputProtocolDict for %s" % protocol)
222
- self._updateProtocol(protocol)
223
-
224
- return inputMissing, penalize
225
-
226
- def schedule(self):
227
- self._log("Scheduling protocol %s, PID: %s,prerequisites: %s, works in streaming: %s." %
228
- (self.protocol.getObjId(), self.protPid, self.prerequisites,
229
- self.protocol.worksInStreaming()))
230
-
231
- initialSleepTime = runScheduler.getInitialSleepTime()
232
- self._log("Waiting %s seconds before start checking inputs " % initialSleepTime)
233
- time.sleep(initialSleepTime)
234
-
235
- while True:
236
- # Clear the list of protocols updated in the previous loop
237
- self.updatedProtocols.clear()
238
- sleepTime = self.getSleepTime()
239
- # FIXME: This does not cover all the cases:
240
- # When the user registers new coordinates after clicking the
241
- # "Analyze result" button, this action is registered in the project.sqlite
242
- # and not in it's own run.db and never gets updated. It is not critical and
243
- # will only affect a combination of json import with extended that will
244
- # appear after clicking on the "Analyze result" button.
245
-
246
- # Check if there are missing inputs
247
- missing, penalize = self._checkMissingInput()
248
- sleepTime += penalize
249
-
250
- # Check the prerequisites
251
- wait, penalize = self._checkPrerequisites(self.prerequisites,
252
- self.project)
253
- sleepTime += penalize
254
-
255
- if not missing and not wait:
256
- break
257
-
258
- sleepTime = max(min(sleepTime, MAX_SLEEP_TIME), self.getSleepTime())
259
-
260
- self._log("Still not ready, sleeping %s seconds...\n" % sleepTime)
261
- time.sleep(sleepTime)
262
-
263
- self._log("Launching the protocol >>>>")
264
- self.project.launchProtocol(self.protocol, scheduled=True, force=True)
265
-
266
- def parseArgs():
267
- parser = argparse.ArgumentParser()
268
- _addArg = parser.add_argument # short notation
269
-
270
- _addArg("projPath", metavar='PROJECT_NAME',
271
- help="Project database path.")
272
-
273
- _addArg("dbPath", metavar='DATABASE_PATH',
274
- help="Protocol database path.")
275
-
276
- _addArg("protId", type=int, metavar='PROTOCOL_ID',
277
- help="Protocol ID.")
278
-
279
- _addArg("logPath", metavar='LOG_PATH', help='Path to the log file.')
280
-
281
- _addArg("--initial_sleep", type=int, default=0,
282
- dest='initial_sleep', metavar='SECONDS',
283
- help="Initial sleeping time (in seconds)")
284
-
285
- _addArg("--sleep_time", type=int, default=15,
286
- dest='sleepTime', metavar='SECONDS',
287
- help="Sleeping time (in seconds) between updates.")
288
-
289
- _addArg("--wait_for", nargs='*', type=int, default=[],
290
- dest='waitProtIds', metavar='PROTOCOL_ID',
291
- help="List of protocol ids that should be not running "
292
- "(i.e, finished, aborted or failed) before this "
293
- "run will be executed.")
294
-
295
- return parser.parse_args()
296
-
297
-
298
- if __name__ == '__main__':
299
-
300
- # Create a child process
301
- # using os.fork() method
302
- pid = os.fork()
303
-
304
- # pid greater than 0 represents
305
- # the parent process
306
- if pid > 0:
307
- sys.exit(0)
308
- else:
309
- try:
310
- # Parse arguments
311
- args = parseArgs()
312
-
313
- # Configure logging
314
- LoggingConfigurator.setUpProtocolSchedulingLog(args.logPath)
315
- logger = logging.getLogger(__name__)
316
-
317
- runScheduler = RunScheduler(args, logger)
318
- runScheduler.schedule()
319
-
320
- except Exception as ex:
321
- print("Scheduling failed with these parameters: ", sys.argv)
322
- raise ex from None
@@ -1,37 +0,0 @@
1
- #!/usr/bin/env python
2
- # **************************************************************************
3
- # *
4
- # * Authors: J.M. De la Rosa Trevin (jmdelarosa@cnb.csic.es)
5
- # *
6
- # * 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, write to the Free Software
20
- # * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21
- # * 02111-1307 USA
22
- # *
23
- # * All comments concerning this program package may be sent to the
24
- # * e-mail address 'scipion@cnb.csic.es'
25
- # *
26
- # **************************************************************************
27
- """
28
- This module is responsible for launching protocol executions.
29
- """
30
- import os
31
- import sys
32
-
33
- if __name__ == '__main__':
34
- seconds = sys.argv[1]
35
- print("Sleeper, pid: ", os.getpid())
36
- print("Sleeping %s seconds...." % seconds)
37
- os.system("sleep %s" % seconds)