fractal-server 2.14.3__py3-none-any.whl → 2.14.4__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/job.py +2 -2
- fractal_server/app/routes/api/v2/images.py +4 -20
- fractal_server/app/routes/api/v2/pre_submission_checks.py +2 -2
- fractal_server/app/runner/{run_subprocess.py → executors/slurm_ssh/run_subprocess.py} +11 -6
- fractal_server/app/runner/executors/slurm_ssh/runner.py +11 -56
- fractal_server/app/runner/executors/slurm_ssh/tar_commands.py +65 -0
- fractal_server/app/runner/v2/_local.py +2 -2
- fractal_server/app/runner/v2/_slurm_ssh.py +2 -2
- fractal_server/app/runner/v2/_slurm_sudo.py +2 -2
- fractal_server/app/runner/v2/runner.py +2 -2
- fractal_server/app/runner/v2/task_interface.py +3 -14
- fractal_server/app/schemas/user.py +11 -35
- fractal_server/app/schemas/user_group.py +3 -23
- fractal_server/app/schemas/user_settings.py +17 -43
- fractal_server/app/schemas/v2/dataset.py +10 -50
- fractal_server/app/schemas/v2/job.py +19 -60
- fractal_server/app/schemas/v2/manifest.py +10 -25
- fractal_server/app/schemas/v2/project.py +3 -11
- fractal_server/app/schemas/v2/task.py +36 -106
- fractal_server/app/schemas/v2/task_collection.py +31 -81
- fractal_server/app/schemas/v2/task_group.py +14 -34
- fractal_server/app/schemas/v2/workflow.py +13 -28
- fractal_server/app/schemas/v2/workflowtask.py +18 -126
- fractal_server/config.py +20 -73
- fractal_server/images/models.py +15 -81
- fractal_server/images/tools.py +3 -3
- fractal_server/ssh/_fabric.py +4 -1
- fractal_server/types/__init__.py +87 -0
- fractal_server/types/validators/__init__.py +6 -0
- fractal_server/types/validators/_common_validators.py +42 -0
- fractal_server/types/validators/_filter_validators.py +24 -0
- fractal_server/types/validators/_workflow_task_arguments_validators.py +10 -0
- {fractal_server-2.14.3.dist-info → fractal_server-2.14.4.dist-info}/METADATA +1 -1
- {fractal_server-2.14.3.dist-info → fractal_server-2.14.4.dist-info}/RECORD +38 -36
- fractal_server/app/runner/compress_folder.py +0 -125
- fractal_server/app/runner/extract_archive.py +0 -99
- fractal_server/app/schemas/_filter_validators.py +0 -46
- fractal_server/app/schemas/_validators.py +0 -86
- {fractal_server-2.14.3.dist-info → fractal_server-2.14.4.dist-info}/LICENSE +0 -0
- {fractal_server-2.14.3.dist-info → fractal_server-2.14.4.dist-info}/WHEEL +0 -0
- {fractal_server-2.14.3.dist-info → fractal_server-2.14.4.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,87 @@
|
|
1
|
+
from typing import Annotated
|
2
|
+
from typing import Any
|
3
|
+
from typing import Optional
|
4
|
+
from typing import Union
|
5
|
+
|
6
|
+
from pydantic import AfterValidator
|
7
|
+
from pydantic.types import NonNegativeInt
|
8
|
+
from pydantic.types import StringConstraints
|
9
|
+
|
10
|
+
from ..urls import normalize_url
|
11
|
+
from .validators import val_absolute_path
|
12
|
+
from .validators import val_http_url
|
13
|
+
from .validators import val_unique_list
|
14
|
+
from .validators import valdict_keys
|
15
|
+
from .validators import validate_attribute_filters
|
16
|
+
from .validators import validate_wft_args
|
17
|
+
|
18
|
+
NonEmptyStr = Annotated[
|
19
|
+
str,
|
20
|
+
StringConstraints(min_length=1, strip_whitespace=True),
|
21
|
+
]
|
22
|
+
|
23
|
+
AbsolutePathStr = Annotated[
|
24
|
+
NonEmptyStr,
|
25
|
+
AfterValidator(val_absolute_path),
|
26
|
+
]
|
27
|
+
HttpUrlStr = Annotated[
|
28
|
+
NonEmptyStr,
|
29
|
+
AfterValidator(val_http_url),
|
30
|
+
]
|
31
|
+
ZarrUrlStr = Annotated[
|
32
|
+
NonEmptyStr,
|
33
|
+
AfterValidator(normalize_url),
|
34
|
+
]
|
35
|
+
ZarrDirStr = Annotated[
|
36
|
+
NonEmptyStr,
|
37
|
+
AfterValidator(normalize_url),
|
38
|
+
]
|
39
|
+
|
40
|
+
DictStrAny = Annotated[
|
41
|
+
dict[str, Any],
|
42
|
+
AfterValidator(valdict_keys),
|
43
|
+
]
|
44
|
+
DictStrStr = Annotated[
|
45
|
+
dict[str, NonEmptyStr],
|
46
|
+
AfterValidator(valdict_keys),
|
47
|
+
]
|
48
|
+
|
49
|
+
ListUniqueNonEmptyString = Annotated[
|
50
|
+
list[NonEmptyStr],
|
51
|
+
AfterValidator(val_unique_list),
|
52
|
+
]
|
53
|
+
ListUniqueNonNegativeInt = Annotated[
|
54
|
+
list[NonNegativeInt],
|
55
|
+
AfterValidator(val_unique_list),
|
56
|
+
]
|
57
|
+
ListUniqueAbsolutePathStr = Annotated[
|
58
|
+
list[AbsolutePathStr],
|
59
|
+
AfterValidator(val_unique_list),
|
60
|
+
]
|
61
|
+
|
62
|
+
WorkflowTaskArgument = Annotated[
|
63
|
+
DictStrAny,
|
64
|
+
AfterValidator(validate_wft_args),
|
65
|
+
]
|
66
|
+
|
67
|
+
ImageAttributeValue = Union[int, float, str, bool]
|
68
|
+
ImageAttributes = Annotated[
|
69
|
+
dict[str, ImageAttributeValue],
|
70
|
+
AfterValidator(valdict_keys),
|
71
|
+
]
|
72
|
+
ImageAttributesWithNone = Annotated[
|
73
|
+
dict[str, Optional[ImageAttributeValue]],
|
74
|
+
AfterValidator(valdict_keys),
|
75
|
+
]
|
76
|
+
AttributeFilters = Annotated[
|
77
|
+
dict[str, list[ImageAttributeValue]],
|
78
|
+
AfterValidator(validate_attribute_filters),
|
79
|
+
]
|
80
|
+
TypeFilters = Annotated[
|
81
|
+
dict[str, bool],
|
82
|
+
AfterValidator(valdict_keys),
|
83
|
+
]
|
84
|
+
ImageTypes = Annotated[
|
85
|
+
dict[str, bool],
|
86
|
+
AfterValidator(valdict_keys),
|
87
|
+
]
|
@@ -0,0 +1,6 @@
|
|
1
|
+
from ._common_validators import val_absolute_path # noqa F401
|
2
|
+
from ._common_validators import val_http_url # noqa F401
|
3
|
+
from ._common_validators import val_unique_list # noqa F401
|
4
|
+
from ._common_validators import valdict_keys # noqa F401
|
5
|
+
from ._filter_validators import validate_attribute_filters # noqa F401
|
6
|
+
from ._workflow_task_arguments_validators import validate_wft_args # noqa F401
|
@@ -0,0 +1,42 @@
|
|
1
|
+
import os
|
2
|
+
from typing import Any
|
3
|
+
|
4
|
+
from pydantic import HttpUrl
|
5
|
+
|
6
|
+
|
7
|
+
def valdict_keys(d: dict[str, Any]) -> dict[str, Any]:
|
8
|
+
"""
|
9
|
+
Strip every key of the dictionary, and fail if there are identical keys
|
10
|
+
"""
|
11
|
+
old_keys = list(d.keys())
|
12
|
+
new_keys = [key.strip() for key in old_keys]
|
13
|
+
if any(k == "" for k in new_keys):
|
14
|
+
raise ValueError(f"Empty string in {new_keys}.")
|
15
|
+
if len(new_keys) != len(set(new_keys)):
|
16
|
+
raise ValueError(
|
17
|
+
f"Dictionary contains multiple identical keys: '{d}'."
|
18
|
+
)
|
19
|
+
for old_key, new_key in zip(old_keys, new_keys):
|
20
|
+
if new_key != old_key:
|
21
|
+
d[new_key] = d.pop(old_key)
|
22
|
+
return d
|
23
|
+
|
24
|
+
|
25
|
+
def val_absolute_path(path: str) -> str:
|
26
|
+
"""
|
27
|
+
Check that a string attribute is an absolute path
|
28
|
+
"""
|
29
|
+
if not os.path.isabs(path):
|
30
|
+
raise ValueError(f"String must be an absolute path (given '{path}').")
|
31
|
+
return path
|
32
|
+
|
33
|
+
|
34
|
+
def val_unique_list(must_be_unique: list) -> list:
|
35
|
+
if len(set(must_be_unique)) != len(must_be_unique):
|
36
|
+
raise ValueError("List has repetitions")
|
37
|
+
return must_be_unique
|
38
|
+
|
39
|
+
|
40
|
+
def val_http_url(value: str) -> str:
|
41
|
+
HttpUrl(value)
|
42
|
+
return value
|
@@ -0,0 +1,24 @@
|
|
1
|
+
from typing import Any
|
2
|
+
from typing import Union
|
3
|
+
|
4
|
+
from ._common_validators import valdict_keys
|
5
|
+
|
6
|
+
|
7
|
+
def validate_attribute_filters(
|
8
|
+
attribute_filters: dict[str, list[Union[int, float, str, bool]]]
|
9
|
+
) -> dict[str, list[Any]]:
|
10
|
+
attribute_filters = valdict_keys(attribute_filters)
|
11
|
+
for key, values in attribute_filters.items():
|
12
|
+
if values == []:
|
13
|
+
raise ValueError(
|
14
|
+
f"attribute_filters[{key}] cannot be an empty list."
|
15
|
+
)
|
16
|
+
else:
|
17
|
+
# values is a non-empty list, and its items must homogeneous
|
18
|
+
_type = type(values[0])
|
19
|
+
if not all(type(value) is _type for value in values):
|
20
|
+
raise ValueError(
|
21
|
+
f"attribute_filters[{key}] has values with "
|
22
|
+
f"non-homogeneous types: {values}."
|
23
|
+
)
|
24
|
+
return attribute_filters
|
@@ -0,0 +1,10 @@
|
|
1
|
+
def validate_wft_args(value: dict) -> dict:
|
2
|
+
RESERVED_ARGUMENTS = {"zarr_dir", "zarr_url", "zarr_urls", "init_args"}
|
3
|
+
args_keys = set(value.keys())
|
4
|
+
intersect_keys = RESERVED_ARGUMENTS.intersection(args_keys)
|
5
|
+
if intersect_keys:
|
6
|
+
raise ValueError(
|
7
|
+
"`args` contains the following forbidden keys: "
|
8
|
+
f"{intersect_keys}"
|
9
|
+
)
|
10
|
+
return value
|
@@ -1,4 +1,4 @@
|
|
1
|
-
fractal_server/__init__.py,sha256=
|
1
|
+
fractal_server/__init__.py,sha256=1GpRTVyXaEa3G3t4ruCfoTeyVcAd3cK5jro1DmuxzU0,23
|
2
2
|
fractal_server/__main__.py,sha256=rkM8xjY1KeS3l63irB8yCrlVobR-73uDapC4wvrIlxI,6957
|
3
3
|
fractal_server/alembic.ini,sha256=MWwi7GzjzawI9cCAK1LW7NxIBQDUqD12-ptJoq5JpP0,3153
|
4
4
|
fractal_server/app/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -13,7 +13,7 @@ fractal_server/app/models/v2/__init__.py,sha256=vjHwek7-IXmaZZL9VF0nD30YL9ca4wNc
|
|
13
13
|
fractal_server/app/models/v2/accounting.py,sha256=f2ALxfKKBNxFLJTtC2-YqRepVK253x68y7zkD2V_Nls,1115
|
14
14
|
fractal_server/app/models/v2/dataset.py,sha256=Xa3YLmqvSChBJoqlSsjmt-5x0zC-6rSx2eafFnMukfo,1240
|
15
15
|
fractal_server/app/models/v2/history.py,sha256=6yuYhsXgahHxv5FmDdv__aFndT228_rBFjTtkS-3Ohg,2082
|
16
|
-
fractal_server/app/models/v2/job.py,sha256=
|
16
|
+
fractal_server/app/models/v2/job.py,sha256=8BYqjeKUrAUVnt3RYHAqNdtl2GO-qGCRX4jWunLjsnU,2036
|
17
17
|
fractal_server/app/models/v2/project.py,sha256=rAHoh5KfYwIaW7rTX0_O0jvWmxEvfo1BafvmcXuSSRk,786
|
18
18
|
fractal_server/app/models/v2/task.py,sha256=8KEROaadgccXRZIP7EriBp2j1FgzYkgiirOi5_fG79M,1494
|
19
19
|
fractal_server/app/models/v2/task_group.py,sha256=yIzKAyJIFYYhG_K3AO-WGWYftygrk5D8H_WvAB7QnQk,3541
|
@@ -37,9 +37,9 @@ fractal_server/app/routes/api/v2/_aux_functions_task_lifecycle.py,sha256=qdXCb6I
|
|
37
37
|
fractal_server/app/routes/api/v2/_aux_functions_tasks.py,sha256=uhNSs-jcS7ndIUFKiOC1yrDiViw3uvKEXi9UL04BMks,11642
|
38
38
|
fractal_server/app/routes/api/v2/dataset.py,sha256=h5AhE0sdhQ20ZlIbEJsFnHIOUW0S1VHFpoflpBkVScs,8936
|
39
39
|
fractal_server/app/routes/api/v2/history.py,sha256=pDztvwQFOh3JChtSk9GIG3H17yg4G5pk1mq14qXF4Ck,17793
|
40
|
-
fractal_server/app/routes/api/v2/images.py,sha256=
|
40
|
+
fractal_server/app/routes/api/v2/images.py,sha256=Ly5Q4yzzm3w-roJi_ZBdzvcP_XUC7pwLPHMv8RnhI6Q,7743
|
41
41
|
fractal_server/app/routes/api/v2/job.py,sha256=MU1sHIKk_89WrD0TD44d4ufzqnywot7On_W71KjyUbQ,6500
|
42
|
-
fractal_server/app/routes/api/v2/pre_submission_checks.py,sha256=
|
42
|
+
fractal_server/app/routes/api/v2/pre_submission_checks.py,sha256=8pG8DbO5Ipk85VaNN9sfVTwXHGAWwk65OrsyRN4iWSo,4800
|
43
43
|
fractal_server/app/routes/api/v2/project.py,sha256=uAZgATiHcOvbnRX-vv1D3HoaEUvLUd7vzVmGcqOP8ZY,4602
|
44
44
|
fractal_server/app/routes/api/v2/status_legacy.py,sha256=0QlbBErOT2Idf-LT0EvOiPtTjrm6WmIY0k69NOgjmWk,6355
|
45
45
|
fractal_server/app/routes/api/v2/submit.py,sha256=hCwwC6bXP7EyhgGyVLv1ClybRH1YytDVoPunOzpsf0s,8822
|
@@ -67,7 +67,6 @@ fractal_server/app/routes/aux/validate_user_settings.py,sha256=FLVi__8YFcm_6c_K5
|
|
67
67
|
fractal_server/app/routes/pagination.py,sha256=L8F5JqekF39qz-LpeScdlhb57MQnSRXjK4ZEtsZqYLk,1210
|
68
68
|
fractal_server/app/runner/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
69
69
|
fractal_server/app/runner/components.py,sha256=-Ii5l8d_V6f5DFOd-Zsr8VYmOsyqw0Hox9fEFQiuqxY,66
|
70
|
-
fractal_server/app/runner/compress_folder.py,sha256=3X8eyC5sdTJqOgWiMKCu-1wI658gVMXRuHKBcqHpFWo,3811
|
71
70
|
fractal_server/app/runner/exceptions.py,sha256=JC5ufHyeA1hYD_rkZUscI30DD8D903ncag7Z3AArmUY,4215
|
72
71
|
fractal_server/app/runner/executors/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
73
72
|
fractal_server/app/runner/executors/base_runner.py,sha256=4xxMpYycIeAOz5niaJj2xtVW_Cq-shCxP1qk4g-KwOM,5137
|
@@ -84,59 +83,57 @@ fractal_server/app/runner/executors/slurm_common/remote.py,sha256=Z7cnAlhYi9Orge
|
|
84
83
|
fractal_server/app/runner/executors/slurm_common/slurm_job_task_models.py,sha256=RoxHLKOn0_wGjnY0Sv0a9nDSiqxYZHKRoMkT3p9_G1E,3607
|
85
84
|
fractal_server/app/runner/executors/slurm_common/utils_executors.py,sha256=naPyJI0I3lD-sYHbSXbMFGUBK4h_SggA5V91Z1Ch1Xg,1416
|
86
85
|
fractal_server/app/runner/executors/slurm_ssh/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
87
|
-
fractal_server/app/runner/executors/slurm_ssh/
|
86
|
+
fractal_server/app/runner/executors/slurm_ssh/run_subprocess.py,sha256=vlkJ0S37wYOmLG6gKC5-x8mBivYcgK7HTVvaroBnqLk,1030
|
87
|
+
fractal_server/app/runner/executors/slurm_ssh/runner.py,sha256=IJ6fHidj8Yv0H59NzOgd3ZIgYuCiOmlkB1_Rt8Jt-Qo,7901
|
88
|
+
fractal_server/app/runner/executors/slurm_ssh/tar_commands.py,sha256=g173siyv7qtjov5i-CjTVRT8d19ibK8re3RVWbsdHYA,1845
|
88
89
|
fractal_server/app/runner/executors/slurm_sudo/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
89
90
|
fractal_server/app/runner/executors/slurm_sudo/_subprocess_run_as_user.py,sha256=BlOz4NElv3v7rUYefyeki33uaJxcSDk6rPuVZx9ocdw,2776
|
90
91
|
fractal_server/app/runner/executors/slurm_sudo/runner.py,sha256=zT-DH61oPEq4dvo08EMnXv3QMYpwAZ3teY7R3MJ5G_8,6291
|
91
|
-
fractal_server/app/runner/extract_archive.py,sha256=8h6ZX7Gy0Vqv5KmrEGbWGPuA0MvW207cQZ-8CPYjwXc,2800
|
92
92
|
fractal_server/app/runner/filenames.py,sha256=lPnxKHtdRizr6FqG3zOdjDPyWA7GoaJGTtiuJV0gA8E,70
|
93
|
-
fractal_server/app/runner/run_subprocess.py,sha256=c3JbYXq3hX2aaflQU19qJ5Xs6J6oXGNvnTEoAfv2bxc,959
|
94
93
|
fractal_server/app/runner/set_start_and_last_task_index.py,sha256=-q4zVybAj8ek2XlbENKlfOAJ39hT_zoJoZkqzDqiAMY,1254
|
95
94
|
fractal_server/app/runner/shutdown.py,sha256=9pfSKHDNdIcm0eY-opgRTi7y0HmvfPmYiu9JR6Idark,2082
|
96
95
|
fractal_server/app/runner/task_files.py,sha256=27xFuPzSJc1Pw912CfSMPOhOIpvNwpkyLCnycqdo9lw,4365
|
97
96
|
fractal_server/app/runner/v2/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
98
|
-
fractal_server/app/runner/v2/_local.py,sha256=
|
99
|
-
fractal_server/app/runner/v2/_slurm_ssh.py,sha256=
|
100
|
-
fractal_server/app/runner/v2/_slurm_sudo.py,sha256=
|
97
|
+
fractal_server/app/runner/v2/_local.py,sha256=fJfSpY72BJeO_hGISIK1jE5q7lx3z3fv9_hlhNcJHLM,3072
|
98
|
+
fractal_server/app/runner/v2/_slurm_ssh.py,sha256=zQYvuTF_pNuBm9t73CSnhxvh1z_fgp2EkXJWclHiI5I,3306
|
99
|
+
fractal_server/app/runner/v2/_slurm_sudo.py,sha256=KmRBGFw9NDNMuMLp4H72iSj4NA3hm9f6OHJHkrMQmHM,3021
|
101
100
|
fractal_server/app/runner/v2/db_tools.py,sha256=du5dKhMMFMErQXbGIgu9JvO_vtMensodyPsyDeqz1yQ,3324
|
102
101
|
fractal_server/app/runner/v2/deduplicate_list.py,sha256=IVTE4abBU1bUprFTkxrTfYKnvkNTanWQ-KWh_etiT08,645
|
103
102
|
fractal_server/app/runner/v2/merge_outputs.py,sha256=D1L4Taieq9i71SPQyNc1kMokgHh-sV_MqF3bv7QMDBc,907
|
104
|
-
fractal_server/app/runner/v2/runner.py,sha256=
|
103
|
+
fractal_server/app/runner/v2/runner.py,sha256=2NQhcaGDw6XJ6Mnmiubru0yq2PpgF6fWFIE5hOVnOY0,17701
|
105
104
|
fractal_server/app/runner/v2/runner_functions.py,sha256=AzsE7VF6NMz_5qc0htQkfow5_2rr-wkx50vFJTndj8I,19250
|
106
105
|
fractal_server/app/runner/v2/runner_functions_low_level.py,sha256=_h_OOffq3d7V0uHa8Uvs0mj31y1GSZBUXjDDF3WjVjY,3620
|
107
106
|
fractal_server/app/runner/v2/submit_workflow.py,sha256=QywUGIoHAHnrWgfnyX8W9kVqKY-RvVyNLpzrbsXZOZ4,13075
|
108
|
-
fractal_server/app/runner/v2/task_interface.py,sha256=
|
107
|
+
fractal_server/app/runner/v2/task_interface.py,sha256=vVNSLiUTnImo82dp910KqP4gYLX3aoiLSJsfvdzGems,2561
|
109
108
|
fractal_server/app/runner/versions.py,sha256=dSaPRWqmFPHjg20kTCHmi_dmGNcCETflDtDLronNanU,852
|
110
109
|
fractal_server/app/schemas/__init__.py,sha256=stURAU_t3AOBaH0HSUbV-GKhlPKngnnIMoqWc3orFyI,135
|
111
|
-
fractal_server/app/schemas/
|
112
|
-
fractal_server/app/schemas/
|
113
|
-
fractal_server/app/schemas/
|
114
|
-
fractal_server/app/schemas/user_group.py,sha256=Uao1igRYflBu7Dg6Zs0kaFU3zBFJzIwDLrkFfaJk6z8,2176
|
115
|
-
fractal_server/app/schemas/user_settings.py,sha256=z7hx54yTrWfjo98oX_1lkeRh1UGrC1dSRH6yIOpnCsY,2772
|
110
|
+
fractal_server/app/schemas/user.py,sha256=0e4fWin0EdStjlbUnNWl7GsvnVfKMJPmVPCt-Mm_9tg,1945
|
111
|
+
fractal_server/app/schemas/user_group.py,sha256=ejk5qHLbmmDotXT6_--kkoDHVm-T5nS9GDtivJ4LjZU,1456
|
112
|
+
fractal_server/app/schemas/user_settings.py,sha256=KgfFdYI36_4OPeBrqxj5l-J5xYuRj7QORPtviLqHSM4,1948
|
116
113
|
fractal_server/app/schemas/v2/__init__.py,sha256=wXS4ZEzobWx5dh-XLjMZWpd-JMwWFPODUeUVoMQGRv4,3099
|
117
114
|
fractal_server/app/schemas/v2/accounting.py,sha256=Wylt7uWTiDIFlHJOh4XEtYitk2FjFlmnodDrJDxcr0E,397
|
118
|
-
fractal_server/app/schemas/v2/dataset.py,sha256=
|
115
|
+
fractal_server/app/schemas/v2/dataset.py,sha256=WSG9QQtcoC6ueDHxXH4mIJhFhlePpAo4N3sWJbluthY,1762
|
119
116
|
fractal_server/app/schemas/v2/dumps.py,sha256=uc9itXekO5IFfR6UucpQ5BX9NZZ8erE4hRR6S6aXlOc,2284
|
120
117
|
fractal_server/app/schemas/v2/history.py,sha256=Y3rc96DOPGQGZWJtBYVHiBjMQEhFtMq4WGkV4vs1oDE,1675
|
121
|
-
fractal_server/app/schemas/v2/job.py,sha256=
|
122
|
-
fractal_server/app/schemas/v2/manifest.py,sha256=
|
123
|
-
fractal_server/app/schemas/v2/project.py,sha256=
|
118
|
+
fractal_server/app/schemas/v2/job.py,sha256=Km7Im3i5OxI8NfBkIxAZFot_4LEBZNfL40Y-sFm5c0k,3363
|
119
|
+
fractal_server/app/schemas/v2/manifest.py,sha256=wYYNLkcyc93AtcxTg4PhjlKRIKRwGGrTWrCwM8D2Uqw,6880
|
120
|
+
fractal_server/app/schemas/v2/project.py,sha256=l96-3bCfB3knhITaLj1WSyBgbzP_k8CdtvgX_5jO_fU,657
|
124
121
|
fractal_server/app/schemas/v2/status_legacy.py,sha256=vc6C3Xri8222bb9OmsghMz05CNuEalO-t2s_nKo341s,954
|
125
|
-
fractal_server/app/schemas/v2/task.py,sha256=
|
126
|
-
fractal_server/app/schemas/v2/task_collection.py,sha256=
|
127
|
-
fractal_server/app/schemas/v2/task_group.py,sha256=
|
128
|
-
fractal_server/app/schemas/v2/workflow.py,sha256=
|
129
|
-
fractal_server/app/schemas/v2/workflowtask.py,sha256=
|
122
|
+
fractal_server/app/schemas/v2/task.py,sha256=5soZ3vp82f4myXi2Jj8Ob7iuGV0zaHbDXoKcARKsf4Y,4336
|
123
|
+
fractal_server/app/schemas/v2/task_collection.py,sha256=N1G5C8qNd93D5XVtK8gwDzrwdgpePlCIGl8Y7rOBBKk,4196
|
124
|
+
fractal_server/app/schemas/v2/task_group.py,sha256=FdIB9RSdoMIrfPkiCM60QpUdUjoVCLESeAxxAL-QAIs,3260
|
125
|
+
fractal_server/app/schemas/v2/workflow.py,sha256=sJWwjmlNN2gRvO8gA0w7wKd_MCucBgEA5iXtu0vPycQ,1806
|
126
|
+
fractal_server/app/schemas/v2/workflowtask.py,sha256=Q_2wM89QLMX19uthrnOigh-bxLYV5mdP-mUZPTgVJpM,3784
|
130
127
|
fractal_server/app/security/__init__.py,sha256=e2cveg5hQpieGD3bSPd5GTOMthvJ-HXH3buSb9WVfEU,14096
|
131
128
|
fractal_server/app/security/signup_email.py,sha256=Xd6QYxcdmg0PHpDwmUE8XQmPcOj3Xjy5oROcIMhmltM,1472
|
132
129
|
fractal_server/app/user_settings.py,sha256=OP1yiYKtPadxwM51_Q0hdPk3z90TCN4z1BLpQsXyWiU,1316
|
133
|
-
fractal_server/config.py,sha256=
|
130
|
+
fractal_server/config.py,sha256=McwfsTwRUzQOfN97ZjTLOHVyUvJKBqKY8xc9vK_eACA,26437
|
134
131
|
fractal_server/data_migrations/README.md,sha256=_3AEFvDg9YkybDqCLlFPdDmGJvr6Tw7HRI14aZ3LOIw,398
|
135
132
|
fractal_server/data_migrations/tools.py,sha256=LeMeASwYGtEqd-3wOLle6WARdTGAimoyMmRbbJl-hAM,572
|
136
133
|
fractal_server/gunicorn_fractal.py,sha256=u6U01TLGlXgq1v8QmEpLih3QnsInZD7CqphgJ_GrGzc,1230
|
137
134
|
fractal_server/images/__init__.py,sha256=-_wjoKtSX02P1KjDxDP_EXKvmbONTRmbf7iGVTsyBpM,154
|
138
|
-
fractal_server/images/models.py,sha256=
|
139
|
-
fractal_server/images/tools.py,sha256
|
135
|
+
fractal_server/images/models.py,sha256=AOIwwhleUtpuP6f_CNlOJEP517Grra9oWRqcBRk75xM,1280
|
136
|
+
fractal_server/images/tools.py,sha256=oapI8j9DmMdIxVsDQQMpo_HXCTVElsn8TvmVBP5iX5s,4120
|
140
137
|
fractal_server/logger.py,sha256=2QxBu5mB6xN3qWqj60nuxdrxcbxwzlx0xL47jKHB5PU,5385
|
141
138
|
fractal_server/main.py,sha256=FD9KzTTsXTQnTW0z3Hu7y0Nj_oAkBeZEInKDXFd4hjE,4561
|
142
139
|
fractal_server/migrations/env.py,sha256=nfyBpMIOT3kny6t-b-tUjyRjZ4k906bb1_wCQ7me1BI,1353
|
@@ -179,7 +176,7 @@ fractal_server/migrations/versions/f384e1c0cf5d_drop_task_default_args_columns.p
|
|
179
176
|
fractal_server/migrations/versions/fbce16ff4e47_new_history_items.py,sha256=TDWCaIoM0Q4SpRWmR9zr_rdp3lJXhCfBPTMhtrP5xYE,3950
|
180
177
|
fractal_server/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
181
178
|
fractal_server/ssh/__init__.py,sha256=sVUmzxf7_DuXG1xoLQ1_00fo5NPhi2LJipSmU5EAkPs,124
|
182
|
-
fractal_server/ssh/_fabric.py,sha256=
|
179
|
+
fractal_server/ssh/_fabric.py,sha256=wLjOh2kBnaBjpmGB6lbrPdcWq9D5BzbaS2vKYwOfxEo,23498
|
183
180
|
fractal_server/string_tools.py,sha256=niViRrrZAOo0y6pEFI9L_eUYS1PoOiQZUBtngiLc2_k,1877
|
184
181
|
fractal_server/syringe.py,sha256=3qSMW3YaMKKnLdgnooAINOPxnCOxP7y2jeAQYB21Gdo,2786
|
185
182
|
fractal_server/tasks/__init__.py,sha256=kadmVUoIghl8s190_Tt-8f-WBqMi8u8oU4Pvw39NHE8,23
|
@@ -206,11 +203,16 @@ fractal_server/tasks/v2/utils_database.py,sha256=yi7793Uue32O59OBVUgomO42oUrVKdS
|
|
206
203
|
fractal_server/tasks/v2/utils_package_names.py,sha256=RDg__xrvQs4ieeVzmVdMcEh95vGQYrv9Hfal-5EDBM8,2393
|
207
204
|
fractal_server/tasks/v2/utils_python_interpreter.py,sha256=5_wrlrTqXyo1YuLZvAW9hrSoh5MyLOzdPVUlUwM7uDQ,955
|
208
205
|
fractal_server/tasks/v2/utils_templates.py,sha256=Kc_nSzdlV6KIsO0CQSPs1w70zLyENPqJeTQEFiz4bOg,3124
|
206
|
+
fractal_server/types/__init__.py,sha256=BK12yh5d-8pecRWQOdey7l9QqXTCD21Eff62ypRoTjw,2057
|
207
|
+
fractal_server/types/validators/__init__.py,sha256=5uj6KJ9MelFZgyoq3MzXLhgWCl0yiriS7XKmb0gathg,392
|
208
|
+
fractal_server/types/validators/_common_validators.py,sha256=MpxyaP2kwgbyCTOaVRjYnJ74Lfi0f2X0q3rjX9w3vTk,1170
|
209
|
+
fractal_server/types/validators/_filter_validators.py,sha256=El8NuMqEy7CPYpWcN-n40DmMOA8cZtpFkUYL0uSjO5w,859
|
210
|
+
fractal_server/types/validators/_workflow_task_arguments_validators.py,sha256=HL7NgV8d56XbcD6gG5PVFUPMHjDm5Q-d7cXhVLdFAGU,387
|
209
211
|
fractal_server/urls.py,sha256=QjIKAC1a46bCdiPMu3AlpgFbcv6a4l3ABcd5xz190Og,471
|
210
212
|
fractal_server/utils.py,sha256=PMwrxWFxRTQRl1b9h-NRIbFGPKqpH_hXnkAT3NfZdpY,3571
|
211
213
|
fractal_server/zip_tools.py,sha256=GjDgo_sf6V_DDg6wWeBlZu5zypIxycn_l257p_YVKGc,4876
|
212
|
-
fractal_server-2.14.
|
213
|
-
fractal_server-2.14.
|
214
|
-
fractal_server-2.14.
|
215
|
-
fractal_server-2.14.
|
216
|
-
fractal_server-2.14.
|
214
|
+
fractal_server-2.14.4.dist-info/LICENSE,sha256=QKAharUuhxL58kSoLizKJeZE3mTCBnX6ucmz8W0lxlk,1576
|
215
|
+
fractal_server-2.14.4.dist-info/METADATA,sha256=eKfSXb3fH8Ac8Y_quuf64HUx8osvyiiK_CXVtjBoqPw,4560
|
216
|
+
fractal_server-2.14.4.dist-info/WHEEL,sha256=7dDg4QLnNKTvwIDR9Ac8jJaAmBC_owJrckbC0jjThyA,88
|
217
|
+
fractal_server-2.14.4.dist-info/entry_points.txt,sha256=8tV2kynvFkjnhbtDnxAqImL6HMVKsopgGfew0DOp5UY,58
|
218
|
+
fractal_server-2.14.4.dist-info/RECORD,,
|
@@ -1,125 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Wrap `tar` compression command.
|
3
|
-
|
4
|
-
This module is used both locally (in the environment where `fractal-server`
|
5
|
-
is running) and remotely (as a standalon Python module, executed over SSH).
|
6
|
-
|
7
|
-
This is a twin-module of `extract_archive.py`.
|
8
|
-
|
9
|
-
The reason for using the `tar` command via `subprocess` rather than Python
|
10
|
-
built-in `tarfile` library has to do with performance issues we observed
|
11
|
-
when handling files which were just created within a SLURM job, and in the
|
12
|
-
context of a CephFS filesystem.
|
13
|
-
"""
|
14
|
-
import sys
|
15
|
-
import time
|
16
|
-
from pathlib import Path
|
17
|
-
|
18
|
-
from fractal_server.app.runner.run_subprocess import run_subprocess
|
19
|
-
from fractal_server.logger import set_logger
|
20
|
-
|
21
|
-
|
22
|
-
def compress_folder(
|
23
|
-
subfolder_path: Path,
|
24
|
-
filelist_path: str | None,
|
25
|
-
default_logging_level: int | None = None,
|
26
|
-
) -> str:
|
27
|
-
"""
|
28
|
-
Compress e.g. `/path/archive` into `/path/archive.tar.gz`
|
29
|
-
|
30
|
-
Note that `/path/archive.tar.gz` may already exist. In this case, it will
|
31
|
-
be overwritten.
|
32
|
-
|
33
|
-
Args:
|
34
|
-
subfolder_path: Absolute path to the folder to compress.
|
35
|
-
remote_to_local: If `True`, exclude some files from the tar.gz archive.
|
36
|
-
default_logging_level:
|
37
|
-
|
38
|
-
Returns:
|
39
|
-
Absolute path to the tar.gz archive.
|
40
|
-
"""
|
41
|
-
|
42
|
-
# Assign an almost-unique label to the logger name, to simplify grepping
|
43
|
-
# logs when several `compress_folder` functions are run concurrently
|
44
|
-
label = round(time.time(), 2)
|
45
|
-
logger_name = f"compress_folder_{label}"
|
46
|
-
logger = set_logger(
|
47
|
-
logger_name,
|
48
|
-
default_logging_level=default_logging_level,
|
49
|
-
)
|
50
|
-
logger.debug("START")
|
51
|
-
t_start = time.perf_counter()
|
52
|
-
|
53
|
-
subfolder_name = subfolder_path.name
|
54
|
-
tarfile_path = (
|
55
|
-
subfolder_path.parent / f"{subfolder_name}.tar.gz"
|
56
|
-
).as_posix()
|
57
|
-
|
58
|
-
logger.debug(f"{subfolder_path=}")
|
59
|
-
logger.debug(f"{tarfile_path=}")
|
60
|
-
|
61
|
-
if filelist_path is None:
|
62
|
-
cmd_tar = (
|
63
|
-
f"tar -c -z -f {tarfile_path} "
|
64
|
-
f"--directory={subfolder_path.as_posix()} "
|
65
|
-
"."
|
66
|
-
)
|
67
|
-
else:
|
68
|
-
cmd_tar = (
|
69
|
-
f"tar -c -z -f {tarfile_path} "
|
70
|
-
f"--directory={subfolder_path.as_posix()} "
|
71
|
-
f"--files-from={filelist_path} --ignore-failed-read"
|
72
|
-
)
|
73
|
-
logger.debug(f"{cmd_tar=}")
|
74
|
-
|
75
|
-
try:
|
76
|
-
run_subprocess(cmd=cmd_tar, logger_name=logger_name)
|
77
|
-
elapsed = time.perf_counter() - t_start
|
78
|
-
logger.debug(f"END {elapsed=} s ({tarfile_path})")
|
79
|
-
return tarfile_path
|
80
|
-
except Exception as e:
|
81
|
-
logger.debug(f"ERROR: {str(e)}")
|
82
|
-
cmd_rm = f"rm {tarfile_path}"
|
83
|
-
try:
|
84
|
-
run_subprocess(cmd=cmd_rm, logger_name=logger_name)
|
85
|
-
except Exception as e_rm:
|
86
|
-
logger.error(
|
87
|
-
f"Running {cmd_rm=} failed, original error: {str(e_rm)}."
|
88
|
-
)
|
89
|
-
|
90
|
-
sys.exit(1)
|
91
|
-
|
92
|
-
|
93
|
-
def main(
|
94
|
-
sys_argv: list[str],
|
95
|
-
default_logging_level: int | None = None,
|
96
|
-
):
|
97
|
-
|
98
|
-
help_msg = (
|
99
|
-
"Expected use:\n"
|
100
|
-
"python -m fractal_server.app.runner.compress_folder "
|
101
|
-
"path/to/folder [--filelist /path/to/filelist]\n"
|
102
|
-
)
|
103
|
-
num_args = len(sys_argv[1:])
|
104
|
-
if num_args == 0:
|
105
|
-
sys.exit(f"Invalid argument.\n{help_msg}\nProvided: {sys_argv[1:]=}")
|
106
|
-
elif num_args == 1:
|
107
|
-
compress_folder(
|
108
|
-
subfolder_path=Path(sys_argv[1]),
|
109
|
-
filelist_path=None,
|
110
|
-
default_logging_level=default_logging_level,
|
111
|
-
)
|
112
|
-
elif num_args == 3 and sys_argv[2] == "--filelist":
|
113
|
-
compress_folder(
|
114
|
-
subfolder_path=Path(sys_argv[1]),
|
115
|
-
filelist_path=sys_argv[3],
|
116
|
-
default_logging_level=default_logging_level,
|
117
|
-
)
|
118
|
-
else:
|
119
|
-
sys.exit(f"Invalid argument.\n{help_msg}\nProvided: {sys_argv[1:]=}")
|
120
|
-
|
121
|
-
|
122
|
-
if __name__ == "__main__":
|
123
|
-
import logging
|
124
|
-
|
125
|
-
main(sys.argv, default_logging_level=logging.DEBUG)
|
@@ -1,99 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Wrap `tar` extraction command.
|
3
|
-
|
4
|
-
This module is used both locally (in the environment where `fractal-server`
|
5
|
-
is running) and remotely (as a standalon Python module, executed over SSH).
|
6
|
-
|
7
|
-
This is a twin-module of `compress_folder.py`.
|
8
|
-
|
9
|
-
The reason for using the `tar` command via `subprocess` rather than Python
|
10
|
-
built-in `tarfile` library has to do with performance issues we observed
|
11
|
-
when handling files which were just created within a SLURM job, and in the
|
12
|
-
context of a CephFS filesystem.
|
13
|
-
"""
|
14
|
-
import sys
|
15
|
-
from pathlib import Path
|
16
|
-
|
17
|
-
from .run_subprocess import run_subprocess
|
18
|
-
from fractal_server.logger import set_logger
|
19
|
-
|
20
|
-
|
21
|
-
def _remove_suffix(*, string: str, suffix: str) -> str:
|
22
|
-
if string.endswith(suffix):
|
23
|
-
return string[: -len(suffix)]
|
24
|
-
else:
|
25
|
-
raise ValueError(f"Cannot remove {suffix=} from {string=}.")
|
26
|
-
|
27
|
-
|
28
|
-
def extract_archive(
|
29
|
-
archive_path: Path,
|
30
|
-
default_logging_level: int | None = None,
|
31
|
-
):
|
32
|
-
"""
|
33
|
-
Extract e.g. `/path/archive.tar.gz` archive into `/path/archive` folder
|
34
|
-
|
35
|
-
Note that `/path/archive` may already exist. In this case, files with
|
36
|
-
the same name are overwritten and new files are added.
|
37
|
-
|
38
|
-
Arguments:
|
39
|
-
archive_path: Absolute path to the archive file.
|
40
|
-
default_logging_level
|
41
|
-
"""
|
42
|
-
|
43
|
-
logger_name = "extract_archive"
|
44
|
-
logger = set_logger(
|
45
|
-
logger_name,
|
46
|
-
default_logging_level=default_logging_level,
|
47
|
-
)
|
48
|
-
|
49
|
-
logger.debug("START")
|
50
|
-
logger.debug(f"{archive_path.as_posix()=}")
|
51
|
-
|
52
|
-
# Check archive_path is valid
|
53
|
-
if not archive_path.exists():
|
54
|
-
sys.exit(f"Missing file {archive_path.as_posix()}.")
|
55
|
-
|
56
|
-
# Prepare subfolder path
|
57
|
-
parent_dir = archive_path.parent
|
58
|
-
subfolder_name = _remove_suffix(string=archive_path.name, suffix=".tar.gz")
|
59
|
-
subfolder_path = parent_dir / subfolder_name
|
60
|
-
logger.debug(f"{subfolder_path.as_posix()=}")
|
61
|
-
|
62
|
-
# Create subfolder
|
63
|
-
subfolder_path.mkdir(exist_ok=True)
|
64
|
-
|
65
|
-
# Run tar command
|
66
|
-
cmd_tar = (
|
67
|
-
f"tar -xzvf {archive_path} --directory={subfolder_path.as_posix()}"
|
68
|
-
)
|
69
|
-
logger.debug(f"{cmd_tar=}")
|
70
|
-
run_subprocess(cmd=cmd_tar, logger_name=logger_name)
|
71
|
-
|
72
|
-
logger.debug("END")
|
73
|
-
|
74
|
-
|
75
|
-
def main(
|
76
|
-
sys_argv: list[str],
|
77
|
-
default_logging_level: int | None = None,
|
78
|
-
):
|
79
|
-
help_msg = (
|
80
|
-
"Expected use:\n"
|
81
|
-
"python -m fractal_server.app.runner.extract_archive "
|
82
|
-
"path/to/archive.tar.gz"
|
83
|
-
)
|
84
|
-
|
85
|
-
if len(sys_argv[1:]) != 1 or not sys_argv[1].endswith(".tar.gz"):
|
86
|
-
sys.exit(f"Invalid argument.\n{help_msg}\nProvided: {sys_argv[1:]=}")
|
87
|
-
else:
|
88
|
-
tarfile_path = Path(sys_argv[1])
|
89
|
-
extract_archive(
|
90
|
-
tarfile_path,
|
91
|
-
default_logging_level=default_logging_level,
|
92
|
-
)
|
93
|
-
|
94
|
-
|
95
|
-
if __name__ == "__main__":
|
96
|
-
|
97
|
-
import logging
|
98
|
-
|
99
|
-
main(sys.argv, default_logging_level=logging.DEBUG)
|
@@ -1,46 +0,0 @@
|
|
1
|
-
from typing import Optional
|
2
|
-
|
3
|
-
from ._validators import valdict_keys
|
4
|
-
from fractal_server.images.models import AttributeFiltersType
|
5
|
-
|
6
|
-
|
7
|
-
def validate_type_filters(
|
8
|
-
cls, type_filters: Optional[dict[str, bool]]
|
9
|
-
) -> dict[str, bool]:
|
10
|
-
if type_filters is None:
|
11
|
-
raise ValueError("'type_filters' cannot be 'None'.")
|
12
|
-
|
13
|
-
type_filters = valdict_keys("type_filters")(cls, type_filters)
|
14
|
-
return type_filters
|
15
|
-
|
16
|
-
|
17
|
-
def validate_attribute_filters(
|
18
|
-
cls,
|
19
|
-
attribute_filters: Optional[AttributeFiltersType],
|
20
|
-
) -> AttributeFiltersType:
|
21
|
-
if attribute_filters is None:
|
22
|
-
raise ValueError("'attribute_filters' cannot be 'None'.")
|
23
|
-
|
24
|
-
attribute_filters = valdict_keys("attribute_filters")(
|
25
|
-
cls, attribute_filters
|
26
|
-
)
|
27
|
-
for key, values in attribute_filters.items():
|
28
|
-
if values == []:
|
29
|
-
raise ValueError(
|
30
|
-
f"attribute_filters[{key}] cannot be an empty list."
|
31
|
-
)
|
32
|
-
else:
|
33
|
-
# values is a non-empty list, and its items must all be of the
|
34
|
-
# same scalar non-None type
|
35
|
-
_type = type(values[0])
|
36
|
-
if not all(type(value) is _type for value in values):
|
37
|
-
raise ValueError(
|
38
|
-
f"attribute_filters[{key}] has values with "
|
39
|
-
f"non-homogeneous types: {values}."
|
40
|
-
)
|
41
|
-
if _type not in (int, float, str, bool):
|
42
|
-
raise ValueError(
|
43
|
-
f"attribute_filters[{key}] has values with "
|
44
|
-
f"invalid types: {values}."
|
45
|
-
)
|
46
|
-
return attribute_filters
|