fractal-server 2.13.1__py3-none-any.whl → 2.14.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.
- fractal_server/__init__.py +1 -1
- fractal_server/__main__.py +3 -1
- fractal_server/app/models/linkusergroup.py +6 -2
- fractal_server/app/models/v2/__init__.py +7 -1
- fractal_server/app/models/v2/dataset.py +1 -11
- fractal_server/app/models/v2/history.py +78 -0
- fractal_server/app/models/v2/job.py +10 -3
- fractal_server/app/models/v2/task_group.py +2 -2
- fractal_server/app/models/v2/workflow.py +1 -1
- fractal_server/app/models/v2/workflowtask.py +1 -1
- fractal_server/app/routes/admin/v2/accounting.py +18 -28
- fractal_server/app/routes/admin/v2/task.py +1 -1
- fractal_server/app/routes/admin/v2/task_group.py +0 -17
- fractal_server/app/routes/api/__init__.py +1 -1
- fractal_server/app/routes/api/v2/__init__.py +8 -2
- fractal_server/app/routes/api/v2/_aux_functions.py +66 -0
- fractal_server/app/routes/api/v2/_aux_functions_history.py +166 -0
- fractal_server/app/routes/api/v2/dataset.py +0 -17
- fractal_server/app/routes/api/v2/history.py +544 -0
- fractal_server/app/routes/api/v2/images.py +31 -43
- fractal_server/app/routes/api/v2/job.py +30 -0
- fractal_server/app/routes/api/v2/project.py +1 -53
- fractal_server/app/routes/api/v2/{status.py → status_legacy.py} +6 -6
- fractal_server/app/routes/api/v2/submit.py +16 -14
- fractal_server/app/routes/api/v2/task.py +3 -10
- fractal_server/app/routes/api/v2/task_collection_custom.py +4 -9
- fractal_server/app/routes/api/v2/task_group.py +0 -17
- fractal_server/app/routes/api/v2/verify_image_types.py +61 -0
- fractal_server/app/routes/api/v2/workflow.py +28 -69
- fractal_server/app/routes/api/v2/workflowtask.py +53 -50
- fractal_server/app/routes/auth/group.py +0 -16
- fractal_server/app/routes/auth/oauth.py +5 -3
- fractal_server/app/routes/pagination.py +47 -0
- fractal_server/app/runner/components.py +0 -3
- fractal_server/app/runner/compress_folder.py +57 -29
- fractal_server/app/runner/exceptions.py +4 -0
- fractal_server/app/runner/executors/base_runner.py +157 -0
- fractal_server/app/runner/{v2/_local/_local_config.py → executors/local/get_local_config.py} +7 -9
- fractal_server/app/runner/executors/local/runner.py +248 -0
- fractal_server/app/runner/executors/{slurm → slurm_common}/_batching.py +1 -1
- fractal_server/app/runner/executors/{slurm → slurm_common}/_slurm_config.py +9 -7
- fractal_server/app/runner/executors/slurm_common/base_slurm_runner.py +868 -0
- fractal_server/app/runner/{v2/_slurm_common → executors/slurm_common}/get_slurm_config.py +48 -17
- fractal_server/app/runner/executors/{slurm → slurm_common}/remote.py +36 -47
- fractal_server/app/runner/executors/slurm_common/slurm_job_task_models.py +134 -0
- fractal_server/app/runner/executors/slurm_ssh/runner.py +268 -0
- fractal_server/app/runner/executors/slurm_sudo/__init__.py +0 -0
- fractal_server/app/runner/executors/{slurm/sudo → slurm_sudo}/_subprocess_run_as_user.py +2 -83
- fractal_server/app/runner/executors/slurm_sudo/runner.py +193 -0
- fractal_server/app/runner/extract_archive.py +1 -3
- fractal_server/app/runner/task_files.py +134 -87
- fractal_server/app/runner/v2/__init__.py +0 -399
- fractal_server/app/runner/v2/_local.py +88 -0
- fractal_server/app/runner/v2/{_slurm_ssh/__init__.py → _slurm_ssh.py} +20 -19
- fractal_server/app/runner/v2/{_slurm_sudo/__init__.py → _slurm_sudo.py} +17 -15
- fractal_server/app/runner/v2/db_tools.py +119 -0
- fractal_server/app/runner/v2/runner.py +206 -95
- fractal_server/app/runner/v2/runner_functions.py +488 -187
- fractal_server/app/runner/v2/runner_functions_low_level.py +40 -43
- fractal_server/app/runner/v2/submit_workflow.py +358 -0
- fractal_server/app/runner/v2/task_interface.py +31 -0
- fractal_server/app/schemas/_validators.py +13 -24
- fractal_server/app/schemas/user.py +10 -7
- fractal_server/app/schemas/user_settings.py +9 -21
- fractal_server/app/schemas/v2/__init__.py +9 -1
- fractal_server/app/schemas/v2/dataset.py +12 -94
- fractal_server/app/schemas/v2/dumps.py +26 -9
- fractal_server/app/schemas/v2/history.py +80 -0
- fractal_server/app/schemas/v2/job.py +15 -8
- fractal_server/app/schemas/v2/manifest.py +14 -7
- fractal_server/app/schemas/v2/project.py +9 -7
- fractal_server/app/schemas/v2/status_legacy.py +35 -0
- fractal_server/app/schemas/v2/task.py +72 -77
- fractal_server/app/schemas/v2/task_collection.py +14 -32
- fractal_server/app/schemas/v2/task_group.py +10 -9
- fractal_server/app/schemas/v2/workflow.py +10 -11
- fractal_server/app/schemas/v2/workflowtask.py +2 -21
- fractal_server/app/security/__init__.py +3 -3
- fractal_server/app/security/signup_email.py +2 -2
- fractal_server/config.py +41 -46
- fractal_server/images/tools.py +23 -0
- fractal_server/migrations/versions/47351f8c7ebc_drop_dataset_filters.py +50 -0
- fractal_server/migrations/versions/9db60297b8b2_set_ondelete.py +250 -0
- fractal_server/migrations/versions/c90a7c76e996_job_id_in_history_run.py +41 -0
- fractal_server/migrations/versions/e81103413827_add_job_type_filters.py +36 -0
- fractal_server/migrations/versions/f37aceb45062_make_historyunit_logfile_required.py +39 -0
- fractal_server/migrations/versions/fbce16ff4e47_new_history_items.py +120 -0
- fractal_server/ssh/_fabric.py +28 -14
- fractal_server/tasks/v2/local/collect.py +2 -2
- fractal_server/tasks/v2/ssh/collect.py +2 -2
- fractal_server/tasks/v2/templates/2_pip_install.sh +1 -1
- fractal_server/tasks/v2/templates/4_pip_show.sh +1 -1
- fractal_server/tasks/v2/utils_background.py +0 -19
- fractal_server/tasks/v2/utils_database.py +30 -17
- fractal_server/tasks/v2/utils_templates.py +6 -0
- {fractal_server-2.13.1.dist-info → fractal_server-2.14.0.dist-info}/METADATA +4 -4
- {fractal_server-2.13.1.dist-info → fractal_server-2.14.0.dist-info}/RECORD +106 -96
- {fractal_server-2.13.1.dist-info → fractal_server-2.14.0.dist-info}/WHEEL +1 -1
- fractal_server/app/runner/executors/slurm/ssh/_executor_wait_thread.py +0 -126
- fractal_server/app/runner/executors/slurm/ssh/_slurm_job.py +0 -116
- fractal_server/app/runner/executors/slurm/ssh/executor.py +0 -1386
- fractal_server/app/runner/executors/slurm/sudo/_check_jobs_status.py +0 -71
- fractal_server/app/runner/executors/slurm/sudo/_executor_wait_thread.py +0 -130
- fractal_server/app/runner/executors/slurm/sudo/executor.py +0 -1281
- fractal_server/app/runner/v2/_local/__init__.py +0 -132
- fractal_server/app/runner/v2/_local/_submit_setup.py +0 -52
- fractal_server/app/runner/v2/_local/executor.py +0 -100
- fractal_server/app/runner/v2/_slurm_ssh/_submit_setup.py +0 -83
- fractal_server/app/runner/v2/_slurm_sudo/_submit_setup.py +0 -83
- fractal_server/app/runner/v2/handle_failed_job.py +0 -59
- fractal_server/app/schemas/v2/status.py +0 -16
- /fractal_server/app/{runner/executors/slurm → history}/__init__.py +0 -0
- /fractal_server/app/runner/executors/{slurm/ssh → local}/__init__.py +0 -0
- /fractal_server/app/runner/executors/{slurm/sudo → slurm_common}/__init__.py +0 -0
- /fractal_server/app/runner/executors/{_job_states.py → slurm_common/_job_states.py} +0 -0
- /fractal_server/app/runner/executors/{slurm → slurm_common}/utils_executors.py +0 -0
- /fractal_server/app/runner/{v2/_slurm_common → executors/slurm_ssh}/__init__.py +0 -0
- {fractal_server-2.13.1.dist-info → fractal_server-2.14.0.dist-info}/LICENSE +0 -0
- {fractal_server-2.13.1.dist-info → fractal_server-2.14.0.dist-info}/entry_points.txt +0 -0
@@ -9,38 +9,64 @@ from pydantic import field_validator
|
|
9
9
|
from pydantic import HttpUrl
|
10
10
|
from pydantic import model_validator
|
11
11
|
|
12
|
+
from .._validators import cant_set_none
|
13
|
+
from fractal_server.app.schemas._validators import NonEmptyString
|
12
14
|
from fractal_server.app.schemas._validators import val_unique_list
|
13
15
|
from fractal_server.app.schemas._validators import valdict_keys
|
14
|
-
from fractal_server.
|
16
|
+
from fractal_server.logger import set_logger
|
15
17
|
from fractal_server.string_tools import validate_cmd
|
16
18
|
|
19
|
+
TaskTypeType = Literal[
|
20
|
+
"compound",
|
21
|
+
"converter_compound",
|
22
|
+
"non_parallel",
|
23
|
+
"converter_non_parallel",
|
24
|
+
"parallel",
|
25
|
+
]
|
26
|
+
|
27
|
+
|
28
|
+
logger = set_logger(__name__)
|
29
|
+
|
17
30
|
|
18
31
|
class TaskCreateV2(BaseModel):
|
19
32
|
model_config = ConfigDict(extra="forbid")
|
20
33
|
|
21
|
-
name:
|
34
|
+
name: NonEmptyString
|
22
35
|
|
23
|
-
command_non_parallel: Optional[
|
24
|
-
command_parallel: Optional[
|
36
|
+
command_non_parallel: Optional[NonEmptyString] = None
|
37
|
+
command_parallel: Optional[NonEmptyString] = None
|
25
38
|
|
26
39
|
meta_non_parallel: Optional[dict[str, Any]] = None
|
27
40
|
meta_parallel: Optional[dict[str, Any]] = None
|
28
|
-
version: Optional[
|
41
|
+
version: Optional[NonEmptyString] = None
|
29
42
|
args_schema_non_parallel: Optional[dict[str, Any]] = None
|
30
43
|
args_schema_parallel: Optional[dict[str, Any]] = None
|
31
|
-
args_schema_version: Optional[
|
44
|
+
args_schema_version: Optional[NonEmptyString] = None
|
32
45
|
docs_info: Optional[str] = None
|
33
46
|
docs_link: Optional[str] = None
|
34
47
|
|
35
48
|
input_types: dict[str, bool] = Field(default={})
|
36
49
|
output_types: dict[str, bool] = Field(default={})
|
37
50
|
|
38
|
-
category: Optional[
|
39
|
-
modality: Optional[
|
40
|
-
tags: list[
|
41
|
-
authors: Optional[
|
51
|
+
category: Optional[NonEmptyString] = None
|
52
|
+
modality: Optional[NonEmptyString] = None
|
53
|
+
tags: list[NonEmptyString] = Field(default_factory=list)
|
54
|
+
authors: Optional[NonEmptyString] = None
|
55
|
+
|
56
|
+
type: Optional[TaskTypeType] = None
|
42
57
|
|
43
58
|
# Validators
|
59
|
+
|
60
|
+
@field_validator(
|
61
|
+
"command_non_parallel",
|
62
|
+
"command_parallel",
|
63
|
+
"version",
|
64
|
+
"args_schema_version",
|
65
|
+
)
|
66
|
+
@classmethod
|
67
|
+
def _cant_set_none(cls, v):
|
68
|
+
return cant_set_none(v)
|
69
|
+
|
44
70
|
@model_validator(mode="after")
|
45
71
|
def validate_commands(self):
|
46
72
|
command_parallel = self.command_parallel
|
@@ -57,14 +83,22 @@ class TaskCreateV2(BaseModel):
|
|
57
83
|
|
58
84
|
return self
|
59
85
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
86
|
+
@model_validator(mode="after")
|
87
|
+
def set_task_type(self):
|
88
|
+
if self.type is None:
|
89
|
+
logger.warning(
|
90
|
+
f"Task type is not set for task '{self.name}', "
|
91
|
+
"which will be deprecated in a future version. "
|
92
|
+
"Please move to `fractal-task-tools`."
|
93
|
+
)
|
94
|
+
if self.command_non_parallel is None:
|
95
|
+
self.type = "parallel"
|
96
|
+
elif self.command_parallel is None:
|
97
|
+
self.type = "non_parallel"
|
98
|
+
else:
|
99
|
+
self.type = "compound"
|
100
|
+
|
101
|
+
return self
|
68
102
|
|
69
103
|
_meta_non_parallel = field_validator("meta_non_parallel")(
|
70
104
|
classmethod(valdict_keys("meta_non_parallel"))
|
@@ -78,9 +112,6 @@ class TaskCreateV2(BaseModel):
|
|
78
112
|
_args_schema_parallel = field_validator("args_schema_parallel")(
|
79
113
|
classmethod(valdict_keys("args_schema_parallel"))
|
80
114
|
)
|
81
|
-
_args_schema_version = field_validator("args_schema_version")(
|
82
|
-
classmethod(valstr("args_schema_version"))
|
83
|
-
)
|
84
115
|
_input_types = field_validator("input_types")(
|
85
116
|
classmethod(valdict_keys("input_types"))
|
86
117
|
)
|
@@ -88,21 +119,9 @@ class TaskCreateV2(BaseModel):
|
|
88
119
|
classmethod(valdict_keys("output_types"))
|
89
120
|
)
|
90
121
|
|
91
|
-
_category = field_validator("category")(
|
92
|
-
classmethod(valstr("category", accept_none=True))
|
93
|
-
)
|
94
|
-
_modality = field_validator("modality")(
|
95
|
-
classmethod(valstr("modality", accept_none=True))
|
96
|
-
)
|
97
|
-
_authors = field_validator("authors")(
|
98
|
-
classmethod(valstr("authors", accept_none=True))
|
99
|
-
)
|
100
|
-
|
101
122
|
@field_validator("tags")
|
102
123
|
@classmethod
|
103
124
|
def validate_list_of_strings(cls, value):
|
104
|
-
for i, tag in enumerate(value):
|
105
|
-
value[i] = valstr(f"tags[{i}]")(cls, tag)
|
106
125
|
return val_unique_list("tags")(cls, value)
|
107
126
|
|
108
127
|
@field_validator("docs_link", mode="after")
|
@@ -116,7 +135,7 @@ class TaskCreateV2(BaseModel):
|
|
116
135
|
class TaskReadV2(BaseModel):
|
117
136
|
id: int
|
118
137
|
name: str
|
119
|
-
type:
|
138
|
+
type: TaskTypeType
|
120
139
|
source: Optional[str] = None
|
121
140
|
version: Optional[str] = None
|
122
141
|
|
@@ -143,17 +162,23 @@ class TaskReadV2(BaseModel):
|
|
143
162
|
class TaskUpdateV2(BaseModel):
|
144
163
|
model_config = ConfigDict(extra="forbid")
|
145
164
|
|
146
|
-
command_parallel: Optional[
|
147
|
-
command_non_parallel: Optional[
|
165
|
+
command_parallel: Optional[NonEmptyString] = None
|
166
|
+
command_non_parallel: Optional[NonEmptyString] = None
|
148
167
|
input_types: Optional[dict[str, bool]] = None
|
149
168
|
output_types: Optional[dict[str, bool]] = None
|
150
169
|
|
151
|
-
category: Optional[
|
152
|
-
modality: Optional[
|
153
|
-
authors: Optional[
|
154
|
-
tags: Optional[list[
|
170
|
+
category: Optional[NonEmptyString] = None
|
171
|
+
modality: Optional[NonEmptyString] = None
|
172
|
+
authors: Optional[NonEmptyString] = None
|
173
|
+
tags: Optional[list[NonEmptyString]] = None
|
155
174
|
|
156
175
|
# Validators
|
176
|
+
|
177
|
+
@field_validator("command_parallel", "command_non_parallel")
|
178
|
+
@classmethod
|
179
|
+
def _cant_set_none(cls, v):
|
180
|
+
return cant_set_none(v)
|
181
|
+
|
157
182
|
@field_validator("input_types", "output_types")
|
158
183
|
@classmethod
|
159
184
|
def val_is_dict(cls, v):
|
@@ -161,12 +186,6 @@ class TaskUpdateV2(BaseModel):
|
|
161
186
|
raise ValueError
|
162
187
|
return v
|
163
188
|
|
164
|
-
_command_parallel = field_validator("command_parallel")(
|
165
|
-
classmethod(valstr("command_parallel"))
|
166
|
-
)
|
167
|
-
_command_non_parallel = field_validator("command_non_parallel")(
|
168
|
-
classmethod(valstr("command_non_parallel"))
|
169
|
-
)
|
170
189
|
_input_types = field_validator("input_types")(
|
171
190
|
classmethod(valdict_keys("input_types"))
|
172
191
|
)
|
@@ -174,49 +193,25 @@ class TaskUpdateV2(BaseModel):
|
|
174
193
|
classmethod(valdict_keys("output_types"))
|
175
194
|
)
|
176
195
|
|
177
|
-
_category = field_validator("category")(
|
178
|
-
classmethod(valstr("category", accept_none=True))
|
179
|
-
)
|
180
|
-
_modality = field_validator("modality")(
|
181
|
-
classmethod(valstr("modality", accept_none=True))
|
182
|
-
)
|
183
|
-
_authors = field_validator("authors")(
|
184
|
-
classmethod(valstr("authors", accept_none=True))
|
185
|
-
)
|
186
|
-
|
187
196
|
@field_validator("tags")
|
188
197
|
@classmethod
|
189
198
|
def validate_tags(cls, value):
|
190
|
-
for i, tag in enumerate(value):
|
191
|
-
value[i] = valstr(f"tags[{i}]")(cls, tag)
|
192
199
|
return val_unique_list("tags")(cls, value)
|
193
200
|
|
194
201
|
|
195
202
|
class TaskImportV2(BaseModel):
|
196
203
|
model_config = ConfigDict(extra="forbid")
|
197
204
|
|
198
|
-
pkg_name:
|
199
|
-
version: Optional[
|
200
|
-
name:
|
201
|
-
_pkg_name = field_validator("pkg_name")(classmethod(valstr("pkg_name")))
|
202
|
-
_version = field_validator("version")(
|
203
|
-
classmethod(valstr("version", accept_none=True))
|
204
|
-
)
|
205
|
-
_name = field_validator("name")(classmethod(valstr("name")))
|
205
|
+
pkg_name: NonEmptyString
|
206
|
+
version: Optional[NonEmptyString] = None
|
207
|
+
name: NonEmptyString
|
206
208
|
|
207
209
|
|
208
210
|
class TaskImportV2Legacy(BaseModel):
|
209
|
-
source:
|
210
|
-
_source = field_validator("source")(classmethod(valstr("source")))
|
211
|
+
source: NonEmptyString
|
211
212
|
|
212
213
|
|
213
214
|
class TaskExportV2(BaseModel):
|
214
|
-
pkg_name:
|
215
|
-
version: Optional[
|
216
|
-
name:
|
217
|
-
|
218
|
-
_pkg_name = field_validator("pkg_name")(classmethod(valstr("pkg_name")))
|
219
|
-
_version = field_validator("version")(
|
220
|
-
classmethod(valstr("version", accept_none=True))
|
221
|
-
)
|
222
|
-
_name = field_validator("name")(classmethod(valstr("name")))
|
215
|
+
pkg_name: NonEmptyString
|
216
|
+
version: Optional[NonEmptyString] = None
|
217
|
+
name: NonEmptyString
|
@@ -7,7 +7,7 @@ from pydantic import ConfigDict
|
|
7
7
|
from pydantic import field_validator
|
8
8
|
from pydantic import model_validator
|
9
9
|
|
10
|
-
from .._validators import
|
10
|
+
from .._validators import NonEmptyString
|
11
11
|
from fractal_server.app.schemas.v2 import ManifestV2
|
12
12
|
from fractal_server.string_tools import validate_cmd
|
13
13
|
|
@@ -46,9 +46,9 @@ class TaskCollectPipV2(BaseModel):
|
|
46
46
|
"""
|
47
47
|
|
48
48
|
model_config = ConfigDict(extra="forbid")
|
49
|
-
package: Optional[
|
50
|
-
package_version: Optional[
|
51
|
-
package_extras: Optional[
|
49
|
+
package: Optional[NonEmptyString] = None
|
50
|
+
package_version: Optional[NonEmptyString] = None
|
51
|
+
package_extras: Optional[NonEmptyString] = None
|
52
52
|
python_version: Optional[Literal["3.9", "3.10", "3.11", "3.12"]] = None
|
53
53
|
pinned_package_versions: Optional[dict[str, str]] = None
|
54
54
|
|
@@ -57,7 +57,6 @@ class TaskCollectPipV2(BaseModel):
|
|
57
57
|
def package_validator(cls, value: Optional[str]) -> Optional[str]:
|
58
58
|
if value is None:
|
59
59
|
return value
|
60
|
-
value = valstr("package")(cls, value)
|
61
60
|
validate_cmd(value, attribute_name="package")
|
62
61
|
return value
|
63
62
|
|
@@ -66,7 +65,6 @@ class TaskCollectPipV2(BaseModel):
|
|
66
65
|
def package_version_validator(cls, value: Optional[str]) -> Optional[str]:
|
67
66
|
if value is None:
|
68
67
|
return value
|
69
|
-
value = valstr("package_version")(cls, value)
|
70
68
|
validate_cmd(value, attribute_name="package_version")
|
71
69
|
return value
|
72
70
|
|
@@ -75,11 +73,11 @@ class TaskCollectPipV2(BaseModel):
|
|
75
73
|
def pinned_package_versions_validator(cls, value):
|
76
74
|
if value is None:
|
77
75
|
return value
|
76
|
+
|
78
77
|
old_keys = list(value.keys())
|
79
|
-
new_keys = [
|
80
|
-
|
81
|
-
|
82
|
-
]
|
78
|
+
new_keys = [key.strip() for key in old_keys]
|
79
|
+
if any(k == "" for k in new_keys):
|
80
|
+
raise ValueError(f"Empty string in {new_keys}.")
|
83
81
|
if len(new_keys) != len(set(new_keys)):
|
84
82
|
raise ValueError(
|
85
83
|
f"Dictionary contains multiple identical keys: {value}."
|
@@ -87,6 +85,7 @@ class TaskCollectPipV2(BaseModel):
|
|
87
85
|
for old_key, new_key in zip(old_keys, new_keys):
|
88
86
|
if new_key != old_key:
|
89
87
|
value[new_key] = value.pop(old_key)
|
88
|
+
|
90
89
|
for pkg, version in value.items():
|
91
90
|
validate_cmd(pkg)
|
92
91
|
validate_cmd(version)
|
@@ -97,7 +96,6 @@ class TaskCollectPipV2(BaseModel):
|
|
97
96
|
def package_extras_validator(cls, value: Optional[str]) -> Optional[str]:
|
98
97
|
if value is None:
|
99
98
|
return value
|
100
|
-
value = valstr("package_extras")(cls, value)
|
101
99
|
validate_cmd(value, attribute_name="package_extras")
|
102
100
|
return value
|
103
101
|
|
@@ -122,26 +120,11 @@ class TaskCollectCustomV2(BaseModel):
|
|
122
120
|
|
123
121
|
model_config = ConfigDict(extra="forbid")
|
124
122
|
manifest: ManifestV2
|
125
|
-
python_interpreter:
|
126
|
-
label:
|
127
|
-
package_root: Optional[
|
128
|
-
package_name: Optional[
|
129
|
-
version: Optional[
|
130
|
-
|
131
|
-
# Valstr
|
132
|
-
_python_interpreter = field_validator("python_interpreter")(
|
133
|
-
classmethod(valstr("python_interpreter"))
|
134
|
-
)
|
135
|
-
_label = field_validator("label")(classmethod(valstr("label")))
|
136
|
-
_package_root = field_validator("package_root")(
|
137
|
-
classmethod(valstr("package_root", accept_none=True))
|
138
|
-
)
|
139
|
-
_package_name = field_validator("package_name")(
|
140
|
-
classmethod(valstr("package_name", accept_none=True))
|
141
|
-
)
|
142
|
-
_version = field_validator("version")(
|
143
|
-
classmethod(valstr("version", accept_none=True))
|
144
|
-
)
|
123
|
+
python_interpreter: NonEmptyString
|
124
|
+
label: NonEmptyString
|
125
|
+
package_root: Optional[NonEmptyString] = None
|
126
|
+
package_name: Optional[NonEmptyString] = None
|
127
|
+
version: Optional[NonEmptyString] = None
|
145
128
|
|
146
129
|
@model_validator(mode="before")
|
147
130
|
@classmethod
|
@@ -165,7 +148,6 @@ class TaskCollectCustomV2(BaseModel):
|
|
165
148
|
"""
|
166
149
|
if value is not None:
|
167
150
|
validate_cmd(value)
|
168
|
-
value = valstr("package_name")(cls, value)
|
169
151
|
value = value.replace(" ", "")
|
170
152
|
return value
|
171
153
|
|
@@ -9,9 +9,10 @@ from pydantic import field_serializer
|
|
9
9
|
from pydantic import field_validator
|
10
10
|
from pydantic.types import AwareDatetime
|
11
11
|
|
12
|
+
from .._validators import cant_set_none
|
13
|
+
from .._validators import NonEmptyString
|
12
14
|
from .._validators import val_absolute_path
|
13
15
|
from .._validators import valdict_keys
|
14
|
-
from .._validators import valstr
|
15
16
|
from .task import TaskReadV2
|
16
17
|
|
17
18
|
|
@@ -42,15 +43,21 @@ class TaskGroupCreateV2(BaseModel):
|
|
42
43
|
origin: TaskGroupV2OriginEnum
|
43
44
|
pkg_name: str
|
44
45
|
version: Optional[str] = None
|
45
|
-
python_version: Optional[
|
46
|
+
python_version: Optional[NonEmptyString] = None
|
46
47
|
path: Optional[str] = None
|
47
48
|
venv_path: Optional[str] = None
|
48
49
|
wheel_path: Optional[str] = None
|
49
|
-
pip_extras: Optional[
|
50
|
+
pip_extras: Optional[NonEmptyString] = None
|
50
51
|
pip_freeze: Optional[str] = None
|
51
52
|
pinned_package_versions: dict[str, str] = Field(default_factory=dict)
|
52
53
|
|
53
54
|
# Validators
|
55
|
+
|
56
|
+
@field_validator("python_version", "pip_extras")
|
57
|
+
@classmethod
|
58
|
+
def _cant_set_none(cls, v):
|
59
|
+
return cant_set_none(v)
|
60
|
+
|
54
61
|
_path = field_validator("path")(classmethod(val_absolute_path("path")))
|
55
62
|
_venv_path = field_validator("venv_path")(
|
56
63
|
classmethod(val_absolute_path("venv_path"))
|
@@ -61,12 +68,6 @@ class TaskGroupCreateV2(BaseModel):
|
|
61
68
|
_pinned_package_versions = field_validator("pinned_package_versions")(
|
62
69
|
valdict_keys("pinned_package_versions")
|
63
70
|
)
|
64
|
-
_pip_extras = field_validator("pip_extras")(
|
65
|
-
classmethod(valstr("pip_extras"))
|
66
|
-
)
|
67
|
-
_python_version = field_validator("python_version")(
|
68
|
-
classmethod(valstr("python_version"))
|
69
|
-
)
|
70
71
|
|
71
72
|
|
72
73
|
class TaskGroupCreateV2Strict(TaskGroupCreateV2):
|
@@ -7,7 +7,8 @@ from pydantic import field_serializer
|
|
7
7
|
from pydantic import field_validator
|
8
8
|
from pydantic.types import AwareDatetime
|
9
9
|
|
10
|
-
from .._validators import
|
10
|
+
from .._validators import cant_set_none
|
11
|
+
from .._validators import NonEmptyString
|
11
12
|
from .project import ProjectReadV2
|
12
13
|
from .workflowtask import WorkflowTaskExportV2
|
13
14
|
from .workflowtask import WorkflowTaskImportV2
|
@@ -19,10 +20,7 @@ class WorkflowCreateV2(BaseModel):
|
|
19
20
|
|
20
21
|
model_config = ConfigDict(extra="forbid")
|
21
22
|
|
22
|
-
name:
|
23
|
-
|
24
|
-
# Validators
|
25
|
-
_name = field_validator("name")(classmethod(valstr("name")))
|
23
|
+
name: NonEmptyString
|
26
24
|
|
27
25
|
|
28
26
|
class WorkflowReadV2(BaseModel):
|
@@ -47,11 +45,15 @@ class WorkflowUpdateV2(BaseModel):
|
|
47
45
|
|
48
46
|
model_config = ConfigDict(extra="forbid")
|
49
47
|
|
50
|
-
name: Optional[
|
48
|
+
name: Optional[NonEmptyString] = None
|
51
49
|
reordered_workflowtask_ids: Optional[list[int]] = None
|
52
50
|
|
53
51
|
# Validators
|
54
|
-
|
52
|
+
|
53
|
+
@field_validator("name")
|
54
|
+
@classmethod
|
55
|
+
def _cant_set_none(cls, v):
|
56
|
+
return cant_set_none(v)
|
55
57
|
|
56
58
|
@field_validator("reordered_workflowtask_ids")
|
57
59
|
@classmethod
|
@@ -72,12 +74,9 @@ class WorkflowImportV2(BaseModel):
|
|
72
74
|
"""
|
73
75
|
|
74
76
|
model_config = ConfigDict(extra="forbid")
|
75
|
-
name:
|
77
|
+
name: NonEmptyString
|
76
78
|
task_list: list[WorkflowTaskImportV2]
|
77
79
|
|
78
|
-
# Validators
|
79
|
-
_name = field_validator("name")(classmethod(valstr("name")))
|
80
|
-
|
81
80
|
|
82
81
|
class WorkflowExportV2(BaseModel):
|
83
82
|
"""
|
@@ -1,4 +1,3 @@
|
|
1
|
-
from enum import Enum
|
2
1
|
from typing import Any
|
3
2
|
from typing import Optional
|
4
3
|
from typing import Union
|
@@ -16,29 +15,11 @@ from .task import TaskExportV2
|
|
16
15
|
from .task import TaskImportV2
|
17
16
|
from .task import TaskImportV2Legacy
|
18
17
|
from .task import TaskReadV2
|
18
|
+
from .task import TaskTypeType
|
19
19
|
|
20
20
|
RESERVED_ARGUMENTS = {"zarr_dir", "zarr_url", "zarr_urls", "init_args"}
|
21
21
|
|
22
22
|
|
23
|
-
class WorkflowTaskStatusTypeV2(str, Enum):
|
24
|
-
"""
|
25
|
-
Define the available values for the status of a `WorkflowTask`.
|
26
|
-
|
27
|
-
This model is used within the `Dataset.history` attribute, which is
|
28
|
-
constructed in the runner and then used in the API (e.g. in the
|
29
|
-
`api/v2/project/{project_id}/dataset/{dataset_id}/status` endpoint).
|
30
|
-
|
31
|
-
Attributes:
|
32
|
-
SUBMITTED: The `WorkflowTask` is part of a running job.
|
33
|
-
DONE: The most-recent execution of this `WorkflowTask` was successful.
|
34
|
-
FAILED: The most-recent execution of this `WorkflowTask` failed.
|
35
|
-
"""
|
36
|
-
|
37
|
-
SUBMITTED = "submitted"
|
38
|
-
DONE = "done"
|
39
|
-
FAILED = "failed"
|
40
|
-
|
41
|
-
|
42
23
|
class WorkflowTaskCreateV2(BaseModel):
|
43
24
|
model_config = ConfigDict(extra="forbid")
|
44
25
|
|
@@ -113,7 +94,7 @@ class WorkflowTaskReadV2(BaseModel):
|
|
113
94
|
|
114
95
|
type_filters: dict[str, bool]
|
115
96
|
|
116
|
-
task_type:
|
97
|
+
task_type: TaskTypeType
|
117
98
|
task_id: int
|
118
99
|
task: TaskReadV2
|
119
100
|
|
@@ -24,7 +24,7 @@ FastAPIUsers with Barer Token and cookie transports and register local routes.
|
|
24
24
|
Then, for each OAuth client defined in the Fractal Settings configuration, it
|
25
25
|
registers the client and the relative routes.
|
26
26
|
|
27
|
-
All routes are
|
27
|
+
All routes are registered under the `auth/` prefix.
|
28
28
|
"""
|
29
29
|
import contextlib
|
30
30
|
from typing import Any
|
@@ -296,7 +296,7 @@ async def _create_first_user(
|
|
296
296
|
Private method to create the first fractal-server user
|
297
297
|
|
298
298
|
Create a user with the given default arguments and return a message with
|
299
|
-
the relevant
|
299
|
+
the relevant information. If the user already exists, for example after a
|
300
300
|
restart, it returns a message to inform that user already exists.
|
301
301
|
|
302
302
|
**WARNING**: This function is only meant to create the first user, and then
|
@@ -312,7 +312,7 @@ async def _create_first_user(
|
|
312
312
|
email: New user's email
|
313
313
|
password: New user's password
|
314
314
|
is_superuser: `True` if the new user is a superuser
|
315
|
-
is_verified: `True` if the new user is
|
315
|
+
is_verified: `True` if the new user is verified
|
316
316
|
username:
|
317
317
|
"""
|
318
318
|
function_logger = set_logger("fractal_server.create_first_user")
|
@@ -36,8 +36,8 @@ def mail_new_oauth_signup(msg: str, email_settings: MailSettings):
|
|
36
36
|
server.ehlo()
|
37
37
|
if email_settings.use_login:
|
38
38
|
password = (
|
39
|
-
Fernet(email_settings.encryption_key)
|
40
|
-
.decrypt(email_settings.encrypted_password)
|
39
|
+
Fernet(email_settings.encryption_key.get_secret_value())
|
40
|
+
.decrypt(email_settings.encrypted_password.get_secret_value())
|
41
41
|
.decode("utf-8")
|
42
42
|
)
|
43
43
|
server.login(user=email_settings.sender, password=password)
|