fractal-server 1.4.10__py3-none-any.whl → 2.0.0a1__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.
- fractal_server/__init__.py +1 -1
- fractal_server/app/models/__init__.py +3 -7
- fractal_server/app/models/linkuserproject.py +9 -0
- fractal_server/app/models/security.py +6 -0
- fractal_server/app/models/state.py +1 -1
- fractal_server/app/models/v1/__init__.py +11 -0
- fractal_server/app/models/{dataset.py → v1/dataset.py} +5 -5
- fractal_server/app/models/{job.py → v1/job.py} +5 -5
- fractal_server/app/models/{project.py → v1/project.py} +5 -5
- fractal_server/app/models/{task.py → v1/task.py} +7 -2
- fractal_server/app/models/{workflow.py → v1/workflow.py} +5 -5
- fractal_server/app/models/v2/__init__.py +20 -0
- fractal_server/app/models/v2/dataset.py +55 -0
- fractal_server/app/models/v2/job.py +51 -0
- fractal_server/app/models/v2/project.py +31 -0
- fractal_server/app/models/v2/task.py +93 -0
- fractal_server/app/models/v2/workflow.py +43 -0
- fractal_server/app/models/v2/workflowtask.py +90 -0
- fractal_server/app/routes/{admin.py → admin/v1.py} +42 -42
- fractal_server/app/routes/admin/v2.py +274 -0
- fractal_server/app/routes/api/v1/__init__.py +7 -7
- fractal_server/app/routes/api/v1/_aux_functions.py +2 -2
- fractal_server/app/routes/api/v1/dataset.py +37 -37
- fractal_server/app/routes/api/v1/job.py +14 -14
- fractal_server/app/routes/api/v1/project.py +23 -21
- fractal_server/app/routes/api/v1/task.py +24 -14
- fractal_server/app/routes/api/v1/task_collection.py +16 -14
- fractal_server/app/routes/api/v1/workflow.py +24 -24
- fractal_server/app/routes/api/v1/workflowtask.py +10 -10
- fractal_server/app/routes/api/v2/__init__.py +28 -0
- fractal_server/app/routes/api/v2/_aux_functions.py +497 -0
- fractal_server/app/routes/api/v2/dataset.py +309 -0
- fractal_server/app/routes/api/v2/images.py +207 -0
- fractal_server/app/routes/api/v2/job.py +200 -0
- fractal_server/app/routes/api/v2/project.py +202 -0
- fractal_server/app/routes/api/v2/submit.py +220 -0
- fractal_server/app/routes/api/v2/task.py +222 -0
- fractal_server/app/routes/api/v2/task_collection.py +229 -0
- fractal_server/app/routes/api/v2/workflow.py +397 -0
- fractal_server/app/routes/api/v2/workflowtask.py +269 -0
- fractal_server/app/routes/aux/_job.py +1 -1
- fractal_server/app/runner/async_wrap.py +27 -0
- fractal_server/app/runner/components.py +5 -0
- fractal_server/app/runner/exceptions.py +129 -0
- fractal_server/app/runner/executors/slurm/__init__.py +3 -0
- fractal_server/app/runner/{_slurm → executors/slurm}/_batching.py +1 -1
- fractal_server/app/runner/{_slurm → executors/slurm}/_check_jobs_status.py +1 -1
- fractal_server/app/runner/{_slurm → executors/slurm}/_executor_wait_thread.py +1 -1
- fractal_server/app/runner/{_slurm → executors/slurm}/_slurm_config.py +3 -152
- fractal_server/app/runner/{_slurm → executors/slurm}/_subprocess_run_as_user.py +1 -1
- fractal_server/app/runner/{_slurm → executors/slurm}/executor.py +32 -19
- fractal_server/app/runner/filenames.py +6 -0
- fractal_server/app/runner/set_start_and_last_task_index.py +39 -0
- fractal_server/app/runner/task_files.py +103 -0
- fractal_server/app/runner/{__init__.py → v1/__init__.py} +22 -20
- fractal_server/app/runner/{_common.py → v1/_common.py} +13 -120
- fractal_server/app/runner/{_local → v1/_local}/__init__.py +5 -5
- fractal_server/app/runner/{_local → v1/_local}/_local_config.py +6 -7
- fractal_server/app/runner/{_local → v1/_local}/_submit_setup.py +1 -5
- fractal_server/app/runner/v1/_slurm/__init__.py +310 -0
- fractal_server/app/runner/{_slurm → v1/_slurm}/_submit_setup.py +3 -9
- fractal_server/app/runner/v1/_slurm/get_slurm_config.py +163 -0
- fractal_server/app/runner/v1/common.py +117 -0
- fractal_server/app/runner/{handle_failed_job.py → v1/handle_failed_job.py} +8 -8
- fractal_server/app/runner/v2/__init__.py +336 -0
- fractal_server/app/runner/v2/_local/__init__.py +167 -0
- fractal_server/app/runner/v2/_local/_local_config.py +118 -0
- fractal_server/app/runner/v2/_local/_submit_setup.py +52 -0
- fractal_server/app/runner/v2/_local/executor.py +100 -0
- fractal_server/app/runner/{_slurm → v2/_slurm}/__init__.py +34 -45
- fractal_server/app/runner/v2/_slurm/_submit_setup.py +83 -0
- fractal_server/app/runner/v2/_slurm/get_slurm_config.py +179 -0
- fractal_server/app/runner/v2/deduplicate_list.py +22 -0
- fractal_server/app/runner/v2/handle_failed_job.py +156 -0
- fractal_server/app/runner/v2/merge_outputs.py +38 -0
- fractal_server/app/runner/v2/runner.py +267 -0
- fractal_server/app/runner/v2/runner_functions.py +341 -0
- fractal_server/app/runner/v2/runner_functions_low_level.py +134 -0
- fractal_server/app/runner/v2/task_interface.py +43 -0
- fractal_server/app/runner/v2/v1_compat.py +21 -0
- fractal_server/app/schemas/__init__.py +4 -42
- fractal_server/app/schemas/v1/__init__.py +42 -0
- fractal_server/app/schemas/{applyworkflow.py → v1/applyworkflow.py} +18 -18
- fractal_server/app/schemas/{dataset.py → v1/dataset.py} +30 -30
- fractal_server/app/schemas/{dumps.py → v1/dumps.py} +8 -8
- fractal_server/app/schemas/{manifest.py → v1/manifest.py} +5 -5
- fractal_server/app/schemas/{project.py → v1/project.py} +9 -9
- fractal_server/app/schemas/{task.py → v1/task.py} +12 -12
- fractal_server/app/schemas/{task_collection.py → v1/task_collection.py} +7 -7
- fractal_server/app/schemas/{workflow.py → v1/workflow.py} +38 -38
- fractal_server/app/schemas/v2/__init__.py +34 -0
- fractal_server/app/schemas/v2/dataset.py +89 -0
- fractal_server/app/schemas/v2/dumps.py +87 -0
- fractal_server/app/schemas/v2/job.py +114 -0
- fractal_server/app/schemas/v2/manifest.py +159 -0
- fractal_server/app/schemas/v2/project.py +37 -0
- fractal_server/app/schemas/v2/task.py +120 -0
- fractal_server/app/schemas/v2/task_collection.py +105 -0
- fractal_server/app/schemas/v2/workflow.py +79 -0
- fractal_server/app/schemas/v2/workflowtask.py +119 -0
- fractal_server/config.py +5 -4
- fractal_server/images/__init__.py +2 -0
- fractal_server/images/models.py +50 -0
- fractal_server/images/tools.py +85 -0
- fractal_server/main.py +11 -3
- fractal_server/migrations/env.py +0 -2
- fractal_server/migrations/versions/d71e732236cd_v2.py +239 -0
- fractal_server/tasks/__init__.py +0 -5
- fractal_server/tasks/endpoint_operations.py +13 -19
- fractal_server/tasks/utils.py +35 -0
- fractal_server/tasks/{_TaskCollectPip.py → v1/_TaskCollectPip.py} +3 -3
- fractal_server/tasks/{background_operations.py → v1/background_operations.py} +18 -50
- fractal_server/tasks/v1/get_collection_data.py +14 -0
- fractal_server/tasks/v2/_TaskCollectPip.py +103 -0
- fractal_server/tasks/v2/background_operations.py +381 -0
- fractal_server/tasks/v2/get_collection_data.py +14 -0
- {fractal_server-1.4.10.dist-info → fractal_server-2.0.0a1.dist-info}/METADATA +1 -1
- fractal_server-2.0.0a1.dist-info/RECORD +160 -0
- fractal_server/app/runner/_slurm/.gitignore +0 -2
- fractal_server/app/runner/common.py +0 -311
- fractal_server-1.4.10.dist-info/RECORD +0 -98
- /fractal_server/app/runner/{_slurm → executors/slurm}/remote.py +0 -0
- /fractal_server/app/runner/{_local → v1/_local}/executor.py +0 -0
- {fractal_server-1.4.10.dist-info → fractal_server-2.0.0a1.dist-info}/LICENSE +0 -0
- {fractal_server-1.4.10.dist-info → fractal_server-2.0.0a1.dist-info}/WHEEL +0 -0
- {fractal_server-1.4.10.dist-info → fractal_server-2.0.0a1.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,134 @@
|
|
1
|
+
import json
|
2
|
+
import logging
|
3
|
+
import shutil
|
4
|
+
import subprocess # nosec
|
5
|
+
from pathlib import Path
|
6
|
+
from shlex import split as shlex_split
|
7
|
+
from typing import Any
|
8
|
+
from typing import Optional
|
9
|
+
|
10
|
+
from ..components import _COMPONENT_KEY_
|
11
|
+
from ..exceptions import JobExecutionError
|
12
|
+
from ..exceptions import TaskExecutionError
|
13
|
+
from fractal_server.app.models.v2 import WorkflowTaskV2
|
14
|
+
from fractal_server.app.runner.task_files import get_task_file_paths
|
15
|
+
|
16
|
+
|
17
|
+
def _call_command_wrapper(cmd: str, log_path: Path) -> None:
|
18
|
+
"""
|
19
|
+
Call a command and write its stdout and stderr to files
|
20
|
+
|
21
|
+
Raises:
|
22
|
+
TaskExecutionError: If the `subprocess.run` call returns a positive
|
23
|
+
exit code
|
24
|
+
JobExecutionError: If the `subprocess.run` call returns a negative
|
25
|
+
exit code (e.g. due to the subprocess receiving a
|
26
|
+
TERM or KILL signal)
|
27
|
+
"""
|
28
|
+
|
29
|
+
# Verify that task command is executable
|
30
|
+
if shutil.which(shlex_split(cmd)[0]) is None:
|
31
|
+
msg = (
|
32
|
+
f'Command "{shlex_split(cmd)[0]}" is not valid. '
|
33
|
+
"Hint: make sure that it is executable."
|
34
|
+
)
|
35
|
+
raise TaskExecutionError(msg)
|
36
|
+
|
37
|
+
fp_log = open(log_path, "w")
|
38
|
+
try:
|
39
|
+
result = subprocess.run( # nosec
|
40
|
+
shlex_split(cmd),
|
41
|
+
stderr=fp_log,
|
42
|
+
stdout=fp_log,
|
43
|
+
)
|
44
|
+
except Exception as e:
|
45
|
+
raise e
|
46
|
+
finally:
|
47
|
+
fp_log.close()
|
48
|
+
|
49
|
+
if result.returncode > 0:
|
50
|
+
with log_path.open("r") as fp_stderr:
|
51
|
+
err = fp_stderr.read()
|
52
|
+
raise TaskExecutionError(err)
|
53
|
+
elif result.returncode < 0:
|
54
|
+
raise JobExecutionError(
|
55
|
+
info=f"Task failed with returncode={result.returncode}"
|
56
|
+
)
|
57
|
+
|
58
|
+
|
59
|
+
def run_single_task(
|
60
|
+
args: dict[str, Any],
|
61
|
+
command: str,
|
62
|
+
wftask: WorkflowTaskV2,
|
63
|
+
workflow_dir: Path,
|
64
|
+
workflow_dir_user: Optional[Path] = None,
|
65
|
+
logger_name: Optional[str] = None,
|
66
|
+
is_task_v1: bool = False,
|
67
|
+
) -> dict[str, Any]:
|
68
|
+
"""
|
69
|
+
Runs within an executor.
|
70
|
+
"""
|
71
|
+
|
72
|
+
logger = logging.getLogger(logger_name)
|
73
|
+
logger.debug(f"Now start running {command=}")
|
74
|
+
|
75
|
+
if not workflow_dir_user:
|
76
|
+
workflow_dir_user = workflow_dir
|
77
|
+
|
78
|
+
component = args.pop(_COMPONENT_KEY_, None)
|
79
|
+
if component is None:
|
80
|
+
task_files = get_task_file_paths(
|
81
|
+
workflow_dir=workflow_dir,
|
82
|
+
workflow_dir_user=workflow_dir_user,
|
83
|
+
task_order=wftask.order,
|
84
|
+
)
|
85
|
+
else:
|
86
|
+
task_files = get_task_file_paths(
|
87
|
+
workflow_dir=workflow_dir,
|
88
|
+
workflow_dir_user=workflow_dir_user,
|
89
|
+
task_order=wftask.order,
|
90
|
+
component=component,
|
91
|
+
)
|
92
|
+
|
93
|
+
# Write arguments to args.json file
|
94
|
+
with task_files.args.open("w") as f:
|
95
|
+
json.dump(args, f, indent=2)
|
96
|
+
|
97
|
+
# Assemble full command
|
98
|
+
if is_task_v1:
|
99
|
+
full_command = (
|
100
|
+
f"{command} "
|
101
|
+
f"--json {task_files.args.as_posix()} "
|
102
|
+
f"--metadata-out {task_files.metadiff.as_posix()}"
|
103
|
+
)
|
104
|
+
else:
|
105
|
+
full_command = (
|
106
|
+
f"{command} "
|
107
|
+
f"--args-json {task_files.args.as_posix()} "
|
108
|
+
f"--out-json {task_files.metadiff.as_posix()}"
|
109
|
+
)
|
110
|
+
|
111
|
+
try:
|
112
|
+
_call_command_wrapper(
|
113
|
+
full_command,
|
114
|
+
log_path=task_files.log,
|
115
|
+
)
|
116
|
+
except TaskExecutionError as e:
|
117
|
+
e.workflow_task_order = wftask.order
|
118
|
+
e.workflow_task_id = wftask.id
|
119
|
+
e.task_name = wftask.task.name
|
120
|
+
raise e
|
121
|
+
|
122
|
+
try:
|
123
|
+
with task_files.metadiff.open("r") as f:
|
124
|
+
out_meta = json.load(f)
|
125
|
+
except FileNotFoundError as e:
|
126
|
+
logger.debug(
|
127
|
+
"Task did not produce output metadata. "
|
128
|
+
f"Original FileNotFoundError: {str(e)}"
|
129
|
+
)
|
130
|
+
out_meta = None
|
131
|
+
|
132
|
+
if out_meta == {}:
|
133
|
+
return None
|
134
|
+
return out_meta
|
@@ -0,0 +1,43 @@
|
|
1
|
+
from typing import Any
|
2
|
+
|
3
|
+
from pydantic import BaseModel
|
4
|
+
from pydantic import Field
|
5
|
+
|
6
|
+
from ....images import SingleImage
|
7
|
+
from fractal_server.images import Filters
|
8
|
+
|
9
|
+
|
10
|
+
class TaskOutput(BaseModel):
|
11
|
+
class Config:
|
12
|
+
extra = "forbid"
|
13
|
+
|
14
|
+
image_list_updates: list[SingleImage] = Field(default_factory=list)
|
15
|
+
image_list_removals: list[str] = Field(default_factory=list)
|
16
|
+
filters: Filters = Field(default_factory=Filters)
|
17
|
+
|
18
|
+
def check_paths_are_unique(self) -> None:
|
19
|
+
paths = [img.path for img in self.image_list_updates]
|
20
|
+
paths.extend(self.image_list_removals)
|
21
|
+
if len(paths) != len(set(paths)):
|
22
|
+
duplicates = [path for path in set(paths) if paths.count(path) > 1]
|
23
|
+
msg = (
|
24
|
+
"TaskOutput image-list updates/removals has non-unique paths:"
|
25
|
+
)
|
26
|
+
for duplicate in duplicates:
|
27
|
+
msg = f"{msg}\n{duplicate}"
|
28
|
+
raise ValueError(msg)
|
29
|
+
|
30
|
+
|
31
|
+
class InitArgsModel(BaseModel):
|
32
|
+
class Config:
|
33
|
+
extra = "forbid"
|
34
|
+
|
35
|
+
path: str
|
36
|
+
init_args: dict[str, Any] = Field(default_factory=dict)
|
37
|
+
|
38
|
+
|
39
|
+
class InitTaskOutput(BaseModel):
|
40
|
+
class Config:
|
41
|
+
extra = "forbid"
|
42
|
+
|
43
|
+
parallelization_list: list[InitArgsModel] = Field(default_factory=list)
|
@@ -0,0 +1,21 @@
|
|
1
|
+
from copy import deepcopy
|
2
|
+
from pathlib import Path
|
3
|
+
from typing import Any
|
4
|
+
|
5
|
+
|
6
|
+
def convert_v2_args_into_v1(kwargs_v2: dict[str, Any]) -> dict[str, Any]:
|
7
|
+
|
8
|
+
kwargs_v1 = deepcopy(kwargs_v2)
|
9
|
+
|
10
|
+
path = kwargs_v2.pop("path")
|
11
|
+
input_path = Path(path).parents[3].as_posix()
|
12
|
+
component = path.replace(input_path, "").lstrip("/")
|
13
|
+
|
14
|
+
kwargs_v1 = dict(
|
15
|
+
input_paths=[input_path],
|
16
|
+
output_path=input_path,
|
17
|
+
metadata={},
|
18
|
+
component=component,
|
19
|
+
)
|
20
|
+
|
21
|
+
return kwargs_v1
|
@@ -1,42 +1,4 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
from .
|
5
|
-
from .applyworkflow import ApplyWorkflowRead # noqa: F401
|
6
|
-
from .applyworkflow import ApplyWorkflowUpdate # noqa: F401
|
7
|
-
from .applyworkflow import JobStatusType # noqa: F401
|
8
|
-
from .dataset import DatasetCreate # noqa: F401
|
9
|
-
from .dataset import DatasetRead # noqa: F401
|
10
|
-
from .dataset import DatasetStatusRead # noqa: F401
|
11
|
-
from .dataset import DatasetUpdate # noqa: F401
|
12
|
-
from .dataset import ResourceCreate # noqa: F401
|
13
|
-
from .dataset import ResourceRead # noqa: F401
|
14
|
-
from .dataset import ResourceUpdate # noqa: F401
|
15
|
-
from .manifest import ManifestV1 # noqa: F401
|
16
|
-
from .manifest import TaskManifestV1 # noqa: F401
|
17
|
-
from .project import ProjectCreate # noqa: F401
|
18
|
-
from .project import ProjectRead # noqa: F401
|
19
|
-
from .project import ProjectUpdate # noqa: F401
|
20
|
-
from .state import _StateBase # noqa: F401
|
21
|
-
from .state import StateRead # noqa: F401
|
22
|
-
from .task import TaskCreate # noqa: F401
|
23
|
-
from .task import TaskImport # noqa: F401
|
24
|
-
from .task import TaskRead # noqa: F401
|
25
|
-
from .task import TaskUpdate # noqa: F401
|
26
|
-
from .task_collection import TaskCollectPip # noqa: F401
|
27
|
-
from .task_collection import TaskCollectStatus # noqa: F401
|
28
|
-
from .user import UserCreate # noqa: F401
|
29
|
-
from .user import UserRead # noqa: F401
|
30
|
-
from .user import UserUpdate # noqa: F401
|
31
|
-
from .user import UserUpdateStrict # noqa: F401
|
32
|
-
from .workflow import WorkflowCreate # noqa: F401
|
33
|
-
from .workflow import WorkflowExport # noqa: F401
|
34
|
-
from .workflow import WorkflowImport # noqa: F401
|
35
|
-
from .workflow import WorkflowRead # noqa: F401
|
36
|
-
from .workflow import WorkflowTaskCreate # noqa: F401
|
37
|
-
from .workflow import WorkflowTaskExport # noqa: F401
|
38
|
-
from .workflow import WorkflowTaskImport # noqa: F401
|
39
|
-
from .workflow import WorkflowTaskRead # noqa: F401
|
40
|
-
from .workflow import WorkflowTaskStatusType # noqa: F401
|
41
|
-
from .workflow import WorkflowTaskUpdate # noqa: F401
|
42
|
-
from .workflow import WorkflowUpdate # noqa: F401
|
1
|
+
from .state import * # noqa: F401, F403
|
2
|
+
from .user import * # noqa: F401, F403
|
3
|
+
from .v1 import * # noqa: F401, F403
|
4
|
+
from .v2 import * # noqa: F401, F403
|
@@ -0,0 +1,42 @@
|
|
1
|
+
"""
|
2
|
+
Schemas for API request/response bodies
|
3
|
+
"""
|
4
|
+
from ..state import _StateBase # noqa: F401
|
5
|
+
from ..state import StateRead # noqa: F401
|
6
|
+
from ..user import UserCreate # noqa: F401
|
7
|
+
from ..user import UserRead # noqa: F401
|
8
|
+
from ..user import UserUpdate # noqa: F401
|
9
|
+
from ..user import UserUpdateStrict # noqa: F401
|
10
|
+
from .applyworkflow import ApplyWorkflowCreateV1 # noqa: F401
|
11
|
+
from .applyworkflow import ApplyWorkflowReadV1 # noqa: F401
|
12
|
+
from .applyworkflow import ApplyWorkflowUpdateV1 # noqa: F401
|
13
|
+
from .applyworkflow import JobStatusTypeV1 # noqa: F401
|
14
|
+
from .dataset import DatasetCreateV1 # noqa: F401
|
15
|
+
from .dataset import DatasetReadV1 # noqa: F401
|
16
|
+
from .dataset import DatasetStatusReadV1 # noqa: F401
|
17
|
+
from .dataset import DatasetUpdateV1 # noqa: F401
|
18
|
+
from .dataset import ResourceCreateV1 # noqa: F401
|
19
|
+
from .dataset import ResourceReadV1 # noqa: F401
|
20
|
+
from .dataset import ResourceUpdateV1 # noqa: F401
|
21
|
+
from .manifest import ManifestV1 # noqa: F401
|
22
|
+
from .manifest import TaskManifestV1 # noqa: F401
|
23
|
+
from .project import ProjectCreateV1 # noqa: F401
|
24
|
+
from .project import ProjectReadV1 # noqa: F401
|
25
|
+
from .project import ProjectUpdateV1 # noqa: F401
|
26
|
+
from .task import TaskCreateV1 # noqa: F401
|
27
|
+
from .task import TaskImportV1 # noqa: F401
|
28
|
+
from .task import TaskReadV1 # noqa: F401
|
29
|
+
from .task import TaskUpdateV1 # noqa: F401
|
30
|
+
from .task_collection import TaskCollectPipV1 # noqa: F401
|
31
|
+
from .task_collection import TaskCollectStatusV1 # noqa: F401
|
32
|
+
from .workflow import WorkflowCreateV1 # noqa: F401
|
33
|
+
from .workflow import WorkflowExportV1 # noqa: F401
|
34
|
+
from .workflow import WorkflowImportV1 # noqa: F401
|
35
|
+
from .workflow import WorkflowReadV1 # noqa: F401
|
36
|
+
from .workflow import WorkflowTaskCreateV1 # noqa: F401
|
37
|
+
from .workflow import WorkflowTaskExportV1 # noqa: F401
|
38
|
+
from .workflow import WorkflowTaskImportV1 # noqa: F401
|
39
|
+
from .workflow import WorkflowTaskReadV1 # noqa: F401
|
40
|
+
from .workflow import WorkflowTaskStatusTypeV1 # noqa: F401
|
41
|
+
from .workflow import WorkflowTaskUpdateV1 # noqa: F401
|
42
|
+
from .workflow import WorkflowUpdateV1 # noqa: F401
|
@@ -6,21 +6,21 @@ from pydantic import BaseModel
|
|
6
6
|
from pydantic import validator
|
7
7
|
from pydantic.types import StrictStr
|
8
8
|
|
9
|
-
from
|
10
|
-
from
|
11
|
-
from .dumps import
|
12
|
-
from .dumps import
|
13
|
-
from .dumps import
|
9
|
+
from .._validators import valstr
|
10
|
+
from .._validators import valutc
|
11
|
+
from .dumps import DatasetDumpV1
|
12
|
+
from .dumps import ProjectDumpV1
|
13
|
+
from .dumps import WorkflowDumpV1
|
14
14
|
|
15
15
|
|
16
16
|
__all__ = (
|
17
|
-
"
|
18
|
-
"
|
19
|
-
"
|
17
|
+
"_ApplyWorkflowBaseV1",
|
18
|
+
"ApplyWorkflowCreateV1",
|
19
|
+
"ApplyWorkflowReadV1",
|
20
20
|
)
|
21
21
|
|
22
22
|
|
23
|
-
class
|
23
|
+
class JobStatusTypeV1(str, Enum):
|
24
24
|
"""
|
25
25
|
Define the available job statuses
|
26
26
|
|
@@ -41,7 +41,7 @@ class JobStatusType(str, Enum):
|
|
41
41
|
FAILED = "failed"
|
42
42
|
|
43
43
|
|
44
|
-
class
|
44
|
+
class _ApplyWorkflowBaseV1(BaseModel):
|
45
45
|
"""
|
46
46
|
Base class for `ApplyWorkflow`.
|
47
47
|
|
@@ -52,7 +52,7 @@ class _ApplyWorkflowBase(BaseModel):
|
|
52
52
|
worker_init: Optional[str]
|
53
53
|
|
54
54
|
|
55
|
-
class
|
55
|
+
class ApplyWorkflowCreateV1(_ApplyWorkflowBaseV1):
|
56
56
|
"""
|
57
57
|
Class for `ApplyWorkflow` creation.
|
58
58
|
|
@@ -104,7 +104,7 @@ class ApplyWorkflowCreate(_ApplyWorkflowBase):
|
|
104
104
|
return v
|
105
105
|
|
106
106
|
|
107
|
-
class
|
107
|
+
class ApplyWorkflowReadV1(_ApplyWorkflowBaseV1):
|
108
108
|
"""
|
109
109
|
Class for `ApplyWorkflow` read from database.
|
110
110
|
|
@@ -132,15 +132,15 @@ class ApplyWorkflowRead(_ApplyWorkflowBase):
|
|
132
132
|
|
133
133
|
id: int
|
134
134
|
project_id: Optional[int]
|
135
|
-
project_dump:
|
135
|
+
project_dump: ProjectDumpV1
|
136
136
|
user_email: str
|
137
137
|
slurm_account: Optional[str]
|
138
138
|
workflow_id: Optional[int]
|
139
|
-
workflow_dump:
|
139
|
+
workflow_dump: WorkflowDumpV1
|
140
140
|
input_dataset_id: Optional[int]
|
141
|
-
input_dataset_dump:
|
141
|
+
input_dataset_dump: DatasetDumpV1
|
142
142
|
output_dataset_id: Optional[int]
|
143
|
-
output_dataset_dump:
|
143
|
+
output_dataset_dump: DatasetDumpV1
|
144
144
|
start_timestamp: datetime
|
145
145
|
end_timestamp: Optional[datetime]
|
146
146
|
status: str
|
@@ -158,7 +158,7 @@ class ApplyWorkflowRead(_ApplyWorkflowBase):
|
|
158
158
|
)
|
159
159
|
|
160
160
|
|
161
|
-
class
|
161
|
+
class ApplyWorkflowUpdateV1(BaseModel):
|
162
162
|
"""
|
163
163
|
Class for updating a job status.
|
164
164
|
|
@@ -166,4 +166,4 @@ class ApplyWorkflowUpdate(BaseModel):
|
|
166
166
|
status: New job status.
|
167
167
|
"""
|
168
168
|
|
169
|
-
status:
|
169
|
+
status: JobStatusTypeV1
|
@@ -6,25 +6,25 @@ from pydantic import BaseModel
|
|
6
6
|
from pydantic import Field
|
7
7
|
from pydantic import validator
|
8
8
|
|
9
|
-
from
|
10
|
-
from
|
11
|
-
from
|
12
|
-
from .dumps import
|
13
|
-
from .project import
|
14
|
-
from .workflow import
|
9
|
+
from .._validators import val_absolute_path
|
10
|
+
from .._validators import valstr
|
11
|
+
from .._validators import valutc
|
12
|
+
from .dumps import WorkflowTaskDumpV1
|
13
|
+
from .project import ProjectReadV1
|
14
|
+
from .workflow import WorkflowTaskStatusTypeV1
|
15
15
|
|
16
16
|
__all__ = (
|
17
|
-
"
|
18
|
-
"
|
19
|
-
"
|
20
|
-
"
|
21
|
-
"
|
22
|
-
"
|
23
|
-
"
|
17
|
+
"DatasetUpdateV1",
|
18
|
+
"DatasetCreateV1",
|
19
|
+
"DatasetReadV1",
|
20
|
+
"ResourceCreateV1",
|
21
|
+
"ResourceReadV1",
|
22
|
+
"ResourceUpdateV1",
|
23
|
+
"DatasetStatusReadV1",
|
24
24
|
)
|
25
25
|
|
26
26
|
|
27
|
-
class
|
27
|
+
class _ResourceBaseV1(BaseModel):
|
28
28
|
"""
|
29
29
|
Base class for `Resource`.
|
30
30
|
|
@@ -35,7 +35,7 @@ class _ResourceBase(BaseModel):
|
|
35
35
|
path: str
|
36
36
|
|
37
37
|
|
38
|
-
class
|
38
|
+
class ResourceCreateV1(_ResourceBaseV1):
|
39
39
|
"""
|
40
40
|
Class for `Resource` creation.
|
41
41
|
"""
|
@@ -44,7 +44,7 @@ class ResourceCreate(_ResourceBase):
|
|
44
44
|
_path = validator("path", allow_reuse=True)(val_absolute_path("path"))
|
45
45
|
|
46
46
|
|
47
|
-
class
|
47
|
+
class ResourceUpdateV1(_ResourceBaseV1):
|
48
48
|
"""
|
49
49
|
Class for `Resource` update.
|
50
50
|
"""
|
@@ -53,7 +53,7 @@ class ResourceUpdate(_ResourceBase):
|
|
53
53
|
_path = validator("path", allow_reuse=True)(val_absolute_path("path"))
|
54
54
|
|
55
55
|
|
56
|
-
class
|
56
|
+
class ResourceReadV1(_ResourceBaseV1):
|
57
57
|
"""
|
58
58
|
Class for `Resource` read from database.
|
59
59
|
|
@@ -66,7 +66,7 @@ class ResourceRead(_ResourceBase):
|
|
66
66
|
dataset_id: int
|
67
67
|
|
68
68
|
|
69
|
-
class
|
69
|
+
class _DatasetHistoryItemV1(BaseModel):
|
70
70
|
"""
|
71
71
|
Class for an item of `Dataset.history`.
|
72
72
|
|
@@ -77,12 +77,12 @@ class _DatasetHistoryItem(BaseModel):
|
|
77
77
|
and `component_list`.
|
78
78
|
"""
|
79
79
|
|
80
|
-
workflowtask:
|
81
|
-
status:
|
80
|
+
workflowtask: WorkflowTaskDumpV1
|
81
|
+
status: WorkflowTaskStatusTypeV1
|
82
82
|
parallelization: Optional[dict]
|
83
83
|
|
84
84
|
|
85
|
-
class
|
85
|
+
class _DatasetBaseV1(BaseModel):
|
86
86
|
"""
|
87
87
|
Base class for `Dataset`.
|
88
88
|
|
@@ -97,11 +97,11 @@ class _DatasetBase(BaseModel):
|
|
97
97
|
name: str
|
98
98
|
type: Optional[str]
|
99
99
|
meta: dict[str, Any] = Field(default={})
|
100
|
-
history: list[
|
100
|
+
history: list[_DatasetHistoryItemV1] = Field(default=[])
|
101
101
|
read_only: bool = False
|
102
102
|
|
103
103
|
|
104
|
-
class
|
104
|
+
class DatasetUpdateV1(_DatasetBaseV1):
|
105
105
|
"""
|
106
106
|
Class for `Dataset` update.
|
107
107
|
|
@@ -114,7 +114,7 @@ class DatasetUpdate(_DatasetBase):
|
|
114
114
|
|
115
115
|
name: Optional[str]
|
116
116
|
meta: Optional[dict[str, Any]] = None
|
117
|
-
history: Optional[list[
|
117
|
+
history: Optional[list[_DatasetHistoryItemV1]] = None
|
118
118
|
read_only: Optional[bool]
|
119
119
|
|
120
120
|
# Validators
|
@@ -122,7 +122,7 @@ class DatasetUpdate(_DatasetBase):
|
|
122
122
|
_type = validator("type", allow_reuse=True)(valstr("type"))
|
123
123
|
|
124
124
|
|
125
|
-
class
|
125
|
+
class DatasetCreateV1(_DatasetBaseV1):
|
126
126
|
"""
|
127
127
|
Class for `Dataset` creation.
|
128
128
|
"""
|
@@ -132,7 +132,7 @@ class DatasetCreate(_DatasetBase):
|
|
132
132
|
_type = validator("type", allow_reuse=True)(valstr("type"))
|
133
133
|
|
134
134
|
|
135
|
-
class
|
135
|
+
class DatasetReadV1(_DatasetBaseV1):
|
136
136
|
"""
|
137
137
|
Class for `Dataset` read from database.
|
138
138
|
|
@@ -145,10 +145,10 @@ class DatasetRead(_DatasetBase):
|
|
145
145
|
"""
|
146
146
|
|
147
147
|
id: int
|
148
|
-
resource_list: list[
|
148
|
+
resource_list: list[ResourceReadV1]
|
149
149
|
project_id: int
|
150
150
|
read_only: bool
|
151
|
-
project:
|
151
|
+
project: ProjectReadV1
|
152
152
|
timestamp_created: datetime
|
153
153
|
|
154
154
|
_timestamp_created = validator("timestamp_created", allow_reuse=True)(
|
@@ -156,7 +156,7 @@ class DatasetRead(_DatasetBase):
|
|
156
156
|
)
|
157
157
|
|
158
158
|
|
159
|
-
class
|
159
|
+
class DatasetStatusReadV1(BaseModel):
|
160
160
|
"""
|
161
161
|
Response type for the
|
162
162
|
`/project/{project_id}/dataset/{dataset_id}/status/` endpoint
|
@@ -165,6 +165,6 @@ class DatasetStatusRead(BaseModel):
|
|
165
165
|
status: Optional[
|
166
166
|
dict[
|
167
167
|
int,
|
168
|
-
|
168
|
+
WorkflowTaskStatusTypeV1,
|
169
169
|
]
|
170
170
|
] = None
|
@@ -14,7 +14,7 @@ from pydantic import BaseModel
|
|
14
14
|
from pydantic import Extra
|
15
15
|
|
16
16
|
|
17
|
-
class
|
17
|
+
class ProjectDumpV1(BaseModel, extra=Extra.forbid):
|
18
18
|
|
19
19
|
id: int
|
20
20
|
name: str
|
@@ -22,7 +22,7 @@ class ProjectDump(BaseModel, extra=Extra.forbid):
|
|
22
22
|
timestamp_created: str
|
23
23
|
|
24
24
|
|
25
|
-
class
|
25
|
+
class TaskDumpV1(BaseModel):
|
26
26
|
id: int
|
27
27
|
source: str
|
28
28
|
name: str
|
@@ -33,32 +33,32 @@ class TaskDump(BaseModel):
|
|
33
33
|
version: Optional[str]
|
34
34
|
|
35
35
|
|
36
|
-
class
|
36
|
+
class WorkflowTaskDumpV1(BaseModel):
|
37
37
|
id: int
|
38
38
|
order: Optional[int]
|
39
39
|
workflow_id: int
|
40
40
|
task_id: int
|
41
|
-
task:
|
41
|
+
task: TaskDumpV1
|
42
42
|
|
43
43
|
|
44
|
-
class
|
44
|
+
class WorkflowDumpV1(BaseModel):
|
45
45
|
id: int
|
46
46
|
name: str
|
47
47
|
project_id: int
|
48
48
|
timestamp_created: str
|
49
49
|
|
50
50
|
|
51
|
-
class
|
51
|
+
class ResourceDumpV1(BaseModel):
|
52
52
|
id: int
|
53
53
|
path: str
|
54
54
|
dataset_id: int
|
55
55
|
|
56
56
|
|
57
|
-
class
|
57
|
+
class DatasetDumpV1(BaseModel):
|
58
58
|
id: int
|
59
59
|
name: str
|
60
60
|
type: Optional[str]
|
61
61
|
read_only: bool
|
62
|
-
resource_list: list[
|
62
|
+
resource_list: list[ResourceDumpV1]
|
63
63
|
project_id: int
|
64
64
|
timestamp_created: str
|
@@ -12,7 +12,7 @@ from pydantic import validator
|
|
12
12
|
__all__ = ("TaskManifestV1", "ManifestV1")
|
13
13
|
|
14
14
|
|
15
|
-
class
|
15
|
+
class _TaskManifestBaseV1(BaseModel):
|
16
16
|
"""
|
17
17
|
Base class for `TaskManifestV1`.
|
18
18
|
|
@@ -54,10 +54,10 @@ class _TaskManifestBase(BaseModel):
|
|
54
54
|
docs_link: Optional[HttpUrl]
|
55
55
|
|
56
56
|
|
57
|
-
TaskManifestType = TypeVar("TaskManifestType", bound=
|
57
|
+
TaskManifestType = TypeVar("TaskManifestType", bound=_TaskManifestBaseV1)
|
58
58
|
|
59
59
|
|
60
|
-
class
|
60
|
+
class _ManifestBaseV1(BaseModel):
|
61
61
|
"""
|
62
62
|
Base class for `ManifestV1`.
|
63
63
|
|
@@ -102,7 +102,7 @@ class _ManifestBase(BaseModel):
|
|
102
102
|
return values
|
103
103
|
|
104
104
|
|
105
|
-
class TaskManifestV1(
|
105
|
+
class TaskManifestV1(_TaskManifestBaseV1):
|
106
106
|
"""
|
107
107
|
Task manifest schema version 1.
|
108
108
|
"""
|
@@ -110,7 +110,7 @@ class TaskManifestV1(_TaskManifestBase):
|
|
110
110
|
pass
|
111
111
|
|
112
112
|
|
113
|
-
class ManifestV1(
|
113
|
+
class ManifestV1(_ManifestBaseV1):
|
114
114
|
"""
|
115
115
|
Manifest schema version 1.
|
116
116
|
|
@@ -4,18 +4,18 @@ from typing import Optional
|
|
4
4
|
from pydantic import BaseModel
|
5
5
|
from pydantic import validator
|
6
6
|
|
7
|
-
from
|
8
|
-
from
|
7
|
+
from .._validators import valstr
|
8
|
+
from .._validators import valutc
|
9
9
|
|
10
10
|
|
11
11
|
__all__ = (
|
12
|
-
"
|
13
|
-
"
|
14
|
-
"
|
12
|
+
"ProjectCreateV1",
|
13
|
+
"ProjectReadV1",
|
14
|
+
"ProjectUpdateV1",
|
15
15
|
)
|
16
16
|
|
17
17
|
|
18
|
-
class
|
18
|
+
class _ProjectBaseV1(BaseModel):
|
19
19
|
"""
|
20
20
|
Base class for `Project`.
|
21
21
|
|
@@ -28,7 +28,7 @@ class _ProjectBase(BaseModel):
|
|
28
28
|
read_only: bool = False
|
29
29
|
|
30
30
|
|
31
|
-
class
|
31
|
+
class ProjectCreateV1(_ProjectBaseV1):
|
32
32
|
"""
|
33
33
|
Class for `Project` creation.
|
34
34
|
"""
|
@@ -37,7 +37,7 @@ class ProjectCreate(_ProjectBase):
|
|
37
37
|
_name = validator("name", allow_reuse=True)(valstr("name"))
|
38
38
|
|
39
39
|
|
40
|
-
class
|
40
|
+
class ProjectReadV1(_ProjectBaseV1):
|
41
41
|
"""
|
42
42
|
Class for `Project` read from database.
|
43
43
|
|
@@ -55,7 +55,7 @@ class ProjectRead(_ProjectBase):
|
|
55
55
|
)
|
56
56
|
|
57
57
|
|
58
|
-
class
|
58
|
+
class ProjectUpdateV1(_ProjectBaseV1):
|
59
59
|
"""
|
60
60
|
Class for `Project` update.
|
61
61
|
|