fractal-server 2.11.1__py3-none-any.whl → 2.12.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.
- fractal_server/__init__.py +1 -1
- fractal_server/app/models/__init__.py +0 -2
- fractal_server/app/models/linkuserproject.py +0 -9
- fractal_server/app/routes/aux/_job.py +1 -3
- fractal_server/app/runner/filenames.py +0 -2
- fractal_server/app/runner/shutdown.py +3 -27
- fractal_server/config.py +1 -15
- fractal_server/main.py +1 -12
- fractal_server/migrations/versions/1eac13a26c83_drop_v1_tables.py +67 -0
- fractal_server/string_tools.py +0 -21
- fractal_server/tasks/utils.py +0 -24
- {fractal_server-2.11.1.dist-info → fractal_server-2.12.0a0.dist-info}/METADATA +1 -1
- {fractal_server-2.11.1.dist-info → fractal_server-2.12.0a0.dist-info}/RECORD +16 -60
- fractal_server/app/models/v1/__init__.py +0 -13
- fractal_server/app/models/v1/dataset.py +0 -71
- fractal_server/app/models/v1/job.py +0 -101
- fractal_server/app/models/v1/project.py +0 -29
- fractal_server/app/models/v1/state.py +0 -34
- fractal_server/app/models/v1/task.py +0 -85
- fractal_server/app/models/v1/workflow.py +0 -133
- fractal_server/app/routes/admin/v1.py +0 -377
- fractal_server/app/routes/api/v1/__init__.py +0 -26
- fractal_server/app/routes/api/v1/_aux_functions.py +0 -478
- fractal_server/app/routes/api/v1/dataset.py +0 -554
- fractal_server/app/routes/api/v1/job.py +0 -195
- fractal_server/app/routes/api/v1/project.py +0 -475
- fractal_server/app/routes/api/v1/task.py +0 -203
- fractal_server/app/routes/api/v1/task_collection.py +0 -239
- fractal_server/app/routes/api/v1/workflow.py +0 -355
- fractal_server/app/routes/api/v1/workflowtask.py +0 -187
- fractal_server/app/runner/async_wrap_v1.py +0 -27
- fractal_server/app/runner/v1/__init__.py +0 -415
- fractal_server/app/runner/v1/_common.py +0 -620
- fractal_server/app/runner/v1/_local/__init__.py +0 -186
- fractal_server/app/runner/v1/_local/_local_config.py +0 -105
- fractal_server/app/runner/v1/_local/_submit_setup.py +0 -48
- fractal_server/app/runner/v1/_local/executor.py +0 -100
- fractal_server/app/runner/v1/_slurm/__init__.py +0 -312
- fractal_server/app/runner/v1/_slurm/_submit_setup.py +0 -81
- fractal_server/app/runner/v1/_slurm/get_slurm_config.py +0 -163
- fractal_server/app/runner/v1/common.py +0 -117
- fractal_server/app/runner/v1/handle_failed_job.py +0 -141
- fractal_server/app/schemas/v1/__init__.py +0 -37
- fractal_server/app/schemas/v1/applyworkflow.py +0 -161
- fractal_server/app/schemas/v1/dataset.py +0 -165
- fractal_server/app/schemas/v1/dumps.py +0 -64
- fractal_server/app/schemas/v1/manifest.py +0 -126
- fractal_server/app/schemas/v1/project.py +0 -66
- fractal_server/app/schemas/v1/state.py +0 -18
- fractal_server/app/schemas/v1/task.py +0 -167
- fractal_server/app/schemas/v1/task_collection.py +0 -110
- fractal_server/app/schemas/v1/workflow.py +0 -212
- fractal_server/tasks/v1/_TaskCollectPip.py +0 -103
- fractal_server/tasks/v1/__init__.py +0 -0
- fractal_server/tasks/v1/background_operations.py +0 -352
- fractal_server/tasks/v1/endpoint_operations.py +0 -156
- fractal_server/tasks/v1/get_collection_data.py +0 -14
- fractal_server/tasks/v1/utils.py +0 -67
- {fractal_server-2.11.1.dist-info → fractal_server-2.12.0a0.dist-info}/LICENSE +0 -0
- {fractal_server-2.11.1.dist-info → fractal_server-2.12.0a0.dist-info}/WHEEL +0 -0
- {fractal_server-2.11.1.dist-info → fractal_server-2.12.0a0.dist-info}/entry_points.txt +0 -0
@@ -1,203 +0,0 @@
|
|
1
|
-
from copy import deepcopy # noqa
|
2
|
-
from typing import Optional
|
3
|
-
|
4
|
-
from fastapi import APIRouter
|
5
|
-
from fastapi import Depends
|
6
|
-
from fastapi import HTTPException
|
7
|
-
from fastapi import Response
|
8
|
-
from fastapi import status
|
9
|
-
from sqlmodel import select
|
10
|
-
|
11
|
-
from .....logger import set_logger
|
12
|
-
from ....db import AsyncSession
|
13
|
-
from ....db import get_async_db
|
14
|
-
from ....models.v1 import Task
|
15
|
-
from ....models.v1 import WorkflowTask
|
16
|
-
from ....models.v2 import TaskV2
|
17
|
-
from ....schemas.v1 import TaskCreateV1
|
18
|
-
from ....schemas.v1 import TaskReadV1
|
19
|
-
from ....schemas.v1 import TaskUpdateV1
|
20
|
-
from ...aux.validate_user_settings import verify_user_has_settings
|
21
|
-
from ._aux_functions import _get_task_check_owner
|
22
|
-
from ._aux_functions import _raise_if_v1_is_read_only
|
23
|
-
from fractal_server.app.models import UserOAuth
|
24
|
-
from fractal_server.app.routes.auth import current_active_user
|
25
|
-
from fractal_server.app.routes.auth import current_active_verified_user
|
26
|
-
|
27
|
-
router = APIRouter()
|
28
|
-
|
29
|
-
logger = set_logger(__name__)
|
30
|
-
|
31
|
-
|
32
|
-
@router.get("/", response_model=list[TaskReadV1])
|
33
|
-
async def get_list_task(
|
34
|
-
user: UserOAuth = Depends(current_active_user),
|
35
|
-
args_schema: bool = True,
|
36
|
-
db: AsyncSession = Depends(get_async_db),
|
37
|
-
) -> list[TaskReadV1]:
|
38
|
-
"""
|
39
|
-
Get list of available tasks
|
40
|
-
"""
|
41
|
-
stm = select(Task)
|
42
|
-
res = await db.execute(stm)
|
43
|
-
task_list = res.scalars().all()
|
44
|
-
await db.close()
|
45
|
-
if not args_schema:
|
46
|
-
for task in task_list:
|
47
|
-
setattr(task, "args_schema", None)
|
48
|
-
|
49
|
-
return task_list
|
50
|
-
|
51
|
-
|
52
|
-
@router.get("/{task_id}/", response_model=TaskReadV1)
|
53
|
-
async def get_task(
|
54
|
-
task_id: int,
|
55
|
-
user: UserOAuth = Depends(current_active_user),
|
56
|
-
db: AsyncSession = Depends(get_async_db),
|
57
|
-
) -> TaskReadV1:
|
58
|
-
"""
|
59
|
-
Get info on a specific task
|
60
|
-
"""
|
61
|
-
task = await db.get(Task, task_id)
|
62
|
-
await db.close()
|
63
|
-
if not task:
|
64
|
-
raise HTTPException(
|
65
|
-
status_code=status.HTTP_404_NOT_FOUND, detail="Task not found"
|
66
|
-
)
|
67
|
-
return task
|
68
|
-
|
69
|
-
|
70
|
-
@router.patch("/{task_id}/", response_model=TaskReadV1)
|
71
|
-
async def patch_task(
|
72
|
-
task_id: int,
|
73
|
-
task_update: TaskUpdateV1,
|
74
|
-
user: UserOAuth = Depends(current_active_verified_user),
|
75
|
-
db: AsyncSession = Depends(get_async_db),
|
76
|
-
) -> Optional[TaskReadV1]:
|
77
|
-
"""
|
78
|
-
Edit a specific task (restricted to superusers and task owner)
|
79
|
-
"""
|
80
|
-
_raise_if_v1_is_read_only()
|
81
|
-
if task_update.source:
|
82
|
-
raise HTTPException(
|
83
|
-
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
84
|
-
detail="patch_task endpoint cannot set `source`",
|
85
|
-
)
|
86
|
-
|
87
|
-
# Retrieve task from database
|
88
|
-
db_task = await _get_task_check_owner(task_id=task_id, user=user, db=db)
|
89
|
-
|
90
|
-
update = task_update.dict(exclude_unset=True)
|
91
|
-
for key, value in update.items():
|
92
|
-
if isinstance(value, str) or (
|
93
|
-
key == "version" and value is None
|
94
|
-
): # special case (issue 817)
|
95
|
-
setattr(db_task, key, value)
|
96
|
-
elif isinstance(value, dict):
|
97
|
-
if key == "args_schema":
|
98
|
-
setattr(db_task, key, value)
|
99
|
-
else:
|
100
|
-
current_dict = deepcopy(getattr(db_task, key))
|
101
|
-
current_dict.update(value)
|
102
|
-
setattr(db_task, key, current_dict)
|
103
|
-
else:
|
104
|
-
raise HTTPException(
|
105
|
-
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
106
|
-
detail=f"Invalid {type(value)=} for {key=}",
|
107
|
-
)
|
108
|
-
|
109
|
-
await db.commit()
|
110
|
-
await db.refresh(db_task)
|
111
|
-
await db.close()
|
112
|
-
return db_task
|
113
|
-
|
114
|
-
|
115
|
-
@router.post(
|
116
|
-
"/", response_model=TaskReadV1, status_code=status.HTTP_201_CREATED
|
117
|
-
)
|
118
|
-
async def create_task(
|
119
|
-
task: TaskCreateV1,
|
120
|
-
user: UserOAuth = Depends(current_active_verified_user),
|
121
|
-
db: AsyncSession = Depends(get_async_db),
|
122
|
-
) -> Optional[TaskReadV1]:
|
123
|
-
"""
|
124
|
-
Create a new task
|
125
|
-
"""
|
126
|
-
_raise_if_v1_is_read_only()
|
127
|
-
# Set task.owner attribute
|
128
|
-
if user.username:
|
129
|
-
owner = user.username
|
130
|
-
else:
|
131
|
-
verify_user_has_settings(user)
|
132
|
-
if user.settings.slurm_user:
|
133
|
-
owner = user.settings.slurm_user
|
134
|
-
else:
|
135
|
-
raise HTTPException(
|
136
|
-
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
137
|
-
detail=(
|
138
|
-
"Cannot add a new task because current user does not "
|
139
|
-
"have `username` or `slurm_user` attributes."
|
140
|
-
),
|
141
|
-
)
|
142
|
-
|
143
|
-
# Prepend owner to task.source
|
144
|
-
task.source = f"{owner}:{task.source}"
|
145
|
-
|
146
|
-
# Verify that source is not already in use (note: this check is only useful
|
147
|
-
# to provide a user-friendly error message, but `task.source` uniqueness is
|
148
|
-
# already guaranteed by a constraint in the table definition).
|
149
|
-
stm = select(Task).where(Task.source == task.source)
|
150
|
-
res = await db.execute(stm)
|
151
|
-
if res.scalars().all():
|
152
|
-
raise HTTPException(
|
153
|
-
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
154
|
-
detail=f"Source '{task.source}' already used by some TaskV1",
|
155
|
-
)
|
156
|
-
stm = select(TaskV2).where(TaskV2.source == task.source)
|
157
|
-
res = await db.execute(stm)
|
158
|
-
if res.scalars().all():
|
159
|
-
raise HTTPException(
|
160
|
-
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
161
|
-
detail=f"Source '{task.source}' already used by some TaskV2",
|
162
|
-
)
|
163
|
-
|
164
|
-
# Add task
|
165
|
-
db_task = Task(**task.dict(), owner=owner)
|
166
|
-
db.add(db_task)
|
167
|
-
await db.commit()
|
168
|
-
await db.refresh(db_task)
|
169
|
-
await db.close()
|
170
|
-
return db_task
|
171
|
-
|
172
|
-
|
173
|
-
@router.delete("/{task_id}/", status_code=204)
|
174
|
-
async def delete_task(
|
175
|
-
task_id: int,
|
176
|
-
user: UserOAuth = Depends(current_active_user),
|
177
|
-
db: AsyncSession = Depends(get_async_db),
|
178
|
-
) -> Response:
|
179
|
-
"""
|
180
|
-
Delete a task
|
181
|
-
"""
|
182
|
-
_raise_if_v1_is_read_only()
|
183
|
-
db_task = await _get_task_check_owner(task_id=task_id, user=user, db=db)
|
184
|
-
|
185
|
-
# Check that the Task is not in relationship with some WorkflowTask
|
186
|
-
stm = select(WorkflowTask).filter(WorkflowTask.task_id == task_id)
|
187
|
-
res = await db.execute(stm)
|
188
|
-
workflowtask_list = res.scalars().all()
|
189
|
-
if workflowtask_list:
|
190
|
-
raise HTTPException(
|
191
|
-
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
192
|
-
detail=(
|
193
|
-
f"Cannot remove Task {task_id} because it is currently "
|
194
|
-
"imported in Workflows "
|
195
|
-
f"{[x.workflow_id for x in workflowtask_list]}. "
|
196
|
-
"If you want to remove this task, then you should first remove"
|
197
|
-
" the workflows.",
|
198
|
-
),
|
199
|
-
)
|
200
|
-
|
201
|
-
await db.delete(db_task)
|
202
|
-
await db.commit()
|
203
|
-
return Response(status_code=status.HTTP_204_NO_CONTENT)
|
@@ -1,239 +0,0 @@
|
|
1
|
-
from pathlib import Path
|
2
|
-
from shutil import copy as shell_copy
|
3
|
-
from tempfile import TemporaryDirectory
|
4
|
-
|
5
|
-
from fastapi import APIRouter
|
6
|
-
from fastapi import BackgroundTasks
|
7
|
-
from fastapi import Depends
|
8
|
-
from fastapi import HTTPException
|
9
|
-
from fastapi import Response
|
10
|
-
from fastapi import status
|
11
|
-
from pydantic.error_wrappers import ValidationError
|
12
|
-
from sqlmodel import select
|
13
|
-
|
14
|
-
from .....config import get_settings
|
15
|
-
from .....logger import close_logger
|
16
|
-
from .....logger import set_logger
|
17
|
-
from .....syringe import Inject
|
18
|
-
from ....db import AsyncSession
|
19
|
-
from ....db import get_async_db
|
20
|
-
from ....models.v1 import State
|
21
|
-
from ....models.v1 import Task
|
22
|
-
from ....schemas.v1 import StateRead
|
23
|
-
from ....schemas.v1 import TaskCollectPipV1
|
24
|
-
from ....schemas.v1 import TaskCollectStatusV1
|
25
|
-
from ._aux_functions import _raise_if_v1_is_read_only
|
26
|
-
from fractal_server.app.models import UserOAuth
|
27
|
-
from fractal_server.app.routes.auth import current_active_user
|
28
|
-
from fractal_server.app.routes.auth import current_active_verified_user
|
29
|
-
from fractal_server.string_tools import slugify_task_name_for_source_v1
|
30
|
-
from fractal_server.tasks.utils import get_collection_log_v1
|
31
|
-
from fractal_server.tasks.v1._TaskCollectPip import _TaskCollectPip
|
32
|
-
from fractal_server.tasks.v1.background_operations import (
|
33
|
-
background_collect_pip,
|
34
|
-
)
|
35
|
-
from fractal_server.tasks.v1.endpoint_operations import create_package_dir_pip
|
36
|
-
from fractal_server.tasks.v1.endpoint_operations import download_package
|
37
|
-
from fractal_server.tasks.v1.endpoint_operations import inspect_package
|
38
|
-
from fractal_server.tasks.v1.get_collection_data import get_collection_data
|
39
|
-
|
40
|
-
router = APIRouter()
|
41
|
-
|
42
|
-
logger = set_logger(__name__)
|
43
|
-
|
44
|
-
|
45
|
-
@router.post(
|
46
|
-
"/collect/pip/",
|
47
|
-
response_model=StateRead,
|
48
|
-
responses={
|
49
|
-
201: dict(
|
50
|
-
description=(
|
51
|
-
"Task collection successfully started in the background"
|
52
|
-
)
|
53
|
-
),
|
54
|
-
200: dict(
|
55
|
-
description=(
|
56
|
-
"Package already collected. Returning info on already "
|
57
|
-
"available tasks"
|
58
|
-
)
|
59
|
-
),
|
60
|
-
},
|
61
|
-
)
|
62
|
-
async def collect_tasks_pip(
|
63
|
-
task_collect: TaskCollectPipV1,
|
64
|
-
background_tasks: BackgroundTasks,
|
65
|
-
response: Response,
|
66
|
-
user: UserOAuth = Depends(current_active_verified_user),
|
67
|
-
db: AsyncSession = Depends(get_async_db),
|
68
|
-
) -> StateRead: # State[TaskCollectStatus]
|
69
|
-
"""
|
70
|
-
Task collection endpoint
|
71
|
-
|
72
|
-
Trigger the creation of a dedicated virtual environment, the installation
|
73
|
-
of a package and the collection of tasks as advertised in the manifest.
|
74
|
-
"""
|
75
|
-
_raise_if_v1_is_read_only()
|
76
|
-
logger = set_logger(logger_name="collect_tasks_pip")
|
77
|
-
|
78
|
-
# Validate payload as _TaskCollectPip, which has more strict checks than
|
79
|
-
# TaskCollectPip
|
80
|
-
try:
|
81
|
-
task_pkg = _TaskCollectPip(**task_collect.dict(exclude_unset=True))
|
82
|
-
except ValidationError as e:
|
83
|
-
raise HTTPException(
|
84
|
-
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
85
|
-
detail=f"Invalid task-collection object. Original error: {e}",
|
86
|
-
)
|
87
|
-
|
88
|
-
with TemporaryDirectory() as tmpdir:
|
89
|
-
try:
|
90
|
-
# Copy or download the package wheel file to tmpdir
|
91
|
-
if task_pkg.is_local_package:
|
92
|
-
shell_copy(task_pkg.package_path.as_posix(), tmpdir)
|
93
|
-
pkg_path = Path(tmpdir) / task_pkg.package_path.name
|
94
|
-
else:
|
95
|
-
pkg_path = await download_package(
|
96
|
-
task_pkg=task_pkg, dest=tmpdir
|
97
|
-
)
|
98
|
-
# Read package info from wheel file, and override the ones coming
|
99
|
-
# from the request body
|
100
|
-
pkg_info = inspect_package(pkg_path)
|
101
|
-
task_pkg.package_name = pkg_info["pkg_name"]
|
102
|
-
task_pkg.package_version = pkg_info["pkg_version"]
|
103
|
-
task_pkg.package_manifest = pkg_info["pkg_manifest"]
|
104
|
-
task_pkg.check()
|
105
|
-
except Exception as e:
|
106
|
-
raise HTTPException(
|
107
|
-
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
108
|
-
detail=f"Invalid package or manifest. Original error: {e}",
|
109
|
-
)
|
110
|
-
|
111
|
-
try:
|
112
|
-
venv_path = create_package_dir_pip(task_pkg=task_pkg)
|
113
|
-
except FileExistsError:
|
114
|
-
venv_path = create_package_dir_pip(task_pkg=task_pkg, create=False)
|
115
|
-
try:
|
116
|
-
task_collect_status = get_collection_data(venv_path)
|
117
|
-
for task in task_collect_status.task_list:
|
118
|
-
db_task = await db.get(Task, task.id)
|
119
|
-
if (
|
120
|
-
(not db_task)
|
121
|
-
or db_task.source != task.source
|
122
|
-
or db_task.name != task.name
|
123
|
-
):
|
124
|
-
await db.close()
|
125
|
-
raise HTTPException(
|
126
|
-
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
127
|
-
detail=(
|
128
|
-
"Cannot collect package. Folder already exists, "
|
129
|
-
f"but task {task.id} does not exists or it does "
|
130
|
-
f"not have the expected source ({task.source}) or "
|
131
|
-
f"name ({task.name})."
|
132
|
-
),
|
133
|
-
)
|
134
|
-
except FileNotFoundError as e:
|
135
|
-
await db.close()
|
136
|
-
raise HTTPException(
|
137
|
-
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
138
|
-
detail=(
|
139
|
-
"Cannot collect package. Possible reason: another "
|
140
|
-
"collection of the same package is in progress. "
|
141
|
-
f"Original error: {e}"
|
142
|
-
),
|
143
|
-
)
|
144
|
-
except ValidationError as e:
|
145
|
-
await db.close()
|
146
|
-
raise HTTPException(
|
147
|
-
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
148
|
-
detail=(
|
149
|
-
"Cannot collect package. Possible reason: an old version "
|
150
|
-
"of the same package has already been collected. "
|
151
|
-
f"Original error: {e}"
|
152
|
-
),
|
153
|
-
)
|
154
|
-
task_collect_status.info = "Already installed"
|
155
|
-
state = State(data=task_collect_status.sanitised_dict())
|
156
|
-
response.status_code == status.HTTP_200_OK
|
157
|
-
await db.close()
|
158
|
-
return state
|
159
|
-
settings = Inject(get_settings)
|
160
|
-
|
161
|
-
# Check that tasks are not already in the DB
|
162
|
-
for new_task in task_pkg.package_manifest.task_list:
|
163
|
-
new_task_name_slug = slugify_task_name_for_source_v1(new_task.name)
|
164
|
-
new_task_source = f"{task_pkg.package_source}:{new_task_name_slug}"
|
165
|
-
stm = select(Task).where(Task.source == new_task_source)
|
166
|
-
res = await db.execute(stm)
|
167
|
-
if res.scalars().all():
|
168
|
-
raise HTTPException(
|
169
|
-
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
170
|
-
detail=(
|
171
|
-
"Cannot collect package. Task with source "
|
172
|
-
f'"{new_task_source}" already exists in the database.'
|
173
|
-
),
|
174
|
-
)
|
175
|
-
|
176
|
-
# All checks are OK, proceed with task collection
|
177
|
-
full_venv_path = venv_path.relative_to(settings.FRACTAL_TASKS_DIR)
|
178
|
-
collection_status = TaskCollectStatusV1(
|
179
|
-
status="pending", venv_path=full_venv_path, package=task_pkg.package
|
180
|
-
)
|
181
|
-
|
182
|
-
# Create State object (after casting venv_path to string)
|
183
|
-
collection_status_dict = collection_status.dict()
|
184
|
-
collection_status_dict["venv_path"] = str(collection_status.venv_path)
|
185
|
-
state = State(data=collection_status_dict)
|
186
|
-
db.add(state)
|
187
|
-
await db.commit()
|
188
|
-
await db.refresh(state)
|
189
|
-
|
190
|
-
background_tasks.add_task(
|
191
|
-
background_collect_pip,
|
192
|
-
state_id=state.id,
|
193
|
-
venv_path=venv_path,
|
194
|
-
task_pkg=task_pkg,
|
195
|
-
)
|
196
|
-
logger.debug(
|
197
|
-
"Task-collection endpoint: start background collection "
|
198
|
-
"and return state"
|
199
|
-
)
|
200
|
-
close_logger(logger)
|
201
|
-
info = (
|
202
|
-
"Collecting tasks in the background. "
|
203
|
-
f"GET /task/collect/{state.id} to query collection status"
|
204
|
-
)
|
205
|
-
state.data["info"] = info
|
206
|
-
response.status_code = status.HTTP_201_CREATED
|
207
|
-
await db.close()
|
208
|
-
return state
|
209
|
-
|
210
|
-
|
211
|
-
@router.get("/collect/{state_id}/", response_model=StateRead)
|
212
|
-
async def check_collection_status(
|
213
|
-
state_id: int,
|
214
|
-
user: UserOAuth = Depends(current_active_user),
|
215
|
-
verbose: bool = False,
|
216
|
-
db: AsyncSession = Depends(get_async_db),
|
217
|
-
) -> StateRead: # State[TaskCollectStatus]
|
218
|
-
"""
|
219
|
-
Check status of background task collection
|
220
|
-
"""
|
221
|
-
logger = set_logger(logger_name="check_collection_status")
|
222
|
-
logger.debug(f"Querying state for state.id={state_id}")
|
223
|
-
state = await db.get(State, state_id)
|
224
|
-
if not state:
|
225
|
-
await db.close()
|
226
|
-
raise HTTPException(
|
227
|
-
status_code=status.HTTP_404_NOT_FOUND,
|
228
|
-
detail=f"No task collection info with id={state_id}",
|
229
|
-
)
|
230
|
-
data = TaskCollectStatusV1(**state.data)
|
231
|
-
|
232
|
-
# In some cases (i.e. a successful or ongoing task collection), data.log is
|
233
|
-
# not set; if so, we collect the current logs
|
234
|
-
if verbose and not data.log:
|
235
|
-
data.log = get_collection_log_v1(data.venv_path)
|
236
|
-
state.data = data.sanitised_dict()
|
237
|
-
close_logger(logger)
|
238
|
-
await db.close()
|
239
|
-
return state
|