fractal-server 2.17.2__py3-none-any.whl → 2.18.0__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 (108) hide show
  1. fractal_server/__init__.py +1 -1
  2. fractal_server/__main__.py +2 -1
  3. fractal_server/app/models/linkuserproject.py +40 -0
  4. fractal_server/app/models/security.py +7 -5
  5. fractal_server/app/models/v2/job.py +13 -2
  6. fractal_server/app/models/v2/resource.py +13 -0
  7. fractal_server/app/routes/admin/v2/__init__.py +11 -11
  8. fractal_server/app/routes/admin/v2/accounting.py +2 -2
  9. fractal_server/app/routes/admin/v2/job.py +34 -23
  10. fractal_server/app/routes/admin/v2/sharing.py +103 -0
  11. fractal_server/app/routes/admin/v2/task.py +9 -8
  12. fractal_server/app/routes/admin/v2/task_group.py +94 -16
  13. fractal_server/app/routes/admin/v2/task_group_lifecycle.py +20 -20
  14. fractal_server/app/routes/api/__init__.py +0 -9
  15. fractal_server/app/routes/api/v2/__init__.py +47 -47
  16. fractal_server/app/routes/api/v2/_aux_functions.py +65 -64
  17. fractal_server/app/routes/api/v2/_aux_functions_history.py +8 -3
  18. fractal_server/app/routes/api/v2/_aux_functions_sharing.py +97 -0
  19. fractal_server/app/routes/api/v2/_aux_functions_task_lifecycle.py +4 -4
  20. fractal_server/app/routes/api/v2/_aux_functions_tasks.py +2 -2
  21. fractal_server/app/routes/api/v2/dataset.py +89 -77
  22. fractal_server/app/routes/api/v2/history.py +28 -16
  23. fractal_server/app/routes/api/v2/images.py +22 -8
  24. fractal_server/app/routes/api/v2/job.py +40 -24
  25. fractal_server/app/routes/api/v2/pre_submission_checks.py +13 -6
  26. fractal_server/app/routes/api/v2/project.py +48 -25
  27. fractal_server/app/routes/api/v2/sharing.py +311 -0
  28. fractal_server/app/routes/api/v2/status_legacy.py +22 -33
  29. fractal_server/app/routes/api/v2/submit.py +76 -71
  30. fractal_server/app/routes/api/v2/task.py +15 -17
  31. fractal_server/app/routes/api/v2/task_collection.py +18 -18
  32. fractal_server/app/routes/api/v2/task_collection_custom.py +11 -13
  33. fractal_server/app/routes/api/v2/task_collection_pixi.py +9 -9
  34. fractal_server/app/routes/api/v2/task_group.py +18 -18
  35. fractal_server/app/routes/api/v2/task_group_lifecycle.py +26 -26
  36. fractal_server/app/routes/api/v2/task_version_update.py +12 -9
  37. fractal_server/app/routes/api/v2/workflow.py +41 -29
  38. fractal_server/app/routes/api/v2/workflow_import.py +25 -23
  39. fractal_server/app/routes/api/v2/workflowtask.py +25 -17
  40. fractal_server/app/routes/auth/_aux_auth.py +100 -0
  41. fractal_server/app/routes/auth/current_user.py +0 -63
  42. fractal_server/app/routes/auth/group.py +1 -30
  43. fractal_server/app/routes/auth/router.py +2 -0
  44. fractal_server/app/routes/auth/users.py +9 -0
  45. fractal_server/app/routes/auth/viewer_paths.py +43 -0
  46. fractal_server/app/schemas/user.py +29 -12
  47. fractal_server/app/schemas/user_group.py +0 -15
  48. fractal_server/app/schemas/v2/__init__.py +55 -48
  49. fractal_server/app/schemas/v2/dataset.py +35 -13
  50. fractal_server/app/schemas/v2/dumps.py +9 -9
  51. fractal_server/app/schemas/v2/job.py +11 -11
  52. fractal_server/app/schemas/v2/project.py +3 -3
  53. fractal_server/app/schemas/v2/resource.py +13 -4
  54. fractal_server/app/schemas/v2/sharing.py +99 -0
  55. fractal_server/app/schemas/v2/status_legacy.py +3 -3
  56. fractal_server/app/schemas/v2/task.py +6 -6
  57. fractal_server/app/schemas/v2/task_collection.py +4 -4
  58. fractal_server/app/schemas/v2/task_group.py +16 -16
  59. fractal_server/app/schemas/v2/workflow.py +16 -16
  60. fractal_server/app/schemas/v2/workflowtask.py +14 -14
  61. fractal_server/app/security/__init__.py +1 -1
  62. fractal_server/app/shutdown.py +6 -6
  63. fractal_server/config/__init__.py +0 -6
  64. fractal_server/config/_data.py +0 -79
  65. fractal_server/config/_main.py +6 -1
  66. fractal_server/data_migrations/2_18_0.py +30 -0
  67. fractal_server/images/models.py +1 -2
  68. fractal_server/main.py +72 -11
  69. fractal_server/migrations/versions/7910eed4cf97_user_project_dirs_and_usergroup_viewer_.py +60 -0
  70. fractal_server/migrations/versions/88270f589c9b_add_prevent_new_submissions.py +39 -0
  71. fractal_server/migrations/versions/bc0e8b3327a7_project_sharing.py +72 -0
  72. fractal_server/migrations/versions/f0702066b007_one_submitted_job_per_dataset.py +40 -0
  73. fractal_server/runner/config/_slurm.py +2 -0
  74. fractal_server/runner/executors/slurm_common/_batching.py +4 -10
  75. fractal_server/runner/executors/slurm_common/slurm_config.py +1 -0
  76. fractal_server/runner/executors/slurm_ssh/runner.py +1 -1
  77. fractal_server/runner/executors/slurm_sudo/runner.py +1 -1
  78. fractal_server/runner/v2/_local.py +4 -3
  79. fractal_server/runner/v2/_slurm_ssh.py +4 -3
  80. fractal_server/runner/v2/_slurm_sudo.py +4 -3
  81. fractal_server/runner/v2/runner.py +36 -17
  82. fractal_server/runner/v2/runner_functions.py +11 -14
  83. fractal_server/runner/v2/submit_workflow.py +22 -9
  84. fractal_server/tasks/v2/local/_utils.py +2 -2
  85. fractal_server/tasks/v2/local/collect.py +5 -6
  86. fractal_server/tasks/v2/local/collect_pixi.py +5 -6
  87. fractal_server/tasks/v2/local/deactivate.py +7 -7
  88. fractal_server/tasks/v2/local/deactivate_pixi.py +3 -3
  89. fractal_server/tasks/v2/local/delete.py +5 -5
  90. fractal_server/tasks/v2/local/reactivate.py +5 -5
  91. fractal_server/tasks/v2/local/reactivate_pixi.py +5 -5
  92. fractal_server/tasks/v2/ssh/collect.py +5 -5
  93. fractal_server/tasks/v2/ssh/collect_pixi.py +5 -5
  94. fractal_server/tasks/v2/ssh/deactivate.py +7 -7
  95. fractal_server/tasks/v2/ssh/deactivate_pixi.py +2 -2
  96. fractal_server/tasks/v2/ssh/delete.py +5 -5
  97. fractal_server/tasks/v2/ssh/reactivate.py +5 -5
  98. fractal_server/tasks/v2/ssh/reactivate_pixi.py +5 -5
  99. fractal_server/tasks/v2/utils_background.py +7 -7
  100. fractal_server/tasks/v2/utils_database.py +5 -5
  101. fractal_server/types/__init__.py +22 -0
  102. fractal_server/types/validators/__init__.py +3 -0
  103. fractal_server/types/validators/_common_validators.py +32 -0
  104. {fractal_server-2.17.2.dist-info → fractal_server-2.18.0.dist-info}/METADATA +3 -2
  105. {fractal_server-2.17.2.dist-info → fractal_server-2.18.0.dist-info}/RECORD +108 -98
  106. {fractal_server-2.17.2.dist-info → fractal_server-2.18.0.dist-info}/WHEEL +0 -0
  107. {fractal_server-2.17.2.dist-info → fractal_server-2.18.0.dist-info}/entry_points.txt +0 -0
  108. {fractal_server-2.17.2.dist-info → fractal_server-2.18.0.dist-info}/licenses/LICENSE +0 -0
@@ -5,8 +5,8 @@ from tempfile import TemporaryDirectory
5
5
  from fractal_server.app.db import get_sync_db
6
6
  from fractal_server.app.models import Profile
7
7
  from fractal_server.app.models import Resource
8
- from fractal_server.app.schemas.v2 import TaskGroupActivityActionV2
9
- from fractal_server.app.schemas.v2 import TaskGroupActivityStatusV2
8
+ from fractal_server.app.schemas.v2 import TaskGroupActivityAction
9
+ from fractal_server.app.schemas.v2 import TaskGroupActivityStatus
10
10
  from fractal_server.logger import reset_logger_handlers
11
11
  from fractal_server.logger import set_logger
12
12
  from fractal_server.ssh._fabric import SingleUseFractalSSH
@@ -150,7 +150,7 @@ def reactivate_ssh_pixi(
150
150
  logger.info("installing - START")
151
151
 
152
152
  # Set status to ONGOING and refresh logs
153
- activity.status = TaskGroupActivityStatusV2.ONGOING
153
+ activity.status = TaskGroupActivityStatus.ONGOING
154
154
  activity.log = get_current_log(log_file_path)
155
155
  activity = add_commit_refresh(obj=activity, db=db)
156
156
 
@@ -164,7 +164,7 @@ def reactivate_ssh_pixi(
164
164
  script_dir_remote=script_dir_remote,
165
165
  prefix=(
166
166
  f"{int(time.time())}_"
167
- f"{TaskGroupActivityActionV2.REACTIVATE}"
167
+ f"{TaskGroupActivityAction.REACTIVATE}"
168
168
  ),
169
169
  logger_name=LOGGER_NAME,
170
170
  fractal_ssh=fractal_ssh,
@@ -247,7 +247,7 @@ def reactivate_ssh_pixi(
247
247
  activity = add_commit_refresh(obj=activity, db=db)
248
248
 
249
249
  # Finalize (write metadata to DB)
250
- activity.status = TaskGroupActivityStatusV2.OK
250
+ activity.status = TaskGroupActivityStatus.OK
251
251
  activity.timestamp_ended = get_timestamp()
252
252
  activity = add_commit_refresh(obj=activity, db=db)
253
253
  task_group.active = True
@@ -6,10 +6,10 @@ from sqlalchemy.orm import Session as DBSyncSession
6
6
 
7
7
  from fractal_server.app.models.v2 import TaskGroupActivityV2
8
8
  from fractal_server.app.models.v2 import TaskGroupV2
9
- from fractal_server.app.schemas.v2 import TaskCreateV2
10
- from fractal_server.app.schemas.v2 import TaskGroupActivityStatusV2
9
+ from fractal_server.app.schemas.v2 import TaskCreate
10
+ from fractal_server.app.schemas.v2 import TaskGroupActivityStatus
11
11
  from fractal_server.app.schemas.v2.manifest import ManifestV2
12
- from fractal_server.app.schemas.v2.task_group import TaskGroupActivityActionV2
12
+ from fractal_server.app.schemas.v2.task_group import TaskGroupActivityAction
13
13
  from fractal_server.exceptions import UnreachableBranchError
14
14
  from fractal_server.logger import get_logger
15
15
  from fractal_server.logger import reset_logger_handlers
@@ -66,11 +66,11 @@ def fail_and_cleanup(
66
66
  f"Original error: {str(exception)}"
67
67
  )
68
68
 
69
- task_group_activity.status = TaskGroupActivityStatusV2.FAILED
69
+ task_group_activity.status = TaskGroupActivityStatus.FAILED
70
70
  task_group_activity.timestamp_ended = get_timestamp()
71
71
  task_group_activity.log = get_current_log(log_file_path)
72
72
  task_group_activity = add_commit_refresh(obj=task_group_activity, db=db)
73
- if task_group_activity.action == TaskGroupActivityActionV2.COLLECT:
73
+ if task_group_activity.action == TaskGroupActivityAction.COLLECT:
74
74
  db.delete(task_group)
75
75
  db.commit()
76
76
  reset_logger_handlers(logger)
@@ -83,7 +83,7 @@ def prepare_tasks_metadata(
83
83
  python_bin: Path | None = None,
84
84
  project_python_wrapper: Path | None = None,
85
85
  package_version: str | None = None,
86
- ) -> list[TaskCreateV2]:
86
+ ) -> list[TaskCreate]:
87
87
  """
88
88
  Based on the package manifest and additional info, prepare the task list.
89
89
 
@@ -129,7 +129,7 @@ def prepare_tasks_metadata(
129
129
  )
130
130
  task_attributes["command_parallel"] = cmd_parallel
131
131
  # Create object
132
- task_obj = TaskCreateV2(
132
+ task_obj = TaskCreate(
133
133
  **_task.model_dump(
134
134
  exclude={
135
135
  "executable_non_parallel",
@@ -3,13 +3,13 @@ from sqlalchemy.orm import Session as DBSyncSession
3
3
 
4
4
  from fractal_server.app.models.v2 import TaskGroupV2
5
5
  from fractal_server.app.models.v2 import TaskV2
6
- from fractal_server.app.schemas.v2 import TaskCreateV2
6
+ from fractal_server.app.schemas.v2 import TaskCreate
7
7
 
8
8
 
9
9
  def create_db_tasks_and_update_task_group_sync(
10
10
  *,
11
11
  task_group_id: int,
12
- task_list: list[TaskCreateV2],
12
+ task_list: list[TaskCreate],
13
13
  db: DBSyncSession,
14
14
  ) -> TaskGroupV2:
15
15
  """
@@ -17,7 +17,7 @@ def create_db_tasks_and_update_task_group_sync(
17
17
 
18
18
  Args:
19
19
  task_group_id: ID of an existing `TaskGroupV2` object.
20
- task_list: List of `TaskCreateV2` objects to be inserted into the db.
20
+ task_list: List of `TaskCreate` objects to be inserted into the db.
21
21
  db: Synchronous database session
22
22
 
23
23
  Returns:
@@ -36,7 +36,7 @@ def create_db_tasks_and_update_task_group_sync(
36
36
  async def create_db_tasks_and_update_task_group_async(
37
37
  *,
38
38
  task_group_id: int,
39
- task_list: list[TaskCreateV2],
39
+ task_list: list[TaskCreate],
40
40
  db: AsyncSession,
41
41
  ) -> TaskGroupV2:
42
42
  """
@@ -44,7 +44,7 @@ async def create_db_tasks_and_update_task_group_async(
44
44
 
45
45
  Args:
46
46
  task_group_id: ID of an existing `TaskGroupV2` object.
47
- task_list: List of `TaskCreateV2` objects to be inserted into the db.
47
+ task_list: List of `TaskCreate` objects to be inserted into the db.
48
48
  db: Synchronous database session
49
49
 
50
50
  Returns:
@@ -10,6 +10,9 @@ from fractal_server.urls import normalize_url
10
10
 
11
11
  from .validators import val_absolute_path
12
12
  from .validators import val_http_url
13
+ from .validators import val_no_dotdot_in_path
14
+ from .validators import val_non_absolute_path
15
+ from .validators import val_os_path_normpath
13
16
  from .validators import val_unique_list
14
17
  from .validators import valdict_keys
15
18
  from .validators import validate_attribute_filters
@@ -27,11 +30,22 @@ A non-empty string, with no leading/trailing whitespaces.
27
30
  AbsolutePathStr = Annotated[
28
31
  NonEmptyStr,
29
32
  AfterValidator(val_absolute_path),
33
+ AfterValidator(val_no_dotdot_in_path),
34
+ AfterValidator(val_os_path_normpath),
30
35
  ]
31
36
  """
32
37
  String representing an absolute path.
38
+
39
+ Validation fails if the path is not absolute or if it contains a
40
+ parent-directory reference "/../".
33
41
  """
34
42
 
43
+ RelativePathStr = Annotated[
44
+ NonEmptyStr,
45
+ AfterValidator(val_no_dotdot_in_path),
46
+ AfterValidator(val_os_path_normpath),
47
+ AfterValidator(val_non_absolute_path),
48
+ ]
35
49
 
36
50
  HttpUrlStr = Annotated[
37
51
  NonEmptyStr,
@@ -44,19 +58,27 @@ String representing an URL.
44
58
 
45
59
  ZarrUrlStr = Annotated[
46
60
  NonEmptyStr,
61
+ AfterValidator(val_no_dotdot_in_path),
47
62
  AfterValidator(normalize_url),
48
63
  ]
49
64
  """
50
65
  String representing a zarr URL/path.
66
+
67
+ Validation fails if the path is not absolute or if it contains a
68
+ parent-directory reference "/../".
51
69
  """
52
70
 
53
71
 
54
72
  ZarrDirStr = Annotated[
55
73
  NonEmptyStr,
74
+ AfterValidator(val_no_dotdot_in_path),
56
75
  AfterValidator(normalize_url),
57
76
  ]
58
77
  """
59
78
  String representing a `zarr_dir` path.
79
+
80
+ Validation fails if the path is not absolute or if it contains a
81
+ parent-directory reference "/../".
60
82
  """
61
83
 
62
84
  DictStrAny = Annotated[
@@ -1,6 +1,9 @@
1
1
  from ._common_validators import val_absolute_path # noqa F401
2
+ from ._common_validators import val_no_dotdot_in_path # noqa F401
3
+ from ._common_validators import val_os_path_normpath # noqa F401
2
4
  from ._common_validators import val_http_url # noqa F401
3
5
  from ._common_validators import val_unique_list # noqa F401
4
6
  from ._common_validators import valdict_keys # noqa F401
7
+ from ._common_validators import val_non_absolute_path # noqa F401
5
8
  from ._filter_validators import validate_attribute_filters # noqa F401
6
9
  from ._workflow_task_arguments_validators import validate_wft_args # noqa F401
@@ -1,4 +1,5 @@
1
1
  import os
2
+ from pathlib import Path
2
3
  from typing import Any
3
4
 
4
5
  from pydantic import HttpUrl
@@ -29,6 +30,37 @@ def val_absolute_path(path: str) -> str:
29
30
  return path
30
31
 
31
32
 
33
+ def val_non_absolute_path(path: str) -> str:
34
+ """
35
+ Check that a string attribute is not an absolute path
36
+ """
37
+ if os.path.isabs(path):
38
+ raise ValueError(
39
+ f"String must not be an absolute path (given '{path}')."
40
+ )
41
+ return path
42
+
43
+
44
+ def val_no_dotdot_in_path(path: str) -> str:
45
+ """
46
+ Check that a string attribute has no '/../' in it
47
+ """
48
+ if ".." in Path(path).parts:
49
+ raise ValueError("String must not contain '/../'.")
50
+ return path
51
+
52
+
53
+ def val_os_path_normpath(path: str) -> str:
54
+ """
55
+ Apply `os.path.normpath` to `path`.
56
+
57
+ Note: we keep this separate from `fractal_server.urls.normalize_url`,
58
+ because this function only applies to on-disk paths, while `normalize_url`
59
+ may apply to s3 URLs as well.
60
+ """
61
+ return os.path.normpath(path)
62
+
63
+
32
64
  def val_unique_list(must_be_unique: list) -> list:
33
65
  if len(set(must_be_unique)) != len(must_be_unique):
34
66
  raise ValueError("List has repetitions")
@@ -1,16 +1,17 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fractal-server
3
- Version: 2.17.2
3
+ Version: 2.18.0
4
4
  Summary: Backend component of the Fractal analytics platform
5
5
  License-Expression: BSD-3-Clause
6
6
  License-File: LICENSE
7
7
  Author: Tommaso Comparin
8
8
  Author-email: tommaso.comparin@exact-lab.it
9
- Requires-Python: >=3.11,<3.14
9
+ Requires-Python: >=3.11,<3.15
10
10
  Classifier: Programming Language :: Python :: 3
11
11
  Classifier: Programming Language :: Python :: 3.11
12
12
  Classifier: Programming Language :: Python :: 3.12
13
13
  Classifier: Programming Language :: Python :: 3.13
14
+ Classifier: Programming Language :: Python :: 3.14
14
15
  Requires-Dist: alembic (>=1.13.1,<2.0.0)
15
16
  Requires-Dist: fabric (>=3.2.2,<3.3.0)
16
17
  Requires-Dist: fastapi (>=0.120.0,<0.121.0)