fractal-server 1.4.9__py3-none-any.whl → 2.0.0a0__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 (132) hide show
  1. fractal_server/__init__.py +1 -1
  2. fractal_server/app/models/__init__.py +4 -7
  3. fractal_server/app/models/linkuserproject.py +9 -0
  4. fractal_server/app/models/security.py +6 -0
  5. fractal_server/app/models/state.py +1 -1
  6. fractal_server/app/models/v1/__init__.py +10 -0
  7. fractal_server/app/models/{dataset.py → v1/dataset.py} +5 -5
  8. fractal_server/app/models/{job.py → v1/job.py} +5 -5
  9. fractal_server/app/models/{project.py → v1/project.py} +5 -5
  10. fractal_server/app/models/{task.py → v1/task.py} +7 -2
  11. fractal_server/app/models/{workflow.py → v1/workflow.py} +5 -5
  12. fractal_server/app/models/v2/__init__.py +20 -0
  13. fractal_server/app/models/v2/dataset.py +55 -0
  14. fractal_server/app/models/v2/job.py +51 -0
  15. fractal_server/app/models/v2/project.py +31 -0
  16. fractal_server/app/models/v2/task.py +93 -0
  17. fractal_server/app/models/v2/workflow.py +43 -0
  18. fractal_server/app/models/v2/workflowtask.py +90 -0
  19. fractal_server/app/routes/{admin.py → admin/v1.py} +42 -42
  20. fractal_server/app/routes/admin/v2.py +275 -0
  21. fractal_server/app/routes/api/v1/__init__.py +7 -7
  22. fractal_server/app/routes/api/v1/_aux_functions.py +2 -2
  23. fractal_server/app/routes/api/v1/dataset.py +44 -37
  24. fractal_server/app/routes/api/v1/job.py +12 -12
  25. fractal_server/app/routes/api/v1/project.py +23 -21
  26. fractal_server/app/routes/api/v1/task.py +24 -14
  27. fractal_server/app/routes/api/v1/task_collection.py +16 -14
  28. fractal_server/app/routes/api/v1/workflow.py +24 -24
  29. fractal_server/app/routes/api/v1/workflowtask.py +10 -10
  30. fractal_server/app/routes/api/v2/__init__.py +28 -0
  31. fractal_server/app/routes/api/v2/_aux_functions.py +497 -0
  32. fractal_server/app/routes/api/v2/apply.py +220 -0
  33. fractal_server/app/routes/api/v2/dataset.py +310 -0
  34. fractal_server/app/routes/api/v2/images.py +212 -0
  35. fractal_server/app/routes/api/v2/job.py +200 -0
  36. fractal_server/app/routes/api/v2/project.py +205 -0
  37. fractal_server/app/routes/api/v2/task.py +222 -0
  38. fractal_server/app/routes/api/v2/task_collection.py +229 -0
  39. fractal_server/app/routes/api/v2/workflow.py +398 -0
  40. fractal_server/app/routes/api/v2/workflowtask.py +269 -0
  41. fractal_server/app/routes/aux/_job.py +1 -1
  42. fractal_server/app/runner/async_wrap.py +27 -0
  43. fractal_server/app/runner/exceptions.py +129 -0
  44. fractal_server/app/runner/executors/local/__init__.py +3 -0
  45. fractal_server/app/runner/{_local → executors/local}/executor.py +2 -2
  46. fractal_server/app/runner/executors/slurm/__init__.py +3 -0
  47. fractal_server/app/runner/{_slurm → executors/slurm}/_batching.py +1 -1
  48. fractal_server/app/runner/executors/slurm/_check_jobs_status.py +72 -0
  49. fractal_server/app/runner/{_slurm → executors/slurm}/_executor_wait_thread.py +3 -4
  50. fractal_server/app/runner/{_slurm → executors/slurm}/_slurm_config.py +3 -152
  51. fractal_server/app/runner/{_slurm → executors/slurm}/_subprocess_run_as_user.py +1 -1
  52. fractal_server/app/runner/{_slurm → executors/slurm}/executor.py +9 -9
  53. fractal_server/app/runner/filenames.py +6 -0
  54. fractal_server/app/runner/set_start_and_last_task_index.py +39 -0
  55. fractal_server/app/runner/task_files.py +105 -0
  56. fractal_server/app/runner/{__init__.py → v1/__init__.py} +36 -49
  57. fractal_server/app/runner/{_common.py → v1/_common.py} +13 -120
  58. fractal_server/app/runner/{_local → v1/_local}/__init__.py +6 -6
  59. fractal_server/app/runner/{_local → v1/_local}/_local_config.py +6 -7
  60. fractal_server/app/runner/{_local → v1/_local}/_submit_setup.py +1 -5
  61. fractal_server/app/runner/v1/_slurm/__init__.py +310 -0
  62. fractal_server/app/runner/{_slurm → v1/_slurm}/_submit_setup.py +3 -9
  63. fractal_server/app/runner/v1/_slurm/get_slurm_config.py +163 -0
  64. fractal_server/app/runner/v1/common.py +117 -0
  65. fractal_server/app/runner/{handle_failed_job.py → v1/handle_failed_job.py} +8 -8
  66. fractal_server/app/runner/v2/__init__.py +337 -0
  67. fractal_server/app/runner/v2/_local/__init__.py +169 -0
  68. fractal_server/app/runner/v2/_local/_local_config.py +118 -0
  69. fractal_server/app/runner/v2/_local/_submit_setup.py +52 -0
  70. fractal_server/app/runner/v2/_slurm/__init__.py +157 -0
  71. fractal_server/app/runner/v2/_slurm/_submit_setup.py +83 -0
  72. fractal_server/app/runner/v2/_slurm/get_slurm_config.py +179 -0
  73. fractal_server/app/runner/v2/components.py +5 -0
  74. fractal_server/app/runner/v2/deduplicate_list.py +24 -0
  75. fractal_server/app/runner/v2/handle_failed_job.py +156 -0
  76. fractal_server/app/runner/v2/merge_outputs.py +41 -0
  77. fractal_server/app/runner/v2/runner.py +264 -0
  78. fractal_server/app/runner/v2/runner_functions.py +339 -0
  79. fractal_server/app/runner/v2/runner_functions_low_level.py +134 -0
  80. fractal_server/app/runner/v2/task_interface.py +43 -0
  81. fractal_server/app/runner/v2/v1_compat.py +21 -0
  82. fractal_server/app/schemas/__init__.py +4 -42
  83. fractal_server/app/schemas/v1/__init__.py +42 -0
  84. fractal_server/app/schemas/{applyworkflow.py → v1/applyworkflow.py} +18 -18
  85. fractal_server/app/schemas/{dataset.py → v1/dataset.py} +30 -30
  86. fractal_server/app/schemas/{dumps.py → v1/dumps.py} +8 -8
  87. fractal_server/app/schemas/{manifest.py → v1/manifest.py} +5 -5
  88. fractal_server/app/schemas/{project.py → v1/project.py} +9 -9
  89. fractal_server/app/schemas/{task.py → v1/task.py} +12 -12
  90. fractal_server/app/schemas/{task_collection.py → v1/task_collection.py} +7 -7
  91. fractal_server/app/schemas/{workflow.py → v1/workflow.py} +38 -38
  92. fractal_server/app/schemas/v2/__init__.py +34 -0
  93. fractal_server/app/schemas/v2/dataset.py +88 -0
  94. fractal_server/app/schemas/v2/dumps.py +87 -0
  95. fractal_server/app/schemas/v2/job.py +113 -0
  96. fractal_server/app/schemas/v2/manifest.py +109 -0
  97. fractal_server/app/schemas/v2/project.py +36 -0
  98. fractal_server/app/schemas/v2/task.py +121 -0
  99. fractal_server/app/schemas/v2/task_collection.py +105 -0
  100. fractal_server/app/schemas/v2/workflow.py +78 -0
  101. fractal_server/app/schemas/v2/workflowtask.py +118 -0
  102. fractal_server/config.py +5 -10
  103. fractal_server/images/__init__.py +50 -0
  104. fractal_server/images/tools.py +86 -0
  105. fractal_server/main.py +11 -3
  106. fractal_server/migrations/versions/4b35c5cefbe3_tmp_is_v2_compatible.py +39 -0
  107. fractal_server/migrations/versions/56af171b0159_v2.py +217 -0
  108. fractal_server/migrations/versions/876f28db9d4e_tmp_split_task_and_wftask_meta.py +68 -0
  109. fractal_server/migrations/versions/974c802f0dd0_tmp_workflowtaskv2_type_in_db.py +37 -0
  110. fractal_server/migrations/versions/9cd305cd6023_tmp_workflowtaskv2.py +40 -0
  111. fractal_server/migrations/versions/a6231ed6273c_tmp_args_schemas_in_taskv2.py +42 -0
  112. fractal_server/migrations/versions/b9e9eed9d442_tmp_taskv2_type.py +37 -0
  113. fractal_server/migrations/versions/e3e639454d4b_tmp_make_task_meta_non_optional.py +50 -0
  114. fractal_server/tasks/__init__.py +0 -5
  115. fractal_server/tasks/endpoint_operations.py +13 -19
  116. fractal_server/tasks/utils.py +35 -0
  117. fractal_server/tasks/{_TaskCollectPip.py → v1/_TaskCollectPip.py} +3 -3
  118. fractal_server/tasks/{background_operations.py → v1/background_operations.py} +18 -50
  119. fractal_server/tasks/v1/get_collection_data.py +14 -0
  120. fractal_server/tasks/v2/_TaskCollectPip.py +103 -0
  121. fractal_server/tasks/v2/background_operations.py +382 -0
  122. fractal_server/tasks/v2/get_collection_data.py +14 -0
  123. {fractal_server-1.4.9.dist-info → fractal_server-2.0.0a0.dist-info}/METADATA +3 -4
  124. fractal_server-2.0.0a0.dist-info/RECORD +166 -0
  125. fractal_server/app/runner/_slurm/.gitignore +0 -2
  126. fractal_server/app/runner/_slurm/__init__.py +0 -150
  127. fractal_server/app/runner/common.py +0 -311
  128. fractal_server-1.4.9.dist-info/RECORD +0 -97
  129. /fractal_server/app/runner/{_slurm → executors/slurm}/remote.py +0 -0
  130. {fractal_server-1.4.9.dist-info → fractal_server-2.0.0a0.dist-info}/LICENSE +0 -0
  131. {fractal_server-1.4.9.dist-info → fractal_server-2.0.0a0.dist-info}/WHEEL +0 -0
  132. {fractal_server-1.4.9.dist-info → fractal_server-2.0.0a0.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,169 @@
1
+ # Copyright 2022 (C) Friedrich Miescher Institute for Biomedical Research and
2
+ # University of Zurich
3
+ #
4
+ # Original authors:
5
+ # Jacopo Nespolo <jacopo.nespolo@exact-lab.it>
6
+ # Tommaso Comparin <tommaso.comparin@exact-lab.it>
7
+ # Marco Franzon <marco.franzon@exact-lab.it>
8
+ #
9
+ # This file is part of Fractal and was originally developed by eXact lab S.r.l.
10
+ # <exact-lab.it> under contract with Liberali Lab from the Friedrich Miescher
11
+ # Institute for Biomedical Research and Pelkmans Lab from the University of
12
+ # Zurich.
13
+ """
14
+ Local Bakend
15
+
16
+ This backend runs Fractal workflows using `FractalThreadPoolExecutor` (a custom
17
+ version of Python
18
+ [ThreadPoolExecutor](https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures.ThreadPoolExecutor))
19
+ to run tasks in several threads.
20
+ Incidentally, it also represents the reference implementation for a backend.
21
+ """
22
+ from pathlib import Path
23
+ from typing import Optional
24
+
25
+ from ....models.v2 import DatasetV2
26
+ from ....models.v2 import WorkflowV2
27
+ from ...async_wrap import async_wrap
28
+ from ...executors.local.executor import FractalThreadPoolExecutor
29
+ from ...set_start_and_last_task_index import set_start_and_last_task_index
30
+ from ..runner import execute_tasks_v2
31
+ from ._submit_setup import _local_submit_setup
32
+
33
+ # from typing import Any
34
+
35
+
36
+ def _process_workflow(
37
+ *,
38
+ workflow: WorkflowV2,
39
+ dataset: DatasetV2,
40
+ logger_name: str,
41
+ workflow_dir: Path,
42
+ first_task_index: int,
43
+ last_task_index: int,
44
+ ) -> dict:
45
+ """
46
+ Internal processing routine
47
+
48
+ Schedules the workflow using a `FractalThreadPoolExecutor`.
49
+
50
+ Cf. [process_workflow][fractal_server.app.runner._local.process_workflow]
51
+ for the call signature.
52
+ """
53
+
54
+ with FractalThreadPoolExecutor() as executor:
55
+ new_dataset_attributes = execute_tasks_v2(
56
+ wf_task_list=workflow.task_list[
57
+ first_task_index : (last_task_index + 1) # noqa
58
+ ], # noqa
59
+ dataset=dataset,
60
+ executor=executor,
61
+ workflow_dir=workflow_dir,
62
+ workflow_dir_user=workflow_dir,
63
+ logger_name=logger_name,
64
+ submit_setup_call=_local_submit_setup,
65
+ )
66
+ return new_dataset_attributes
67
+
68
+
69
+ async def process_workflow(
70
+ *,
71
+ workflow: WorkflowV2,
72
+ dataset: DatasetV2,
73
+ workflow_dir: Path,
74
+ workflow_dir_user: Optional[Path] = None,
75
+ first_task_index: Optional[int] = None,
76
+ last_task_index: Optional[int] = None,
77
+ logger_name: str,
78
+ # Slurm-specific
79
+ user_cache_dir: Optional[str] = None,
80
+ slurm_user: Optional[str] = None,
81
+ slurm_account: Optional[str] = None,
82
+ worker_init: Optional[str] = None,
83
+ ) -> dict:
84
+ """
85
+ Run a workflow
86
+
87
+ This function is responsible for running a workflow on some input data,
88
+ saving the output and taking care of any exception raised during the run.
89
+
90
+ NOTE: This is the `local` backend's public interface, which also works as
91
+ a reference implementation for other backends.
92
+
93
+ Args:
94
+ workflow:
95
+ The workflow to be run
96
+ input_paths:
97
+ The paths to the input files to pass to the first task of the
98
+ workflow
99
+ output_path:
100
+ The destination path for the last task of the workflow
101
+ input_metadata:
102
+ Initial metadata, passed to the first task
103
+ logger_name:
104
+ Name of the logger to log information on the run to
105
+ workflow_dir:
106
+ Working directory for this run.
107
+ workflow_dir_user:
108
+ Working directory for this run, on the user side. This argument is
109
+ present for compatibility with the standard backend interface, but
110
+ for the `local` backend it cannot be different from `workflow_dir`.
111
+ slurm_user:
112
+ Username to impersonate to run the workflow. This argument is
113
+ present for compatibility with the standard backend interface, but
114
+ is ignored in the `local` backend.
115
+ slurm_account:
116
+ SLURM account to use when running the workflow. This argument is
117
+ present for compatibility with the standard backend interface, but
118
+ is ignored in the `local` backend.
119
+ user_cache_dir:
120
+ Cache directory of the user who will run the workflow. This
121
+ argument is present for compatibility with the standard backend
122
+ interface, but is ignored in the `local` backend.
123
+ worker_init:
124
+ Any additional, usually backend specific, information to be passed
125
+ to the backend executor. This argument is present for compatibility
126
+ with the standard backend interface, but is ignored in the `local`
127
+ backend.
128
+ first_task_index:
129
+ Positional index of the first task to execute; if `None`, start
130
+ from `0`.
131
+ last_task_index:
132
+ Positional index of the last task to execute; if `None`, proceed
133
+ until the last task.
134
+
135
+ Raises:
136
+ TaskExecutionError: wrapper for errors raised during tasks' execution
137
+ (positive exit codes).
138
+ JobExecutionError: wrapper for errors raised by the tasks' executors
139
+ (negative exit codes).
140
+
141
+ Returns:
142
+ output_dataset_metadata:
143
+ The updated metadata for the dataset, as returned by the last task
144
+ of the workflow
145
+ """
146
+
147
+ if workflow_dir_user and (workflow_dir_user != workflow_dir):
148
+ raise NotImplementedError(
149
+ "Local backend does not support different directories "
150
+ f"{workflow_dir=} and {workflow_dir_user=}"
151
+ )
152
+
153
+ # Set values of first_task_index and last_task_index
154
+ num_tasks = len(workflow.task_list)
155
+ first_task_index, last_task_index = set_start_and_last_task_index(
156
+ num_tasks,
157
+ first_task_index=first_task_index,
158
+ last_task_index=last_task_index,
159
+ )
160
+
161
+ new_dataset_attributes = await async_wrap(_process_workflow)(
162
+ workflow=workflow,
163
+ dataset=dataset,
164
+ logger_name=logger_name,
165
+ workflow_dir=workflow_dir,
166
+ first_task_index=first_task_index,
167
+ last_task_index=last_task_index,
168
+ )
169
+ return new_dataset_attributes
@@ -0,0 +1,118 @@
1
+ # Copyright 2022 (C) Friedrich Miescher Institute for Biomedical Research and
2
+ # University of Zurich
3
+ #
4
+ # Original authors:
5
+ # Tommaso Comparin <tommaso.comparin@exact-lab.it>
6
+ #
7
+ # This file is part of Fractal and was originally developed by eXact lab S.r.l.
8
+ # <exact-lab.it> under contract with Liberali Lab from the Friedrich Miescher
9
+ # Institute for Biomedical Research and Pelkmans Lab from the University of
10
+ # Zurich.
11
+ """
12
+ Submodule to handle the local-backend configuration for a WorkflowTask
13
+ """
14
+ import json
15
+ from pathlib import Path
16
+ from typing import Literal
17
+ from typing import Optional
18
+
19
+ from pydantic import BaseModel
20
+ from pydantic import Extra
21
+ from pydantic.error_wrappers import ValidationError
22
+
23
+ from .....config import get_settings
24
+ from .....syringe import Inject
25
+ from ....models.v2 import WorkflowTaskV2
26
+
27
+
28
+ class LocalBackendConfigError(ValueError):
29
+ """
30
+ Local-backend configuration error
31
+ """
32
+
33
+ pass
34
+
35
+
36
+ class LocalBackendConfig(BaseModel, extra=Extra.forbid):
37
+ """
38
+ Specifications of the local-backend configuration
39
+
40
+ Attributes:
41
+ parallel_tasks_per_job:
42
+ Maximum number of tasks to be run in parallel as part of a call to
43
+ `FractalThreadPoolExecutor.map`; if `None`, then all tasks will
44
+ start at the same time.
45
+ """
46
+
47
+ parallel_tasks_per_job: Optional[int]
48
+
49
+
50
+ def get_default_local_backend_config():
51
+ """
52
+ Return a default `LocalBackendConfig` configuration object
53
+ """
54
+ return LocalBackendConfig(parallel_tasks_per_job=None)
55
+
56
+
57
+ def get_local_backend_config(
58
+ wftask: WorkflowTaskV2,
59
+ which_type: Literal["non_parallel", "parallel"],
60
+ config_path: Optional[Path] = None,
61
+ ) -> LocalBackendConfig:
62
+ """
63
+ Prepare a `LocalBackendConfig` configuration object
64
+
65
+ The sources for `parallel_tasks_per_job` attributes, starting from the
66
+ highest-priority one, are
67
+
68
+ 1. Properties in `wftask.meta_parallel` or `wftask.meta_non_parallel`
69
+ (depending on `which_type`);
70
+ 2. The general content of the local-backend configuration file;
71
+ 3. The default value (`None`).
72
+
73
+ Arguments:
74
+ wftask:
75
+ WorkflowTaskV2 for which the backend configuration should
76
+ be prepared.
77
+ config_path:
78
+ Path of local-backend configuration file; if `None`, use
79
+ `FRACTAL_LOCAL_CONFIG_FILE` variable from settings.
80
+
81
+ Returns:
82
+ A local-backend configuration object
83
+ """
84
+
85
+ key = "parallel_tasks_per_job"
86
+ default_value = None
87
+
88
+ if which_type == "non_parallel":
89
+ wftask_meta = wftask.meta_non_parallel
90
+ elif which_type == "parallel":
91
+ wftask_meta = wftask.meta_parallel
92
+ else:
93
+ raise ValueError(
94
+ "`get_local_backend_config` received an invalid argument"
95
+ f" {which_type=}."
96
+ )
97
+
98
+ if wftask_meta and key in wftask_meta:
99
+ parallel_tasks_per_job = wftask.meta[key]
100
+ else:
101
+ if not config_path:
102
+ settings = Inject(get_settings)
103
+ config_path = settings.FRACTAL_LOCAL_CONFIG_FILE
104
+ if config_path is None:
105
+ parallel_tasks_per_job = default_value
106
+ else:
107
+ with config_path.open("r") as f:
108
+ env = json.load(f)
109
+ try:
110
+ _ = LocalBackendConfig(**env)
111
+ except ValidationError as e:
112
+ raise LocalBackendConfigError(
113
+ f"Error while loading {config_path=}. "
114
+ f"Original error:\n{str(e)}"
115
+ )
116
+
117
+ parallel_tasks_per_job = env.get(key, default_value)
118
+ return LocalBackendConfig(parallel_tasks_per_job=parallel_tasks_per_job)
@@ -0,0 +1,52 @@
1
+ # Copyright 2022 (C) Friedrich Miescher Institute for Biomedical Research and
2
+ # University of Zurich
3
+ #
4
+ # Original authors:
5
+ # Tommaso Comparin <tommaso.comparin@exact-lab.it>
6
+ #
7
+ # This file is part of Fractal and was originally developed by eXact lab S.r.l.
8
+ # <exact-lab.it> under contract with Liberali Lab from the Friedrich Miescher
9
+ # Institute for Biomedical Research and Pelkmans Lab from the University of
10
+ # Zurich.
11
+ """
12
+ Submodule to define _local_submit_setup
13
+ """
14
+ from pathlib import Path
15
+ from typing import Literal
16
+ from typing import Optional
17
+
18
+ from ....models.v2 import WorkflowTaskV2
19
+ from ._local_config import get_local_backend_config
20
+
21
+
22
+ def _local_submit_setup(
23
+ *,
24
+ wftask: WorkflowTaskV2,
25
+ workflow_dir: Optional[Path] = None,
26
+ workflow_dir_user: Optional[Path] = None,
27
+ which_type: Literal["non_parallel", "parallel"],
28
+ ) -> dict[str, object]:
29
+ """
30
+ Collect WorfklowTask-specific configuration parameters from different
31
+ sources, and inject them for execution.
32
+
33
+ Arguments:
34
+ wftask:
35
+ WorkflowTask for which the configuration is to be assembled
36
+ workflow_dir:
37
+ Not used in this function.
38
+ workflow_dir_user:
39
+ Not used in this function.
40
+
41
+ Returns:
42
+ submit_setup_dict:
43
+ A dictionary that will be passed on to
44
+ `FractalThreadPoolExecutor.submit` and
45
+ `FractalThreadPoolExecutor.map`, so as to set extra options.
46
+ """
47
+
48
+ local_backend_config = get_local_backend_config(
49
+ wftask=wftask, which_type=which_type
50
+ )
51
+
52
+ return dict(local_backend_config=local_backend_config)
@@ -0,0 +1,157 @@
1
+ # Copyright 2022 (C) Friedrich Miescher Institute for Biomedical Research and
2
+ # University of Zurich
3
+ #
4
+ # Original authors:
5
+ # Jacopo Nespolo <jacopo.nespolo@exact-lab.it>
6
+ # Tommaso Comparin <tommaso.comparin@exact-lab.it>
7
+ # Marco Franzon <marco.franzon@exact-lab.it>
8
+ #
9
+ # This file is part of Fractal and was originally developed by eXact lab S.r.l.
10
+ # <exact-lab.it> under contract with Liberali Lab from the Friedrich Miescher
11
+ # Institute for Biomedical Research and Pelkmans Lab from the University of
12
+ # Zurich.
13
+ """
14
+ Slurm Bakend
15
+
16
+ This backend runs fractal workflows in a SLURM cluster using Clusterfutures
17
+ Executor objects.
18
+ """
19
+ from pathlib import Path
20
+ from typing import Any
21
+ from typing import Optional
22
+ from typing import Union
23
+
24
+ from fractal_server.app.models.v2 import WorkflowV2
25
+
26
+ # from ...executors.slurm.executor import FractalSlurmExecutor
27
+ # from ._submit_setup import _slurm_submit_setup
28
+ # from .get_slurm_config import get_slurm_config
29
+
30
+ # from .._common import execute_tasks
31
+ # from ..common import async_wrap
32
+ # from ..common import set_start_and_last_task_index
33
+ # from ..common import TaskParameters
34
+
35
+
36
+ def _process_workflow(
37
+ *,
38
+ workflow: WorkflowV2,
39
+ input_paths: list[Path],
40
+ output_path: Path,
41
+ input_metadata: dict[str, Any],
42
+ input_history: list[dict[str, Any]],
43
+ logger_name: str,
44
+ workflow_dir: Path,
45
+ workflow_dir_user: Path,
46
+ first_task_index: int,
47
+ last_task_index: int,
48
+ slurm_user: Optional[str] = None,
49
+ slurm_account: Optional[str] = None,
50
+ user_cache_dir: str,
51
+ worker_init: Optional[Union[str, list[str]]] = None,
52
+ ) -> dict[str, Any]:
53
+ """
54
+ Internal processing routine for the SLURM backend
55
+
56
+ This function initialises the a FractalSlurmExecutor, setting logging,
57
+ workflow working dir and user to impersonate. It then schedules the
58
+ workflow tasks and returns the output dataset metadata.
59
+
60
+ Cf. [process_workflow][fractal_server.app.runner._local.process_workflow]
61
+
62
+ Returns:
63
+ output_dataset_metadata: Metadata of the output dataset
64
+ """
65
+
66
+ raise NotImplementedError
67
+
68
+ # if not slurm_user:
69
+ # raise RuntimeError(
70
+ # "slurm_user argument is required, for slurm backend"
71
+ # )
72
+
73
+ # if isinstance(worker_init, str):
74
+ # worker_init = worker_init.split("\n")
75
+
76
+ # with FractalSlurmExecutor(
77
+ # debug=True,
78
+ # keep_logs=True,
79
+ # slurm_user=slurm_user,
80
+ # user_cache_dir=user_cache_dir,
81
+ # working_dir=workflow_dir,
82
+ # working_dir_user=workflow_dir_user,
83
+ # common_script_lines=worker_init,
84
+ # slurm_account=slurm_account,
85
+ # ) as executor:
86
+ # output_task_pars = execute_tasks(
87
+ # executor=executor,
88
+ # task_list=workflow.task_list[
89
+ # first_task_index : (last_task_index + 1) # noqa
90
+ # ], # noqa
91
+ # task_pars=TaskParameters(
92
+ # input_paths=input_paths,
93
+ # output_path=output_path,
94
+ # metadata=input_metadata,
95
+ # history=input_history,
96
+ # ),
97
+ # workflow_dir=workflow_dir,
98
+ # workflow_dir_user=workflow_dir_user,
99
+ # submit_setup_call=_slurm_submit_setup,
100
+ # logger_name=logger_name,
101
+ # )
102
+ # output_dataset_metadata_history = dict(
103
+ # metadata=output_task_pars.metadata, history=output_task_pars.history
104
+ # )
105
+ # return output_dataset_metadata_history
106
+
107
+
108
+ async def process_workflow(
109
+ *,
110
+ workflow: WorkflowV2,
111
+ input_paths: list[Path],
112
+ output_path: Path,
113
+ input_metadata: dict[str, Any],
114
+ input_history: list[dict[str, Any]],
115
+ logger_name: str,
116
+ workflow_dir: Path,
117
+ workflow_dir_user: Optional[Path] = None,
118
+ user_cache_dir: Optional[str] = None,
119
+ slurm_user: Optional[str] = None,
120
+ slurm_account: Optional[str] = None,
121
+ worker_init: Optional[str] = None,
122
+ first_task_index: Optional[int] = None,
123
+ last_task_index: Optional[int] = None,
124
+ ) -> dict[str, Any]:
125
+ """
126
+ Process workflow (SLURM backend public interface)
127
+
128
+ Cf. [process_workflow][fractal_server.app.runner._local.process_workflow]
129
+ """
130
+
131
+ raise NotImplementedError
132
+
133
+ # # Set values of first_task_index and last_task_index
134
+ # num_tasks = len(workflow.task_list)
135
+ # first_task_index, last_task_index = set_start_and_last_task_index(
136
+ # num_tasks,
137
+ # first_task_index=first_task_index,
138
+ # last_task_index=last_task_index,
139
+ # )
140
+
141
+ # output_dataset_metadata_history = await async_wrap(_process_workflow)(
142
+ # workflow=workflow,
143
+ # input_paths=input_paths,
144
+ # output_path=output_path,
145
+ # input_metadata=input_metadata,
146
+ # input_history=input_history,
147
+ # logger_name=logger_name,
148
+ # workflow_dir=workflow_dir,
149
+ # workflow_dir_user=workflow_dir_user,
150
+ # slurm_user=slurm_user,
151
+ # slurm_account=slurm_account,
152
+ # user_cache_dir=user_cache_dir,
153
+ # worker_init=worker_init,
154
+ # first_task_index=first_task_index,
155
+ # last_task_index=last_task_index,
156
+ # )
157
+ # return output_dataset_metadata_history
@@ -0,0 +1,83 @@
1
+ # Copyright 2022 (C) Friedrich Miescher Institute for Biomedical Research and
2
+ # University of Zurich
3
+ #
4
+ # Original authors:
5
+ # Jacopo Nespolo <jacopo.nespolo@exact-lab.it>
6
+ # Tommaso Comparin <tommaso.comparin@exact-lab.it>
7
+ #
8
+ # This file is part of Fractal and was originally developed by eXact lab S.r.l.
9
+ # <exact-lab.it> under contract with Liberali Lab from the Friedrich Miescher
10
+ # Institute for Biomedical Research and Pelkmans Lab from the University of
11
+ # Zurich.
12
+ """
13
+ Submodule to define _slurm_submit_setup, which is also the reference
14
+ implementation of `submit_setup_call` in
15
+ [fractal_server.app.runner._common][]).
16
+ """
17
+ from pathlib import Path
18
+ from typing import Literal
19
+
20
+ from ...task_files import get_task_file_paths
21
+ from .get_slurm_config import get_slurm_config
22
+ from fractal_server.app.models.v2 import WorkflowTaskV2
23
+
24
+
25
+ def _slurm_submit_setup(
26
+ *,
27
+ wftask: WorkflowTaskV2,
28
+ workflow_dir: Path,
29
+ workflow_dir_user: Path,
30
+ which_type: Literal["non_parallel", "parallel"],
31
+ ) -> dict[str, object]:
32
+ """
33
+ Collect WorfklowTask-specific configuration parameters from different
34
+ sources, and inject them for execution.
35
+
36
+ Here goes all the logic for reading attributes from the appropriate sources
37
+ and transforming them into an appropriate `SlurmConfig` object (encoding
38
+ SLURM configuration) and `TaskFiles` object (with details e.g. about file
39
+ paths or filename prefixes).
40
+
41
+ For now, this is the reference implementation for the argument
42
+ `submit_setup_call` of
43
+ [fractal_server.app.runner._common.execute_tasks][].
44
+
45
+ Arguments:
46
+ wftask:
47
+ WorkflowTask for which the configuration is to be assembled
48
+ workflow_dir:
49
+ Server-owned directory to store all task-execution-related relevant
50
+ files (inputs, outputs, errors, and all meta files related to the
51
+ job execution). Note: users cannot write directly to this folder.
52
+ workflow_dir_user:
53
+ User-side directory with the same scope as `workflow_dir`, and
54
+ where a user can write.
55
+
56
+ Returns:
57
+ submit_setup_dict:
58
+ A dictionary that will be passed on to
59
+ `FractalSlurmExecutor.submit` and `FractalSlurmExecutor.map`, so
60
+ as to set extra options.
61
+ """
62
+
63
+ # Get SlurmConfig object
64
+ slurm_config = get_slurm_config(
65
+ wftask=wftask,
66
+ workflow_dir=workflow_dir,
67
+ workflow_dir_user=workflow_dir_user,
68
+ which_type=which_type,
69
+ )
70
+
71
+ # Get TaskFiles object
72
+ task_files = get_task_file_paths(
73
+ workflow_dir=workflow_dir,
74
+ workflow_dir_user=workflow_dir_user,
75
+ task_order=wftask.order,
76
+ )
77
+
78
+ # Prepare and return output dictionary
79
+ submit_setup_dict = dict(
80
+ slurm_config=slurm_config,
81
+ task_files=task_files,
82
+ )
83
+ return submit_setup_dict