fractal-server 2.17.0a5__py3-none-any.whl → 2.17.0a6__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.
@@ -1 +1 @@
1
- __VERSION__ = "2.17.0a5"
1
+ __VERSION__ = "2.17.0a6"
@@ -10,6 +10,7 @@ from ._aux_functions import _check_profile_name
10
10
  from ._aux_functions import _get_profile_or_404
11
11
  from fractal_server.app.db import AsyncSession
12
12
  from fractal_server.app.db import get_async_db
13
+ from fractal_server.app.models import Profile
13
14
  from fractal_server.app.models import UserOAuth
14
15
  from fractal_server.app.routes.auth import current_superuser_act
15
16
  from fractal_server.app.schemas.v2 import ProfileCreate
@@ -31,6 +32,19 @@ async def get_single_profile(
31
32
  return profile
32
33
 
33
34
 
35
+ @router.get("/", response_model=list[ProfileRead], status_code=200)
36
+ async def get_profile_list(
37
+ superuser: UserOAuth = Depends(current_superuser_act),
38
+ db: AsyncSession = Depends(get_async_db),
39
+ ) -> ProfileRead:
40
+ """
41
+ Query single `Profile`.
42
+ """
43
+ res = await db.execute(select(Profile).order_by(Profile.id))
44
+ profiles = res.scalars().all()
45
+ return profiles
46
+
47
+
34
48
  @router.put("/{profile_id}/", response_model=ProfileRead, status_code=200)
35
49
  async def put_profile(
36
50
  profile_id: int,
@@ -10,6 +10,7 @@ from sqlmodel import select
10
10
 
11
11
  from fractal_server.app.db import AsyncSession
12
12
  from fractal_server.app.db import get_async_db
13
+ from fractal_server.app.models import TaskGroupV2
13
14
  from fractal_server.app.models import UserOAuth
14
15
  from fractal_server.app.models.v2 import TaskV2
15
16
  from fractal_server.app.models.v2 import WorkflowTaskV2
@@ -58,6 +59,7 @@ async def query_tasks(
58
59
  category: str | None = None,
59
60
  modality: str | None = None,
60
61
  author: str | None = None,
62
+ resource_id: int | None = None,
61
63
  user: UserOAuth = Depends(current_superuser_act),
62
64
  db: AsyncSession = Depends(get_async_db),
63
65
  ) -> list[TaskV2Info]:
@@ -75,6 +77,7 @@ async def query_tasks(
75
77
  category:
76
78
  modality:
77
79
  author:
80
+ resource_id:
78
81
  """
79
82
 
80
83
  stm = select(TaskV2)
@@ -93,6 +96,12 @@ async def query_tasks(
93
96
  stm = stm.where(func.lower(TaskV2.modality) == modality.lower())
94
97
  if author is not None:
95
98
  stm = stm.where(TaskV2.authors.icontains(author))
99
+ if resource_id is not None:
100
+ stm = (
101
+ stm.join(TaskGroupV2)
102
+ .where(TaskGroupV2.id == TaskV2.taskgroupv2_id)
103
+ .where(TaskGroupV2.resource_id == resource_id)
104
+ )
96
105
 
97
106
  res = await db.execute(stm)
98
107
  task_list = res.scalars().all()
@@ -19,11 +19,12 @@ from fractal_server.app.routes.auth._aux_auth import (
19
19
  from fractal_server.app.schemas.v2 import TaskGroupActivityActionV2
20
20
  from fractal_server.app.schemas.v2 import TaskGroupActivityStatusV2
21
21
  from fractal_server.app.schemas.v2 import TaskGroupActivityV2Read
22
- from fractal_server.app.schemas.v2 import TaskGroupReadV2
22
+ from fractal_server.app.schemas.v2 import TaskGroupReadSuperuser
23
23
  from fractal_server.app.schemas.v2 import TaskGroupUpdateV2
24
24
  from fractal_server.app.schemas.v2 import TaskGroupV2OriginEnum
25
25
  from fractal_server.logger import set_logger
26
26
 
27
+
27
28
  router = APIRouter()
28
29
 
29
30
  logger = set_logger(__name__)
@@ -64,12 +65,12 @@ async def get_task_group_activity_list(
64
65
  return activities
65
66
 
66
67
 
67
- @router.get("/{task_group_id}/", response_model=TaskGroupReadV2)
68
+ @router.get("/{task_group_id}/", response_model=TaskGroupReadSuperuser)
68
69
  async def query_task_group(
69
70
  task_group_id: int,
70
71
  user: UserOAuth = Depends(current_superuser_act),
71
72
  db: AsyncSession = Depends(get_async_db),
72
- ) -> TaskGroupReadV2:
73
+ ) -> TaskGroupReadSuperuser:
73
74
  task_group = await db.get(TaskGroupV2, task_group_id)
74
75
  if task_group is None:
75
76
  raise HTTPException(
@@ -79,7 +80,7 @@ async def query_task_group(
79
80
  return task_group
80
81
 
81
82
 
82
- @router.get("/", response_model=list[TaskGroupReadV2])
83
+ @router.get("/", response_model=list[TaskGroupReadSuperuser])
83
84
  async def query_task_group_list(
84
85
  user_id: int | None = None,
85
86
  user_group_id: int | None = None,
@@ -89,9 +90,10 @@ async def query_task_group_list(
89
90
  origin: TaskGroupV2OriginEnum | None = None,
90
91
  timestamp_last_used_min: AwareDatetime | None = None,
91
92
  timestamp_last_used_max: AwareDatetime | None = None,
93
+ resource_id: int | None = None,
92
94
  user: UserOAuth = Depends(current_superuser_act),
93
95
  db: AsyncSession = Depends(get_async_db),
94
- ) -> list[TaskGroupReadV2]:
96
+ ) -> list[TaskGroupReadSuperuser]:
95
97
  stm = select(TaskGroupV2)
96
98
 
97
99
  if user_group_id is not None and private is True:
@@ -128,19 +130,21 @@ async def query_task_group_list(
128
130
  stm = stm.where(
129
131
  TaskGroupV2.timestamp_last_used <= timestamp_last_used_max
130
132
  )
133
+ if resource_id is not None:
134
+ stm = stm.where(TaskGroupV2.resource_id == resource_id)
131
135
 
132
136
  res = await db.execute(stm)
133
137
  task_groups_list = res.scalars().all()
134
138
  return task_groups_list
135
139
 
136
140
 
137
- @router.patch("/{task_group_id}/", response_model=TaskGroupReadV2)
141
+ @router.patch("/{task_group_id}/", response_model=TaskGroupReadSuperuser)
138
142
  async def patch_task_group(
139
143
  task_group_id: int,
140
144
  task_group_update: TaskGroupUpdateV2,
141
145
  user: UserOAuth = Depends(current_superuser_act),
142
146
  db: AsyncSession = Depends(get_async_db),
143
- ) -> list[TaskGroupReadV2]:
147
+ ) -> list[TaskGroupReadSuperuser]:
144
148
  task_group = await db.get(TaskGroupV2, task_group_id)
145
149
  if task_group is None:
146
150
  raise HTTPException(
@@ -7,6 +7,7 @@ from fastapi import Depends
7
7
  import fractal_server
8
8
  from fractal_server.app.models import UserOAuth
9
9
  from fractal_server.app.routes.auth import current_superuser_act
10
+ from fractal_server.config import get_data_settings
10
11
  from fractal_server.config import get_db_settings
11
12
  from fractal_server.config import get_email_settings
12
13
  from fractal_server.config import get_oauth_settings
@@ -48,6 +49,14 @@ async def view_email_settings(
48
49
  return settings.model_dump()
49
50
 
50
51
 
52
+ @router_api.get("/settings/data/")
53
+ async def view_data_settings(
54
+ user: UserOAuth = Depends(current_superuser_act),
55
+ ):
56
+ settings = Inject(get_data_settings)
57
+ return settings.model_dump()
58
+
59
+
51
60
  @router_api.get("/settings/oauth/")
52
61
  async def view_oauth_settings(
53
62
  user: UserOAuth = Depends(current_superuser_act),
@@ -196,10 +196,8 @@ async def apply_workflow(
196
196
  dataset_id=dataset_id,
197
197
  workflow_id=workflow_id,
198
198
  user_email=user.email,
199
- # The 'filters' field is not supported any more but still exists as a
200
- # database column, therefore we manually exclude it from dumps.
201
199
  dataset_dump=json.loads(
202
- dataset.model_dump_json(exclude={"images", "history", "filters"})
200
+ dataset.model_dump_json(exclude={"images", "history"})
203
201
  ),
204
202
  workflow_dump=json.loads(
205
203
  workflow.model_dump_json(exclude={"task_list"})
@@ -5,7 +5,6 @@ import os
5
5
 
6
6
  from fastapi import APIRouter
7
7
  from fastapi import Depends
8
- from fastapi_users import schemas
9
8
  from sqlalchemy.ext.asyncio import AsyncSession
10
9
  from sqlmodel import select
11
10
 
@@ -25,8 +24,8 @@ from fractal_server.app.schemas.user import UserUpdate
25
24
  from fractal_server.app.schemas.user import UserUpdateStrict
26
25
  from fractal_server.app.security import get_user_manager
27
26
  from fractal_server.app.security import UserManager
28
- from fractal_server.config import get_settings
29
- from fractal_server.config import ViewerAuthScheme
27
+ from fractal_server.config import DataAuthScheme
28
+ from fractal_server.config import get_data_settings
30
29
  from fractal_server.syringe import Inject
31
30
 
32
31
  router_current_user = APIRouter()
@@ -66,7 +65,7 @@ async def patch_current_user(
66
65
  # their own password
67
66
 
68
67
  user = await user_manager.update(update, current_user, safe=True)
69
- validated_user = schemas.model_validate(UserOAuth, user.model_dump())
68
+ validated_user = UserOAuth.model_validate(user.model_dump())
70
69
 
71
70
  patched_user = await db.get(
72
71
  UserOAuth, validated_user.id, populate_existing=True
@@ -117,14 +116,14 @@ async def get_current_user_allowed_viewer_paths(
117
116
  ) -> list[str]:
118
117
  """
119
118
  Returns the allowed viewer paths for current user, according to the
120
- selected FRACTAL_VIEWER_AUTHORIZATION_SCHEME
119
+ selected FRACTAL_DATA_AUTH_SCHEME
121
120
  """
122
121
 
123
- settings = Inject(get_settings)
122
+ data_settings = Inject(get_data_settings)
124
123
 
125
124
  authorized_paths = []
126
125
 
127
- if settings.FRACTAL_VIEWER_AUTHORIZATION_SCHEME == ViewerAuthScheme.NONE:
126
+ if data_settings.FRACTAL_DATA_AUTH_SCHEME == DataAuthScheme.NONE:
128
127
  return authorized_paths
129
128
 
130
129
  # Append `project_dir` to the list of authorized paths
@@ -133,20 +132,16 @@ async def get_current_user_allowed_viewer_paths(
133
132
  # If auth scheme is "users-folders" and `slurm_user` is set,
134
133
  # build and append the user folder
135
134
  if (
136
- settings.FRACTAL_VIEWER_AUTHORIZATION_SCHEME
137
- == ViewerAuthScheme.USERS_FOLDERS
135
+ data_settings.FRACTAL_DATA_AUTH_SCHEME == DataAuthScheme.USERS_FOLDERS
138
136
  and current_user.profile_id is not None
139
137
  ):
140
138
  profile = await db.get(Profile, current_user.profile_id)
141
139
  if profile is not None and profile.username is not None:
142
- base_folder = settings.FRACTAL_VIEWER_BASE_FOLDER
140
+ base_folder = data_settings.FRACTAL_DATA_BASE_FOLDER
143
141
  user_folder = os.path.join(base_folder, profile.username)
144
142
  authorized_paths.append(user_folder)
145
143
 
146
- if (
147
- settings.FRACTAL_VIEWER_AUTHORIZATION_SCHEME
148
- == ViewerAuthScheme.VIEWER_PATHS
149
- ):
144
+ if data_settings.FRACTAL_DATA_AUTH_SCHEME == DataAuthScheme.VIEWER_PATHS:
150
145
  # Returns the union of `viewer_paths` for all user's groups
151
146
  cmd = (
152
147
  select(UserGroup.viewer_paths)
@@ -29,7 +29,7 @@ def _create_client_oidc(cfg: OAuthSettings) -> OpenID:
29
29
  return OpenID(
30
30
  client_id=cfg.OAUTH_CLIENT_ID.get_secret_value(),
31
31
  client_secret=cfg.OAUTH_CLIENT_SECRET.get_secret_value(),
32
- openid_configuration_endpoint=cfg.OAUTH_OIDC_CONFIG_ENDPOINT,
32
+ openid_configuration_endpoint=cfg.OAUTH_OIDC_CONFIG_ENDPOINT.get_secret_value(), # noqa
33
33
  )
34
34
 
35
35
 
@@ -6,7 +6,6 @@ from fastapi import Depends
6
6
  from fastapi import HTTPException
7
7
  from fastapi import status
8
8
  from fastapi_users import exceptions
9
- from fastapi_users import schemas
10
9
  from fastapi_users.router.common import ErrorCode
11
10
  from sqlalchemy.ext.asyncio import AsyncSession
12
11
  from sqlmodel import func
@@ -80,7 +79,7 @@ async def patch_user(
80
79
  safe=False,
81
80
  request=None,
82
81
  )
83
- validated_user = schemas.model_validate(UserOAuth, user.model_dump())
82
+ validated_user = UserOAuth.model_validate(user.model_dump())
84
83
  patched_user = await db.get(
85
84
  UserOAuth, validated_user.id, populate_existing=True
86
85
  )
@@ -76,8 +76,8 @@ class UserUpdate(schemas.BaseUserUpdate):
76
76
  profile_id: int | None = None
77
77
  project_dir: Annotated[
78
78
  AbsolutePathStr, AfterValidator(_validate_cmd)
79
- ] | None = None
80
- slurm_accounts: ListUniqueNonEmptyString | None = None
79
+ ] = None
80
+ slurm_accounts: ListUniqueNonEmptyString = None
81
81
 
82
82
 
83
83
  class UserUpdateStrict(BaseModel):
@@ -89,7 +89,7 @@ class UserUpdateStrict(BaseModel):
89
89
  """
90
90
 
91
91
  model_config = ConfigDict(extra="forbid")
92
- slurm_accounts: ListUniqueNonEmptyString | None = None
92
+ slurm_accounts: ListUniqueNonEmptyString = None
93
93
 
94
94
 
95
95
  class UserCreate(schemas.BaseUserCreate):
@@ -52,6 +52,7 @@ from .task_group import TaskGroupActivityStatusV2 # noqa F401
52
52
  from .task_group import TaskGroupActivityV2Read # noqa F401
53
53
  from .task_group import TaskGroupCreateV2 # noqa F401
54
54
  from .task_group import TaskGroupCreateV2Strict # noqa F401
55
+ from .task_group import TaskGroupReadSuperuser # noqa F401
55
56
  from .task_group import TaskGroupReadV2 # noqa F401
56
57
  from .task_group import TaskGroupUpdateV2 # noqa F401
57
58
  from .task_group import TaskGroupV2OriginEnum # noqa F401
@@ -96,6 +96,10 @@ class TaskGroupReadV2(BaseModel):
96
96
  return v.isoformat()
97
97
 
98
98
 
99
+ class TaskGroupReadSuperuser(TaskGroupReadV2):
100
+ resource_id: int
101
+
102
+
99
103
  class TaskGroupUpdateV2(BaseModel):
100
104
  model_config = ConfigDict(extra="forbid")
101
105
  user_group_id: int | None = None
@@ -1,8 +1,9 @@
1
+ from ._data import DataAuthScheme # noqa F401
2
+ from ._data import DataSettings
1
3
  from ._database import DatabaseSettings
2
4
  from ._email import EmailSettings
3
5
  from ._email import PublicEmailSettings # noqa F401
4
6
  from ._main import Settings
5
- from ._main import ViewerAuthScheme # noqa F401
6
7
  from ._oauth import OAuthSettings
7
8
 
8
9
 
@@ -20,3 +21,7 @@ def get_email_settings(email_settings=EmailSettings()) -> EmailSettings:
20
21
 
21
22
  def get_oauth_settings(oauth_settings=OAuthSettings()) -> OAuthSettings:
22
23
  return oauth_settings
24
+
25
+
26
+ def get_data_settings(data_settings=DataSettings()) -> DataSettings:
27
+ return data_settings
@@ -0,0 +1,68 @@
1
+ from enum import StrEnum
2
+ from typing import Self
3
+
4
+ from pydantic import model_validator
5
+ from pydantic_settings import BaseSettings
6
+ from pydantic_settings import SettingsConfigDict
7
+
8
+ from ._settings_config import SETTINGS_CONFIG_DICT
9
+ from fractal_server.types import AbsolutePathStr
10
+
11
+
12
+ class DataAuthScheme(StrEnum):
13
+ VIEWER_PATHS = "viewer-paths"
14
+ USERS_FOLDERS = "users-folders"
15
+ NONE = "none"
16
+
17
+
18
+ class DataSettings(BaseSettings):
19
+ """
20
+ Settings for the `fractal-data` integration.
21
+ """
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.
28
+
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).
32
+
33
+ Options:
34
+
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.
44
+ """
45
+
46
+ 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
+
53
+ @model_validator(mode="after")
54
+ def check(self: Self) -> Self:
55
+ """
56
+ `FRACTAL_DATA_BASE_FOLDER` is required when
57
+ `FRACTAL_DATA_AUTHORIZATION_SCHEME` is set to `"users-folders"`.
58
+ """
59
+ if (
60
+ self.FRACTAL_DATA_AUTH_SCHEME == DataAuthScheme.USERS_FOLDERS
61
+ and self.FRACTAL_DATA_BASE_FOLDER is None
62
+ ):
63
+ raise ValueError(
64
+ "FRACTAL_DATA_BASE_FOLDER is required when "
65
+ "FRACTAL_DATA_AUTH_SCHEME is set to "
66
+ "users-folders"
67
+ )
68
+ return self
@@ -1,7 +1,5 @@
1
1
  import logging
2
- from enum import StrEnum
3
2
  from typing import Literal
4
- from typing import TypeVar
5
3
 
6
4
  from pydantic import HttpUrl
7
5
  from pydantic import SecretStr
@@ -9,20 +7,6 @@ from pydantic_settings import BaseSettings
9
7
  from pydantic_settings import SettingsConfigDict
10
8
 
11
9
  from ._settings_config import SETTINGS_CONFIG_DICT
12
- from fractal_server.types import AbsolutePathStr
13
-
14
-
15
- class FractalConfigurationError(ValueError):
16
- pass
17
-
18
-
19
- class ViewerAuthScheme(StrEnum):
20
- VIEWER_PATHS = "viewer-paths"
21
- USERS_FOLDERS = "users-folders"
22
- NONE = "none"
23
-
24
-
25
- T = TypeVar("T")
26
10
 
27
11
 
28
12
  class Settings(BaseSettings):
@@ -34,7 +18,6 @@ class Settings(BaseSettings):
34
18
 
35
19
  model_config = SettingsConfigDict(**SETTINGS_CONFIG_DICT)
36
20
 
37
- # JWT TOKEN
38
21
  JWT_EXPIRE_SECONDS: int = 180
39
22
  """
40
23
  JWT token lifetime, in seconds.
@@ -48,7 +31,6 @@ class Settings(BaseSettings):
48
31
  it.
49
32
  """
50
33
 
51
- # COOKIE TOKEN
52
34
  COOKIE_EXPIRE_SECONDS: int = 86400
53
35
  """
54
36
  Cookie token lifetime, in seconds.
@@ -80,52 +62,6 @@ class Settings(BaseSettings):
80
62
  Waiting time for the shutdown phase of executors
81
63
  """
82
64
 
83
- FRACTAL_VIEWER_AUTHORIZATION_SCHEME: ViewerAuthScheme = "none"
84
- """
85
- Defines how the list of allowed viewer paths is built.
86
-
87
- This variable affects the `GET /auth/current-user/allowed-viewer-paths/`
88
- response, which is then consumed by
89
- [fractal-vizarr-viewer](https://github.com/fractal-analytics-platform/fractal-vizarr-viewer).
90
-
91
- Options:
92
-
93
- - "viewer-paths": The list of allowed viewer paths will include the user's
94
- `project_dir` along with any path defined in user groups' `viewer_paths`
95
- attributes.
96
- - "users-folders": The list will consist of the user's `project_dir` and a
97
- user-specific folder. The user folder is constructed by concatenating
98
- the base folder `FRACTAL_VIEWER_BASE_FOLDER` with the user's
99
- `slurm_user`.
100
- - "none": An empty list will be returned, indicating no access to
101
- viewer paths. Useful when vizarr viewer is not used.
102
- """
103
-
104
- FRACTAL_VIEWER_BASE_FOLDER: AbsolutePathStr | None = None
105
- """
106
- Base path to Zarr files that will be served by fractal-vizarr-viewer;
107
- This variable is required and used only when
108
- FRACTAL_VIEWER_AUTHORIZATION_SCHEME is set to "users-folders".
109
- """
110
-
111
- def check(self):
112
- """
113
- Make sure that required variables are set
114
-
115
- This method must be called before the server starts
116
- """
117
- # FRACTAL_VIEWER_BASE_FOLDER is required when
118
- # FRACTAL_VIEWER_AUTHORIZATION_SCHEME is set to "users-folders"
119
- # and it must be an absolute path
120
- if self.FRACTAL_VIEWER_AUTHORIZATION_SCHEME == "users-folders":
121
- viewer_base_folder = self.FRACTAL_VIEWER_BASE_FOLDER
122
- if viewer_base_folder is None:
123
- raise FractalConfigurationError(
124
- "FRACTAL_VIEWER_BASE_FOLDER is required when "
125
- "FRACTAL_VIEWER_AUTHORIZATION_SCHEME is set to "
126
- "users-folders"
127
- )
128
-
129
65
  FRACTAL_HELP_URL: HttpUrl | None = None
130
66
  """
131
67
  The URL of an instance-specific Fractal help page.
@@ -37,7 +37,7 @@ class OAuthSettings(BaseSettings):
37
37
  """
38
38
  Secret to authorise against the identity provider.
39
39
  """
40
- OAUTH_OIDC_CONFIG_ENDPOINT: str | None = None
40
+ OAUTH_OIDC_CONFIG_ENDPOINT: SecretStr | None = None
41
41
  """
42
42
  OpenID configuration endpoint, for autodiscovery of relevant endpoints.
43
43
  """
@@ -55,7 +55,7 @@ class OAuthSettings(BaseSettings):
55
55
  and self.OAUTH_OIDC_CONFIG_ENDPOINT is None
56
56
  ):
57
57
  raise ValueError(
58
- f"{self.OAUTH_OIDC_CONFIG_ENDPOINT=} but "
58
+ f"self.OAUTH_OIDC_CONFIG_ENDPOINT=None but "
59
59
  f"{self.OAUTH_CLIENT_NAME=}"
60
60
  )
61
61
  return self
fractal_server/main.py CHANGED
@@ -6,6 +6,7 @@ from fastapi import FastAPI
6
6
 
7
7
  from .app.routes.aux._runner import _backend_supports_shutdown
8
8
  from .app.shutdown import cleanup_after_shutdown
9
+ from .config import get_data_settings
9
10
  from .config import get_db_settings
10
11
  from .config import get_email_settings
11
12
  from .config import get_settings
@@ -50,16 +51,16 @@ def check_settings() -> None:
50
51
  ValidationError: If the configuration is invalid.
51
52
  """
52
53
  settings = Inject(get_settings)
53
- settings.check()
54
54
  db_settings = Inject(get_db_settings)
55
55
  email_settings = Inject(get_email_settings)
56
-
56
+ data_settings = Inject(get_data_settings)
57
57
  logger = set_logger("fractal_server_settings")
58
58
  logger.debug("Fractal Settings:")
59
59
  for key, value in chain(
60
60
  db_settings.model_dump().items(),
61
61
  settings.model_dump().items(),
62
62
  email_settings.model_dump().items(),
63
+ data_settings.model_dump().items(),
63
64
  ):
64
65
  if any(s in key.upper() for s in ["PASSWORD", "SECRET", "KEY"]):
65
66
  value = "*****"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fractal-server
3
- Version: 2.17.0a5
3
+ Version: 2.17.0a6
4
4
  Summary: Backend component of the Fractal analytics platform
5
5
  License-Expression: BSD-3-Clause
6
6
  License-File: LICENSE
@@ -13,18 +13,17 @@ Classifier: Programming Language :: Python :: 3.12
13
13
  Classifier: Programming Language :: Python :: 3.13
14
14
  Requires-Dist: alembic (>=1.13.1,<2.0.0)
15
15
  Requires-Dist: fabric (>=3.2.2,<3.3.0)
16
- Requires-Dist: fastapi (>=0.118.0,<0.119.0)
17
- Requires-Dist: fastapi-users[oauth] (>=14,<15)
16
+ Requires-Dist: fastapi (>=0.120.0,<0.121.0)
17
+ Requires-Dist: fastapi-users[oauth] (>=15,<16)
18
18
  Requires-Dist: gunicorn (>=23.0,<24.0)
19
19
  Requires-Dist: packaging (>=25.0.0,<26.0.0)
20
20
  Requires-Dist: psycopg[binary] (>=3.1.0,<4.0.0)
21
21
  Requires-Dist: pydantic (>=2.12.0,<2.13.0)
22
22
  Requires-Dist: pydantic-settings (==2.11.0)
23
- Requires-Dist: python-dotenv (>=1.1.0,<1.2.0)
24
23
  Requires-Dist: sqlalchemy[asyncio] (>=2.0.23,<2.1)
25
24
  Requires-Dist: sqlmodel (==0.0.27)
26
25
  Requires-Dist: tomli_w (>=1.2.0,<1.3.0)
27
- Requires-Dist: uvicorn (>=0.37.0,<0.38.0)
26
+ Requires-Dist: uvicorn (>=0.38.0,<0.39.0)
28
27
  Requires-Dist: uvicorn-worker (==0.4.0)
29
28
  Project-URL: Documentation, https://fractal-analytics-platform.github.io/fractal-server
30
29
  Project-URL: Homepage, https://github.com/fractal-analytics-platform/fractal-server
@@ -1,4 +1,4 @@
1
- fractal_server/__init__.py,sha256=twgXmjGJdfHSKap7ALSL1NPDHaBCT4z5bFl9BlhdIyk,25
1
+ fractal_server/__init__.py,sha256=m6ro3f4bjmvJJ9DFzqslf5NSM9OxOGIbAGvKTxl1rZQ,25
2
2
  fractal_server/__main__.py,sha256=68FlTuST3zbzVofFI8JSYsSBrBQ07Bv3Mu3PsZX9Fw0,11423
3
3
  fractal_server/alembic.ini,sha256=MWwi7GzjzawI9cCAK1LW7NxIBQDUqD12-ptJoq5JpP0,3153
4
4
  fractal_server/app/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -27,13 +27,13 @@ fractal_server/app/routes/admin/v2/_aux_functions.py,sha256=fqA5sUCFuD2iVANQt2WU
27
27
  fractal_server/app/routes/admin/v2/accounting.py,sha256=DjgMqzdrL8hYMn19cZj2pkwtLKl3QfBwxd473kH4KaI,3584
28
28
  fractal_server/app/routes/admin/v2/impersonate.py,sha256=ictDjuvBr3iLv3YtwkVRMNQRq5qtPAeAXbbC7STSsEg,1125
29
29
  fractal_server/app/routes/admin/v2/job.py,sha256=sFgMbOtUCIJ-ri6YD3ZWP7XETZZDQsLqPfT1kaH9RHQ,8577
30
- fractal_server/app/routes/admin/v2/profile.py,sha256=h9R4bwZQXBg0FAm2lj-DQ3vKQSFDtvjRARFpxfI3WR4,2733
30
+ fractal_server/app/routes/admin/v2/profile.py,sha256=0Y_1Qv-BA6cHVrxPTDDBOpttpfuJN8g1FqFlG6JiOD8,3164
31
31
  fractal_server/app/routes/admin/v2/project.py,sha256=rRq7ZDngr_29skASnte1xfycZCjK-WPdeTf7siBXiCU,1182
32
32
  fractal_server/app/routes/admin/v2/resource.py,sha256=uel-MN3f9TkkIJ7flEC4yPH7q2qGQxoaxPB0LxfZzYs,7796
33
- fractal_server/app/routes/admin/v2/task.py,sha256=B_RfL320acBKFkOa34S0sWI44VCFBE_jg_jGHZASKO8,4303
34
- fractal_server/app/routes/admin/v2/task_group.py,sha256=sxASS5948inqcP2IU3C2tcLB5egXfxef0TPlVcRtP-U,6028
33
+ fractal_server/app/routes/admin/v2/task.py,sha256=aACI0RXVODclIqfaFYyQ3ncB8YCcd36qy3a0vFGnsfo,4621
34
+ fractal_server/app/routes/admin/v2/task_group.py,sha256=RV697PI79X9w5zEKQTlQplAsp-vDS4fGyXwqsHc5eY0,6210
35
35
  fractal_server/app/routes/admin/v2/task_group_lifecycle.py,sha256=W7LjIBAheyjrn0fEz0SsWINqcZK5HMB5GRGMjPrc6a4,9994
36
- fractal_server/app/routes/api/__init__.py,sha256=wJE77LxZ51p1N9AIX-kd4VdUDEk0RYbCy-T_pn2V73I,1408
36
+ fractal_server/app/routes/api/__init__.py,sha256=ewprevw6hZ0FWM-GPHoQZU0w-yfItqLeQT-Jr_Nbjnw,1658
37
37
  fractal_server/app/routes/api/v2/__init__.py,sha256=D3sRRsqkmZO6kBxUjg40q0aRDsnuXI4sOOfn0xF9JsM,2820
38
38
  fractal_server/app/routes/api/v2/_aux_functions.py,sha256=8xnXYPjzo1yZfcg18b5ZY5tu9OQ1e55fOnX1IEmDSHk,15019
39
39
  fractal_server/app/routes/api/v2/_aux_functions_history.py,sha256=PXsqMQ3sfkABqAMI7v1_VAzUEDF_-kvaZyyhEicqsCw,4431
@@ -48,7 +48,7 @@ fractal_server/app/routes/api/v2/job.py,sha256=fyIYGcplsxzx91FxYWlImp1ATPk5IC8bf
48
48
  fractal_server/app/routes/api/v2/pre_submission_checks.py,sha256=DEnlFj6PMNMy9DrnH6_pMW9evdKl6iTlAb0zlzBR1Qs,4953
49
49
  fractal_server/app/routes/api/v2/project.py,sha256=eQcQs0ElMpUN0OTcgG7DXk70t9Dn8Fdd6oHeQ0WbgJI,4782
50
50
  fractal_server/app/routes/api/v2/status_legacy.py,sha256=vZA4AYMehXbNFgekl4j6p8idETC3IylQQL64CmFCr98,6330
51
- fractal_server/app/routes/api/v2/submit.py,sha256=jPPvJNeLBcPVl0BsLnOZn_KtxoQvdBnAVnzFVihUJIc,9364
51
+ fractal_server/app/routes/api/v2/submit.py,sha256=l12Duakx0lV43LCyX4C6cCIBsg-BEc-XxjRRe8l8Wys,9203
52
52
  fractal_server/app/routes/api/v2/task.py,sha256=KDIBrQpIbbVrffOBtxah-gXiOnN-EG84ujXeGPOqKhg,7160
53
53
  fractal_server/app/routes/api/v2/task_collection.py,sha256=A0mfajyJVVrWNuI7YaPih7juSWOnks78NnJDwnGfvdo,12281
54
54
  fractal_server/app/routes/api/v2/task_collection_custom.py,sha256=9SqiMPuED5LEGKo3Tiq5KfXFqmjaZPg9KWL-Yn5jdLo,7010
@@ -61,22 +61,22 @@ fractal_server/app/routes/api/v2/workflow_import.py,sha256=iFy8jPuMMt1DpIcs5iJc5
61
61
  fractal_server/app/routes/api/v2/workflowtask.py,sha256=-V7WjTfYb2L7i3_dQ0Am_ydqepdqs-j3BY67_5iZPfU,7960
62
62
  fractal_server/app/routes/auth/__init__.py,sha256=Y-RQMwY5V25ZVgyYYoFIXvEDQgm6PGTDgxH755oa_NM,2358
63
63
  fractal_server/app/routes/auth/_aux_auth.py,sha256=fyGxBVb6yrVrsE7-2tTyiJ7orb9Jzkg36m_q-rP7Zs8,4868
64
- fractal_server/app/routes/auth/current_user.py,sha256=A8GJpWV90FnheuhhYsAGjiuQn8IAoOVNAR0e53JHwPU,5611
64
+ fractal_server/app/routes/auth/current_user.py,sha256=BsM_lm9iNiaL8_iMY8NZnfgSXhzEY8xgkQUgtC40h8o,5517
65
65
  fractal_server/app/routes/auth/group.py,sha256=wZnqzIOZHpoUW2Yp6dkAMRqIiM_otVdG4fZuBYmLocA,6919
66
66
  fractal_server/app/routes/auth/login.py,sha256=tSu6OBLOieoBtMZB4JkBAdEgH2Y8KqPGSbwy7NIypIo,566
67
- fractal_server/app/routes/auth/oauth.py,sha256=iI2vEdvDlEE5BrFz5Krq96VUk39HDuE0NzqW9fS3dDE,2261
67
+ fractal_server/app/routes/auth/oauth.py,sha256=3TaGZpjgjUyqqbhdcUv1PwgiHdkUk41X5tc98FOIw-s,2288
68
68
  fractal_server/app/routes/auth/register.py,sha256=Ola-lNdYYEOK8Wh0Q-TFKwIJ25e6UswlUojJ8QGBCfc,581
69
69
  fractal_server/app/routes/auth/router.py,sha256=-E87A8h2UvcLucy5xjzKiWbXHVKcqxUmmZGeV_utEzA,598
70
- fractal_server/app/routes/auth/users.py,sha256=L94-1A62FFfASflURggYsVDOxtWNRU-gK6eSx8ZckyA,6921
70
+ fractal_server/app/routes/auth/users.py,sha256=Gjj3_W4Zu1RZJv0r578wPJrbicMmiSELmJGJDeStyus,6878
71
71
  fractal_server/app/routes/aux/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
72
72
  fractal_server/app/routes/aux/_job.py,sha256=nqqdcW5B7fL_PbvHf57_TcifjUfcMgl04tKNvG2sV1U,628
73
73
  fractal_server/app/routes/aux/_runner.py,sha256=SDzI7glEfkW_XecWFuRQitbSWSvAPegI-J5c7i5d0_w,957
74
74
  fractal_server/app/routes/aux/validate_user_profile.py,sha256=fGqJDdAFkbQoEIjqZ5F9-SDY_4os63R2EUMqODC7eBg,1969
75
75
  fractal_server/app/routes/pagination.py,sha256=IGy8Ll5lYr6ENYE18h3huH5s0GMX1DCs5VdCi6j1cdk,1174
76
76
  fractal_server/app/schemas/__init__.py,sha256=VIWJCaqokte3OljDLX00o-EC2d12rFoPb5HOLKQI94Y,86
77
- fractal_server/app/schemas/user.py,sha256=nXsE4yEt8xiMlr2IhLoul0M0x2vYWaXIJBG_-NmRj6w,2919
77
+ fractal_server/app/schemas/user.py,sha256=MGggiWGqQV97426IzoaKNIkqHUMEuadW7BbJgom6tB8,2898
78
78
  fractal_server/app/schemas/user_group.py,sha256=x3-kqbo0q2wTP7QI0iZ7PU_9Dr957UYrFMKqS7BXLhE,1425
79
- fractal_server/app/schemas/v2/__init__.py,sha256=ShdbfHQe_MNMQzyjaEl7NGj30h2u8mUD9-UX3hsS3sA,3669
79
+ fractal_server/app/schemas/v2/__init__.py,sha256=XQex5ojpELgO0xvq2l-Y8oV85ZgM3GBj6lrGGctPb1g,3729
80
80
  fractal_server/app/schemas/v2/accounting.py,sha256=C_ekrYQwhi7PtrxxB07oVAG2y1NLigXjYwyp4E38fao,396
81
81
  fractal_server/app/schemas/v2/dataset.py,sha256=NKCjBwGBC7mPiSlXktZAcleJsvlLY6KfNKw7Wx4Zfqk,1728
82
82
  fractal_server/app/schemas/v2/dumps.py,sha256=LCYiNF_FNYiA6HYp5GyFao3IKRX0RpzgNpiX56IwgCE,2293
@@ -89,17 +89,18 @@ fractal_server/app/schemas/v2/resource.py,sha256=4iXzZJeHVLcXYY08-okoJM_4gqpzhG4
89
89
  fractal_server/app/schemas/v2/status_legacy.py,sha256=eQT1zGxbkzSwd0EqclsOdZ60n1x6J3DB1CZ3m4LYyxc,955
90
90
  fractal_server/app/schemas/v2/task.py,sha256=IJv8loB4kx9FBkaIHoiMsswQyq02FxvyAnHK1u074fU,4364
91
91
  fractal_server/app/schemas/v2/task_collection.py,sha256=BzHQXq2_zLZTbigWauOR5Zi-mlsqCIF2NEF_z12Nqxg,4480
92
- fractal_server/app/schemas/v2/task_group.py,sha256=anC7YPiOEcLmxN2JyARLMMHp6l7NfvsCpx3sMcnug4o,3436
92
+ fractal_server/app/schemas/v2/task_group.py,sha256=4hNZUXnWYSozpLXR3JqBvGzfZBG2TbjqydckHHu2Aq0,3506
93
93
  fractal_server/app/schemas/v2/workflow.py,sha256=L-dW6SzCH_VNoH6ENip44lTgGGqVYHHBk_3PtM-Ooy8,1772
94
94
  fractal_server/app/schemas/v2/workflowtask.py,sha256=6eweAMyziwaoMT-7R1fVJYunIeZKzT0-7fAVgPO_FEc,3639
95
95
  fractal_server/app/security/__init__.py,sha256=gtfJkwdXTm_F38sFgb5LH3AcdvKs42fOUJa8jo8Cmbw,17484
96
96
  fractal_server/app/security/signup_email.py,sha256=kphjq6TAygvPpYpg95QJWefyqmzdVrGz7fyRMctUJWE,1982
97
97
  fractal_server/app/shutdown.py,sha256=ViSNJyXWU_iWPSDOOMGNh_iQdUFrdPh_jvf8vVKLpAo,1950
98
- fractal_server/config/__init__.py,sha256=EDk6ylmCXc8FoCYWTQ1bC-27yZ7iYHWxbhcjjMbQX2A,611
98
+ fractal_server/config/__init__.py,sha256=ZCmroNB50sUxJiFtkW0a4fFtmfyPnL4LWhtKY5FbQfg,737
99
+ fractal_server/config/_data.py,sha256=9Jyt83yrSsr_0_9ANWDAXz88_jjyFlcB5VWJGXq8aUY,2311
99
100
  fractal_server/config/_database.py,sha256=YOBi3xuJno5wLGw1hKsjLm-bftaxVWiBNIQWVTMX3Ag,1661
100
101
  fractal_server/config/_email.py,sha256=j1QmZCyspNbD1xxkypc9Kv299tU3vTO1AqDFJ8-LZzQ,4201
101
- fractal_server/config/_main.py,sha256=Xtcz2q2HuHYdk7DaD6uBG1KtQeBiQhKz6CANvevg1AA,3877
102
- fractal_server/config/_oauth.py,sha256=OYWqJnL0yn8ymagKb4fK-2zNqXVBbumRWwZrr9TFUms,1926
102
+ fractal_server/config/_main.py,sha256=y1WQPFjEyctsVpRX2LVKfR_nJjFQHAey_i8e6Hmsq6E,1605
103
+ fractal_server/config/_oauth.py,sha256=7J4FphGVFfVmtQycCkas6scEJQJGZUGEzQ-t2PZiqSo,1934
103
104
  fractal_server/config/_settings_config.py,sha256=tsyXQOnn9QKCFJD6hRo_dJXlQQyl70DbqgHMJoZ1xnY,144
104
105
  fractal_server/data_migrations/2_14_10.py,sha256=jzMg2c1zNO8C_Nho_9_EZJD6kR1-gkFNpNrMR5Hr8hM,1598
105
106
  fractal_server/data_migrations/README.md,sha256=_3AEFvDg9YkybDqCLlFPdDmGJvr6Tw7HRI14aZ3LOIw,398
@@ -111,7 +112,7 @@ fractal_server/images/models.py,sha256=6WchcIzLLLwdkLNRfg71Dl4Y-9UFLPyrrzh1lWgju
111
112
  fractal_server/images/status_tools.py,sha256=KICcThwHniHNkDftzJmK_n2gQK2IeTKlR_PFAesf204,4912
112
113
  fractal_server/images/tools.py,sha256=37jVIU6RiAGbiyucNDlKe9J3yN3Y47NOvv-RJor9Jm0,4154
113
114
  fractal_server/logger.py,sha256=2_IN0WcIzLEX20HFUUkwyZGSIi0yLbE0JamkzXREDZw,5302
114
- fractal_server/main.py,sha256=uTKl1XH3tZ1jvaGeZDEgVXC5WMWRM1Ep4gB-vYRPb-8,4313
115
+ fractal_server/main.py,sha256=4HJO8EiGJp0Iw0p3xEm_zhwjnT4joFG1KuGccIIndjo,4419
115
116
  fractal_server/migrations/env.py,sha256=nfyBpMIOT3kny6t-b-tUjyRjZ4k906bb1_wCQ7me1BI,1353
116
117
  fractal_server/migrations/naming_convention.py,sha256=htbKrVdetx3pklowb_9Cdo5RqeF0fJ740DNecY5de_M,265
117
118
  fractal_server/migrations/versions/034a469ec2eb_task_groups.py,sha256=vrPhC8hfFu1c4HmLHNZyCuqEfecFD8-bWc49bXMNes0,6199
@@ -256,8 +257,8 @@ fractal_server/types/validators/_workflow_task_arguments_validators.py,sha256=HL
256
257
  fractal_server/urls.py,sha256=QjIKAC1a46bCdiPMu3AlpgFbcv6a4l3ABcd5xz190Og,471
257
258
  fractal_server/utils.py,sha256=SYVVUuXe_nWyrJLsy7QA-KJscwc5PHEXjvsW4TK7XQI,2180
258
259
  fractal_server/zip_tools.py,sha256=H0w7wS5yE4ebj7hw1_77YQ959dl2c-L0WX6J_ro1TY4,4884
259
- fractal_server-2.17.0a5.dist-info/METADATA,sha256=oUgYkhW5EongBJTrbWUUyPKU6j64g8F9GG4PPY0NR0c,4272
260
- fractal_server-2.17.0a5.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
261
- fractal_server-2.17.0a5.dist-info/entry_points.txt,sha256=8tV2kynvFkjnhbtDnxAqImL6HMVKsopgGfew0DOp5UY,58
262
- fractal_server-2.17.0a5.dist-info/licenses/LICENSE,sha256=QKAharUuhxL58kSoLizKJeZE3mTCBnX6ucmz8W0lxlk,1576
263
- fractal_server-2.17.0a5.dist-info/RECORD,,
260
+ fractal_server-2.17.0a6.dist-info/METADATA,sha256=X3vrUW4wnIOGZ8jAWbE4Ks9CaPszKHL2WuSPHtBk_aM,4226
261
+ fractal_server-2.17.0a6.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
262
+ fractal_server-2.17.0a6.dist-info/entry_points.txt,sha256=8tV2kynvFkjnhbtDnxAqImL6HMVKsopgGfew0DOp5UY,58
263
+ fractal_server-2.17.0a6.dist-info/licenses/LICENSE,sha256=QKAharUuhxL58kSoLizKJeZE3mTCBnX6ucmz8W0lxlk,1576
264
+ fractal_server-2.17.0a6.dist-info/RECORD,,