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
pyworkflow/config.py
CHANGED
@@ -97,12 +97,15 @@ class Variable:
|
|
97
97
|
self.value = new_value
|
98
98
|
self.isDefault= self._isValueDefault()
|
99
99
|
def _isValueDefault(self):
|
100
|
-
return self.value==self.default
|
100
|
+
return self.value == self.default
|
101
|
+
|
102
|
+
|
101
103
|
class VariablesRegistry:
|
102
|
-
_variables={}
|
104
|
+
_variables = {}
|
103
105
|
|
104
106
|
def __init__(self):
|
105
107
|
raise RuntimeError("Variables class doesn't need to be instantiated.")
|
108
|
+
|
106
109
|
@classmethod
|
107
110
|
def register(cls, variable: Variable):
|
108
111
|
cls._variables[variable.name] = variable
|
@@ -146,7 +149,7 @@ class Config:
|
|
146
149
|
|
147
150
|
if key in os.environ:
|
148
151
|
value = os.environ.get(key)
|
149
|
-
isDefault = (value==default)
|
152
|
+
isDefault = (value == default)
|
150
153
|
else:
|
151
154
|
isDefault = True
|
152
155
|
value = default
|
@@ -154,10 +157,10 @@ class Config:
|
|
154
157
|
# If the caster is passed do the casting, if fails go back to default
|
155
158
|
if caster:
|
156
159
|
try:
|
157
|
-
value=caster(value)
|
160
|
+
value = caster(value)
|
158
161
|
except:
|
159
162
|
logger.warning("Variable %s has this value %s that can't be casted to the right type (%s). Using %s (default value)" %
|
160
|
-
(key,value, caster, default))
|
163
|
+
(key, value, caster, default))
|
161
164
|
value = default
|
162
165
|
# If empty use default value
|
163
166
|
if value == "" != default:
|
@@ -168,10 +171,23 @@ class Config:
|
|
168
171
|
if isinstance(value, str):
|
169
172
|
value = os.path.expandvars(os.path.expanduser(value))
|
170
173
|
|
171
|
-
# Register the variable
|
174
|
+
# Register the variable. Boolean variables are converted to booleans after this call. May not be accurate.
|
175
|
+
# 1 turns into False in the Config
|
172
176
|
VariablesRegistry.register(Variable(key,description, source, value, default, var_type=var_type, isDefault=isDefault))
|
173
177
|
return value
|
174
178
|
|
179
|
+
@staticmethod
|
180
|
+
def __notFalse(value):
|
181
|
+
return value != FALSE_STR
|
182
|
+
|
183
|
+
@staticmethod
|
184
|
+
def __notTrue(value):
|
185
|
+
return value != TRUE_STR
|
186
|
+
|
187
|
+
@staticmethod
|
188
|
+
def __bool(value):
|
189
|
+
return value.lower() in TRUE_YES_ON_
|
190
|
+
|
175
191
|
class Root:
|
176
192
|
""" Simple helper to return path from a root. """
|
177
193
|
|
@@ -185,13 +201,17 @@ class Config:
|
|
185
201
|
# join will not join if expanded is absolute
|
186
202
|
return os.path.join(self._root, expanded)
|
187
203
|
|
188
|
-
# Home for scipion
|
189
204
|
_get = __get.__func__
|
190
|
-
|
191
|
-
|
205
|
+
_notFalse = __notFalse.__func__
|
206
|
+
__bool = __bool.__func__
|
207
|
+
|
208
|
+
# Home for scipion
|
209
|
+
_home_var = _get(SCIPION_HOME_VAR, '',
|
210
|
+
"Path where Scipion is installed. Other paths are based on this like SCIPION_SOFTWARE, SCIPION_TESTS,... unless specified")
|
211
|
+
SCIPION_HOME = os.path.abspath(_home_var)
|
192
212
|
|
193
213
|
# False if SCIPION_HOME is not found in the environment. To distinguish API documentation generation execution.
|
194
|
-
SCIPION_HOME_DEFINED =
|
214
|
+
SCIPION_HOME_DEFINED = _home_var != ''
|
195
215
|
|
196
216
|
_root = Root(str(SCIPION_HOME))
|
197
217
|
_join = _root.join
|
@@ -201,68 +221,75 @@ class Config:
|
|
201
221
|
__defaultSpritesFile = _join(getResourcesPath(),'sprites.png')
|
202
222
|
|
203
223
|
CONDA_ACTIVATION_CMD = _get(CONDA_ACTIVATION_CMD_VAR,'',
|
204
|
-
|
224
|
+
"str: Command to activate/initialize conda itself. Do not confuse it with 'conda activate'. It should be defined at installation time. It looks like this: eval \"$(/extra/miniconda3/bin/conda shell.bash hook)\"")
|
205
225
|
|
206
226
|
# SCIPION PATHS
|
207
227
|
SCIPION_SOFTWARE = _get('SCIPION_SOFTWARE', _join('software'),
|
208
|
-
|
228
|
+
"Path where Scipion will install the software. Defaults to SCIPION_HOME/software.", var_type=VarTypes.FOLDER)
|
209
229
|
|
210
230
|
SCIPION_TESTS = _get('SCIPION_TESTS', _join('data', 'tests'),
|
211
|
-
|
231
|
+
"Path where to find/download test data. Defaults to SCIPION_HOME/data/tests.", var_type=VarTypes.FOLDER)
|
212
232
|
|
213
233
|
# User dependent paths
|
214
234
|
SCIPION_USER_DATA = _get('SCIPION_USER_DATA', '~/ScipionUserData',
|
215
|
-
|
235
|
+
"Path where Scipion projects are or will be created. Defaults to ~/ScipionUserData", var_type=VarTypes.FOLDER)
|
216
236
|
|
217
237
|
# LOGGING variables
|
218
238
|
SCIPION_LOGS = _get('SCIPION_LOGS', _join(SCIPION_USER_DATA, 'logs'),
|
219
|
-
|
239
|
+
"Folder for Scipion logs used by the GUI. Defaults to SCIPION_USER_DATA/logs.", var_type=VarTypes.FOLDER)
|
220
240
|
|
221
241
|
SCIPION_LOG_CONFIG = _get('SCIPION_LOG_CONFIG', None,
|
222
|
-
|
242
|
+
"Optional. Path to a python logging configuration file to fine tune the logging.", var_type=VarTypes.PATH)
|
223
243
|
|
224
244
|
SCIPION_LOG = _get('SCIPION_LOG', _join(SCIPION_LOGS, 'scipion.log'),
|
225
|
-
|
245
|
+
"Path to the file where scipion will write GUI logging messages. Defaults to SCIPION_LOGS/scipion.log", var_type=VarTypes.PATH)
|
226
246
|
|
227
247
|
SCIPION_LOG_FORMAT = _get('SCIPION_LOG_FORMAT', "%(message)s",
|
228
|
-
|
248
|
+
"str: Format for all the log lines, defaults to %(message)s. To compose the format see https://docs.python.org/3/library/logging.html#logrecord-attributes")
|
229
249
|
|
230
250
|
SCIPION_LOG_LEVEL = _get(SCIPION_LOG_LEVEL, 'INFO',
|
231
|
-
|
251
|
+
"Default logging level. String among CRITICAL, ERROR, WARNING, INFO, DEBUG, NOTSET. Default value is INFO.")
|
232
252
|
|
233
253
|
NO_COLOR = _get('NO_COLOR', '',
|
234
|
-
|
254
|
+
"str: Comply with https://no-color.org/ initiative. Set it to something different than '' to deactivate colors in the output.")
|
235
255
|
|
236
256
|
SCIPION_SCRATCH = _get(SCIPION_SCRATCH, None,
|
237
|
-
|
257
|
+
"Optional. Path to a location mounted in a scratch drive (SSD,...)")
|
238
258
|
|
239
259
|
SCIPION_TESTS_OUTPUT = _get('SCIPION_TESTS_OUTPUT', _join(SCIPION_USER_DATA, 'Tests'),
|
240
|
-
|
260
|
+
"Path to a folder where the output of the tests will be written. Defaults to SCIPION_USER_DATA/Tests.", var_type=VarTypes.FOLDER)
|
241
261
|
|
242
262
|
SCIPION_TEST_NOSYNC = _get('SCIPION_TEST_NOSYNC', FALSE_STR,
|
243
|
-
|
263
|
+
"Set it to any value except False to cancel test dataset synchronization."
|
264
|
+
" Needed when updating files in a dataset.", caster=_notFalse)
|
244
265
|
|
245
266
|
SCIPION_SUPPORT_EMAIL = 'scipion@cnb.csic.es'
|
246
267
|
|
247
268
|
# Config variables
|
248
269
|
SCIPION_CONFIG = _get('SCIPION_CONFIG', _join('config','scipion.conf'),
|
249
|
-
|
270
|
+
"Path to the scipion configuration file where all this variables could be defined.", var_type=VarTypes.PATH)
|
250
271
|
|
251
272
|
SCIPION_LOCAL_CONFIG = _get('SCIPION_LOCAL_CONFIG', SCIPION_CONFIG,
|
252
|
-
|
273
|
+
"Path to an optional/extra/user configuration file meant to overwrite default variables.", var_type=VarTypes.PATH)
|
253
274
|
|
254
275
|
SCIPION_HOSTS = _get('SCIPION_HOSTS', _join('config','hosts.conf'),
|
255
|
-
|
276
|
+
"Path to the host.cof file to allow scipion to use queue engines and run in HPC environments.")
|
256
277
|
|
257
278
|
SCIPION_PROTOCOLS = _get('SCIPION_PROTOCOLS', _join('config','protocols.conf'),
|
258
|
-
|
279
|
+
"Custom conf file to extend the protocols tree view panel (panel on the left)")
|
259
280
|
|
260
281
|
SCIPION_PLUGIN_JSON = _get('SCIPION_PLUGIN_JSON', None,
|
261
|
-
|
282
|
+
"Optional. Path to get the json file with all the plugins available for Scipion.")
|
283
|
+
|
284
|
+
SCIPION_SITE = _get('SCIPION_SITE', 'https://scipion.i2pc.es',
|
285
|
+
"Scipion site URL.")
|
286
|
+
SCIPION_SITE_API = SCIPION_SITE + '/report_protocols/api/v2'
|
287
|
+
SCIPION_STATS_WORKFLOW_APP = SCIPION_SITE_API + '/workflow/'
|
288
|
+
SCIPION_STATS_SUGGESTION = SCIPION_SITE_API + '/nextprotocol/suggestion/%s'
|
262
289
|
|
263
290
|
SCIPION_PLUGIN_REPO_URL = _get('SCIPION_PLUGIN_REPO_URL',
|
264
|
-
'
|
265
|
-
|
291
|
+
SCIPION_SITE + '/getplugins/',
|
292
|
+
"Url from where to get the list of plugins.")
|
266
293
|
|
267
294
|
# REMOTE Section
|
268
295
|
SCIPION_URL = 'https://scipion.cnb.csic.es/downloads/scipion'
|
@@ -271,65 +298,69 @@ class Config:
|
|
271
298
|
|
272
299
|
# Scipion Notes
|
273
300
|
SCIPION_NOTES_FILE = _get(SCIPION_NOTES_FILE, 'notes.txt',
|
274
|
-
|
301
|
+
"Name of the file where to write per project notes.")
|
275
302
|
|
276
303
|
SCIPION_NOTES_PROGRAM = _get(SCIPION_NOTES_PROGRAM, None,
|
277
|
-
|
304
|
+
"Command or program to use to open the notes file. Otherwise system will extension association will take place.")
|
278
305
|
|
279
306
|
SCIPION_NOTES_ARGS = _get(SCIPION_NOTES_ARGS, None)
|
280
307
|
|
281
308
|
# External text editor:
|
282
309
|
SCIPION_TEXT_EDITOR = _get(SCIPION_TEXT_EDITOR, '',
|
283
|
-
|
310
|
+
"Preferred text editor executable.", caster=str)
|
284
311
|
|
285
312
|
# Aspect
|
286
313
|
SCIPION_FONT_NAME = _get('SCIPION_FONT_NAME', "Helvetica",
|
287
|
-
|
314
|
+
"Name of the font to use in Scipion GUI. Defaults to Helvetica.")
|
288
315
|
|
289
|
-
SCIPION_FONT_SIZE = _get('SCIPION_FONT_SIZE', SCIPION_DEFAULT_FONT_SIZE,
|
290
|
-
|
316
|
+
SCIPION_FONT_SIZE = _get('SCIPION_FONT_SIZE', str(SCIPION_DEFAULT_FONT_SIZE),
|
317
|
+
"Size of the 'normal' font to be used in Scipion GUI. "
|
318
|
+
"Defaults to 10.", caster=int)
|
291
319
|
|
292
320
|
SCIPION_MAIN_COLOR = _get('SCIPION_MAIN_COLOR', Color.MAIN_COLOR,
|
293
|
-
|
321
|
+
"str: Main color of the GUI. Background will be white, so for better contrast choose a dark color. Probably any name here will work: https://matplotlib.org/stable/gallery/color/named_colors.html",
|
294
322
|
caster=validColor)
|
295
323
|
|
296
324
|
SCIPION_BG_COLOR = _get('SCIPION_BG_COLOR', Color.BG_COLOR,
|
297
|
-
|
325
|
+
"str: Main background color of the GUI. Default is white, chose a light one. Probably any name here will work: https://matplotlib.org/stable/gallery/color/named_colors.html",
|
298
326
|
validColor)
|
299
327
|
|
300
|
-
SCIPION_CONTRAST_COLOR = _get('SCIPION_CONTRAST_COLOR', 'cyan',
|
301
|
-
|
328
|
+
SCIPION_CONTRAST_COLOR = _get('SCIPION_CONTRAST_COLOR', 'cyan', "Color used to highlight features over "
|
329
|
+
"gray-scaled images.", caster=validColor)
|
302
330
|
|
303
331
|
SCIPION_SPRITES_FILE = _get('SCIPION_SPRITES_FILE', __defaultSpritesFile,
|
304
|
-
|
332
|
+
"File (png) with the icons in a collage. Default is found at "
|
333
|
+
"pyworkflow/resources/sprites.png. And a GIMP file could be found at the same "
|
334
|
+
"folder in the github repo.")
|
305
335
|
|
306
|
-
SCIPION_SHOW_TEXT_IN_TOOLBAR = _get('SCIPION_SHOW_TEXT_IN_TOOLBAR', TRUE_STR,
|
307
|
-
|
336
|
+
SCIPION_SHOW_TEXT_IN_TOOLBAR = _get('SCIPION_SHOW_TEXT_IN_TOOLBAR', TRUE_STR, "Define it to anything else except "
|
337
|
+
"%s to hide labels. It will take less space." % TRUE_YES_ON_, caster=__bool)
|
308
338
|
|
309
|
-
SCIPION_ICON_ZOOM = _get('SCIPION_ICON_ZOOM', 50,
|
310
|
-
|
339
|
+
SCIPION_ICON_ZOOM = _get('SCIPION_ICON_ZOOM', "50",
|
340
|
+
"Define it to any integer value(percentage) to increase/decrease the size of the icons.",
|
341
|
+
var_type=VarTypes.INTEGER, caster=int)
|
311
342
|
|
312
343
|
# Notification
|
313
|
-
SCIPION_NOTIFY = _get('SCIPION_NOTIFY', TRUE_STR,
|
314
|
-
|
344
|
+
SCIPION_NOTIFY = _get('SCIPION_NOTIFY', TRUE_STR, "If set to anything except %s Scipion developers will know "
|
345
|
+
"nothing abut Scipion usage and will have less information to improve it." % TRUE_YES_ON_,
|
346
|
+
caster=__bool)
|
315
347
|
|
316
348
|
# *** Execution variables ***
|
317
|
-
SCIPION_CWD = _get('SCIPION_CWD', os.path.abspath(os.getcwd()),
|
318
|
-
"Directory when scipion was launched")
|
349
|
+
SCIPION_CWD = _get('SCIPION_CWD', os.path.abspath(os.getcwd()), "Directory when scipion was launched")
|
319
350
|
|
320
351
|
SCIPION_GUI_REFRESH_IN_THREAD = _get('SCIPION_GUI_REFRESH_IN_THREAD', FALSE_STR,
|
321
|
-
|
352
|
+
"True to refresh the runs graph with a thread. Unstable.") != FALSE_STR
|
322
353
|
|
323
354
|
SCIPION_GUI_REFRESH_INITIAL_WAIT = _get("SCIPION_GUI_REFRESH_INITIAL_WAIT", 5,
|
324
|
-
|
355
|
+
"Seconds to wait after a manual refresh", caster=int)
|
325
356
|
|
326
357
|
SCIPION_GUI_CANCEL_AUTO_REFRESH = _get("SCIPION_GUI_CANCEL_AUTO_REFRESH",FALSE_STR,
|
327
|
-
|
358
|
+
"Set it to True to cancel automatic refresh of the runs.") != FALSE_STR
|
328
359
|
|
329
360
|
# Cancel shutil fast copy. In GPFS, shutil.copy does fail when trying a fastcopy and does not
|
330
361
|
# fall back on the slow copy. For legacy reasons None is also False.
|
331
362
|
SCIPION_CANCEL_FASTCOPY = _get('SCIPION_CANCEL_FASTCOPY', FALSE_STR,
|
332
|
-
|
363
|
+
"Cancel fast copy done by shutil (copying files) when it fails. Has happened in GPFS environments. Defaults to False. None is also False otherwise fastcopy is cancelled."
|
333
364
|
) not in [NONE_STR, FALSE_STR]
|
334
365
|
|
335
366
|
# Priority package list: This variable is used in the view protocols in
|
@@ -339,26 +370,40 @@ class Config:
|
|
339
370
|
SCIPION_PRIORITY_PACKAGE_LIST = _get('SCIPION_PRIORITY_PACKAGE_LIST', EMPTY_STR)
|
340
371
|
|
341
372
|
SCIPION_STEPS_CHECK_SEC = _get('SCIPION_STEPS_CHECK_SEC', 5,
|
342
|
-
|
373
|
+
"Number of seconds to wait before checking if new input is available in "
|
374
|
+
"streamified protocols.", caster=int)
|
343
375
|
|
344
376
|
SCIPION_UPDATE_SET_ATTEMPTS = _get('SCIPION_UPDATE_SET_ATTEMPTS', 3,
|
345
|
-
|
377
|
+
"Number of attempts to modify the protocol output before failing. "
|
378
|
+
"The default value is 3", caster=int)
|
346
379
|
|
347
380
|
SCIPION_UPDATE_SET_ATTEMPT_WAIT = _get('SCIPION_UPDATE_SET_ATTEMPT_WAIT', 2,
|
348
|
-
|
381
|
+
"Time in seconds to wait until the next attempt when checking new outputs. "
|
382
|
+
"The default value is 2 seconds", caster=int)
|
383
|
+
|
384
|
+
SCIPION_UNLOAD_FORM_ON_SAVE = _get('SCIPION_UNLOAD_FORM_ON_SAVE', TRUE_STR,
|
385
|
+
"When a protocol is saved it is unloaded if all goes fine. Set it to false "
|
386
|
+
"otherwise to rescue old behaviour.", caster=__bool)
|
349
387
|
|
350
388
|
SCIPION_USE_QUEUE = _get("SCIPION_USE_QUEUE", FALSE_STR,
|
351
|
-
|
389
|
+
"Default value for using the queue. By default is False. "
|
390
|
+
"ANY value will be True except and empty value. \"False\" or \"0\" "
|
391
|
+
"will be True too.") != FALSE_STR
|
352
392
|
|
353
393
|
SCIPION_DEFAULT_EXECUTION_ACTION = _get('SCIPION_DEFAULT_EXECUTION_ACTION', DEFAULT_EXECUTION_ACTION_ASK,
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
394
|
+
"""Ask if you want to launch a single protocol or a sub-workflow. The default value is 1
|
395
|
+
1: Scipion always ask
|
396
|
+
2: Run a single protocol
|
397
|
+
3: Run a sub-workflow """, caster=int)
|
358
398
|
|
359
399
|
SCIPION_MAPPER_USE_TEMPLATE = _get('SCIPION_MAPPER_USE_TEMPLATE', TRUE_STR,
|
360
|
-
|
361
|
-
|
400
|
+
"Set it to False to force instantiation for each item during sets iterations. Experimental. This penalize the iteration but avoids"
|
401
|
+
"the use of .clone() ot the items.") == TRUE_STR
|
402
|
+
|
403
|
+
CUDA_DEVICE_ORDER = _get('CUDA_DEVICE_ORDER', 'PCI_BUS_ID',
|
404
|
+
"To make GPU ID match what you see in nvidia-smi, that is the PCI ID."
|
405
|
+
" Use FASTEST_FIRST for default behaviour but this may not match what is returned by nvidia-smi."
|
406
|
+
" See https://docs.nvidia.com/cuda/cuda-c-programming-guide/#:~:text=in%20device%20memory.-,CUDA_DEVICE_ORDER,-FASTEST_FIRST%2C%20PCI_BUS_ID%2C%20(default ")
|
362
407
|
|
363
408
|
try:
|
364
409
|
VIEWERS = ast.literal_eval(_get('VIEWERS', "{}", "Json string to define which viewer are the default ones per output type."))
|
@@ -377,7 +422,8 @@ class Config:
|
|
377
422
|
:return: Folder where libraries must be placed in case a binding needs them
|
378
423
|
"""
|
379
424
|
lib = cls._join(cls.SCIPION_SOFTWARE, 'lib')
|
380
|
-
|
425
|
+
if cls.SCIPION_HOME_DEFINED:
|
426
|
+
os.makedirs(lib, exist_ok=True)
|
381
427
|
return lib
|
382
428
|
|
383
429
|
@classmethod
|
@@ -388,7 +434,8 @@ class Config:
|
|
388
434
|
:return: The bindings folder
|
389
435
|
"""
|
390
436
|
bindings = cls._join(cls.SCIPION_SOFTWARE, 'bindings')
|
391
|
-
|
437
|
+
if cls.SCIPION_HOME_DEFINED:
|
438
|
+
os.makedirs(bindings, exist_ok=True)
|
392
439
|
return bindings
|
393
440
|
|
394
441
|
@classmethod
|
@@ -397,7 +444,8 @@ class Config:
|
|
397
444
|
Folder where scipion logs must be placed. The folder is created
|
398
445
|
"""
|
399
446
|
logsFolder = cls.SCIPION_LOGS
|
400
|
-
|
447
|
+
if cls.SCIPION_HOME_DEFINED:
|
448
|
+
os.makedirs(logsFolder, exist_ok=True)
|
401
449
|
return logsFolder
|
402
450
|
|
403
451
|
@classmethod
|
@@ -455,8 +503,13 @@ class Config:
|
|
455
503
|
debugOn = not Config.debugOn()
|
456
504
|
os.environ[SCIPION_DEBUG] = str(debugOn)
|
457
505
|
os.environ[SCIPION_DEBUG_NOCLEAN] = str(debugOn)
|
458
|
-
os.environ[SCIPION_LOG_LEVEL] = "INFO" if not debugOn else "DEBUG"
|
459
506
|
|
507
|
+
newLevel = "DEBUG" if debugOn else "INFO"
|
508
|
+
os.environ[SCIPION_LOG_LEVEL] = newLevel
|
509
|
+
|
510
|
+
from pyworkflow.utils import changeLogLevel
|
511
|
+
changeLogLevel(newLevel)
|
512
|
+
logger.info("Log level set to %s" % newLevel)
|
460
513
|
@staticmethod
|
461
514
|
def debugSQLOn():
|
462
515
|
from .utils import envVarOn
|
@@ -545,6 +598,17 @@ class Config:
|
|
545
598
|
condaExe = os.path.join(envFolder, "bin", "python")
|
546
599
|
return condaExe == getPython()
|
547
600
|
|
601
|
+
@classmethod
|
602
|
+
def getEnvName(cls):
|
603
|
+
""" Returns Scipion's environment name(conda or venv)"""
|
604
|
+
if cls.isCondaInstallation():
|
605
|
+
envPath = os.environ['CONDA_PREFIX']
|
606
|
+
else: # Virtualenv
|
607
|
+
envPath = os.environ['VIRTUAL_ENV']
|
608
|
+
|
609
|
+
return os.path.basename(envPath)
|
610
|
+
|
611
|
+
|
548
612
|
@classmethod
|
549
613
|
def getSpritesFile(cls):
|
550
614
|
if not os.path.exists(Config.SCIPION_SPRITES_FILE):
|
pyworkflow/constants.py
CHANGED
@@ -43,7 +43,7 @@ VERSION_1 = '1.0.0'
|
|
43
43
|
VERSION_1_1 = '1.1.0'
|
44
44
|
VERSION_1_2 = '1.2.0'
|
45
45
|
VERSION_2_0 = '2.0.0'
|
46
|
-
VERSION_3_0 = '3.
|
46
|
+
VERSION_3_0 = '3.11.0'
|
47
47
|
|
48
48
|
# For a new release, define a new constant and assign it to LAST_VERSION
|
49
49
|
# The existing one has to be added to OLD_VERSIONS list.
|
@@ -141,6 +141,7 @@ PROJECT_SETTINGS = 'settings.sqlite'
|
|
141
141
|
FALSE_STR = str(False)
|
142
142
|
TRUE_STR = str(True)
|
143
143
|
NONE_STR = str(None)
|
144
|
+
TRUE_YES_ON_ = ['true', 'yes', 'on', '1']
|
144
145
|
EMPTY_STR = ""
|
145
146
|
|
146
147
|
# GUI colors
|
pyworkflow/plugin.py
CHANGED
@@ -28,6 +28,7 @@
|
|
28
28
|
# **************************************************************************
|
29
29
|
import logging
|
30
30
|
import sys
|
31
|
+
from functools import lru_cache
|
31
32
|
|
32
33
|
from pyworkflow import Variable, VariablesRegistry, VarTypes
|
33
34
|
from .protocol import Protocol
|
@@ -79,6 +80,9 @@ class Domain:
|
|
79
80
|
_viewers = {}
|
80
81
|
_wizards = {}
|
81
82
|
|
83
|
+
# Preferred viewers:
|
84
|
+
_preferred_viewers = None
|
85
|
+
|
82
86
|
@classmethod
|
83
87
|
def registerPlugin(cls, name):
|
84
88
|
""" Register a new plugin. This function should only be called when
|
@@ -113,15 +117,17 @@ class Domain:
|
|
113
117
|
|
114
118
|
# Catch any import exception, warn about it but continue.
|
115
119
|
except ModuleNotFoundError as e:
|
120
|
+
|
121
|
+
logger.debug("Module %s not found: %s" %(name, e))
|
116
122
|
if e.name == name:
|
117
123
|
# This is probably due to a priority package like pwchem not being installed
|
118
|
-
|
124
|
+
logger.debug("Name is different!!: e.name='%s', name='%s'" %( e.name , name))
|
119
125
|
else:
|
120
126
|
logger.warning("Plugin '%s' has import errors: %s. Maybe a missing dependency?. "
|
121
127
|
"Is it devel mode and need to be reinstalled?. Ignoring it and continuing." % (name, str(e)))
|
122
128
|
except Exception as e:
|
123
129
|
|
124
|
-
(pwutils.yellow("WARNING!!: Plugin containing module %s does not import properly. "
|
130
|
+
logger.info(pwutils.yellow("WARNING!!: Plugin containing module %s does not import properly. "
|
125
131
|
"All its content will be missing in this execution." % name))
|
126
132
|
logger.info("Please, contact developers at %s and send this ugly information below. They'll understand it!." % DOCSITEURLS.CONTACTUS)
|
127
133
|
logger.info("Error message: %s"% str(e))
|
@@ -390,56 +396,99 @@ class Domain:
|
|
390
396
|
@classmethod
|
391
397
|
def getPreferredViewers(cls, className):
|
392
398
|
""" Find and import the preferred viewers for this class. """
|
393
|
-
|
394
|
-
if
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
399
|
+
|
400
|
+
if cls._preferred_viewers is None:
|
401
|
+
logger.info("Caching preferred viewers from VIEWERS config variable.")
|
402
|
+
cls._preferred_viewers = dict()
|
403
|
+
|
404
|
+
for target, viewerNames in pw.Config.VIEWERS.items():
|
405
|
+
viewers = []
|
406
|
+
for prefViewerStr in viewerNames:
|
407
|
+
try:
|
408
|
+
viewerModule, viewerClassName = prefViewerStr.rsplit('.', 1)
|
409
|
+
prefViewer = cls.importFromPlugin(viewerModule,
|
410
|
+
viewerClassName,
|
411
|
+
doRaise=True)
|
412
|
+
viewers.append(prefViewer)
|
413
|
+
except Exception as e:
|
414
|
+
logger.error("Couldn't load \"%s\" as preferred viewer for %s.\n"
|
415
|
+
"There might be a typo in your VIEWERS variable "
|
416
|
+
"or an error in the viewer's plugin installation"
|
417
|
+
% (prefViewerStr, className), exc_info=e)
|
418
|
+
|
419
|
+
cls._preferred_viewers[target] = viewers
|
420
|
+
|
421
|
+
return cls._preferred_viewers.get(className, [])
|
422
|
+
|
423
|
+
@classmethod
|
424
|
+
@lru_cache
|
425
|
+
def getViewersSorted(cls):
|
426
|
+
""" Returns all viewers sorted by its class name"""
|
427
|
+
|
428
|
+
viewers = cls.getViewers()
|
429
|
+
return [viewers[key] for key in sorted(viewers)]
|
410
430
|
|
411
431
|
@classmethod
|
412
|
-
def findViewers(cls,
|
413
|
-
""" Find the available viewers in this Domain for this
|
432
|
+
def findViewers(cls, target, environment):
|
433
|
+
""" Find the available viewers in this Domain for this target.
|
434
|
+
|
435
|
+
Sorting criteria:
|
436
|
+
|
437
|
+
1st Will appear those viewers in VIEWERS variable (preferred viewers) in appearance order
|
438
|
+
2nd Viewers targeting specifically the target and not any super class of it
|
439
|
+
3rd rest.
|
440
|
+
|
441
|
+
In 2nd and 3rd case the order viewers are added depends on the alphabetical order the viewer when discovered.
|
442
|
+
This usually matches the viewer class name, but could be fine tune using import aliases like:
|
443
|
+
|
444
|
+
from my_viewer import MyViewer as AAAMyViewer in the viewers folder of the plugin.
|
445
|
+
|
446
|
+
In case viewers is a file and not a folder with an __init__, I'm afraid class name is what is taken into account
|
447
|
+
|
448
|
+
The import order is not possible to use since python sort them automatically.
|
449
|
+
|
450
|
+
"""
|
414
451
|
viewers = []
|
415
452
|
try:
|
416
|
-
|
453
|
+
instance = None
|
454
|
+
if isinstance(target, str):
|
455
|
+
logger.warning("DEVELOPERS: pass the instance/object instead of the class. This mode will be deprecated soon")
|
456
|
+
className = target
|
457
|
+
clazz = cls.findClass(className)
|
458
|
+
else:
|
459
|
+
className = target.__class__.__name__
|
460
|
+
clazz = target.__class__
|
461
|
+
instance = target
|
462
|
+
|
417
463
|
baseClasses = clazz.mro()
|
418
|
-
preferredViewers = cls.getPreferredViewers(className)
|
419
|
-
preferedFlag = 0
|
420
464
|
|
421
|
-
|
422
|
-
|
465
|
+
# Add preferred viewers
|
466
|
+
preferred_viewers = []
|
467
|
+
available_preferred_viewers = cls.getPreferredViewers(className)
|
468
|
+
for prefViewer in available_preferred_viewers:
|
469
|
+
if prefViewer.can_handle_this(baseClasses, instance=instance):
|
470
|
+
preferred_viewers.append(prefViewer)
|
471
|
+
|
472
|
+
|
473
|
+
specific_viewers = []
|
474
|
+
other_viewers=[]
|
475
|
+
# get all the viewers available
|
476
|
+
|
477
|
+
for viewer in cls.getViewersSorted():
|
478
|
+
|
423
479
|
if environment in viewer._environments:
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
480
|
+
|
481
|
+
if viewer not in preferred_viewers:
|
482
|
+
|
483
|
+
t = viewer.can_handle_this(baseClasses, target)
|
484
|
+
if t is not None:
|
485
|
+
if t == clazz:
|
486
|
+
specific_viewers.append(viewer)
|
487
|
+
|
432
488
|
else:
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
else:
|
437
|
-
viewers.append(viewer)
|
438
|
-
viewerAdded = True
|
439
|
-
break
|
440
|
-
|
441
|
-
if viewerAdded:
|
442
|
-
break
|
489
|
+
other_viewers.append(viewer)
|
490
|
+
|
491
|
+
viewers = preferred_viewers + specific_viewers + other_viewers
|
443
492
|
|
444
493
|
except Exception as e:
|
445
494
|
# Catch if there is a missing plugin, we will get Legacy which triggers and Exception
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|