fractal-server 2.17.1a1__py3-none-any.whl → 2.17.2__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 (203) hide show
  1. fractal_server/__init__.py +1 -1
  2. fractal_server/__main__.py +19 -18
  3. fractal_server/app/db/__init__.py +3 -3
  4. fractal_server/app/models/__init__.py +1 -0
  5. fractal_server/app/models/linkuserproject.py +3 -1
  6. fractal_server/app/models/security.py +21 -3
  7. fractal_server/app/models/v2/__init__.py +3 -1
  8. fractal_server/app/models/v2/accounting.py +9 -1
  9. fractal_server/app/models/v2/dataset.py +5 -1
  10. fractal_server/app/models/v2/history.py +15 -1
  11. fractal_server/app/models/v2/job.py +4 -0
  12. fractal_server/app/models/v2/profile.py +29 -0
  13. fractal_server/app/models/v2/project.py +4 -10
  14. fractal_server/app/models/v2/resource.py +4 -0
  15. fractal_server/app/models/v2/task_group.py +4 -3
  16. fractal_server/app/models/v2/workflow.py +2 -1
  17. fractal_server/app/routes/admin/v2/__init__.py +1 -2
  18. fractal_server/app/routes/admin/v2/accounting.py +1 -1
  19. fractal_server/app/routes/admin/v2/job.py +9 -9
  20. fractal_server/app/routes/admin/v2/profile.py +3 -2
  21. fractal_server/app/routes/admin/v2/resource.py +5 -5
  22. fractal_server/app/routes/admin/v2/task.py +28 -18
  23. fractal_server/app/routes/admin/v2/task_group.py +0 -1
  24. fractal_server/app/routes/admin/v2/task_group_lifecycle.py +1 -2
  25. fractal_server/app/routes/api/__init__.py +1 -0
  26. fractal_server/app/routes/api/v2/__init__.py +5 -6
  27. fractal_server/app/routes/api/v2/_aux_functions.py +70 -63
  28. fractal_server/app/routes/api/v2/_aux_functions_history.py +43 -20
  29. fractal_server/app/routes/api/v2/_aux_functions_task_lifecycle.py +2 -4
  30. fractal_server/app/routes/api/v2/_aux_functions_tasks.py +5 -7
  31. fractal_server/app/routes/api/v2/_aux_task_group_disambiguation.py +1 -2
  32. fractal_server/app/routes/api/v2/dataset.py +13 -32
  33. fractal_server/app/routes/api/v2/history.py +35 -21
  34. fractal_server/app/routes/api/v2/images.py +3 -2
  35. fractal_server/app/routes/api/v2/job.py +17 -14
  36. fractal_server/app/routes/api/v2/pre_submission_checks.py +5 -4
  37. fractal_server/app/routes/api/v2/project.py +22 -17
  38. fractal_server/app/routes/api/v2/status_legacy.py +12 -11
  39. fractal_server/app/routes/api/v2/submit.py +11 -12
  40. fractal_server/app/routes/api/v2/task.py +4 -3
  41. fractal_server/app/routes/api/v2/task_collection.py +28 -30
  42. fractal_server/app/routes/api/v2/task_collection_custom.py +8 -7
  43. fractal_server/app/routes/api/v2/task_collection_pixi.py +1 -2
  44. fractal_server/app/routes/api/v2/task_group.py +7 -6
  45. fractal_server/app/routes/api/v2/task_group_lifecycle.py +6 -6
  46. fractal_server/app/routes/api/v2/task_version_update.py +13 -12
  47. fractal_server/app/routes/api/v2/workflow.py +14 -31
  48. fractal_server/app/routes/api/v2/workflow_import.py +17 -19
  49. fractal_server/app/routes/api/v2/workflowtask.py +10 -12
  50. fractal_server/app/routes/auth/__init__.py +1 -3
  51. fractal_server/app/routes/auth/_aux_auth.py +1 -2
  52. fractal_server/app/routes/auth/current_user.py +4 -5
  53. fractal_server/app/routes/auth/group.py +7 -5
  54. fractal_server/app/routes/auth/login.py +1 -0
  55. fractal_server/app/routes/auth/oauth.py +4 -3
  56. fractal_server/app/routes/auth/register.py +4 -2
  57. fractal_server/app/routes/auth/users.py +10 -10
  58. fractal_server/app/routes/aux/_job.py +1 -1
  59. fractal_server/app/routes/aux/_runner.py +2 -2
  60. fractal_server/app/routes/pagination.py +1 -1
  61. fractal_server/app/schemas/user.py +3 -3
  62. fractal_server/app/schemas/v2/accounting.py +11 -0
  63. fractal_server/app/schemas/v2/dataset.py +28 -4
  64. fractal_server/app/schemas/v2/dumps.py +1 -0
  65. fractal_server/app/schemas/v2/manifest.py +4 -3
  66. fractal_server/app/schemas/v2/profile.py +53 -2
  67. fractal_server/app/schemas/v2/resource.py +109 -13
  68. fractal_server/app/schemas/v2/task.py +0 -1
  69. fractal_server/app/schemas/v2/task_collection.py +1 -1
  70. fractal_server/app/schemas/v2/workflowtask.py +4 -3
  71. fractal_server/app/security/__init__.py +4 -7
  72. fractal_server/app/security/signup_email.py +4 -5
  73. fractal_server/config/_data.py +36 -25
  74. fractal_server/config/_database.py +19 -20
  75. fractal_server/config/_email.py +30 -38
  76. fractal_server/config/_main.py +33 -52
  77. fractal_server/config/_oauth.py +17 -21
  78. fractal_server/exceptions.py +4 -0
  79. fractal_server/images/models.py +3 -3
  80. fractal_server/images/status_tools.py +4 -2
  81. fractal_server/logger.py +1 -1
  82. fractal_server/main.py +4 -3
  83. fractal_server/migrations/versions/034a469ec2eb_task_groups.py +4 -8
  84. fractal_server/migrations/versions/091b01f51f88_add_usergroup_and_linkusergroup_table.py +1 -1
  85. fractal_server/migrations/versions/0f5f85bb2ae7_add_pre_pinned_packages.py +1 -0
  86. fractal_server/migrations/versions/19eca0dd47a9_user_settings_project_dir.py +1 -1
  87. fractal_server/migrations/versions/1a83a5260664_rename.py +1 -1
  88. fractal_server/migrations/versions/1eac13a26c83_drop_v1_tables.py +1 -0
  89. fractal_server/migrations/versions/316140ff7ee1_remove_usersettings_cache_dir.py +1 -1
  90. fractal_server/migrations/versions/40d6d6511b20_add_index_to_history_models.py +47 -0
  91. fractal_server/migrations/versions/45fbb391d7af_make_resource_id_fk_non_nullable.py +1 -1
  92. fractal_server/migrations/versions/47351f8c7ebc_drop_dataset_filters.py +1 -0
  93. fractal_server/migrations/versions/49d0856e9569_drop_table.py +2 -3
  94. fractal_server/migrations/versions/4c308bcaea2b_add_task_args_schema_and_task_args_.py +1 -1
  95. fractal_server/migrations/versions/4cedeb448a53_workflowtask_foreign_keys_not_nullables.py +1 -1
  96. fractal_server/migrations/versions/501961cfcd85_remove_link_between_v1_and_v2_tasks_.py +2 -1
  97. fractal_server/migrations/versions/50a13d6138fd_initial_schema.py +7 -19
  98. fractal_server/migrations/versions/5bf02391cfef_v2.py +4 -10
  99. fractal_server/migrations/versions/70e77f1c38b0_add_applyworkflow_first_task_index_and_.py +1 -0
  100. fractal_server/migrations/versions/71eefd1dd202_add_slurm_accounts.py +1 -1
  101. fractal_server/migrations/versions/7673fe18c05d_remove_project_dir_server_default.py +1 -1
  102. fractal_server/migrations/versions/791ce783d3d8_add_indices.py +1 -1
  103. fractal_server/migrations/versions/83bc2ad3ffcc_2_17_0.py +1 -0
  104. fractal_server/migrations/versions/84bf0fffde30_add_dumps_to_applyworkflow.py +1 -0
  105. fractal_server/migrations/versions/8e8f227a3e36_update_taskv2_post_2_7_0.py +2 -4
  106. fractal_server/migrations/versions/8f79bd162e35_add_docs_info_and_docs_link_to_task_.py +1 -1
  107. fractal_server/migrations/versions/94a47ea2d3ff_remove_cache_dir_slurm_user_and_slurm_.py +1 -0
  108. fractal_server/migrations/versions/969d84257cac_add_historyrun_task_id.py +1 -1
  109. fractal_server/migrations/versions/97f444d47249_add_applyworkflow_project_dump.py +1 -1
  110. fractal_server/migrations/versions/981d588fe248_add_executor_error_log.py +1 -1
  111. fractal_server/migrations/versions/99ea79d9e5d2_add_dataset_history.py +2 -4
  112. fractal_server/migrations/versions/9c5ae74c9b98_add_user_settings_table.py +1 -1
  113. fractal_server/migrations/versions/9db60297b8b2_set_ondelete.py +1 -1
  114. fractal_server/migrations/versions/9fd26a2b0de4_add_workflow_timestamp_created.py +1 -1
  115. fractal_server/migrations/versions/a7f4d6137b53_add_workflow_dump_to_applyworkflow.py +1 -1
  116. fractal_server/migrations/versions/af1ef1c83c9b_add_accounting_tables.py +1 -0
  117. fractal_server/migrations/versions/af8673379a5c_drop_old_filter_columns.py +1 -0
  118. fractal_server/migrations/versions/b1e7f7a1ff71_task_group_for_pixi.py +1 -1
  119. fractal_server/migrations/versions/b3ffb095f973_json_to_jsonb.py +1 -0
  120. fractal_server/migrations/versions/c90a7c76e996_job_id_in_history_run.py +1 -1
  121. fractal_server/migrations/versions/caba9fb1ea5e_drop_useroauth_user_settings_id.py +1 -1
  122. fractal_server/migrations/versions/d256a7379ab8_taskgroup_activity_and_venv_info_to_.py +4 -9
  123. fractal_server/migrations/versions/d4fe3708d309_make_applyworkflow_workflow_dump_non_.py +1 -0
  124. fractal_server/migrations/versions/da2cb2ac4255_user_group_viewer_paths.py +1 -1
  125. fractal_server/migrations/versions/db09233ad13a_split_filters_and_keep_old_columns.py +1 -0
  126. fractal_server/migrations/versions/e0e717ae2f26_delete_linkuserproject_ondelete_project.py +50 -0
  127. fractal_server/migrations/versions/e75cac726012_make_applyworkflow_start_timestamp_not_.py +1 -0
  128. fractal_server/migrations/versions/e81103413827_add_job_type_filters.py +1 -1
  129. fractal_server/migrations/versions/efa89c30e0a4_add_project_timestamp_created.py +1 -0
  130. fractal_server/migrations/versions/f37aceb45062_make_historyunit_logfile_required.py +1 -1
  131. fractal_server/migrations/versions/f384e1c0cf5d_drop_task_default_args_columns.py +1 -0
  132. fractal_server/migrations/versions/fbce16ff4e47_new_history_items.py +4 -9
  133. fractal_server/runner/config/_local.py +8 -5
  134. fractal_server/runner/config/_slurm.py +37 -33
  135. fractal_server/runner/config/slurm_mem_to_MB.py +0 -1
  136. fractal_server/runner/executors/base_runner.py +29 -4
  137. fractal_server/runner/executors/local/get_local_config.py +1 -0
  138. fractal_server/runner/executors/local/runner.py +14 -13
  139. fractal_server/runner/executors/slurm_common/_batching.py +5 -10
  140. fractal_server/runner/executors/slurm_common/base_slurm_runner.py +53 -27
  141. fractal_server/runner/executors/slurm_common/get_slurm_config.py +14 -7
  142. fractal_server/runner/executors/slurm_common/remote.py +3 -1
  143. fractal_server/runner/executors/slurm_common/slurm_config.py +1 -0
  144. fractal_server/runner/executors/slurm_common/slurm_job_task_models.py +1 -3
  145. fractal_server/runner/executors/slurm_ssh/runner.py +16 -11
  146. fractal_server/runner/executors/slurm_ssh/tar_commands.py +1 -0
  147. fractal_server/runner/executors/slurm_sudo/_subprocess_run_as_user.py +1 -0
  148. fractal_server/runner/executors/slurm_sudo/runner.py +16 -11
  149. fractal_server/runner/task_files.py +9 -3
  150. fractal_server/runner/v2/_local.py +9 -4
  151. fractal_server/runner/v2/_slurm_ssh.py +11 -5
  152. fractal_server/runner/v2/_slurm_sudo.py +11 -5
  153. fractal_server/runner/v2/db_tools.py +0 -1
  154. fractal_server/runner/v2/deduplicate_list.py +2 -1
  155. fractal_server/runner/v2/runner.py +11 -14
  156. fractal_server/runner/v2/runner_functions.py +11 -14
  157. fractal_server/runner/v2/submit_workflow.py +7 -6
  158. fractal_server/ssh/_fabric.py +6 -13
  159. fractal_server/string_tools.py +0 -1
  160. fractal_server/syringe.py +1 -1
  161. fractal_server/tasks/config/_pixi.py +1 -1
  162. fractal_server/tasks/config/_python.py +16 -9
  163. fractal_server/tasks/utils.py +0 -1
  164. fractal_server/tasks/v2/local/_utils.py +1 -1
  165. fractal_server/tasks/v2/local/collect.py +10 -12
  166. fractal_server/tasks/v2/local/collect_pixi.py +9 -10
  167. fractal_server/tasks/v2/local/deactivate.py +7 -8
  168. fractal_server/tasks/v2/local/deactivate_pixi.py +4 -4
  169. fractal_server/tasks/v2/local/delete.py +1 -3
  170. fractal_server/tasks/v2/local/reactivate.py +7 -7
  171. fractal_server/tasks/v2/local/reactivate_pixi.py +7 -7
  172. fractal_server/tasks/v2/ssh/_utils.py +3 -3
  173. fractal_server/tasks/v2/ssh/collect.py +14 -19
  174. fractal_server/tasks/v2/ssh/collect_pixi.py +17 -19
  175. fractal_server/tasks/v2/ssh/deactivate.py +10 -8
  176. fractal_server/tasks/v2/ssh/deactivate_pixi.py +6 -5
  177. fractal_server/tasks/v2/ssh/delete.py +7 -5
  178. fractal_server/tasks/v2/ssh/reactivate.py +11 -11
  179. fractal_server/tasks/v2/ssh/reactivate_pixi.py +8 -9
  180. fractal_server/tasks/v2/templates/1_create_venv.sh +2 -0
  181. fractal_server/tasks/v2/templates/2_pip_install.sh +2 -0
  182. fractal_server/tasks/v2/templates/3_pip_freeze.sh +2 -0
  183. fractal_server/tasks/v2/templates/4_pip_show.sh +2 -0
  184. fractal_server/tasks/v2/templates/5_get_venv_size_and_file_number.sh +3 -1
  185. fractal_server/tasks/v2/templates/6_pip_install_from_freeze.sh +2 -0
  186. fractal_server/tasks/v2/templates/pixi_1_extract.sh +2 -0
  187. fractal_server/tasks/v2/templates/pixi_2_install.sh +2 -0
  188. fractal_server/tasks/v2/templates/pixi_3_post_install.sh +2 -0
  189. fractal_server/tasks/v2/utils_background.py +3 -3
  190. fractal_server/tasks/v2/utils_package_names.py +1 -2
  191. fractal_server/tasks/v2/utils_pixi.py +1 -3
  192. fractal_server/types/__init__.py +76 -1
  193. fractal_server/types/validators/_common_validators.py +1 -3
  194. fractal_server/types/validators/_workflow_task_arguments_validators.py +1 -2
  195. fractal_server/utils.py +1 -0
  196. fractal_server/zip_tools.py +34 -0
  197. {fractal_server-2.17.1a1.dist-info → fractal_server-2.17.2.dist-info}/METADATA +1 -1
  198. fractal_server-2.17.2.dist-info/RECORD +265 -0
  199. fractal_server/app/routes/admin/v2/project.py +0 -41
  200. fractal_server-2.17.1a1.dist-info/RECORD +0 -264
  201. {fractal_server-2.17.1a1.dist-info → fractal_server-2.17.2.dist-info}/WHEEL +0 -0
  202. {fractal_server-2.17.1a1.dist-info → fractal_server-2.17.2.dist-info}/entry_points.txt +0 -0
  203. {fractal_server-2.17.1a1.dist-info → fractal_server-2.17.2.dist-info}/licenses/LICENSE +0 -0
@@ -14,7 +14,6 @@ from fractal_server.types import ListUniqueNonEmptyString
14
14
  from fractal_server.types import NonEmptyStr
15
15
  from fractal_server.types import TypeFilters
16
16
 
17
-
18
17
  logger = set_logger(__name__)
19
18
 
20
19
 
@@ -86,7 +86,7 @@ class TaskCollectPipV2(BaseModel):
86
86
  def validate_pinned_package_versions(cls, value):
87
87
  if value is not None:
88
88
  for pkg, version in value.items():
89
- validate_cmd(pkg)
89
+ validate_cmd(pkg, allow_char="[]")
90
90
  validate_cmd(version)
91
91
  return value
92
92
 
@@ -5,14 +5,15 @@ from pydantic import ConfigDict
5
5
  from pydantic import Field
6
6
  from pydantic import model_validator
7
7
 
8
+ from fractal_server.types import DictStrAny
9
+ from fractal_server.types import TypeFilters
10
+ from fractal_server.types import WorkflowTaskArgument
11
+
8
12
  from .task import TaskExportV2
9
13
  from .task import TaskImportV2
10
14
  from .task import TaskImportV2Legacy
11
15
  from .task import TaskReadV2
12
16
  from .task import TaskType
13
- from fractal_server.types import DictStrAny
14
- from fractal_server.types import TypeFilters
15
- from fractal_server.types import WorkflowTaskArgument
16
17
 
17
18
 
18
19
  class WorkflowTaskCreateV2(BaseModel):
@@ -15,6 +15,7 @@ registers the client and the relative routes.
15
15
 
16
16
  All routes are registered under the `auth/` prefix.
17
17
  """
18
+
18
19
  import contextlib
19
20
  from collections.abc import AsyncGenerator
20
21
  from typing import Any
@@ -39,7 +40,7 @@ from sqlalchemy.orm import selectinload
39
40
  from sqlmodel import func
40
41
  from sqlmodel import select
41
42
 
42
- from ..db import get_async_db
43
+ from fractal_server.app.db import get_async_db
43
44
  from fractal_server.app.db import get_sync_db
44
45
  from fractal_server.app.models import LinkUserGroup
45
46
  from fractal_server.app.models import OAuthAccount
@@ -275,9 +276,7 @@ class UserManager(IntegerIDMixin, BaseUserManager[UserOAuth, int]):
275
276
  )
276
277
  except exceptions.UserNotExists:
277
278
  # (0) Log
278
- logger.warning(
279
- f"Self-registration attempt by {account_email}."
280
- )
279
+ logger.warning(f"Self-registration attempt by {account_email}.")
281
280
 
282
281
  # (1) Prepare user-facing error message
283
282
  error_msg = (
@@ -459,9 +458,7 @@ def _create_first_group():
459
458
  )
460
459
  return
461
460
 
462
- function_logger.info(
463
- f"START, name '{settings.FRACTAL_DEFAULT_GROUP_NAME}'"
464
- )
461
+ function_logger.info(f"START, name '{settings.FRACTAL_DEFAULT_GROUP_NAME}'")
465
462
  with next(get_sync_db()) as db:
466
463
  group_all = db.execute(
467
464
  select(UserGroup).where(
@@ -36,9 +36,9 @@ def send_fractal_email_or_log_failure(
36
36
  for recipient in email_settings.recipients
37
37
  ]
38
38
  )
39
- mail_msg[
40
- "Subject"
41
- ] = f"[Fractal, {email_settings.instance_name}] {subject}"
39
+ mail_msg["Subject"] = (
40
+ f"[Fractal, {email_settings.instance_name}] {subject}"
41
+ )
42
42
  with smtplib.SMTP(
43
43
  email_settings.smtp_server,
44
44
  email_settings.port,
@@ -61,6 +61,5 @@ def send_fractal_email_or_log_failure(
61
61
 
62
62
  except Exception as e:
63
63
  logger.error(
64
- "Could not send self-registration email, "
65
- f"original error: {str(e)}."
64
+ f"Could not send self-registration email, original error: {str(e)}."
66
65
  )
@@ -5,9 +5,10 @@ from pydantic import model_validator
5
5
  from pydantic_settings import BaseSettings
6
6
  from pydantic_settings import SettingsConfigDict
7
7
 
8
- from ._settings_config import SETTINGS_CONFIG_DICT
9
8
  from fractal_server.types import AbsolutePathStr
10
9
 
10
+ from ._settings_config import SETTINGS_CONFIG_DICT
11
+
11
12
 
12
13
  class DataAuthScheme(StrEnum):
13
14
  VIEWER_PATHS = "viewer-paths"
@@ -18,37 +19,47 @@ class DataAuthScheme(StrEnum):
18
19
  class DataSettings(BaseSettings):
19
20
  """
20
21
  Settings for the `fractal-data` integration.
21
- """
22
22
 
23
- model_config = SettingsConfigDict(**SETTINGS_CONFIG_DICT)
24
-
25
- FRACTAL_DATA_AUTH_SCHEME: DataAuthScheme = "none"
26
- """
27
- Defines how the list of allowed viewer paths is built.
23
+ See https://github.com/fractal-analytics-platform/fractal-data.
28
24
 
29
- This variable affects the `GET /auth/current-user/allowed-viewer-paths/`
30
- response, which is then consumed by
31
- [fractal-data](https://github.com/fractal-analytics-platform/fractal-data).
25
+ Attributes:
26
+ FRACTAL_DATA_AUTH_SCHEME:
27
+ Defines how the list of allowed viewer paths is built.
32
28
 
33
- Options:
29
+ This variable affects the
30
+ `GET /auth/current-user/allowed-viewer-paths/` response, which is
31
+ then consumed by
32
+ [fractal-data](https://github.com/fractal-analytics-platform/fractal-data).
34
33
 
35
- - "viewer-paths": The list of allowed viewer paths will include the user's
36
- `project_dir` along with any path defined in user groups' `viewer_paths`
37
- attributes.
38
- - "users-folders": The list will consist of the user's `project_dir` and a
39
- user-specific folder. The user folder is constructed by concatenating
40
- the base folder `FRACTAL_DATA_BASE_FOLDER` with the user's profile
41
- `username`.
42
- - "none": An empty list will be returned, indicating no access to
43
- viewer paths. Useful when vizarr viewer is not used.
34
+ Options:
35
+ <ul>
36
+ <li> `"viewer-paths"`: The list of allowed viewer paths will
37
+ include the user's `project_dir` along with any path
38
+ defined in UserGroups `viewer_paths` attributes.
39
+ </li>
40
+ <li> `"users-folders"`: The list will consist of the user's
41
+ `project_dir` and a user-specific folder. The user folder
42
+ is constructed by concatenating the base folder
43
+ `FRACTAL_DATA_BASE_FOLDER` with the user's profile
44
+ `username`.
45
+ </li>
46
+ <li> `"none"`: An empty list will be returned, indicating no
47
+ access to viewer paths. Useful when vizarr viewer is not
48
+ used.
49
+ </li>
50
+ </ul>
51
+ FRACTAL_DATA_BASE_FOLDER:
52
+ Base path to Zarr files that will be served by
53
+ fractal-vizarr-viewer.
54
+ This variable is required and used only when
55
+ `FRACTAL_DATA_AUTHORIZATION_SCHEME` is set to `"users-folders"`.
44
56
  """
45
57
 
58
+ model_config = SettingsConfigDict(**SETTINGS_CONFIG_DICT)
59
+
60
+ FRACTAL_DATA_AUTH_SCHEME: DataAuthScheme = "none"
61
+
46
62
  FRACTAL_DATA_BASE_FOLDER: AbsolutePathStr | None = None
47
- """
48
- Base path to Zarr files that will be served by fractal-vizarr-viewer;
49
- This variable is required and used only when
50
- FRACTAL_DATA_AUTHORIZATION_SCHEME is set to "users-folders".
51
- """
52
63
 
53
64
  @model_validator(mode="after")
54
65
  def check(self: Self) -> Self:
@@ -1,45 +1,44 @@
1
+ from typing import Literal
2
+
1
3
  from pydantic import SecretStr
2
4
  from pydantic.types import NonNegativeInt
3
5
  from pydantic_settings import BaseSettings
4
6
  from pydantic_settings import SettingsConfigDict
5
7
  from sqlalchemy.engine import URL
6
8
 
7
- from ._settings_config import SETTINGS_CONFIG_DICT
8
9
  from fractal_server.types import NonEmptyStr
9
10
 
11
+ from ._settings_config import SETTINGS_CONFIG_DICT
12
+
10
13
 
11
14
  class DatabaseSettings(BaseSettings):
12
15
  """
13
16
  Minimal set of configurations needed for operating on the database (e.g
14
17
  for schema migrations).
18
+
19
+ Attributes:
20
+ DB_ECHO:
21
+ If `"true"`, make database operations verbose.
22
+ POSTGRES_USER:
23
+ User to use when connecting to the PostgreSQL database.
24
+ POSTGRES_PASSWORD:
25
+ Password to use when connecting to the PostgreSQL database.
26
+ POSTGRES_HOST:
27
+ URL to the PostgreSQL server or path to a UNIX domain socket.
28
+ POSTGRES_PORT:
29
+ Port number to use when connecting to the PostgreSQL server.
30
+ POSTGRES_DB:
31
+ Name of the PostgreSQL database to connect to.
15
32
  """
16
33
 
17
34
  model_config = SettingsConfigDict(**SETTINGS_CONFIG_DICT)
18
35
 
19
- DB_ECHO: bool = False
20
- """
21
- If `True`, make database operations verbose.
22
- """
36
+ DB_ECHO: Literal["true", "false"] = "false"
23
37
  POSTGRES_USER: NonEmptyStr | None = None
24
- """
25
- User to use when connecting to the PostgreSQL database.
26
- """
27
38
  POSTGRES_PASSWORD: SecretStr | None = None
28
- """
29
- Password to use when connecting to the PostgreSQL database.
30
- """
31
39
  POSTGRES_HOST: NonEmptyStr = "localhost"
32
- """
33
- URL to the PostgreSQL server or path to a UNIX domain socket.
34
- """
35
40
  POSTGRES_PORT: NonNegativeInt = 5432
36
- """
37
- Port number to use when connecting to the PostgreSQL server.
38
- """
39
41
  POSTGRES_DB: NonEmptyStr
40
- """
41
- Name of the PostgreSQL database to connect to.
42
- """
43
42
 
44
43
  @property
45
44
  def DATABASE_URL(self) -> URL:
@@ -4,8 +4,8 @@ from typing import Self
4
4
  from pydantic import BaseModel
5
5
  from pydantic import EmailStr
6
6
  from pydantic import Field
7
- from pydantic import model_validator
8
7
  from pydantic import SecretStr
8
+ from pydantic import model_validator
9
9
  from pydantic_settings import BaseSettings
10
10
  from pydantic_settings import SettingsConfigDict
11
11
 
@@ -17,14 +17,14 @@ class PublicEmailSettings(BaseModel):
17
17
  Schema for `EmailSettings.public`, namely the ready-to-use settings.
18
18
 
19
19
  Attributes:
20
- sender: Sender email address
21
- recipients: List of recipients email address
22
- smtp_server: SMTP server address
23
- port: SMTP server port
24
- password: Sender password
25
- instance_name: Name of SMTP server instance
26
- use_starttls: Whether to use the security protocol
27
- use_login: Whether to use login
20
+ sender: Sender email address.
21
+ recipients: List of recipients email address.
22
+ smtp_server: SMTP server address.
23
+ port: SMTP server port.
24
+ password: Sender password.
25
+ instance_name: Name of SMTP server instance.
26
+ use_starttls: Whether to use the security protocol.
27
+ use_login: Whether to use login.
28
28
  """
29
29
 
30
30
  sender: EmailStr
@@ -40,50 +40,42 @@ class PublicEmailSettings(BaseModel):
40
40
  class EmailSettings(BaseSettings):
41
41
  """
42
42
  Class with settings for email-sending feature.
43
+
44
+ Attributes:
45
+ FRACTAL_EMAIL_SENDER:
46
+ Address of the OAuth-signup email sender.
47
+ FRACTAL_EMAIL_PASSWORD:
48
+ Password for the OAuth-signup email sender.
49
+ FRACTAL_EMAIL_SMTP_SERVER:
50
+ SMTP server for the OAuth-signup emails.
51
+ FRACTAL_EMAIL_SMTP_PORT:
52
+ SMTP server port for the OAuth-signup emails.
53
+ FRACTAL_EMAIL_INSTANCE_NAME:
54
+ Fractal instance name, to be included in the OAuth-signup emails.
55
+ FRACTAL_EMAIL_RECIPIENTS:
56
+ Comma-separated list of recipients of the OAuth-signup emails.
57
+ FRACTAL_EMAIL_USE_STARTTLS:
58
+ Whether to use StartTLS when using the SMTP server.
59
+ FRACTAL_EMAIL_USE_LOGIN:
60
+ Whether to use login when using the SMTP server.
61
+ If 'true', FRACTAL_EMAIL_PASSWORD must be provided.
43
62
  """
44
63
 
45
64
  model_config = SettingsConfigDict(**SETTINGS_CONFIG_DICT)
46
65
 
47
66
  FRACTAL_EMAIL_SENDER: EmailStr | None = None
48
- """
49
- Address of the OAuth-signup email sender.
50
- """
51
67
  FRACTAL_EMAIL_PASSWORD: SecretStr | None = None
52
- """
53
- Password for the OAuth-signup email sender.
54
- """
55
68
  FRACTAL_EMAIL_SMTP_SERVER: str | None = None
56
- """
57
- SMTP server for the OAuth-signup emails.
58
- """
59
69
  FRACTAL_EMAIL_SMTP_PORT: int | None = None
60
- """
61
- SMTP server port for the OAuth-signup emails.
62
- """
63
70
  FRACTAL_EMAIL_INSTANCE_NAME: str | None = None
64
- """
65
- Fractal instance name, to be included in the OAuth-signup emails.
66
- """
67
71
  FRACTAL_EMAIL_RECIPIENTS: str | None = None
68
- """
69
- Comma-separated list of recipients of the OAuth-signup emails.
70
- """
71
72
  FRACTAL_EMAIL_USE_STARTTLS: Literal["true", "false"] = "true"
72
- """
73
- Whether to use StartTLS when using the SMTP server.
74
- Accepted values: 'true', 'false'.
75
- """
76
73
  FRACTAL_EMAIL_USE_LOGIN: Literal["true", "false"] = "true"
77
- """
78
- Whether to use login when using the SMTP server.
79
- If 'true', FRACTAL_EMAIL_PASSWORD must be provided.
80
- Accepted values: 'true', 'false'.
81
- """
82
74
 
83
75
  public: PublicEmailSettings | None = None
84
76
  """
85
- The validated field which is actually used in `fractal-server
86
- (automatically populated upon creation).
77
+ The validated field which is actually used in `fractal-server`,
78
+ automatically populated upon creation.
87
79
  """
88
80
 
89
81
  @model_validator(mode="after")
@@ -11,68 +11,49 @@ from ._settings_config import SETTINGS_CONFIG_DICT
11
11
 
12
12
  class Settings(BaseSettings):
13
13
  """
14
- Contains all the configuration variables for Fractal Server
15
-
16
- The attributes of this class are set from the environment.
14
+ Contains the general configuration variables for Fractal Server.
15
+
16
+ Attributes:
17
+ JWT_EXPIRE_SECONDS:
18
+ JWT token lifetime, in seconds.
19
+ JWT_SECRET_KEY:
20
+ JWT secret.<br>
21
+ ⚠️ Set this variable to a secure string, and do not disclose it.
22
+ COOKIE_EXPIRE_SECONDS:
23
+ Cookie token lifetime, in seconds.
24
+ FRACTAL_RUNNER_BACKEND:
25
+ Select which runner backend to use.
26
+ FRACTAL_LOGGING_LEVEL:
27
+ Logging-level threshold for logging
28
+ Only logs of with this level (or higher) will appear in the console
29
+ logs.
30
+ FRACTAL_API_MAX_JOB_LIST_LENGTH:
31
+ Number of ids that can be stored in the `jobsV2` attribute of
32
+ `app.state`.
33
+ FRACTAL_GRACEFUL_SHUTDOWN_TIME:
34
+ Waiting time for the shutdown phase of executors, in seconds.
35
+ FRACTAL_HELP_URL:
36
+ The URL of an instance-specific Fractal help page.
37
+ FRACTAL_DEFAULT_GROUP_NAME:
38
+ Name of the default user group.
39
+
40
+ If set to `"All"`, then the user group with that name is a special
41
+ user group (e.g. it cannot be deleted, and new users are
42
+ automatically added to it). If set to `None` (the default value),
43
+ then user groups are all equivalent, independently on their name.
17
44
  """
18
45
 
19
46
  model_config = SettingsConfigDict(**SETTINGS_CONFIG_DICT)
20
47
 
21
48
  JWT_EXPIRE_SECONDS: int = 180
22
- """
23
- JWT token lifetime, in seconds.
24
- """
25
-
26
49
  JWT_SECRET_KEY: SecretStr
27
- """
28
- JWT secret
29
-
30
- ⚠️ **IMPORTANT**: set this variable to a secure string, and do not disclose
31
- it.
32
- """
33
-
34
50
  COOKIE_EXPIRE_SECONDS: int = 86400
35
- """
36
- Cookie token lifetime, in seconds.
37
- """
38
-
39
51
  # Note: we do not use ResourceType here to avoid circular imports
40
- FRACTAL_RUNNER_BACKEND: Literal[
41
- "local", "slurm_ssh", "slurm_sudo"
42
- ] = "local"
43
- """
44
- Select which runner backend to use.
45
- """
46
-
52
+ FRACTAL_RUNNER_BACKEND: Literal["local", "slurm_ssh", "slurm_sudo"] = (
53
+ "local"
54
+ )
47
55
  FRACTAL_LOGGING_LEVEL: int = logging.INFO
48
- """
49
- Logging-level threshold for logging
50
-
51
- Only logs of with this level (or higher) will appear in the console logs.
52
- """
53
-
54
56
  FRACTAL_API_MAX_JOB_LIST_LENGTH: int = 25
55
- """
56
- Number of ids that can be stored in the `jobsV2` attribute of
57
- `app.state`.
58
- """
59
-
60
57
  FRACTAL_GRACEFUL_SHUTDOWN_TIME: float = 30.0
61
- """
62
- Waiting time for the shutdown phase of executors
63
- """
64
-
65
58
  FRACTAL_HELP_URL: HttpUrl | None = None
66
- """
67
- The URL of an instance-specific Fractal help page.
68
- """
69
-
70
59
  FRACTAL_DEFAULT_GROUP_NAME: Literal["All"] | None = None
71
- """
72
- Name of the default user group.
73
-
74
- If set to `"All"`, then the user group with that name is a special user
75
- group (e.g. it cannot be deleted, and new users are automatically added
76
- to it). If set to `None` (the default value), then user groups are all
77
- equivalent, independently on their name.
78
- """
@@ -1,20 +1,33 @@
1
1
  from typing import Annotated
2
2
  from typing import Self
3
3
 
4
- from pydantic import model_validator
5
4
  from pydantic import SecretStr
6
5
  from pydantic import StringConstraints
6
+ from pydantic import model_validator
7
7
  from pydantic_settings import BaseSettings
8
8
  from pydantic_settings import SettingsConfigDict
9
9
 
10
- from ._settings_config import SETTINGS_CONFIG_DICT
11
10
  from fractal_server.types import NonEmptyStr
12
11
 
12
+ from ._settings_config import SETTINGS_CONFIG_DICT
13
+
13
14
 
14
15
  class OAuthSettings(BaseSettings):
15
16
  """
16
- Minimal set of configurations needed for operating on the database (e.g
17
- for schema migrations).
17
+ Settings for integration with an OAuth identity provider.
18
+
19
+ Attributes:
20
+ OAUTH_CLIENT_NAME: Name of the client.
21
+ OAUTH_CLIENT_ID: ID of client.
22
+ OAUTH_CLIENT_SECRET:
23
+ Secret to authorise against the identity provider.
24
+ OAUTH_OIDC_CONFIG_ENDPOINT:
25
+ OpenID Connect configuration endpoint, for autodiscovery of
26
+ relevant endpoints.
27
+ OAUTH_REDIRECT_URL:
28
+ String to be used as `redirect_url` argument in
29
+ `fastapi_users.get_oauth_router`, and then in
30
+ `httpx_oauth.integrations.fastapi.OAuth2AuthorizeCallback`.
18
31
  """
19
32
 
20
33
  model_config = SettingsConfigDict(**SETTINGS_CONFIG_DICT)
@@ -26,27 +39,10 @@ class OAuthSettings(BaseSettings):
26
39
  ]
27
40
  | None
28
41
  ) = None
29
- """
30
- The name of the client.
31
- """
32
42
  OAUTH_CLIENT_ID: SecretStr | None = None
33
- """
34
- ID of client.
35
- """
36
43
  OAUTH_CLIENT_SECRET: SecretStr | None = None
37
- """
38
- Secret to authorise against the identity provider.
39
- """
40
44
  OAUTH_OIDC_CONFIG_ENDPOINT: SecretStr | None = None
41
- """
42
- OpenID configuration endpoint, for autodiscovery of relevant endpoints.
43
- """
44
45
  OAUTH_REDIRECT_URL: str | None = None
45
- """
46
- String to be used as `redirect_url` argument in
47
- `fastapi_users.get_oauth_router`, and then in
48
- `httpx_oauth.integrations.fastapi.OAuth2AuthorizeCallback`
49
- """
50
46
 
51
47
  @model_validator(mode="after")
52
48
  def check_configuration(self: Self) -> Self:
@@ -1,2 +1,6 @@
1
1
  class UnreachableBranchError(RuntimeError):
2
+ """
3
+ Exception marking a code branch that should have not been reached.
4
+ """
5
+
2
6
  pass
@@ -9,7 +9,7 @@ from fractal_server.types import ZarrDirStr
9
9
  from fractal_server.types import ZarrUrlStr
10
10
 
11
11
 
12
- class _SingleImageBase(BaseModel):
12
+ class SingleImageBase(BaseModel):
13
13
  """
14
14
  Base for SingleImage and SingleImageTaskOutput.
15
15
 
@@ -27,7 +27,7 @@ class _SingleImageBase(BaseModel):
27
27
  types: ImageTypes = Field(default_factory=dict)
28
28
 
29
29
 
30
- class SingleImageTaskOutput(_SingleImageBase):
30
+ class SingleImageTaskOutput(SingleImageBase):
31
31
  """
32
32
  `SingleImageBase`, with scalar `attributes` values (`None` included).
33
33
  """
@@ -35,7 +35,7 @@ class SingleImageTaskOutput(_SingleImageBase):
35
35
  attributes: ImageAttributesWithNone = Field(default_factory=dict)
36
36
 
37
37
 
38
- class SingleImage(_SingleImageBase):
38
+ class SingleImage(SingleImageBase):
39
39
  """
40
40
  `SingleImageBase`, with scalar `attributes` values (`None` excluded).
41
41
  """
@@ -37,10 +37,12 @@ def _prepare_query(
37
37
  """
38
38
  stm = (
39
39
  select(HistoryImageCache.zarr_url, HistoryUnit.status)
40
- .join(HistoryUnit)
40
+ .join(
41
+ HistoryUnit,
42
+ HistoryImageCache.latest_history_unit_id == HistoryUnit.id,
43
+ )
41
44
  .where(HistoryImageCache.dataset_id == dataset_id)
42
45
  .where(HistoryImageCache.workflowtask_id == workflowtask_id)
43
- .where(HistoryImageCache.latest_history_unit_id == HistoryUnit.id)
44
46
  )
45
47
  return stm
46
48
 
fractal_server/logger.py CHANGED
@@ -12,13 +12,13 @@
12
12
  """
13
13
  This module provides logging utilities
14
14
  """
15
+
15
16
  import logging
16
17
  from pathlib import Path
17
18
 
18
19
  from .config import get_settings
19
20
  from .syringe import Inject
20
21
 
21
-
22
22
  LOG_FORMAT = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
23
23
  LOG_FORMATTER = logging.Formatter(LOG_FORMAT)
24
24
 
fractal_server/main.py CHANGED
@@ -4,6 +4,9 @@ from itertools import chain
4
4
 
5
5
  from fastapi import FastAPI
6
6
 
7
+ from fractal_server import __VERSION__
8
+ from fractal_server.app.schemas.v2 import ResourceType
9
+
7
10
  from .app.routes.aux._runner import _backend_supports_shutdown
8
11
  from .app.shutdown import cleanup_after_shutdown
9
12
  from .config import get_data_settings
@@ -15,8 +18,6 @@ from .logger import get_logger
15
18
  from .logger import reset_logger_handlers
16
19
  from .logger import set_logger
17
20
  from .syringe import Inject
18
- from fractal_server import __VERSION__
19
- from fractal_server.app.schemas.v2 import ResourceType
20
21
 
21
22
 
22
23
  def collect_routers(app: FastAPI) -> None:
@@ -27,9 +28,9 @@ def collect_routers(app: FastAPI) -> None:
27
28
  app:
28
29
  The application to register the routers to.
29
30
  """
31
+ from .app.routes.admin.v2 import router_admin_v2
30
32
  from .app.routes.api import router_api
31
33
  from .app.routes.api.v2 import router_api_v2
32
- from .app.routes.admin.v2 import router_admin_v2
33
34
  from .app.routes.auth.router import router_auth
34
35
 
35
36
  app.include_router(router_api, prefix="/api")
@@ -5,6 +5,7 @@ Revises: da2cb2ac4255
5
5
  Create Date: 2024-10-10 16:14:13.976231
6
6
 
7
7
  """
8
+
8
9
  from datetime import datetime
9
10
  from datetime import timezone
10
11
 
@@ -12,7 +13,6 @@ import sqlalchemy as sa
12
13
  import sqlmodel
13
14
  from alembic import op
14
15
 
15
-
16
16
  # revision identifiers, used by Alembic.
17
17
  revision = "034a469ec2eb"
18
18
  down_revision = "da2cb2ac4255"
@@ -26,15 +26,11 @@ def upgrade() -> None:
26
26
  sa.Column("id", sa.Integer(), nullable=False),
27
27
  sa.Column("user_id", sa.Integer(), nullable=False),
28
28
  sa.Column("user_group_id", sa.Integer(), nullable=True),
29
- sa.Column(
30
- "origin", sqlmodel.sql.sqltypes.AutoString(), nullable=False
31
- ),
29
+ sa.Column("origin", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
32
30
  sa.Column(
33
31
  "pkg_name", sqlmodel.sql.sqltypes.AutoString(), nullable=False
34
32
  ),
35
- sa.Column(
36
- "version", sqlmodel.sql.sqltypes.AutoString(), nullable=True
37
- ),
33
+ sa.Column("version", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
38
34
  sa.Column(
39
35
  "python_version", sqlmodel.sql.sqltypes.AutoString(), nullable=True
40
36
  ),
@@ -123,8 +119,8 @@ def upgrade() -> None:
123
119
  except BaseException as e:
124
120
  if op.get_bind().dialect.name != "sqlite":
125
121
  raise e
126
- import sqlite3
127
122
  import logging
123
+ import sqlite3
128
124
 
129
125
  logger = logging.getLogger("alembic.runtime.migration")
130
126
  logger.warning(
@@ -5,11 +5,11 @@ Revises: 5bf02391cfef
5
5
  Create Date: 2024-09-09 13:17:51.008231
6
6
 
7
7
  """
8
+
8
9
  import sqlalchemy as sa
9
10
  import sqlmodel
10
11
  from alembic import op
11
12
 
12
-
13
13
  # revision identifiers, used by Alembic.
14
14
  revision = "091b01f51f88"
15
15
  down_revision = "5bf02391cfef"