fractal-server 2.17.1a0__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 (206) 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 -1
  5. fractal_server/app/models/linkuserproject.py +3 -1
  6. fractal_server/app/models/security.py +22 -17
  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 +5 -14
  14. fractal_server/app/models/v2/resource.py +4 -0
  15. fractal_server/app/models/v2/task_group.py +5 -7
  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/app/shutdown.py +23 -19
  74. fractal_server/config/_data.py +36 -25
  75. fractal_server/config/_database.py +19 -20
  76. fractal_server/config/_email.py +30 -38
  77. fractal_server/config/_main.py +34 -53
  78. fractal_server/config/_oauth.py +17 -21
  79. fractal_server/exceptions.py +4 -0
  80. fractal_server/images/models.py +3 -3
  81. fractal_server/images/status_tools.py +4 -2
  82. fractal_server/logger.py +1 -1
  83. fractal_server/main.py +4 -3
  84. fractal_server/migrations/versions/034a469ec2eb_task_groups.py +4 -8
  85. fractal_server/migrations/versions/091b01f51f88_add_usergroup_and_linkusergroup_table.py +1 -1
  86. fractal_server/migrations/versions/0f5f85bb2ae7_add_pre_pinned_packages.py +1 -0
  87. fractal_server/migrations/versions/19eca0dd47a9_user_settings_project_dir.py +1 -1
  88. fractal_server/migrations/versions/1a83a5260664_rename.py +1 -1
  89. fractal_server/migrations/versions/1eac13a26c83_drop_v1_tables.py +1 -0
  90. fractal_server/migrations/versions/316140ff7ee1_remove_usersettings_cache_dir.py +1 -1
  91. fractal_server/migrations/versions/40d6d6511b20_add_index_to_history_models.py +47 -0
  92. fractal_server/migrations/versions/45fbb391d7af_make_resource_id_fk_non_nullable.py +46 -0
  93. fractal_server/migrations/versions/47351f8c7ebc_drop_dataset_filters.py +1 -0
  94. fractal_server/migrations/versions/49d0856e9569_drop_table.py +62 -0
  95. fractal_server/migrations/versions/4c308bcaea2b_add_task_args_schema_and_task_args_.py +1 -1
  96. fractal_server/migrations/versions/4cedeb448a53_workflowtask_foreign_keys_not_nullables.py +1 -1
  97. fractal_server/migrations/versions/501961cfcd85_remove_link_between_v1_and_v2_tasks_.py +2 -1
  98. fractal_server/migrations/versions/50a13d6138fd_initial_schema.py +7 -19
  99. fractal_server/migrations/versions/5bf02391cfef_v2.py +4 -10
  100. fractal_server/migrations/versions/70e77f1c38b0_add_applyworkflow_first_task_index_and_.py +1 -0
  101. fractal_server/migrations/versions/71eefd1dd202_add_slurm_accounts.py +1 -1
  102. fractal_server/migrations/versions/7673fe18c05d_remove_project_dir_server_default.py +29 -0
  103. fractal_server/migrations/versions/791ce783d3d8_add_indices.py +1 -1
  104. fractal_server/migrations/versions/83bc2ad3ffcc_2_17_0.py +1 -0
  105. fractal_server/migrations/versions/84bf0fffde30_add_dumps_to_applyworkflow.py +1 -0
  106. fractal_server/migrations/versions/8e8f227a3e36_update_taskv2_post_2_7_0.py +2 -4
  107. fractal_server/migrations/versions/8f79bd162e35_add_docs_info_and_docs_link_to_task_.py +1 -1
  108. fractal_server/migrations/versions/94a47ea2d3ff_remove_cache_dir_slurm_user_and_slurm_.py +1 -0
  109. fractal_server/migrations/versions/969d84257cac_add_historyrun_task_id.py +1 -1
  110. fractal_server/migrations/versions/97f444d47249_add_applyworkflow_project_dump.py +1 -1
  111. fractal_server/migrations/versions/981d588fe248_add_executor_error_log.py +1 -1
  112. fractal_server/migrations/versions/99ea79d9e5d2_add_dataset_history.py +2 -4
  113. fractal_server/migrations/versions/9c5ae74c9b98_add_user_settings_table.py +1 -1
  114. fractal_server/migrations/versions/9db60297b8b2_set_ondelete.py +1 -1
  115. fractal_server/migrations/versions/9fd26a2b0de4_add_workflow_timestamp_created.py +1 -1
  116. fractal_server/migrations/versions/a7f4d6137b53_add_workflow_dump_to_applyworkflow.py +1 -1
  117. fractal_server/migrations/versions/af1ef1c83c9b_add_accounting_tables.py +1 -0
  118. fractal_server/migrations/versions/af8673379a5c_drop_old_filter_columns.py +1 -0
  119. fractal_server/migrations/versions/b1e7f7a1ff71_task_group_for_pixi.py +1 -1
  120. fractal_server/migrations/versions/b3ffb095f973_json_to_jsonb.py +1 -0
  121. fractal_server/migrations/versions/c90a7c76e996_job_id_in_history_run.py +1 -1
  122. fractal_server/migrations/versions/caba9fb1ea5e_drop_useroauth_user_settings_id.py +49 -0
  123. fractal_server/migrations/versions/d256a7379ab8_taskgroup_activity_and_venv_info_to_.py +4 -9
  124. fractal_server/migrations/versions/d4fe3708d309_make_applyworkflow_workflow_dump_non_.py +1 -0
  125. fractal_server/migrations/versions/da2cb2ac4255_user_group_viewer_paths.py +1 -1
  126. fractal_server/migrations/versions/db09233ad13a_split_filters_and_keep_old_columns.py +1 -0
  127. fractal_server/migrations/versions/e0e717ae2f26_delete_linkuserproject_ondelete_project.py +50 -0
  128. fractal_server/migrations/versions/e75cac726012_make_applyworkflow_start_timestamp_not_.py +1 -0
  129. fractal_server/migrations/versions/e81103413827_add_job_type_filters.py +1 -1
  130. fractal_server/migrations/versions/efa89c30e0a4_add_project_timestamp_created.py +1 -0
  131. fractal_server/migrations/versions/f37aceb45062_make_historyunit_logfile_required.py +1 -1
  132. fractal_server/migrations/versions/f384e1c0cf5d_drop_task_default_args_columns.py +1 -0
  133. fractal_server/migrations/versions/fbce16ff4e47_new_history_items.py +4 -9
  134. fractal_server/runner/config/_local.py +8 -5
  135. fractal_server/runner/config/_slurm.py +37 -33
  136. fractal_server/runner/config/slurm_mem_to_MB.py +0 -1
  137. fractal_server/runner/executors/base_runner.py +29 -4
  138. fractal_server/runner/executors/local/get_local_config.py +1 -0
  139. fractal_server/runner/executors/local/runner.py +14 -13
  140. fractal_server/runner/executors/slurm_common/_batching.py +5 -10
  141. fractal_server/runner/executors/slurm_common/base_slurm_runner.py +53 -27
  142. fractal_server/runner/executors/slurm_common/get_slurm_config.py +14 -7
  143. fractal_server/runner/executors/slurm_common/remote.py +3 -1
  144. fractal_server/runner/executors/slurm_common/slurm_config.py +1 -0
  145. fractal_server/runner/executors/slurm_common/slurm_job_task_models.py +1 -3
  146. fractal_server/runner/executors/slurm_ssh/runner.py +16 -11
  147. fractal_server/runner/executors/slurm_ssh/tar_commands.py +1 -0
  148. fractal_server/runner/executors/slurm_sudo/_subprocess_run_as_user.py +1 -0
  149. fractal_server/runner/executors/slurm_sudo/runner.py +16 -11
  150. fractal_server/runner/task_files.py +9 -3
  151. fractal_server/runner/v2/_local.py +9 -4
  152. fractal_server/runner/v2/_slurm_ssh.py +11 -5
  153. fractal_server/runner/v2/_slurm_sudo.py +11 -5
  154. fractal_server/runner/v2/db_tools.py +0 -1
  155. fractal_server/runner/v2/deduplicate_list.py +2 -1
  156. fractal_server/runner/v2/runner.py +11 -14
  157. fractal_server/runner/v2/runner_functions.py +11 -14
  158. fractal_server/runner/v2/submit_workflow.py +7 -6
  159. fractal_server/ssh/_fabric.py +6 -13
  160. fractal_server/string_tools.py +0 -1
  161. fractal_server/syringe.py +1 -1
  162. fractal_server/tasks/config/_pixi.py +1 -1
  163. fractal_server/tasks/config/_python.py +16 -9
  164. fractal_server/tasks/utils.py +0 -1
  165. fractal_server/tasks/v2/local/_utils.py +1 -1
  166. fractal_server/tasks/v2/local/collect.py +10 -12
  167. fractal_server/tasks/v2/local/collect_pixi.py +9 -10
  168. fractal_server/tasks/v2/local/deactivate.py +7 -8
  169. fractal_server/tasks/v2/local/deactivate_pixi.py +4 -4
  170. fractal_server/tasks/v2/local/delete.py +1 -3
  171. fractal_server/tasks/v2/local/reactivate.py +7 -7
  172. fractal_server/tasks/v2/local/reactivate_pixi.py +7 -7
  173. fractal_server/tasks/v2/ssh/_utils.py +3 -3
  174. fractal_server/tasks/v2/ssh/collect.py +14 -19
  175. fractal_server/tasks/v2/ssh/collect_pixi.py +17 -19
  176. fractal_server/tasks/v2/ssh/deactivate.py +10 -8
  177. fractal_server/tasks/v2/ssh/deactivate_pixi.py +6 -5
  178. fractal_server/tasks/v2/ssh/delete.py +7 -5
  179. fractal_server/tasks/v2/ssh/reactivate.py +11 -11
  180. fractal_server/tasks/v2/ssh/reactivate_pixi.py +8 -9
  181. fractal_server/tasks/v2/templates/1_create_venv.sh +2 -0
  182. fractal_server/tasks/v2/templates/2_pip_install.sh +2 -0
  183. fractal_server/tasks/v2/templates/3_pip_freeze.sh +2 -0
  184. fractal_server/tasks/v2/templates/4_pip_show.sh +2 -0
  185. fractal_server/tasks/v2/templates/5_get_venv_size_and_file_number.sh +3 -1
  186. fractal_server/tasks/v2/templates/6_pip_install_from_freeze.sh +2 -0
  187. fractal_server/tasks/v2/templates/pixi_1_extract.sh +2 -0
  188. fractal_server/tasks/v2/templates/pixi_2_install.sh +2 -0
  189. fractal_server/tasks/v2/templates/pixi_3_post_install.sh +2 -0
  190. fractal_server/tasks/v2/utils_background.py +3 -3
  191. fractal_server/tasks/v2/utils_package_names.py +1 -2
  192. fractal_server/tasks/v2/utils_pixi.py +1 -3
  193. fractal_server/types/__init__.py +76 -1
  194. fractal_server/types/validators/_common_validators.py +1 -3
  195. fractal_server/types/validators/_workflow_task_arguments_validators.py +1 -2
  196. fractal_server/utils.py +1 -0
  197. fractal_server/zip_tools.py +34 -0
  198. {fractal_server-2.17.1a0.dist-info → fractal_server-2.17.2.dist-info}/METADATA +1 -1
  199. fractal_server-2.17.2.dist-info/RECORD +265 -0
  200. fractal_server/app/models/user_settings.py +0 -37
  201. fractal_server/app/routes/admin/v2/project.py +0 -41
  202. fractal_server/data_migrations/2_17_0.py +0 -339
  203. fractal_server-2.17.1a0.dist-info/RECORD +0 -262
  204. {fractal_server-2.17.1a0.dist-info → fractal_server-2.17.2.dist-info}/WHEEL +0 -0
  205. {fractal_server-2.17.1a0.dist-info → fractal_server-2.17.2.dist-info}/entry_points.txt +0 -0
  206. {fractal_server-2.17.1a0.dist-info → fractal_server-2.17.2.dist-info}/licenses/LICENSE +0 -0
@@ -1 +1 @@
1
- __VERSION__ = "2.17.1a0"
1
+ __VERSION__ = "2.17.2"
@@ -7,7 +7,6 @@ from pathlib import Path
7
7
  import uvicorn
8
8
  from pydantic import ValidationError
9
9
 
10
-
11
10
  parser = ap.ArgumentParser(description="fractal-server commands")
12
11
 
13
12
  subparsers = parser.add_subparsers(title="Commands", dest="cmd", required=True)
@@ -48,9 +47,7 @@ openapi_parser.add_argument(
48
47
  # fractalctl set-db
49
48
  set_db_parser = subparsers.add_parser(
50
49
  "set-db",
51
- description=(
52
- "Initialise/upgrade database schemas and create first group&user."
53
- ),
50
+ description="Initialise/upgrade database schemas.",
54
51
  )
55
52
 
56
53
  # fractalctl init-db-data
@@ -114,12 +111,13 @@ def set_db():
114
111
  Call alembic to upgrade to the latest migration.
115
112
  Ref: https://stackoverflow.com/a/56683030/283972
116
113
  """
117
- from fractal_server.syringe import Inject
118
- from fractal_server.config import get_db_settings
114
+ from pathlib import Path
119
115
 
120
116
  import alembic.config
121
- from pathlib import Path
117
+
122
118
  import fractal_server
119
+ from fractal_server.config import get_db_settings
120
+ from fractal_server.syringe import Inject
123
121
 
124
122
  # Validate DB settings
125
123
  Inject(get_db_settings)
@@ -140,15 +138,18 @@ def init_db_data(
140
138
  admin_password: str | None = None,
141
139
  admin_project_dir: str | None = None,
142
140
  ) -> None:
143
- from fractal_server.app.security import _create_first_user
144
- from fractal_server.app.security import _create_first_group
141
+ from sqlalchemy import func
142
+ from sqlalchemy import select
143
+
145
144
  from fractal_server.app.db import get_sync_db
146
- from sqlalchemy import select, func
145
+ from fractal_server.app.models import Profile
146
+ from fractal_server.app.models import Resource
147
147
  from fractal_server.app.models.security import UserOAuth
148
- from fractal_server.app.models import Resource, Profile
149
- from fractal_server.app.schemas.v2.resource import cast_serialize_resource
150
- from fractal_server.app.schemas.v2.profile import cast_serialize_profile
151
148
  from fractal_server.app.schemas.v2 import ResourceType
149
+ from fractal_server.app.schemas.v2.profile import cast_serialize_profile
150
+ from fractal_server.app.schemas.v2.resource import cast_serialize_resource
151
+ from fractal_server.app.security import _create_first_group
152
+ from fractal_server.app.security import _create_first_user
152
153
 
153
154
  # Create default group and user
154
155
  print()
@@ -185,9 +186,7 @@ def init_db_data(
185
186
  if resource and profile:
186
187
  with next(get_sync_db()) as db:
187
188
  # Preliminary check
188
- num_resources = db.execute(
189
- select(func.count(Resource.id))
190
- ).scalar()
189
+ num_resources = db.execute(select(func.count(Resource.id))).scalar()
191
190
  if num_resources != 0:
192
191
  print(f"There exist already {num_resources=} resources. Exit.")
193
192
  sys.exit(1)
@@ -270,10 +269,12 @@ def update_db_data():
270
269
  Apply data migrations.
271
270
  """
272
271
 
273
- import fractal_server
272
+ import os
274
273
  from importlib import import_module
274
+
275
275
  from packaging.version import parse
276
- import os
276
+
277
+ import fractal_server
277
278
 
278
279
  def _slugify_version(raw_version: str) -> str:
279
280
  v = parse(raw_version)
@@ -2,6 +2,7 @@
2
2
  `db` module, loosely adapted from
3
3
  https://testdriven.io/blog/fastapi-sqlmodel/#async-sqlmodel
4
4
  """
5
+
5
6
  from collections.abc import AsyncGenerator
6
7
  from collections.abc import Generator
7
8
 
@@ -15,7 +16,6 @@ from fractal_server.config import get_db_settings
15
16
  from fractal_server.logger import set_logger
16
17
  from fractal_server.syringe import Inject
17
18
 
18
-
19
19
  logger = set_logger(__name__)
20
20
 
21
21
 
@@ -46,7 +46,7 @@ class DB:
46
46
 
47
47
  cls._engine_async = create_async_engine(
48
48
  db_settings.DATABASE_URL,
49
- echo=db_settings.DB_ECHO,
49
+ echo=(db_settings.DB_ECHO == "true"),
50
50
  future=True,
51
51
  pool_pre_ping=True,
52
52
  )
@@ -63,7 +63,7 @@ class DB:
63
63
 
64
64
  cls._engine_sync = create_engine(
65
65
  db_settings.DATABASE_URL,
66
- echo=db_settings.DB_ECHO,
66
+ echo=(db_settings.DB_ECHO == "true"),
67
67
  future=True,
68
68
  pool_pre_ping=True,
69
69
  )
@@ -3,8 +3,8 @@ Note that this module is imported from `fractal_server/migrations/env.py`,
3
3
  thus we should always export all relevant database models from here or they
4
4
  will not be picked up by alembic.
5
5
  """
6
+
6
7
  from .linkusergroup import LinkUserGroup # noqa: F401
7
8
  from .linkuserproject import LinkUserProjectV2 # noqa: F401
8
9
  from .security import * # noqa
9
- from .user_settings import UserSettings # noqa
10
10
  from .v2 import * # noqa
@@ -7,5 +7,7 @@ class LinkUserProjectV2(SQLModel, table=True):
7
7
  Crossing table between User and ProjectV2
8
8
  """
9
9
 
10
- project_id: int = Field(foreign_key="projectv2.id", primary_key=True)
10
+ project_id: int = Field(
11
+ foreign_key="projectv2.id", primary_key=True, ondelete="CASCADE"
12
+ )
11
13
  user_id: int = Field(foreign_key="user_oauth.id", primary_key=True)
@@ -52,21 +52,39 @@ class UserOAuth(SQLModel, table=True):
52
52
  """
53
53
  ORM model for the `user_oauth` database table.
54
54
 
55
- This class is a modification of SQLModelBaseUserDB from from
56
- fastapi_users_db_sqlmodel. Original Copyright: 2022 François Voron,
57
- released under MIT licence.
55
+ This class is a modification of
56
+ [`SQLModelBaseUserDB`](https://github.com/fastapi-users/fastapi-users-db-sqlmodel/blob/83980d7f20886120f4636a102ab1822b4c366f63/fastapi_users_db_sqlmodel/__init__.py#L15-L32)
57
+ from `fastapi_users_db_sqlmodel`.
58
+ Original Copyright: 2022 François Voron, released under MIT licence.
59
+
60
+ Note that several class attributes are
61
+ [the default ones from `fastapi-users`
62
+ ](https://fastapi-users.github.io/fastapi-users/latest/configuration/schemas/).
58
63
 
59
64
  Attributes:
60
65
  id:
61
66
  email:
62
67
  hashed_password:
63
68
  is_active:
69
+ If this is `False`, the user has no access to the `/api/v2/`
70
+ endpoints.
64
71
  is_superuser:
65
72
  is_verified:
73
+ If this is `False`, the user has no access to the `/api/v2/`
74
+ endpoints.
66
75
  oauth_accounts:
67
76
  profile_id:
77
+ Foreign key linking the user to a `Profile`. If this is unset,
78
+ the user has no access to the `/api/v2/` endpoints.
68
79
  project_dir:
80
+ Absolute path of the user's project directory. This is used (A) as
81
+ a default base folder for the `zarr_dir` of new datasets (where
82
+ the output Zarr are located), and (B) as a folder which is included
83
+ by default in the paths that a user is allowed to stream (if the
84
+ `fractal-data` integration is set up).
85
+ two goals:
69
86
  slurm_accounts:
87
+ List of SLURM accounts that the user can select upon running a job.
70
88
  """
71
89
 
72
90
  model_config = ConfigDict(from_attributes=True)
@@ -95,24 +113,11 @@ class UserOAuth(SQLModel, table=True):
95
113
  ondelete="RESTRICT",
96
114
  )
97
115
 
98
- # TODO-2.17.1: update to `project_dir: str`
99
- project_dir: str = Field(
100
- sa_column=Column(
101
- String,
102
- server_default="/PLACEHOLDER",
103
- nullable=False,
104
- )
105
- )
116
+ project_dir: str
106
117
  slurm_accounts: list[str] = Field(
107
118
  sa_column=Column(ARRAY(String), server_default="{}"),
108
119
  )
109
120
 
110
- # TODO-2.17.1: remove
111
- user_settings_id: int | None = Field(
112
- foreign_key="user_settings.id",
113
- default=None,
114
- )
115
-
116
121
 
117
122
  class UserGroup(SQLModel, table=True):
118
123
  """
@@ -1,7 +1,9 @@
1
1
  """
2
2
  v2 `models` module
3
3
  """
4
- from ..linkuserproject import LinkUserProjectV2
4
+
5
+ from fractal_server.app.models.linkuserproject import LinkUserProjectV2
6
+
5
7
  from .accounting import AccountingRecord
6
8
  from .accounting import AccountingRecordSlurm
7
9
  from .dataset import DatasetV2
@@ -7,10 +7,14 @@ from sqlalchemy.types import DateTime
7
7
  from sqlmodel import Field
8
8
  from sqlmodel import SQLModel
9
9
 
10
- from ....utils import get_timestamp
10
+ from fractal_server.utils import get_timestamp
11
11
 
12
12
 
13
13
  class AccountingRecord(SQLModel, table=True):
14
+ """
15
+ AccountingRecord table.
16
+ """
17
+
14
18
  id: int | None = Field(default=None, primary_key=True)
15
19
  user_id: int = Field(foreign_key="user_oauth.id", nullable=False)
16
20
  timestamp: datetime = Field(
@@ -22,6 +26,10 @@ class AccountingRecord(SQLModel, table=True):
22
26
 
23
27
 
24
28
  class AccountingRecordSlurm(SQLModel, table=True):
29
+ """
30
+ AccountingRecordSlurm table.
31
+ """
32
+
25
33
  id: int | None = Field(default=None, primary_key=True)
26
34
  user_id: int = Field(foreign_key="user_oauth.id", nullable=False)
27
35
  timestamp: datetime = Field(
@@ -9,10 +9,14 @@ from sqlmodel import Field
9
9
  from sqlmodel import Relationship
10
10
  from sqlmodel import SQLModel
11
11
 
12
- from ....utils import get_timestamp
12
+ from fractal_server.utils import get_timestamp
13
13
 
14
14
 
15
15
  class DatasetV2(SQLModel, table=True):
16
+ """
17
+ Dataset table.
18
+ """
19
+
16
20
  model_config = ConfigDict(arbitrary_types_allowed=True)
17
21
 
18
22
  id: int | None = Field(default=None, primary_key=True)
@@ -10,10 +10,14 @@ from sqlalchemy.types import DateTime
10
10
  from sqlmodel import Field
11
11
  from sqlmodel import SQLModel
12
12
 
13
- from ....utils import get_timestamp
13
+ from fractal_server.utils import get_timestamp
14
14
 
15
15
 
16
16
  class HistoryRun(SQLModel, table=True):
17
+ """
18
+ HistoryRun table.
19
+ """
20
+
17
21
  model_config = ConfigDict(arbitrary_types_allowed=True)
18
22
 
19
23
  id: int | None = Field(default=None, primary_key=True)
@@ -45,10 +49,15 @@ class HistoryRun(SQLModel, table=True):
45
49
 
46
50
 
47
51
  class HistoryUnit(SQLModel, table=True):
52
+ """
53
+ HistoryUnit table.
54
+ """
55
+
48
56
  id: int | None = Field(default=None, primary_key=True)
49
57
  history_run_id: int = Field(
50
58
  foreign_key="historyrun.id",
51
59
  ondelete="CASCADE",
60
+ index=True,
52
61
  )
53
62
 
54
63
  logfile: str
@@ -60,6 +69,10 @@ class HistoryUnit(SQLModel, table=True):
60
69
 
61
70
 
62
71
  class HistoryImageCache(SQLModel, table=True):
72
+ """
73
+ HistoryImageCache table.
74
+ """
75
+
63
76
  zarr_url: str = Field(primary_key=True)
64
77
  dataset_id: int = Field(
65
78
  primary_key=True,
@@ -77,4 +90,5 @@ class HistoryImageCache(SQLModel, table=True):
77
90
  latest_history_unit_id: int = Field(
78
91
  foreign_key="historyunit.id",
79
92
  ondelete="CASCADE",
93
+ index=True,
80
94
  )
@@ -13,6 +13,10 @@ from fractal_server.utils import get_timestamp
13
13
 
14
14
 
15
15
  class JobV2(SQLModel, table=True):
16
+ """
17
+ Job table.
18
+ """
19
+
16
20
  model_config = ConfigDict(arbitrary_types_allowed=True)
17
21
 
18
22
  id: int | None = Field(default=None, primary_key=True)
@@ -3,14 +3,43 @@ from sqlmodel import SQLModel
3
3
 
4
4
 
5
5
  class Profile(SQLModel, table=True):
6
+ """
7
+ Profile table.
8
+ """
9
+
6
10
  id: int | None = Field(default=None, primary_key=True)
11
+
7
12
  resource_id: int = Field(foreign_key="resource.id", ondelete="RESTRICT")
13
+
8
14
  resource_type: str
15
+ """
16
+ Type of resource (either `local`, `slurm_sudo` or `slurm_ssh`).
17
+ """
9
18
 
10
19
  name: str = Field(unique=True)
20
+ """
21
+ Profile name.
22
+ """
11
23
 
12
24
  username: str | None = None
25
+ """
26
+ Username to be impersonated, either via `sudo -u` or via `ssh`.
27
+ """
28
+
13
29
  ssh_key_path: str | None = None
30
+ """
31
+ Path to the private SSH key of user `username` (only relevant if
32
+ `resource_type="slurm_ssh"`).
33
+ """
14
34
 
15
35
  jobs_remote_dir: str | None = None
36
+ """
37
+ Remote path of the job folder (only relevant if
38
+ `resource_type="slurm_ssh"`).
39
+ """
40
+
16
41
  tasks_remote_dir: str | None = None
42
+ """
43
+ Remote path of the task folder (only relevant if
44
+ `resource_type="slurm_ssh"`).
45
+ """
@@ -3,30 +3,21 @@ from datetime import datetime
3
3
  from sqlalchemy import Column
4
4
  from sqlalchemy.types import DateTime
5
5
  from sqlmodel import Field
6
- from sqlmodel import Relationship
7
6
  from sqlmodel import SQLModel
8
7
 
9
- from .. import LinkUserProjectV2
10
- from fractal_server.app.models import UserOAuth
11
8
  from fractal_server.utils import get_timestamp
12
9
 
13
10
 
14
11
  class ProjectV2(SQLModel, table=True):
12
+ """
13
+ Project table.
14
+ """
15
+
15
16
  id: int | None = Field(default=None, primary_key=True)
16
17
  name: str
17
18
 
18
- # TODO-2.17.1: make `resource_id` not nullable
19
- resource_id: int | None = Field(
20
- foreign_key="resource.id", default=None, ondelete="RESTRICT"
21
- )
19
+ resource_id: int = Field(foreign_key="resource.id", ondelete="RESTRICT")
22
20
  timestamp_created: datetime = Field(
23
21
  default_factory=get_timestamp,
24
22
  sa_column=Column(DateTime(timezone=True), nullable=False),
25
23
  )
26
-
27
- user_list: list[UserOAuth] = Relationship(
28
- link_model=LinkUserProjectV2,
29
- sa_relationship_kwargs={
30
- "lazy": "selectin",
31
- },
32
- )
@@ -13,6 +13,10 @@ from fractal_server.utils import get_timestamp
13
13
 
14
14
 
15
15
  class Resource(SQLModel, table=True):
16
+ """
17
+ Resource table.
18
+ """
19
+
16
20
  id: int | None = Field(default=None, primary_key=True)
17
21
 
18
22
  type: str
@@ -8,9 +8,10 @@ from sqlmodel import Field
8
8
  from sqlmodel import Relationship
9
9
  from sqlmodel import SQLModel
10
10
 
11
- from .task import TaskV2
12
11
  from fractal_server.utils import get_timestamp
13
12
 
13
+ from .task import TaskV2
14
+
14
15
 
15
16
  def _check_origin_not_pixi(origin: str):
16
17
  """
@@ -22,10 +23,10 @@ def _check_origin_not_pixi(origin: str):
22
23
 
23
24
  def _create_dependency_string(pinned_versions: dict[str, str]) -> str:
24
25
  """
25
- Expand e.g. `{"a": "1.2", "b": "3"}` into `"a==1.2 b==3"`.
26
+ Expand e.g. `{"a": "1.2", "b": "3"}` into `'"a==1.2" "b==3"'`.
26
27
  """
27
28
  output = " ".join(
28
- [f"{key}=={value}" for key, value in pinned_versions.items()]
29
+ [f'"{key}=={value}"' for key, value in pinned_versions.items()]
29
30
  )
30
31
  return output
31
32
 
@@ -42,10 +43,7 @@ class TaskGroupV2(SQLModel, table=True):
42
43
  user_group_id: int | None = Field(
43
44
  foreign_key="usergroup.id", default=None, ondelete="SET NULL"
44
45
  )
45
- # TODO-2.17.1: make `resource_id` not nullable
46
- resource_id: int | None = Field(
47
- foreign_key="resource.id", default=None, ondelete="RESTRICT"
48
- )
46
+ resource_id: int = Field(foreign_key="resource.id", ondelete="RESTRICT")
49
47
 
50
48
  origin: str
51
49
  pkg_name: str
@@ -7,7 +7,8 @@ from sqlmodel import Field
7
7
  from sqlmodel import Relationship
8
8
  from sqlmodel import SQLModel
9
9
 
10
- from ....utils import get_timestamp
10
+ from fractal_server.utils import get_timestamp
11
+
11
12
  from .workflowtask import WorkflowTaskV2
12
13
 
13
14
 
@@ -1,13 +1,13 @@
1
1
  """
2
2
  `admin/v2` module
3
3
  """
4
+
4
5
  from fastapi import APIRouter
5
6
 
6
7
  from .accounting import router as accounting_router
7
8
  from .impersonate import router as impersonate_router
8
9
  from .job import router as job_router
9
10
  from .profile import router as profile_router
10
- from .project import router as project_router
11
11
  from .resource import router as resource_router
12
12
  from .task import router as task_router
13
13
  from .task_group import router as task_group_router
@@ -17,7 +17,6 @@ router_admin_v2 = APIRouter()
17
17
 
18
18
  router_admin_v2.include_router(accounting_router, prefix="/accounting")
19
19
  router_admin_v2.include_router(job_router, prefix="/job")
20
- router_admin_v2.include_router(project_router, prefix="/project")
21
20
  router_admin_v2.include_router(task_router, prefix="/task")
22
21
  router_admin_v2.include_router(task_group_router, prefix="/task-group")
23
22
  router_admin_v2.include_router(
@@ -14,9 +14,9 @@ from fractal_server.app.models import UserOAuth
14
14
  from fractal_server.app.models.v2 import AccountingRecord
15
15
  from fractal_server.app.models.v2 import AccountingRecordSlurm
16
16
  from fractal_server.app.routes.auth import current_superuser_act
17
- from fractal_server.app.routes.pagination import get_pagination_params
18
17
  from fractal_server.app.routes.pagination import PaginationRequest
19
18
  from fractal_server.app.routes.pagination import PaginationResponse
19
+ from fractal_server.app.routes.pagination import get_pagination_params
20
20
  from fractal_server.app.schemas.v2 import AccountingRecordRead
21
21
 
22
22
 
@@ -12,17 +12,17 @@ from sqlmodel import select
12
12
 
13
13
  from fractal_server.app.db import AsyncSession
14
14
  from fractal_server.app.db import get_async_db
15
+ from fractal_server.app.models import LinkUserProjectV2
15
16
  from fractal_server.app.models import UserOAuth
16
17
  from fractal_server.app.models.v2 import HistoryRun
17
18
  from fractal_server.app.models.v2 import HistoryUnit
18
19
  from fractal_server.app.models.v2 import JobV2
19
- from fractal_server.app.models.v2 import ProjectV2
20
20
  from fractal_server.app.routes.auth import current_superuser_act
21
21
  from fractal_server.app.routes.aux._job import _write_shutdown_file
22
22
  from fractal_server.app.routes.aux._runner import _check_shutdown_is_supported
23
- from fractal_server.app.routes.pagination import get_pagination_params
24
23
  from fractal_server.app.routes.pagination import PaginationRequest
25
24
  from fractal_server.app.routes.pagination import PaginationResponse
25
+ from fractal_server.app.routes.pagination import get_pagination_params
26
26
  from fractal_server.app.schemas.v2 import HistoryUnitStatus
27
27
  from fractal_server.app.schemas.v2 import JobReadV2
28
28
  from fractal_server.app.schemas.v2 import JobStatusTypeV2
@@ -52,7 +52,7 @@ async def view_job(
52
52
  db: AsyncSession = Depends(get_async_db),
53
53
  ) -> PaginationResponse[JobReadV2]:
54
54
  """
55
- Query `ApplyWorkflow` table.
55
+ Query `JobV2` table.
56
56
 
57
57
  Args:
58
58
  id: If not `None`, select a given `applyworkflow.id`.
@@ -84,12 +84,12 @@ async def view_job(
84
84
  stm = stm.where(JobV2.id == id)
85
85
  stm_count = stm_count.where(JobV2.id == id)
86
86
  if user_id is not None:
87
- stm = stm.join(ProjectV2).where(
88
- ProjectV2.user_list.any(UserOAuth.id == user_id)
89
- )
90
- stm_count = stm_count.join(ProjectV2).where(
91
- ProjectV2.user_list.any(UserOAuth.id == user_id)
92
- )
87
+ stm = stm.join(
88
+ LinkUserProjectV2, LinkUserProjectV2.project_id == JobV2.project_id
89
+ ).where(LinkUserProjectV2.user_id == user_id)
90
+ stm_count = stm_count.join(
91
+ LinkUserProjectV2, LinkUserProjectV2.project_id == JobV2.project_id
92
+ ).where(LinkUserProjectV2.user_id == user_id)
93
93
  if project_id is not None:
94
94
  stm = stm.where(JobV2.project_id == project_id)
95
95
  stm_count = stm_count.where(JobV2.project_id == project_id)
@@ -6,8 +6,6 @@ from fastapi import status
6
6
  from sqlmodel import func
7
7
  from sqlmodel import select
8
8
 
9
- from ._aux_functions import _check_profile_name
10
- from ._aux_functions import _get_profile_or_404
11
9
  from fractal_server.app.db import AsyncSession
12
10
  from fractal_server.app.db import get_async_db
13
11
  from fractal_server.app.models import Profile
@@ -16,6 +14,9 @@ from fractal_server.app.routes.auth import current_superuser_act
16
14
  from fractal_server.app.schemas.v2 import ProfileCreate
17
15
  from fractal_server.app.schemas.v2 import ProfileRead
18
16
 
17
+ from ._aux_functions import _check_profile_name
18
+ from ._aux_functions import _get_profile_or_404
19
+
19
20
  router = APIRouter()
20
21
 
21
22
 
@@ -6,9 +6,6 @@ from fastapi import status
6
6
  from sqlalchemy.exc import IntegrityError
7
7
  from sqlmodel import select
8
8
 
9
- from ._aux_functions import _check_resource_name
10
- from ._aux_functions import _get_resource_or_404
11
- from .profile import _check_profile_name
12
9
  from fractal_server.app.db import AsyncSession
13
10
  from fractal_server.app.db import get_async_db
14
11
  from fractal_server.app.models import UserOAuth
@@ -22,6 +19,10 @@ from fractal_server.app.schemas.v2 import ResourceRead
22
19
  from fractal_server.config import get_settings
23
20
  from fractal_server.syringe import Inject
24
21
 
22
+ from ._aux_functions import _check_resource_name
23
+ from ._aux_functions import _get_resource_or_404
24
+ from .profile import _check_profile_name
25
+
25
26
  router = APIRouter()
26
27
 
27
28
 
@@ -47,8 +48,7 @@ def _check_type_match_or_422(new_resource: ResourceCreate) -> None:
47
48
  raise HTTPException(
48
49
  status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
49
50
  detail=(
50
- f"{settings.FRACTAL_RUNNER_BACKEND=} != "
51
- f"{new_resource.type=}"
51
+ f"{settings.FRACTAL_RUNNER_BACKEND=} != {new_resource.type=}"
52
52
  ),
53
53
  )
54
54