fractal-server 2.14.3__py3-none-any.whl → 2.14.4a0__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.
Files changed (41) hide show
  1. fractal_server/__init__.py +1 -1
  2. fractal_server/app/models/v2/job.py +2 -2
  3. fractal_server/app/routes/api/v2/images.py +4 -20
  4. fractal_server/app/routes/api/v2/pre_submission_checks.py +2 -2
  5. fractal_server/app/runner/{run_subprocess.py → executors/slurm_ssh/run_subprocess.py} +11 -6
  6. fractal_server/app/runner/executors/slurm_ssh/runner.py +11 -56
  7. fractal_server/app/runner/executors/slurm_ssh/tar_commands.py +65 -0
  8. fractal_server/app/runner/v2/_local.py +2 -2
  9. fractal_server/app/runner/v2/_slurm_ssh.py +2 -2
  10. fractal_server/app/runner/v2/_slurm_sudo.py +2 -2
  11. fractal_server/app/runner/v2/runner.py +2 -2
  12. fractal_server/app/runner/v2/task_interface.py +3 -14
  13. fractal_server/app/schemas/user.py +11 -35
  14. fractal_server/app/schemas/user_group.py +3 -23
  15. fractal_server/app/schemas/user_settings.py +17 -43
  16. fractal_server/app/schemas/v2/dataset.py +10 -50
  17. fractal_server/app/schemas/v2/job.py +19 -60
  18. fractal_server/app/schemas/v2/manifest.py +10 -25
  19. fractal_server/app/schemas/v2/project.py +3 -11
  20. fractal_server/app/schemas/v2/task.py +36 -106
  21. fractal_server/app/schemas/v2/task_collection.py +31 -81
  22. fractal_server/app/schemas/v2/task_group.py +14 -34
  23. fractal_server/app/schemas/v2/workflow.py +13 -28
  24. fractal_server/app/schemas/v2/workflowtask.py +18 -126
  25. fractal_server/config.py +20 -73
  26. fractal_server/images/models.py +15 -81
  27. fractal_server/images/tools.py +3 -3
  28. fractal_server/types/__init__.py +87 -0
  29. fractal_server/types/validators/__init__.py +6 -0
  30. fractal_server/types/validators/_common_validators.py +42 -0
  31. fractal_server/types/validators/_filter_validators.py +24 -0
  32. fractal_server/types/validators/_workflow_task_arguments_validators.py +10 -0
  33. {fractal_server-2.14.3.dist-info → fractal_server-2.14.4a0.dist-info}/METADATA +1 -1
  34. {fractal_server-2.14.3.dist-info → fractal_server-2.14.4a0.dist-info}/RECORD +37 -35
  35. fractal_server/app/runner/compress_folder.py +0 -125
  36. fractal_server/app/runner/extract_archive.py +0 -99
  37. fractal_server/app/schemas/_filter_validators.py +0 -46
  38. fractal_server/app/schemas/_validators.py +0 -86
  39. {fractal_server-2.14.3.dist-info → fractal_server-2.14.4a0.dist-info}/LICENSE +0 -0
  40. {fractal_server-2.14.3.dist-info → fractal_server-2.14.4a0.dist-info}/WHEEL +0 -0
  41. {fractal_server-2.14.3.dist-info → fractal_server-2.14.4a0.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,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: fractal-server
3
- Version: 2.14.3
3
+ Version: 2.14.4a0
4
4
  Summary: Backend component of the Fractal analytics platform
5
5
  License: BSD-3-Clause
6
6
  Author: Tommaso Comparin
@@ -1,4 +1,4 @@
1
- fractal_server/__init__.py,sha256=20SgG8fPO0eewuM_dSHcBRp5Xaupoj5yomTxw0STcSI,23
1
+ fractal_server/__init__.py,sha256=ogag4AVsfl_E8OtJRekIRakeld3q5BpgpzxnhBgTkfs,25
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=JWrEjX_E4iRFr5MbmtV_aY28J-5D469awLr0rfa5Kig,2052
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=BGpO94gVd8BTpCN6Mun2RXmjrPmfkIp73m8RN7uiGW4,8361
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=WyJAco9-96c15ImjgvsNfhd2169gG29CXkwtCTVLs38,4816
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/runner.py,sha256=yKK_cjskHDiasn_QQ-k14GhplP3tNaK7Kp4yiVn44Y0,9437
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=Ggdxx_XOlMya3bgXn_vGd2WMNVmLQaO3w9ZPaxYlRQk,3088
99
- fractal_server/app/runner/v2/_slurm_ssh.py,sha256=CEaJLajwdDjdpxY1_7aTLb9wqgzeOuxLlSewScMEx_Y,3322
100
- fractal_server/app/runner/v2/_slurm_sudo.py,sha256=TVihkQKMX6YWEWxXJjQo0WEQOjVy7FVVLmbM3MCulR0,3037
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=tYG-LB9Dm9_Lz3uYgAhcIeeFLy5I6xMqCdVuUKNXyII,17717
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=IXdQTI8rXFgXv1Ez0js4CjKFf3QwO2GCHRTuwiFtiTQ,2891
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/_filter_validators.py,sha256=Gkf2USrkuxZx1TWeeMRmhgfmG60AAIDQfbaWslLsvJQ,1572
112
- fractal_server/app/schemas/_validators.py,sha256=ZzTlTTzRATzf9Snx4Xp67aDmG77GaM2ewssFtlxQaaY,2680
113
- fractal_server/app/schemas/user.py,sha256=oCftAKeHdFFowpLyh1G-RiylR8cIO7fTn0PkT5xjs0E,2494
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=xNWdOW8hhL5Wx-iwyUPrZfWcC8fFuGDgdOHvZLbGVME,2782
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=OXPB4oPiMVWYgZu0lGzM_LGACvhWBavsW7c3MmivdDM,4556
122
- fractal_server/app/schemas/v2/manifest.py,sha256=8mmB0QwxEgAeGgwKD_fT-o-wFy7lb6HxNXbp17IJqNY,7281
123
- fractal_server/app/schemas/v2/project.py,sha256=ulgCmUnX0w-0jrSjVYIT7sxeK95CSNGh2msXydhsgYI,885
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=8vc8c3ZL6dJo9kyCrfKozgO_pF37BBLvD5XYIXynlEc,6551
126
- fractal_server/app/schemas/v2/task_collection.py,sha256=dLu4sy-su5k5vDJqCZdJMW8mLT5TX2SV60l_RAvKhwY,5930
127
- fractal_server/app/schemas/v2/task_group.py,sha256=A3SFHNHLKPJyrnDz-wbnQvycetafKltp6UsH1u-euwA,3850
128
- fractal_server/app/schemas/v2/workflow.py,sha256=ZpM43zTMyLRnEUtkbr_J5DYP00NwjItaC8gweB7GGAA,2172
129
- fractal_server/app/schemas/v2/workflowtask.py,sha256=rVbmNihDAJL_Sckbt1hBK2JEcb-8Xpxn3McvaomZLmQ,7429
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=A3j1bxa2inTNqIp5Ry0sY6DS72k7X_AKA3OUaDwoYbA,28439
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=jdGKMPi8WlO9Kvns4grIOU5LjujnvwIGjMFMC0wNy08,3501
139
- fractal_server/images/tools.py,sha256=-zFDzRv6cbbRo21OrD0eZY5qWcoMX8dxgEnfyI3tOcg,4140
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
@@ -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.3.dist-info/LICENSE,sha256=QKAharUuhxL58kSoLizKJeZE3mTCBnX6ucmz8W0lxlk,1576
213
- fractal_server-2.14.3.dist-info/METADATA,sha256=jWGz8N3CZga8UzjSeagUSYuLxxqDbZSBnkZnd15zrTo,4560
214
- fractal_server-2.14.3.dist-info/WHEEL,sha256=7dDg4QLnNKTvwIDR9Ac8jJaAmBC_owJrckbC0jjThyA,88
215
- fractal_server-2.14.3.dist-info/entry_points.txt,sha256=8tV2kynvFkjnhbtDnxAqImL6HMVKsopgGfew0DOp5UY,58
216
- fractal_server-2.14.3.dist-info/RECORD,,
214
+ fractal_server-2.14.4a0.dist-info/LICENSE,sha256=QKAharUuhxL58kSoLizKJeZE3mTCBnX6ucmz8W0lxlk,1576
215
+ fractal_server-2.14.4a0.dist-info/METADATA,sha256=Hl3iQzK2CtzTsqeTm4h_I4DZOX318S_WRsFjGmDEwhQ,4562
216
+ fractal_server-2.14.4a0.dist-info/WHEEL,sha256=7dDg4QLnNKTvwIDR9Ac8jJaAmBC_owJrckbC0jjThyA,88
217
+ fractal_server-2.14.4a0.dist-info/entry_points.txt,sha256=8tV2kynvFkjnhbtDnxAqImL6HMVKsopgGfew0DOp5UY,58
218
+ fractal_server-2.14.4a0.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