fractal-server 2.14.4a0__py3-none-any.whl → 2.14.6__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/db/__init__.py +2 -2
- fractal_server/app/models/security.py +8 -8
- fractal_server/app/models/user_settings.py +8 -10
- fractal_server/app/models/v2/accounting.py +2 -3
- fractal_server/app/models/v2/dataset.py +1 -2
- fractal_server/app/models/v2/history.py +3 -4
- fractal_server/app/models/v2/job.py +10 -11
- fractal_server/app/models/v2/project.py +1 -2
- fractal_server/app/models/v2/task.py +13 -14
- fractal_server/app/models/v2/task_group.py +15 -16
- fractal_server/app/models/v2/workflow.py +1 -2
- fractal_server/app/models/v2/workflowtask.py +6 -7
- fractal_server/app/routes/admin/v2/accounting.py +3 -4
- fractal_server/app/routes/admin/v2/job.py +13 -14
- fractal_server/app/routes/admin/v2/project.py +2 -4
- fractal_server/app/routes/admin/v2/task.py +11 -13
- fractal_server/app/routes/admin/v2/task_group.py +15 -17
- fractal_server/app/routes/admin/v2/task_group_lifecycle.py +5 -8
- fractal_server/app/routes/api/v2/__init__.py +2 -0
- fractal_server/app/routes/api/v2/_aux_functions.py +7 -9
- fractal_server/app/routes/api/v2/_aux_functions_history.py +1 -1
- fractal_server/app/routes/api/v2/_aux_functions_task_lifecycle.py +1 -3
- fractal_server/app/routes/api/v2/_aux_functions_tasks.py +5 -6
- fractal_server/app/routes/api/v2/dataset.py +6 -8
- fractal_server/app/routes/api/v2/history.py +5 -8
- fractal_server/app/routes/api/v2/images.py +2 -3
- fractal_server/app/routes/api/v2/job.py +5 -6
- fractal_server/app/routes/api/v2/pre_submission_checks.py +1 -3
- fractal_server/app/routes/api/v2/project.py +2 -4
- fractal_server/app/routes/api/v2/status_legacy.py +2 -4
- fractal_server/app/routes/api/v2/submit.py +3 -4
- fractal_server/app/routes/api/v2/task.py +6 -7
- fractal_server/app/routes/api/v2/task_collection.py +11 -13
- fractal_server/app/routes/api/v2/task_collection_custom.py +4 -4
- fractal_server/app/routes/api/v2/task_group.py +6 -8
- fractal_server/app/routes/api/v2/task_group_lifecycle.py +6 -9
- fractal_server/app/routes/api/v2/task_version_update.py +270 -0
- fractal_server/app/routes/api/v2/workflow.py +5 -6
- fractal_server/app/routes/api/v2/workflow_import.py +3 -5
- fractal_server/app/routes/api/v2/workflowtask.py +2 -114
- fractal_server/app/routes/auth/current_user.py +2 -2
- fractal_server/app/routes/pagination.py +2 -3
- fractal_server/app/runner/exceptions.py +16 -22
- fractal_server/app/runner/executors/base_runner.py +19 -7
- fractal_server/app/runner/executors/call_command_wrapper.py +52 -0
- fractal_server/app/runner/executors/local/get_local_config.py +2 -3
- fractal_server/app/runner/executors/local/runner.py +52 -13
- fractal_server/app/runner/executors/slurm_common/_batching.py +2 -3
- fractal_server/app/runner/executors/slurm_common/_slurm_config.py +27 -29
- fractal_server/app/runner/executors/slurm_common/base_slurm_runner.py +95 -63
- fractal_server/app/runner/executors/slurm_common/get_slurm_config.py +2 -3
- fractal_server/app/runner/executors/slurm_common/remote.py +47 -92
- fractal_server/app/runner/executors/slurm_common/slurm_job_task_models.py +22 -22
- fractal_server/app/runner/executors/slurm_ssh/run_subprocess.py +2 -3
- fractal_server/app/runner/executors/slurm_ssh/runner.py +4 -6
- fractal_server/app/runner/executors/slurm_sudo/_subprocess_run_as_user.py +2 -6
- fractal_server/app/runner/executors/slurm_sudo/runner.py +9 -18
- fractal_server/app/runner/set_start_and_last_task_index.py +2 -5
- fractal_server/app/runner/shutdown.py +5 -11
- fractal_server/app/runner/task_files.py +3 -13
- fractal_server/app/runner/v2/_local.py +3 -4
- fractal_server/app/runner/v2/_slurm_ssh.py +5 -7
- fractal_server/app/runner/v2/_slurm_sudo.py +8 -10
- fractal_server/app/runner/v2/runner.py +4 -5
- fractal_server/app/runner/v2/runner_functions.py +20 -35
- fractal_server/app/runner/v2/submit_workflow.py +7 -10
- fractal_server/app/runner/v2/task_interface.py +2 -3
- fractal_server/app/runner/versions.py +3 -13
- fractal_server/app/schemas/user.py +2 -4
- fractal_server/app/schemas/user_group.py +1 -2
- fractal_server/app/schemas/user_settings.py +19 -21
- fractal_server/app/schemas/v2/dataset.py +2 -3
- fractal_server/app/schemas/v2/dumps.py +13 -15
- fractal_server/app/schemas/v2/history.py +6 -7
- fractal_server/app/schemas/v2/job.py +17 -18
- fractal_server/app/schemas/v2/manifest.py +12 -13
- fractal_server/app/schemas/v2/status_legacy.py +2 -2
- fractal_server/app/schemas/v2/task.py +29 -30
- fractal_server/app/schemas/v2/task_collection.py +8 -9
- fractal_server/app/schemas/v2/task_group.py +22 -23
- fractal_server/app/schemas/v2/workflow.py +1 -2
- fractal_server/app/schemas/v2/workflowtask.py +27 -29
- fractal_server/app/security/__init__.py +10 -12
- fractal_server/config.py +32 -42
- fractal_server/images/models.py +2 -4
- fractal_server/images/tools.py +4 -7
- fractal_server/logger.py +3 -5
- fractal_server/ssh/_fabric.py +41 -13
- fractal_server/string_tools.py +2 -2
- fractal_server/syringe.py +1 -1
- fractal_server/tasks/v2/local/collect.py +2 -3
- fractal_server/tasks/v2/local/deactivate.py +1 -1
- fractal_server/tasks/v2/local/reactivate.py +1 -1
- fractal_server/tasks/v2/ssh/collect.py +256 -245
- fractal_server/tasks/v2/ssh/deactivate.py +210 -187
- fractal_server/tasks/v2/ssh/reactivate.py +154 -146
- fractal_server/tasks/v2/utils_background.py +2 -3
- fractal_server/types/__init__.py +1 -2
- fractal_server/types/validators/_filter_validators.py +1 -2
- fractal_server/utils.py +4 -5
- fractal_server/zip_tools.py +1 -1
- {fractal_server-2.14.4a0.dist-info → fractal_server-2.14.6.dist-info}/METADATA +2 -9
- {fractal_server-2.14.4a0.dist-info → fractal_server-2.14.6.dist-info}/RECORD +107 -108
- fractal_server/app/history/__init__.py +0 -0
- fractal_server/app/runner/executors/slurm_common/utils_executors.py +0 -58
- fractal_server/app/runner/v2/runner_functions_low_level.py +0 -122
- {fractal_server-2.14.4a0.dist-info → fractal_server-2.14.6.dist-info}/LICENSE +0 -0
- {fractal_server-2.14.4a0.dist-info → fractal_server-2.14.6.dist-info}/WHEEL +0 -0
- {fractal_server-2.14.4a0.dist-info → fractal_server-2.14.6.dist-info}/entry_points.txt +0 -0
@@ -30,6 +30,7 @@ from fractal_server.app.schemas.v2 import TaskGroupReadV2
|
|
30
30
|
from fractal_server.app.schemas.v2 import TaskGroupV2OriginEnum
|
31
31
|
from fractal_server.config import get_settings
|
32
32
|
from fractal_server.logger import set_logger
|
33
|
+
from fractal_server.ssh._fabric import SSHConfig
|
33
34
|
from fractal_server.syringe import Inject
|
34
35
|
from fractal_server.tasks.v2.local import deactivate_local
|
35
36
|
from fractal_server.tasks.v2.local import reactivate_local
|
@@ -120,19 +121,17 @@ async def deactivate_task_group(
|
|
120
121
|
user=user, backend=settings.FRACTAL_RUNNER_BACKEND, db=db
|
121
122
|
)
|
122
123
|
# User appropriate FractalSSH object
|
123
|
-
|
124
|
+
ssh_config = SSHConfig(
|
124
125
|
user=user_settings.ssh_username,
|
125
126
|
host=user_settings.ssh_host,
|
126
127
|
key_path=user_settings.ssh_private_key_path,
|
127
128
|
)
|
128
|
-
fractal_ssh_list = request.app.state.fractal_ssh_list
|
129
|
-
fractal_ssh = fractal_ssh_list.get(**ssh_credentials)
|
130
129
|
|
131
130
|
background_tasks.add_task(
|
132
131
|
deactivate_ssh,
|
133
132
|
task_group_id=task_group.id,
|
134
133
|
task_group_activity_id=task_group_activity.id,
|
135
|
-
|
134
|
+
ssh_config=ssh_config,
|
136
135
|
tasks_base_dir=user_settings.ssh_tasks_dir,
|
137
136
|
)
|
138
137
|
else:
|
@@ -238,19 +237,17 @@ async def reactivate_task_group(
|
|
238
237
|
user=user, backend=settings.FRACTAL_RUNNER_BACKEND, db=db
|
239
238
|
)
|
240
239
|
# Use appropriate FractalSSH object
|
241
|
-
|
240
|
+
ssh_config = SSHConfig(
|
242
241
|
user=user_settings.ssh_username,
|
243
242
|
host=user_settings.ssh_host,
|
244
243
|
key_path=user_settings.ssh_private_key_path,
|
245
244
|
)
|
246
|
-
fractal_ssh_list = request.app.state.fractal_ssh_list
|
247
|
-
fractal_ssh = fractal_ssh_list.get(**ssh_credentials)
|
248
245
|
|
249
246
|
background_tasks.add_task(
|
250
247
|
reactivate_ssh,
|
251
248
|
task_group_id=task_group.id,
|
252
249
|
task_group_activity_id=task_group_activity.id,
|
253
|
-
|
250
|
+
ssh_config=ssh_config,
|
254
251
|
tasks_base_dir=user_settings.ssh_tasks_dir,
|
255
252
|
)
|
256
253
|
else:
|
@@ -16,6 +16,7 @@ from .task_collection import router as task_collection_router_v2
|
|
16
16
|
from .task_collection_custom import router as task_collection_router_v2_custom
|
17
17
|
from .task_group import router as task_group_router_v2
|
18
18
|
from .task_group_lifecycle import router as task_group_lifecycle_router_v2
|
19
|
+
from .task_version_update import router as task_version_update_router_v2
|
19
20
|
from .workflow import router as workflow_router_v2
|
20
21
|
from .workflow_import import router as workflow_import_router_v2
|
21
22
|
from .workflowtask import router as workflowtask_router_v2
|
@@ -55,6 +56,7 @@ router_api_v2.include_router(
|
|
55
56
|
)
|
56
57
|
|
57
58
|
router_api_v2.include_router(task_router_v2, prefix="/task", tags=["V2 Task"])
|
59
|
+
router_api_v2.include_router(task_version_update_router_v2, tags=["V2 Task"])
|
58
60
|
router_api_v2.include_router(
|
59
61
|
task_group_router_v2, prefix="/task-group", tags=["V2 TaskGroup"]
|
60
62
|
)
|
@@ -3,8 +3,6 @@ Auxiliary functions to get object from the database or perform simple checks
|
|
3
3
|
"""
|
4
4
|
from typing import Any
|
5
5
|
from typing import Literal
|
6
|
-
from typing import Optional
|
7
|
-
from typing import Union
|
8
6
|
|
9
7
|
from fastapi import HTTPException
|
10
8
|
from fastapi import status
|
@@ -233,7 +231,7 @@ async def _get_dataset_check_owner(
|
|
233
231
|
dataset_id: int,
|
234
232
|
user_id: int,
|
235
233
|
db: AsyncSession,
|
236
|
-
) -> dict[Literal["dataset", "project"],
|
234
|
+
) -> dict[Literal["dataset", "project"], DatasetV2 | ProjectV2]:
|
237
235
|
"""
|
238
236
|
Get a dataset and a project, after access control on the project
|
239
237
|
|
@@ -279,7 +277,7 @@ async def _get_job_check_owner(
|
|
279
277
|
job_id: int,
|
280
278
|
user_id: int,
|
281
279
|
db: AsyncSession,
|
282
|
-
) -> dict[Literal["job", "project"],
|
280
|
+
) -> dict[Literal["job", "project"], JobV2 | ProjectV2]:
|
283
281
|
"""
|
284
282
|
Get a job and a project, after access control on the project
|
285
283
|
|
@@ -331,11 +329,11 @@ async def _workflow_insert_task(
|
|
331
329
|
*,
|
332
330
|
workflow_id: int,
|
333
331
|
task_id: int,
|
334
|
-
meta_parallel:
|
335
|
-
meta_non_parallel:
|
336
|
-
args_non_parallel:
|
337
|
-
args_parallel:
|
338
|
-
type_filters:
|
332
|
+
meta_parallel: dict[str, Any] | None = None,
|
333
|
+
meta_non_parallel: dict[str, Any] | None = None,
|
334
|
+
args_non_parallel: dict[str, Any] | None = None,
|
335
|
+
args_parallel: dict[str, Any] | None = None,
|
336
|
+
type_filters: dict[str, bool] | None = None,
|
339
337
|
db: AsyncSession,
|
340
338
|
) -> WorkflowTaskV2:
|
341
339
|
"""
|
@@ -1,5 +1,3 @@
|
|
1
|
-
from typing import Optional
|
2
|
-
|
3
1
|
from fastapi import HTTPException
|
4
2
|
from fastapi import status
|
5
3
|
from httpx import AsyncClient
|
@@ -23,7 +21,7 @@ logger = set_logger(__name__)
|
|
23
21
|
|
24
22
|
async def get_package_version_from_pypi(
|
25
23
|
name: str,
|
26
|
-
version:
|
24
|
+
version: str | None = None,
|
27
25
|
) -> str:
|
28
26
|
"""
|
29
27
|
Make a GET call to PyPI JSON API and get latest *compatible* version.
|
@@ -3,7 +3,6 @@ Auxiliary functions to get task and task-group object from the database or
|
|
3
3
|
perform simple checks
|
4
4
|
"""
|
5
5
|
from typing import Any
|
6
|
-
from typing import Optional
|
7
6
|
|
8
7
|
from fastapi import HTTPException
|
9
8
|
from fastapi import status
|
@@ -191,11 +190,11 @@ async def _get_task_read_access(
|
|
191
190
|
|
192
191
|
async def _get_valid_user_group_id(
|
193
192
|
*,
|
194
|
-
user_group_id:
|
193
|
+
user_group_id: int | None = None,
|
195
194
|
private: bool,
|
196
195
|
user_id: int,
|
197
196
|
db: AsyncSession,
|
198
|
-
) ->
|
197
|
+
) -> int | None:
|
199
198
|
"""
|
200
199
|
Validate query parameters for endpoints that create some task(s).
|
201
200
|
|
@@ -257,7 +256,7 @@ async def _verify_non_duplication_user_constraint(
|
|
257
256
|
db: AsyncSession,
|
258
257
|
user_id: int,
|
259
258
|
pkg_name: str,
|
260
|
-
version:
|
259
|
+
version: str | None,
|
261
260
|
):
|
262
261
|
stm = (
|
263
262
|
select(TaskGroupV2)
|
@@ -294,9 +293,9 @@ async def _verify_non_duplication_user_constraint(
|
|
294
293
|
|
295
294
|
async def _verify_non_duplication_group_constraint(
|
296
295
|
db: AsyncSession,
|
297
|
-
user_group_id:
|
296
|
+
user_group_id: int | None,
|
298
297
|
pkg_name: str,
|
299
|
-
version:
|
298
|
+
version: str | None,
|
300
299
|
):
|
301
300
|
if user_group_id is None:
|
302
301
|
return
|
@@ -1,5 +1,3 @@
|
|
1
|
-
from typing import Optional
|
2
|
-
|
3
1
|
from fastapi import APIRouter
|
4
2
|
from fastapi import Depends
|
5
3
|
from fastapi import HTTPException
|
@@ -38,7 +36,7 @@ async def create_dataset(
|
|
38
36
|
dataset: DatasetCreateV2,
|
39
37
|
user: UserOAuth = Depends(current_active_user),
|
40
38
|
db: AsyncSession = Depends(get_async_db),
|
41
|
-
) ->
|
39
|
+
) -> DatasetReadV2 | None:
|
42
40
|
"""
|
43
41
|
Add new dataset to current project
|
44
42
|
"""
|
@@ -92,7 +90,7 @@ async def read_dataset_list(
|
|
92
90
|
project_id: int,
|
93
91
|
user: UserOAuth = Depends(current_active_user),
|
94
92
|
db: AsyncSession = Depends(get_async_db),
|
95
|
-
) ->
|
93
|
+
) -> list[DatasetReadV2] | None:
|
96
94
|
"""
|
97
95
|
Get dataset list for given project
|
98
96
|
"""
|
@@ -120,7 +118,7 @@ async def read_dataset(
|
|
120
118
|
dataset_id: int,
|
121
119
|
user: UserOAuth = Depends(current_active_user),
|
122
120
|
db: AsyncSession = Depends(get_async_db),
|
123
|
-
) ->
|
121
|
+
) -> DatasetReadV2 | None:
|
124
122
|
"""
|
125
123
|
Get info on a dataset associated to the current project
|
126
124
|
"""
|
@@ -145,7 +143,7 @@ async def update_dataset(
|
|
145
143
|
dataset_update: DatasetUpdateV2,
|
146
144
|
user: UserOAuth = Depends(current_active_user),
|
147
145
|
db: AsyncSession = Depends(get_async_db),
|
148
|
-
) ->
|
146
|
+
) -> DatasetReadV2 | None:
|
149
147
|
"""
|
150
148
|
Edit a dataset associated to the current project
|
151
149
|
"""
|
@@ -247,7 +245,7 @@ async def export_dataset(
|
|
247
245
|
dataset_id: int,
|
248
246
|
user: UserOAuth = Depends(current_active_user),
|
249
247
|
db: AsyncSession = Depends(get_async_db),
|
250
|
-
) ->
|
248
|
+
) -> DatasetExportV2 | None:
|
251
249
|
"""
|
252
250
|
Export an existing dataset
|
253
251
|
"""
|
@@ -274,7 +272,7 @@ async def import_dataset(
|
|
274
272
|
dataset: DatasetImportV2,
|
275
273
|
user: UserOAuth = Depends(current_active_user),
|
276
274
|
db: AsyncSession = Depends(get_async_db),
|
277
|
-
) ->
|
275
|
+
) -> DatasetReadV2 | None:
|
278
276
|
"""
|
279
277
|
Import an existing dataset into a project
|
280
278
|
"""
|
@@ -1,6 +1,5 @@
|
|
1
1
|
from copy import deepcopy
|
2
2
|
from typing import Any
|
3
|
-
from typing import Optional
|
4
3
|
|
5
4
|
from fastapi import APIRouter
|
6
5
|
from fastapi import Depends
|
@@ -123,19 +122,17 @@ async def get_workflow_tasks_statuses(
|
|
123
122
|
.where(
|
124
123
|
HistoryImageCache.latest_history_unit_id == HistoryUnit.id
|
125
124
|
)
|
126
|
-
.where(HistoryUnit.status == target_status
|
125
|
+
.where(HistoryUnit.status == target_status)
|
127
126
|
)
|
128
127
|
res = await db.execute(stm)
|
129
128
|
num_images = res.scalar()
|
130
|
-
response[wftask.id][
|
131
|
-
f"num_{target_status.value}_images"
|
132
|
-
] = num_images
|
129
|
+
response[wftask.id][f"num_{target_status}_images"] = num_images
|
133
130
|
|
134
131
|
new_response = deepcopy(response)
|
135
132
|
for key, value in response.items():
|
136
133
|
if value is not None:
|
137
134
|
num_total_images = sum(
|
138
|
-
value[f"num_{target_status
|
135
|
+
value[f"num_{target_status}_images"]
|
139
136
|
for target_status in HistoryUnitStatus
|
140
137
|
)
|
141
138
|
if num_total_images > value["num_available_images"]:
|
@@ -213,7 +210,7 @@ async def get_history_run_units(
|
|
213
210
|
dataset_id: int,
|
214
211
|
workflowtask_id: int,
|
215
212
|
history_run_id: int,
|
216
|
-
unit_status:
|
213
|
+
unit_status: HistoryUnitStatus | None = None,
|
217
214
|
user: UserOAuth = Depends(current_active_user),
|
218
215
|
db: AsyncSession = Depends(get_async_db),
|
219
216
|
pagination: PaginationRequest = Depends(get_pagination_params),
|
@@ -274,7 +271,7 @@ async def get_history_images(
|
|
274
271
|
dataset_id: int,
|
275
272
|
workflowtask_id: int,
|
276
273
|
request_body: ImageQuery,
|
277
|
-
unit_status:
|
274
|
+
unit_status: HistoryUnitStatusQuery | None = None,
|
278
275
|
user: UserOAuth = Depends(current_active_user),
|
279
276
|
db: AsyncSession = Depends(get_async_db),
|
280
277
|
pagination: PaginationRequest = Depends(get_pagination_params),
|
@@ -1,5 +1,4 @@
|
|
1
1
|
from typing import Any
|
2
|
-
from typing import Optional
|
3
2
|
|
4
3
|
from fastapi import APIRouter
|
5
4
|
from fastapi import Depends
|
@@ -44,7 +43,7 @@ class ImageQuery(BaseModel):
|
|
44
43
|
|
45
44
|
|
46
45
|
class ImageQueryWithZarrUrl(ImageQuery):
|
47
|
-
zarr_url:
|
46
|
+
zarr_url: str | None = None
|
48
47
|
|
49
48
|
|
50
49
|
@router.post(
|
@@ -106,7 +105,7 @@ async def post_new_image(
|
|
106
105
|
async def query_dataset_images(
|
107
106
|
project_id: int,
|
108
107
|
dataset_id: int,
|
109
|
-
query:
|
108
|
+
query: ImageQueryWithZarrUrl | None = None,
|
110
109
|
pagination: PaginationRequest = Depends(get_pagination_params),
|
111
110
|
user: UserOAuth = Depends(current_active_user),
|
112
111
|
db: AsyncSession = Depends(get_async_db),
|
@@ -1,7 +1,6 @@
|
|
1
1
|
import asyncio
|
2
|
+
from collections.abc import Iterator
|
2
3
|
from pathlib import Path
|
3
|
-
from typing import Iterator
|
4
|
-
from typing import Optional
|
5
4
|
|
6
5
|
from fastapi import APIRouter
|
7
6
|
from fastapi import Depends
|
@@ -71,7 +70,7 @@ async def get_workflow_jobs(
|
|
71
70
|
workflow_id: int,
|
72
71
|
user: UserOAuth = Depends(current_active_user),
|
73
72
|
db: AsyncSession = Depends(get_async_db),
|
74
|
-
) ->
|
73
|
+
) -> list[JobReadV2] | None:
|
75
74
|
"""
|
76
75
|
Returns all the jobs related to a specific workflow
|
77
76
|
"""
|
@@ -123,7 +122,7 @@ async def read_job(
|
|
123
122
|
show_tmp_logs: bool = False,
|
124
123
|
user: UserOAuth = Depends(current_active_user),
|
125
124
|
db: AsyncSession = Depends(get_async_db),
|
126
|
-
) ->
|
125
|
+
) -> JobReadV2 | None:
|
127
126
|
"""
|
128
127
|
Return info on an existing job
|
129
128
|
"""
|
@@ -139,7 +138,7 @@ async def read_job(
|
|
139
138
|
|
140
139
|
if show_tmp_logs and (job.status == JobStatusTypeV2.SUBMITTED):
|
141
140
|
try:
|
142
|
-
with open(f"{job.working_dir}/{WORKFLOW_LOG_FILENAME}"
|
141
|
+
with open(f"{job.working_dir}/{WORKFLOW_LOG_FILENAME}") as f:
|
143
142
|
job.log = f.read()
|
144
143
|
except FileNotFoundError:
|
145
144
|
pass
|
@@ -187,7 +186,7 @@ async def get_job_list(
|
|
187
186
|
user: UserOAuth = Depends(current_active_user),
|
188
187
|
log: bool = True,
|
189
188
|
db: AsyncSession = Depends(get_async_db),
|
190
|
-
) ->
|
189
|
+
) -> list[JobReadV2] | None:
|
191
190
|
"""
|
192
191
|
Get job list for given project
|
193
192
|
"""
|
@@ -1,5 +1,3 @@
|
|
1
|
-
from typing import Optional
|
2
|
-
|
3
1
|
from fastapi import APIRouter
|
4
2
|
from fastapi import Depends
|
5
3
|
from fastapi import status
|
@@ -32,7 +30,7 @@ router = APIRouter()
|
|
32
30
|
async def verify_unique_types(
|
33
31
|
project_id: int,
|
34
32
|
dataset_id: int,
|
35
|
-
query:
|
33
|
+
query: ImageQuery | None = None,
|
36
34
|
user: UserOAuth = Depends(current_active_user),
|
37
35
|
db: AsyncSession = Depends(get_async_db),
|
38
36
|
) -> list[str]:
|
@@ -1,5 +1,3 @@
|
|
1
|
-
from typing import Optional
|
2
|
-
|
3
1
|
from fastapi import APIRouter
|
4
2
|
from fastapi import Depends
|
5
3
|
from fastapi import HTTPException
|
@@ -50,7 +48,7 @@ async def create_project(
|
|
50
48
|
project: ProjectCreateV2,
|
51
49
|
user: UserOAuth = Depends(current_active_user),
|
52
50
|
db: AsyncSession = Depends(get_async_db),
|
53
|
-
) ->
|
51
|
+
) -> ProjectReadV2 | None:
|
54
52
|
"""
|
55
53
|
Create new project
|
56
54
|
"""
|
@@ -76,7 +74,7 @@ async def read_project(
|
|
76
74
|
project_id: int,
|
77
75
|
user: UserOAuth = Depends(current_active_user),
|
78
76
|
db: AsyncSession = Depends(get_async_db),
|
79
|
-
) ->
|
77
|
+
) -> ProjectReadV2 | None:
|
80
78
|
"""
|
81
79
|
Return info on an existing project
|
82
80
|
"""
|
@@ -1,5 +1,3 @@
|
|
1
|
-
from typing import Optional
|
2
|
-
|
3
1
|
from fastapi import APIRouter
|
4
2
|
from fastapi import Depends
|
5
3
|
from fastapi import HTTPException
|
@@ -32,7 +30,7 @@ async def get_workflowtask_status(
|
|
32
30
|
workflow_id: int,
|
33
31
|
user: UserOAuth = Depends(current_active_user),
|
34
32
|
db: AsyncSession = Depends(get_async_db),
|
35
|
-
) ->
|
33
|
+
) -> LegacyStatusReadV2 | None:
|
36
34
|
"""
|
37
35
|
Extract the status of all `WorkflowTaskV2` of a given `WorkflowV2` that ran
|
38
36
|
on a given `DatasetV2`.
|
@@ -119,7 +117,7 @@ async def get_workflowtask_status(
|
|
119
117
|
except ValueError:
|
120
118
|
logger.warning(
|
121
119
|
f"Job {running_job.id} is submitted but its task list does not"
|
122
|
-
f" contain a {WorkflowTaskStatusTypeV2.SUBMITTED
|
120
|
+
f" contain a {WorkflowTaskStatusTypeV2.SUBMITTED} task."
|
123
121
|
)
|
124
122
|
first_submitted_index = 0
|
125
123
|
|
@@ -1,7 +1,6 @@
|
|
1
1
|
import json
|
2
2
|
import os
|
3
3
|
from pathlib import Path
|
4
|
-
from typing import Optional
|
5
4
|
|
6
5
|
from fastapi import APIRouter
|
7
6
|
from fastapi import BackgroundTasks
|
@@ -57,7 +56,7 @@ async def apply_workflow(
|
|
57
56
|
request: Request,
|
58
57
|
user: UserOAuth = Depends(current_active_verified_user),
|
59
58
|
db: AsyncSession = Depends(get_async_db),
|
60
|
-
) ->
|
59
|
+
) -> JobReadV2 | None:
|
61
60
|
|
62
61
|
# Remove non-submitted V2 jobs from the app state when the list grows
|
63
62
|
# beyond a threshold
|
@@ -223,13 +222,13 @@ async def apply_workflow(
|
|
223
222
|
|
224
223
|
# User appropriate FractalSSH object
|
225
224
|
if settings.FRACTAL_RUNNER_BACKEND == "slurm_ssh":
|
226
|
-
|
225
|
+
ssh_config = dict(
|
227
226
|
user=user_settings.ssh_username,
|
228
227
|
host=user_settings.ssh_host,
|
229
228
|
key_path=user_settings.ssh_private_key_path,
|
230
229
|
)
|
231
230
|
fractal_ssh_list = request.app.state.fractal_ssh_list
|
232
|
-
fractal_ssh = fractal_ssh_list.get(**
|
231
|
+
fractal_ssh = fractal_ssh_list.get(**ssh_config)
|
233
232
|
else:
|
234
233
|
fractal_ssh = None
|
235
234
|
|
@@ -1,5 +1,4 @@
|
|
1
1
|
from copy import deepcopy # noqa
|
2
|
-
from typing import Optional
|
3
2
|
|
4
3
|
from fastapi import APIRouter
|
5
4
|
from fastapi import Depends
|
@@ -37,9 +36,9 @@ logger = set_logger(__name__)
|
|
37
36
|
@router.get("/", response_model=list[TaskReadV2])
|
38
37
|
async def get_list_task(
|
39
38
|
args_schema: bool = True,
|
40
|
-
category:
|
41
|
-
modality:
|
42
|
-
author:
|
39
|
+
category: str | None = None,
|
40
|
+
modality: str | None = None,
|
41
|
+
author: str | None = None,
|
43
42
|
user: UserOAuth = Depends(current_active_user),
|
44
43
|
db: AsyncSession = Depends(get_async_db),
|
45
44
|
) -> list[TaskReadV2]:
|
@@ -98,7 +97,7 @@ async def patch_task(
|
|
98
97
|
task_update: TaskUpdateV2,
|
99
98
|
user: UserOAuth = Depends(current_active_verified_user),
|
100
99
|
db: AsyncSession = Depends(get_async_db),
|
101
|
-
) ->
|
100
|
+
) -> TaskReadV2 | None:
|
102
101
|
"""
|
103
102
|
Edit a specific task (restricted to task owner)
|
104
103
|
"""
|
@@ -135,11 +134,11 @@ async def patch_task(
|
|
135
134
|
)
|
136
135
|
async def create_task(
|
137
136
|
task: TaskCreateV2,
|
138
|
-
user_group_id:
|
137
|
+
user_group_id: int | None = None,
|
139
138
|
private: bool = False,
|
140
139
|
user: UserOAuth = Depends(current_active_verified_user),
|
141
140
|
db: AsyncSession = Depends(get_async_db),
|
142
|
-
) ->
|
141
|
+
) -> TaskReadV2 | None:
|
143
142
|
"""
|
144
143
|
Create a new task
|
145
144
|
"""
|
@@ -1,6 +1,5 @@
|
|
1
1
|
import json
|
2
2
|
from pathlib import Path
|
3
|
-
from typing import Optional
|
4
3
|
|
5
4
|
from fastapi import APIRouter
|
6
5
|
from fastapi import BackgroundTasks
|
@@ -41,6 +40,7 @@ from fractal_server.app.schemas.v2 import (
|
|
41
40
|
TaskGroupActivityActionV2,
|
42
41
|
)
|
43
42
|
from fractal_server.app.schemas.v2 import TaskGroupV2OriginEnum
|
43
|
+
from fractal_server.ssh._fabric import SSHConfig
|
44
44
|
from fractal_server.tasks.v2.local.collect import (
|
45
45
|
collect_local,
|
46
46
|
)
|
@@ -65,7 +65,7 @@ class CollectionRequestData(BaseModel):
|
|
65
65
|
"""
|
66
66
|
|
67
67
|
task_collect: TaskCollectPipV2
|
68
|
-
file:
|
68
|
+
file: UploadFile | None = None
|
69
69
|
origin: TaskGroupV2OriginEnum
|
70
70
|
|
71
71
|
@model_validator(mode="before")
|
@@ -105,12 +105,12 @@ class CollectionRequestData(BaseModel):
|
|
105
105
|
|
106
106
|
|
107
107
|
def parse_request_data(
|
108
|
-
package:
|
109
|
-
package_version:
|
110
|
-
package_extras:
|
111
|
-
python_version:
|
112
|
-
pinned_package_versions:
|
113
|
-
file:
|
108
|
+
package: str | None = Form(None),
|
109
|
+
package_version: str | None = Form(None),
|
110
|
+
package_extras: str | None = Form(None),
|
111
|
+
python_version: str | None = Form(None),
|
112
|
+
pinned_package_versions: str | None = Form(None),
|
113
|
+
file: UploadFile | None = File(None),
|
114
114
|
) -> CollectionRequestData:
|
115
115
|
"""
|
116
116
|
Expand the parsing/validation of `parse_form_data`, based on `file`.
|
@@ -156,7 +156,7 @@ async def collect_tasks_pip(
|
|
156
156
|
background_tasks: BackgroundTasks,
|
157
157
|
request_data: CollectionRequestData = Depends(parse_request_data),
|
158
158
|
private: bool = False,
|
159
|
-
user_group_id:
|
159
|
+
user_group_id: int | None = None,
|
160
160
|
user: UserOAuth = Depends(current_active_verified_user),
|
161
161
|
db: AsyncSession = Depends(get_async_db),
|
162
162
|
) -> TaskGroupActivityV2Read:
|
@@ -342,19 +342,17 @@ async def collect_tasks_pip(
|
|
342
342
|
if settings.FRACTAL_RUNNER_BACKEND == "slurm_ssh":
|
343
343
|
# SSH task collection
|
344
344
|
# Use appropriate FractalSSH object
|
345
|
-
|
345
|
+
ssh_config = SSHConfig(
|
346
346
|
user=user_settings.ssh_username,
|
347
347
|
host=user_settings.ssh_host,
|
348
348
|
key_path=user_settings.ssh_private_key_path,
|
349
349
|
)
|
350
|
-
fractal_ssh_list = request.app.state.fractal_ssh_list
|
351
|
-
fractal_ssh = fractal_ssh_list.get(**ssh_credentials)
|
352
350
|
|
353
351
|
background_tasks.add_task(
|
354
352
|
collect_ssh,
|
355
353
|
task_group_id=task_group.id,
|
356
354
|
task_group_activity_id=task_group_activity.id,
|
357
|
-
|
355
|
+
ssh_config=ssh_config,
|
358
356
|
tasks_base_dir=user_settings.ssh_tasks_dir,
|
359
357
|
wheel_file=wheel_file,
|
360
358
|
)
|
@@ -2,7 +2,6 @@ import os
|
|
2
2
|
import shlex
|
3
3
|
import subprocess # nosec
|
4
4
|
from pathlib import Path
|
5
|
-
from typing import Optional
|
6
5
|
|
7
6
|
from fastapi import APIRouter
|
8
7
|
from fastapi import Depends
|
@@ -44,7 +43,7 @@ logger = set_logger(__name__)
|
|
44
43
|
async def collect_task_custom(
|
45
44
|
task_collect: TaskCollectCustomV2,
|
46
45
|
private: bool = False,
|
47
|
-
user_group_id:
|
46
|
+
user_group_id: int | None = None,
|
48
47
|
user: UserOAuth = Depends(current_active_verified_user),
|
49
48
|
db: AsyncSession = Depends(get_async_db),
|
50
49
|
) -> list[TaskReadV2]:
|
@@ -152,6 +151,7 @@ async def collect_task_custom(
|
|
152
151
|
pkg_name=task_collect.label,
|
153
152
|
user_id=user.id,
|
154
153
|
user_group_id=user_group_id,
|
154
|
+
version=task_collect.version,
|
155
155
|
)
|
156
156
|
TaskGroupCreateV2(**task_group_attrs)
|
157
157
|
|
@@ -159,13 +159,13 @@ async def collect_task_custom(
|
|
159
159
|
await _verify_non_duplication_user_constraint(
|
160
160
|
user_id=user.id,
|
161
161
|
pkg_name=task_group_attrs["pkg_name"],
|
162
|
-
version=
|
162
|
+
version=task_group_attrs["version"],
|
163
163
|
db=db,
|
164
164
|
)
|
165
165
|
await _verify_non_duplication_group_constraint(
|
166
166
|
user_group_id=task_group_attrs["user_group_id"],
|
167
167
|
pkg_name=task_group_attrs["pkg_name"],
|
168
|
-
version=
|
168
|
+
version=task_group_attrs["version"],
|
169
169
|
db=db,
|
170
170
|
)
|
171
171
|
|
@@ -1,5 +1,3 @@
|
|
1
|
-
from typing import Optional
|
2
|
-
|
3
1
|
from fastapi import APIRouter
|
4
2
|
from fastapi import Depends
|
5
3
|
from fastapi import HTTPException
|
@@ -37,12 +35,12 @@ logger = set_logger(__name__)
|
|
37
35
|
|
38
36
|
@router.get("/activity/", response_model=list[TaskGroupActivityV2Read])
|
39
37
|
async def get_task_group_activity_list(
|
40
|
-
task_group_activity_id:
|
41
|
-
taskgroupv2_id:
|
42
|
-
pkg_name:
|
43
|
-
status:
|
44
|
-
action:
|
45
|
-
timestamp_started_min:
|
38
|
+
task_group_activity_id: int | None = None,
|
39
|
+
taskgroupv2_id: int | None = None,
|
40
|
+
pkg_name: str | None = None,
|
41
|
+
status: TaskGroupActivityStatusV2 | None = None,
|
42
|
+
action: TaskGroupActivityActionV2 | None = None,
|
43
|
+
timestamp_started_min: AwareDatetime | None = None,
|
46
44
|
user: UserOAuth = Depends(current_active_user),
|
47
45
|
db: AsyncSession = Depends(get_async_db),
|
48
46
|
) -> list[TaskGroupActivityV2Read]:
|