fractal-server 2.14.15__py3-none-any.whl → 2.15.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/v2/history.py +2 -0
- fractal_server/app/models/v2/task_group.py +17 -5
- fractal_server/app/routes/admin/v2/task_group_lifecycle.py +2 -2
- fractal_server/app/routes/api/v2/__init__.py +6 -0
- fractal_server/app/routes/api/v2/history.py +2 -2
- fractal_server/app/routes/api/v2/pre_submission_checks.py +3 -3
- fractal_server/app/routes/api/v2/task_collection.py +3 -3
- fractal_server/app/routes/api/v2/task_collection_custom.py +2 -2
- fractal_server/app/routes/api/v2/task_collection_pixi.py +236 -0
- fractal_server/app/routes/api/v2/task_group_lifecycle.py +8 -3
- fractal_server/app/runner/executors/slurm_ssh/runner.py +3 -1
- fractal_server/app/runner/v2/runner.py +2 -2
- fractal_server/app/schemas/v2/__init__.py +2 -1
- fractal_server/app/schemas/v2/dumps.py +1 -1
- fractal_server/app/schemas/v2/task_collection.py +1 -1
- fractal_server/app/schemas/v2/task_group.py +16 -5
- fractal_server/config.py +42 -0
- fractal_server/images/status_tools.py +80 -75
- fractal_server/migrations/versions/791ce783d3d8_add_indices.py +41 -0
- fractal_server/migrations/versions/b1e7f7a1ff71_task_group_for_pixi.py +53 -0
- fractal_server/ssh/_fabric.py +3 -0
- fractal_server/tasks/v2/local/__init__.py +2 -0
- fractal_server/tasks/v2/local/_utils.py +7 -2
- fractal_server/tasks/v2/local/collect.py +14 -12
- fractal_server/tasks/v2/local/collect_pixi.py +222 -0
- fractal_server/tasks/v2/local/deactivate.py +29 -25
- fractal_server/tasks/v2/local/deactivate_pixi.py +110 -0
- fractal_server/tasks/v2/local/reactivate.py +1 -1
- fractal_server/tasks/v2/ssh/__init__.py +1 -0
- fractal_server/tasks/v2/ssh/_utils.py +5 -5
- fractal_server/tasks/v2/ssh/collect.py +16 -15
- fractal_server/tasks/v2/ssh/collect_pixi.py +296 -0
- fractal_server/tasks/v2/ssh/deactivate.py +32 -31
- fractal_server/tasks/v2/ssh/reactivate.py +1 -1
- fractal_server/tasks/v2/templates/pixi_1_collect.sh +70 -0
- fractal_server/tasks/v2/utils_background.py +37 -9
- fractal_server/tasks/v2/utils_pixi.py +36 -0
- {fractal_server-2.14.15.dist-info → fractal_server-2.15.0a0.dist-info}/METADATA +4 -4
- {fractal_server-2.14.15.dist-info → fractal_server-2.15.0a0.dist-info}/RECORD +43 -35
- {fractal_server-2.14.15.dist-info → fractal_server-2.15.0a0.dist-info}/LICENSE +0 -0
- {fractal_server-2.14.15.dist-info → fractal_server-2.15.0a0.dist-info}/WHEEL +0 -0
- {fractal_server-2.14.15.dist-info → fractal_server-2.15.0a0.dist-info}/entry_points.txt +0 -0
@@ -1,5 +1,4 @@
|
|
1
1
|
import time
|
2
|
-
from copy import deepcopy
|
3
2
|
from typing import Any
|
4
3
|
|
5
4
|
from sqlalchemy import Select
|
@@ -11,7 +10,6 @@ from fractal_server.app.models.v2 import HistoryImageCache
|
|
11
10
|
from fractal_server.app.models.v2 import HistoryUnit
|
12
11
|
from fractal_server.app.schemas.v2 import HistoryUnitStatusWithUnset
|
13
12
|
from fractal_server.logger import set_logger
|
14
|
-
from fractal_server.types import ImageAttributeValue
|
15
13
|
|
16
14
|
logger = set_logger(__name__)
|
17
15
|
|
@@ -19,36 +17,84 @@ logger = set_logger(__name__)
|
|
19
17
|
IMAGE_STATUS_KEY = "__wftask_dataset_image_status__"
|
20
18
|
|
21
19
|
|
22
|
-
def _enriched_image(
|
23
|
-
|
24
|
-
|
20
|
+
def _enriched_image(
|
21
|
+
*,
|
22
|
+
img: dict[str, Any],
|
23
|
+
status: str,
|
24
|
+
) -> dict[str, Any]:
|
25
|
+
return img | {
|
26
|
+
"attributes": (img["attributes"] | {IMAGE_STATUS_KEY: status})
|
27
|
+
}
|
25
28
|
|
26
29
|
|
27
30
|
def _prepare_query(
|
28
31
|
*,
|
29
32
|
dataset_id: int,
|
30
33
|
workflowtask_id: int,
|
31
|
-
zarr_urls: list[str],
|
32
34
|
) -> Select:
|
35
|
+
"""
|
36
|
+
Note: the query does not include `.order_by`.
|
37
|
+
"""
|
33
38
|
stm = (
|
34
39
|
select(HistoryImageCache.zarr_url, HistoryUnit.status)
|
35
40
|
.join(HistoryUnit)
|
36
41
|
.where(HistoryImageCache.dataset_id == dataset_id)
|
37
42
|
.where(HistoryImageCache.workflowtask_id == workflowtask_id)
|
38
43
|
.where(HistoryImageCache.latest_history_unit_id == HistoryUnit.id)
|
39
|
-
.where(HistoryImageCache.zarr_url.in_(zarr_urls))
|
40
|
-
.order_by(HistoryImageCache.zarr_url)
|
41
44
|
)
|
42
45
|
return stm
|
43
46
|
|
44
47
|
|
45
|
-
|
48
|
+
def _postprocess_image_lists(
|
49
|
+
target_images: list[dict[str, Any]],
|
50
|
+
list_query_url_status: list[tuple[str, str]],
|
51
|
+
) -> list[dict[str, Any]]:
|
52
|
+
""" """
|
53
|
+
t_1 = time.perf_counter()
|
54
|
+
|
55
|
+
# Select only processed images that are part of the target image set
|
56
|
+
zarr_url_to_image = {img["zarr_url"]: img for img in target_images}
|
57
|
+
target_zarr_urls = zarr_url_to_image.keys()
|
58
|
+
list_processed_url_status = [
|
59
|
+
url_status
|
60
|
+
for url_status in list_query_url_status
|
61
|
+
if url_status[0] in target_zarr_urls
|
62
|
+
]
|
63
|
+
|
64
|
+
set_processed_urls = set(
|
65
|
+
url_status[0] for url_status in list_processed_url_status
|
66
|
+
)
|
67
|
+
processed_images_with_status = [
|
68
|
+
_enriched_image(
|
69
|
+
img=zarr_url_to_image[item[0]],
|
70
|
+
status=item[1],
|
71
|
+
)
|
72
|
+
for item in list_processed_url_status
|
73
|
+
]
|
74
|
+
|
75
|
+
non_processed_urls = target_zarr_urls - set_processed_urls
|
76
|
+
non_processed_images_with_status = [
|
77
|
+
_enriched_image(
|
78
|
+
img=zarr_url_to_image[zarr_url],
|
79
|
+
status=HistoryUnitStatusWithUnset.UNSET,
|
80
|
+
)
|
81
|
+
for zarr_url in non_processed_urls
|
82
|
+
]
|
83
|
+
t_2 = time.perf_counter()
|
84
|
+
logger.debug(
|
85
|
+
f"[enrich_images_async] post-processing, elapsed={t_2 - t_1:.5f} s"
|
86
|
+
)
|
87
|
+
|
88
|
+
return processed_images_with_status + non_processed_images_with_status
|
89
|
+
|
90
|
+
|
91
|
+
async def enrich_images_unsorted_async(
|
46
92
|
*,
|
47
93
|
images: list[dict[str, Any]],
|
48
94
|
dataset_id: int,
|
49
95
|
workflowtask_id: int,
|
50
96
|
db: AsyncSession,
|
51
|
-
) -> list[dict[str,
|
97
|
+
) -> list[dict[str, Any]]:
|
52
98
|
"""
|
53
99
|
Enrich images with a status-related attribute.
|
54
100
|
|
@@ -59,116 +105,75 @@ async def enrich_images_async(
|
|
59
105
|
db: An async db session
|
60
106
|
|
61
107
|
Returns:
|
62
|
-
The list of enriched images
|
108
|
+
The list of enriched images, not necessarily in the same order as
|
109
|
+
the input.
|
63
110
|
"""
|
64
111
|
t_0 = time.perf_counter()
|
65
112
|
logger.info(
|
66
113
|
f"[enrich_images_async] START, {dataset_id=}, {workflowtask_id=}"
|
67
114
|
)
|
68
115
|
|
69
|
-
|
70
|
-
|
116
|
+
# Get `(zarr_url, status)` for _all_ processed images (including those that
|
117
|
+
# are not part of the target image set)
|
71
118
|
res = await db.execute(
|
72
119
|
_prepare_query(
|
73
120
|
dataset_id=dataset_id,
|
74
121
|
workflowtask_id=workflowtask_id,
|
75
|
-
zarr_urls=zarr_url_to_image.keys(),
|
76
122
|
)
|
77
123
|
)
|
78
|
-
|
124
|
+
list_query_url_status = res.all()
|
79
125
|
t_1 = time.perf_counter()
|
80
|
-
logger.debug(f"[enrich_images_async]
|
126
|
+
logger.debug(f"[enrich_images_async] query, elapsed={t_1 - t_0:.5f} s")
|
81
127
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
img=zarr_url_to_image[item[0]],
|
86
|
-
status=item[1],
|
87
|
-
)
|
88
|
-
for item in list_processed_url_status
|
89
|
-
]
|
90
|
-
t_2 = time.perf_counter()
|
91
|
-
logger.debug(
|
92
|
-
"[enrich_images_async] processed-images, " f"elapsed={t_2 - t_1:.3f} s"
|
93
|
-
)
|
94
|
-
|
95
|
-
non_processed_urls = zarr_url_to_image.keys() - set_processed_urls
|
96
|
-
non_processed_images_with_status = [
|
97
|
-
_enriched_image(
|
98
|
-
img=zarr_url_to_image[zarr_url],
|
99
|
-
status=HistoryUnitStatusWithUnset.UNSET,
|
100
|
-
)
|
101
|
-
for zarr_url in non_processed_urls
|
102
|
-
]
|
103
|
-
t_3 = time.perf_counter()
|
104
|
-
logger.debug(
|
105
|
-
"[enrich_images_async] non-processed-images, "
|
106
|
-
f"elapsed={t_3 - t_2:.3f} s"
|
128
|
+
output = _postprocess_image_lists(
|
129
|
+
target_images=images,
|
130
|
+
list_query_url_status=list_query_url_status,
|
107
131
|
)
|
108
132
|
|
109
|
-
return
|
133
|
+
return output
|
110
134
|
|
111
135
|
|
112
|
-
def
|
136
|
+
def enrich_images_unsorted_sync(
|
113
137
|
*,
|
114
138
|
images: list[dict[str, Any]],
|
115
139
|
dataset_id: int,
|
116
140
|
workflowtask_id: int,
|
117
|
-
) -> list[dict[str,
|
141
|
+
) -> list[dict[str, Any]]:
|
118
142
|
"""
|
119
143
|
Enrich images with a status-related attribute.
|
120
144
|
|
145
|
+
|
121
146
|
Args:
|
122
147
|
images: The input image list
|
123
148
|
dataset_id: The dataset ID
|
124
149
|
workflowtask_id: The workflow-task ID
|
125
150
|
|
126
151
|
Returns:
|
127
|
-
The list of enriched images
|
152
|
+
The list of enriched images, not necessarily in the same order as
|
153
|
+
the input.
|
128
154
|
"""
|
155
|
+
|
129
156
|
t_0 = time.perf_counter()
|
130
157
|
logger.info(
|
131
158
|
f"[enrich_images_async] START, {dataset_id=}, {workflowtask_id=}"
|
132
159
|
)
|
133
160
|
|
134
|
-
|
161
|
+
# Get `(zarr_url, status)` for _all_ processed images (including those that
|
162
|
+
# are not part of the target image set)
|
135
163
|
with next(get_sync_db()) as db:
|
136
164
|
res = db.execute(
|
137
165
|
_prepare_query(
|
138
166
|
dataset_id=dataset_id,
|
139
167
|
workflowtask_id=workflowtask_id,
|
140
|
-
zarr_urls=zarr_url_to_image.keys(),
|
141
168
|
)
|
142
169
|
)
|
143
|
-
|
170
|
+
list_query_url_status = res.all()
|
144
171
|
t_1 = time.perf_counter()
|
145
|
-
logger.debug(f"[enrich_images_async]
|
146
|
-
|
147
|
-
set_processed_urls = set(item[0] for item in list_processed_url_status)
|
148
|
-
processed_images_with_status = [
|
149
|
-
_enriched_image(
|
150
|
-
img=zarr_url_to_image[item[0]],
|
151
|
-
status=item[1],
|
152
|
-
)
|
153
|
-
for item in list_processed_url_status
|
154
|
-
]
|
155
|
-
t_2 = time.perf_counter()
|
156
|
-
logger.debug(
|
157
|
-
"[enrich_images_async] processed-images, " f"elapsed={t_2 - t_1:.3f} s"
|
158
|
-
)
|
172
|
+
logger.debug(f"[enrich_images_async] query, elapsed={t_1 - t_0:.5f} s")
|
159
173
|
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
img=zarr_url_to_image[zarr_url],
|
164
|
-
status=HistoryUnitStatusWithUnset.UNSET,
|
165
|
-
)
|
166
|
-
for zarr_url in non_processed_urls
|
167
|
-
]
|
168
|
-
t_3 = time.perf_counter()
|
169
|
-
logger.debug(
|
170
|
-
"[enrich_images_async] non-processed-images, "
|
171
|
-
f"elapsed={t_3 - t_2:.3f} s"
|
174
|
+
output = _postprocess_image_lists(
|
175
|
+
target_images=images,
|
176
|
+
list_query_url_status=list_query_url_status,
|
172
177
|
)
|
173
178
|
|
174
|
-
return
|
179
|
+
return output
|
@@ -0,0 +1,41 @@
|
|
1
|
+
"""Add indices
|
2
|
+
|
3
|
+
Revision ID: 791ce783d3d8
|
4
|
+
Revises: 969d84257cac
|
5
|
+
Create Date: 2025-06-03 09:32:30.757651
|
6
|
+
|
7
|
+
"""
|
8
|
+
from alembic import op
|
9
|
+
|
10
|
+
|
11
|
+
# revision identifiers, used by Alembic.
|
12
|
+
revision = "791ce783d3d8"
|
13
|
+
down_revision = "969d84257cac"
|
14
|
+
branch_labels = None
|
15
|
+
depends_on = None
|
16
|
+
|
17
|
+
|
18
|
+
def upgrade() -> None:
|
19
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
20
|
+
with op.batch_alter_table("historyimagecache", schema=None) as batch_op:
|
21
|
+
batch_op.create_index(
|
22
|
+
batch_op.f("ix_historyimagecache_dataset_id"),
|
23
|
+
["dataset_id"],
|
24
|
+
unique=False,
|
25
|
+
)
|
26
|
+
batch_op.create_index(
|
27
|
+
batch_op.f("ix_historyimagecache_workflowtask_id"),
|
28
|
+
["workflowtask_id"],
|
29
|
+
unique=False,
|
30
|
+
)
|
31
|
+
|
32
|
+
# ### end Alembic commands ###
|
33
|
+
|
34
|
+
|
35
|
+
def downgrade() -> None:
|
36
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
37
|
+
with op.batch_alter_table("historyimagecache", schema=None) as batch_op:
|
38
|
+
batch_op.drop_index(batch_op.f("ix_historyimagecache_workflowtask_id"))
|
39
|
+
batch_op.drop_index(batch_op.f("ix_historyimagecache_dataset_id"))
|
40
|
+
|
41
|
+
# ### end Alembic commands ###
|
@@ -0,0 +1,53 @@
|
|
1
|
+
"""Task group for pixi
|
2
|
+
|
3
|
+
Revision ID: b1e7f7a1ff71
|
4
|
+
Revises: 791ce783d3d8
|
5
|
+
Create Date: 2025-05-29 16:31:17.565973
|
6
|
+
|
7
|
+
"""
|
8
|
+
import sqlalchemy as sa
|
9
|
+
import sqlmodel
|
10
|
+
from alembic import op
|
11
|
+
|
12
|
+
|
13
|
+
# revision identifiers, used by Alembic.
|
14
|
+
revision = "b1e7f7a1ff71"
|
15
|
+
down_revision = "791ce783d3d8"
|
16
|
+
branch_labels = None
|
17
|
+
depends_on = None
|
18
|
+
|
19
|
+
|
20
|
+
def upgrade() -> None:
|
21
|
+
with op.batch_alter_table("taskgroupv2", schema=None) as batch_op:
|
22
|
+
batch_op.add_column(
|
23
|
+
sa.Column(
|
24
|
+
"pixi_version",
|
25
|
+
sqlmodel.sql.sqltypes.AutoString(),
|
26
|
+
nullable=True,
|
27
|
+
)
|
28
|
+
)
|
29
|
+
batch_op.alter_column(
|
30
|
+
"wheel_path",
|
31
|
+
nullable=True,
|
32
|
+
new_column_name="archive_path",
|
33
|
+
)
|
34
|
+
batch_op.alter_column(
|
35
|
+
"pip_freeze",
|
36
|
+
nullable=True,
|
37
|
+
new_column_name="env_info",
|
38
|
+
)
|
39
|
+
|
40
|
+
|
41
|
+
def downgrade() -> None:
|
42
|
+
with op.batch_alter_table("taskgroupv2", schema=None) as batch_op:
|
43
|
+
batch_op.alter_column(
|
44
|
+
"archive_path",
|
45
|
+
nullable=True,
|
46
|
+
new_column_name="wheel_path",
|
47
|
+
)
|
48
|
+
batch_op.alter_column(
|
49
|
+
"env_info",
|
50
|
+
nullable=True,
|
51
|
+
new_column_name="pip_freeze",
|
52
|
+
)
|
53
|
+
batch_op.drop_column("pixi_version")
|
fractal_server/ssh/_fabric.py
CHANGED
@@ -642,6 +642,9 @@ class FractalSSHList:
|
|
642
642
|
connect_kwargs={
|
643
643
|
"key_filename": key_path,
|
644
644
|
"look_for_keys": False,
|
645
|
+
"banner_timeout": 30,
|
646
|
+
"auth_timeout": 30, # default value
|
647
|
+
"channel_timeout": 60 * 60, # default value
|
645
648
|
},
|
646
649
|
)
|
647
650
|
with _acquire_lock_with_timeout(
|
@@ -50,19 +50,24 @@ def check_task_files_exist(task_list: list[TaskCreateV2]) -> None:
|
|
50
50
|
"""
|
51
51
|
Check that the modules listed in task commands point to existing files.
|
52
52
|
|
53
|
+
Note: commands may be like `/one/python /another/task.py` or
|
54
|
+
`/one/pixi [...] /another/task.py`, and in both cases `split()[-1]`
|
55
|
+
returns `/another/task.py`.
|
56
|
+
|
53
57
|
Args:
|
54
58
|
task_list:
|
55
59
|
"""
|
60
|
+
|
56
61
|
for _task in task_list:
|
57
62
|
if _task.command_non_parallel is not None:
|
58
|
-
_task_path = _task.command_non_parallel.split()[1]
|
63
|
+
_task_path = _task.command_non_parallel.split()[-1]
|
59
64
|
if not Path(_task_path).exists():
|
60
65
|
raise FileNotFoundError(
|
61
66
|
f"Task `{_task.name}` has `command_non_parallel` "
|
62
67
|
f"pointing to missing file `{_task_path}`."
|
63
68
|
)
|
64
69
|
if _task.command_parallel is not None:
|
65
|
-
_task_path = _task.command_parallel.split()[1]
|
70
|
+
_task_path = _task.command_parallel.split()[-1]
|
66
71
|
if not Path(_task_path).exists():
|
67
72
|
raise FileNotFoundError(
|
68
73
|
f"Task `{_task.name}` has `command_parallel` "
|
@@ -10,18 +10,18 @@ from ._utils import _customize_and_run_template
|
|
10
10
|
from fractal_server.app.db import get_sync_db
|
11
11
|
from fractal_server.app.models.v2 import TaskGroupActivityV2
|
12
12
|
from fractal_server.app.models.v2 import TaskGroupV2
|
13
|
+
from fractal_server.app.schemas.v2 import FractalUploadedFile
|
13
14
|
from fractal_server.app.schemas.v2 import TaskGroupActivityActionV2
|
14
15
|
from fractal_server.app.schemas.v2 import TaskGroupActivityStatusV2
|
15
|
-
from fractal_server.app.schemas.v2 import WheelFile
|
16
16
|
from fractal_server.app.schemas.v2.manifest import ManifestV2
|
17
17
|
from fractal_server.logger import reset_logger_handlers
|
18
18
|
from fractal_server.logger import set_logger
|
19
19
|
from fractal_server.tasks.utils import get_log_path
|
20
20
|
from fractal_server.tasks.v2.local._utils import check_task_files_exist
|
21
|
-
from fractal_server.tasks.v2.utils_background import _prepare_tasks_metadata
|
22
21
|
from fractal_server.tasks.v2.utils_background import add_commit_refresh
|
23
22
|
from fractal_server.tasks.v2.utils_background import fail_and_cleanup
|
24
23
|
from fractal_server.tasks.v2.utils_background import get_current_log
|
24
|
+
from fractal_server.tasks.v2.utils_background import prepare_tasks_metadata
|
25
25
|
from fractal_server.tasks.v2.utils_package_names import compare_package_names
|
26
26
|
from fractal_server.tasks.v2.utils_python_interpreter import (
|
27
27
|
get_python_interpreter_v2,
|
@@ -38,7 +38,7 @@ def collect_local(
|
|
38
38
|
*,
|
39
39
|
task_group_activity_id: int,
|
40
40
|
task_group_id: int,
|
41
|
-
wheel_file:
|
41
|
+
wheel_file: FractalUploadedFile | None = None,
|
42
42
|
) -> None:
|
43
43
|
"""
|
44
44
|
Collect a task package.
|
@@ -103,16 +103,18 @@ def collect_local(
|
|
103
103
|
Path(task_group.path).mkdir(parents=True)
|
104
104
|
logger.info(f"Created {task_group.path}")
|
105
105
|
|
106
|
-
# Write wheel file and set task_group.
|
106
|
+
# Write wheel file and set task_group.archive_path
|
107
107
|
if wheel_file is not None:
|
108
108
|
|
109
|
-
|
109
|
+
archive_path = (
|
110
110
|
Path(task_group.path) / wheel_file.filename
|
111
111
|
).as_posix()
|
112
|
-
logger.info(
|
113
|
-
|
112
|
+
logger.info(
|
113
|
+
f"Write wheel-file contents into {archive_path}"
|
114
|
+
)
|
115
|
+
with open(archive_path, "wb") as f:
|
114
116
|
f.write(wheel_file.contents)
|
115
|
-
task_group.
|
117
|
+
task_group.archive_path = archive_path
|
116
118
|
task_group = add_commit_refresh(obj=task_group, db=db)
|
117
119
|
|
118
120
|
# Prepare replacements for templates
|
@@ -220,7 +222,7 @@ def collect_local(
|
|
220
222
|
activity = add_commit_refresh(obj=activity, db=db)
|
221
223
|
|
222
224
|
logger.info("_prepare_tasks_metadata - start")
|
223
|
-
task_list =
|
225
|
+
task_list = prepare_tasks_metadata(
|
224
226
|
package_manifest=pkg_manifest,
|
225
227
|
package_version=task_group.version,
|
226
228
|
package_root=Path(package_root),
|
@@ -241,15 +243,15 @@ def collect_local(
|
|
241
243
|
|
242
244
|
# Update task_group data
|
243
245
|
logger.info(
|
244
|
-
"Add
|
246
|
+
"Add env_info, venv_size and venv_file_number "
|
245
247
|
"to TaskGroupV2 - start"
|
246
248
|
)
|
247
|
-
task_group.
|
249
|
+
task_group.env_info = pip_freeze_stdout
|
248
250
|
task_group.venv_size_in_kB = int(venv_size)
|
249
251
|
task_group.venv_file_number = int(venv_file_number)
|
250
252
|
task_group = add_commit_refresh(obj=task_group, db=db)
|
251
253
|
logger.info(
|
252
|
-
"Add
|
254
|
+
"Add env_info, venv_size and venv_file_number "
|
253
255
|
"to TaskGroupV2 - end"
|
254
256
|
)
|
255
257
|
|