fractal-server 2.17.0a4__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.
Files changed (67) hide show
  1. fractal_server/__init__.py +1 -1
  2. fractal_server/__main__.py +22 -26
  3. fractal_server/app/models/security.py +19 -21
  4. fractal_server/app/models/user_settings.py +1 -0
  5. fractal_server/app/models/v2/task_group.py +1 -0
  6. fractal_server/app/routes/admin/v2/accounting.py +3 -3
  7. fractal_server/app/routes/admin/v2/impersonate.py +2 -2
  8. fractal_server/app/routes/admin/v2/job.py +6 -6
  9. fractal_server/app/routes/admin/v2/profile.py +18 -4
  10. fractal_server/app/routes/admin/v2/project.py +2 -2
  11. fractal_server/app/routes/admin/v2/resource.py +8 -8
  12. fractal_server/app/routes/admin/v2/task.py +11 -2
  13. fractal_server/app/routes/admin/v2/task_group.py +16 -12
  14. fractal_server/app/routes/admin/v2/task_group_lifecycle.py +4 -4
  15. fractal_server/app/routes/api/__init__.py +14 -5
  16. fractal_server/app/routes/api/v2/dataset.py +10 -19
  17. fractal_server/app/routes/api/v2/history.py +8 -8
  18. fractal_server/app/routes/api/v2/images.py +5 -5
  19. fractal_server/app/routes/api/v2/job.py +8 -8
  20. fractal_server/app/routes/api/v2/pre_submission_checks.py +3 -3
  21. fractal_server/app/routes/api/v2/project.py +6 -6
  22. fractal_server/app/routes/api/v2/status_legacy.py +2 -2
  23. fractal_server/app/routes/api/v2/submit.py +25 -29
  24. fractal_server/app/routes/api/v2/task.py +6 -7
  25. fractal_server/app/routes/api/v2/task_collection.py +4 -3
  26. fractal_server/app/routes/api/v2/task_collection_custom.py +4 -3
  27. fractal_server/app/routes/api/v2/task_collection_pixi.py +2 -2
  28. fractal_server/app/routes/api/v2/task_group.py +6 -6
  29. fractal_server/app/routes/api/v2/task_group_lifecycle.py +4 -4
  30. fractal_server/app/routes/api/v2/task_version_update.py +3 -3
  31. fractal_server/app/routes/api/v2/workflow.py +9 -9
  32. fractal_server/app/routes/api/v2/workflow_import.py +2 -2
  33. fractal_server/app/routes/api/v2/workflowtask.py +5 -5
  34. fractal_server/app/routes/auth/__init__.py +34 -5
  35. fractal_server/app/routes/auth/current_user.py +22 -72
  36. fractal_server/app/routes/auth/group.py +8 -35
  37. fractal_server/app/routes/auth/oauth.py +1 -1
  38. fractal_server/app/routes/auth/register.py +2 -2
  39. fractal_server/app/routes/auth/users.py +6 -48
  40. fractal_server/app/schemas/__init__.py +0 -1
  41. fractal_server/app/schemas/user.py +23 -0
  42. fractal_server/app/schemas/v2/__init__.py +1 -0
  43. fractal_server/app/schemas/v2/task_group.py +5 -0
  44. fractal_server/app/security/__init__.py +134 -46
  45. fractal_server/app/security/signup_email.py +52 -34
  46. fractal_server/config/__init__.py +6 -0
  47. fractal_server/config/_data.py +68 -0
  48. fractal_server/config/_email.py +10 -47
  49. fractal_server/config/_main.py +3 -56
  50. fractal_server/config/_oauth.py +2 -2
  51. fractal_server/main.py +3 -2
  52. fractal_server/migrations/versions/f65ee53991e3_user_settings_related.py +67 -0
  53. fractal_server/runner/executors/slurm_common/base_slurm_runner.py +1 -1
  54. fractal_server/runner/executors/slurm_common/slurm_config.py +5 -8
  55. fractal_server/runner/executors/slurm_ssh/runner.py +1 -1
  56. fractal_server/runner/executors/slurm_sudo/runner.py +1 -1
  57. fractal_server/runner/v2/_slurm_ssh.py +2 -1
  58. fractal_server/runner/v2/_slurm_sudo.py +1 -1
  59. fractal_server/runner/v2/submit_workflow.py +12 -12
  60. {fractal_server-2.17.0a4.dist-info → fractal_server-2.17.0a6.dist-info}/METADATA +4 -6
  61. {fractal_server-2.17.0a4.dist-info → fractal_server-2.17.0a6.dist-info}/RECORD +64 -65
  62. fractal_server/app/routes/aux/validate_user_settings.py +0 -76
  63. fractal_server/app/schemas/user_settings.py +0 -63
  64. fractal_server/app/user_settings.py +0 -32
  65. {fractal_server-2.17.0a4.dist-info → fractal_server-2.17.0a6.dist-info}/WHEEL +0 -0
  66. {fractal_server-2.17.0a4.dist-info → fractal_server-2.17.0a6.dist-info}/entry_points.txt +0 -0
  67. {fractal_server-2.17.0a4.dist-info → fractal_server-2.17.0a6.dist-info}/licenses/LICENSE +0 -0
@@ -1,6 +1,6 @@
1
1
  from typing import Literal
2
+ from typing import Self
2
3
 
3
- from cryptography.fernet import Fernet
4
4
  from pydantic import BaseModel
5
5
  from pydantic import EmailStr
6
6
  from pydantic import Field
@@ -31,8 +31,7 @@ class PublicEmailSettings(BaseModel):
31
31
  recipients: list[EmailStr] = Field(min_length=1)
32
32
  smtp_server: str
33
33
  port: int
34
- encrypted_password: SecretStr | None = None
35
- encryption_key: SecretStr | None = None
34
+ password: SecretStr | None = None
36
35
  instance_name: str
37
36
  use_starttls: bool
38
37
  use_login: bool
@@ -53,10 +52,6 @@ class EmailSettings(BaseSettings):
53
52
  """
54
53
  Password for the OAuth-signup email sender.
55
54
  """
56
- FRACTAL_EMAIL_PASSWORD_KEY: SecretStr | None = None
57
- """
58
- Key value for `cryptography.fernet` decrypt
59
- """
60
55
  FRACTAL_EMAIL_SMTP_SERVER: str | None = None
61
56
  """
62
57
  SMTP server for the OAuth-signup emails.
@@ -81,8 +76,7 @@ class EmailSettings(BaseSettings):
81
76
  FRACTAL_EMAIL_USE_LOGIN: Literal["true", "false"] = "true"
82
77
  """
83
78
  Whether to use login when using the SMTP server.
84
- If 'true', FRACTAL_EMAIL_PASSWORD and FRACTAL_EMAIL_PASSWORD_KEY must be
85
- provided.
79
+ If 'true', FRACTAL_EMAIL_PASSWORD must be provided.
86
80
  Accepted values: 'true', 'false'.
87
81
  """
88
82
 
@@ -93,7 +87,7 @@ class EmailSettings(BaseSettings):
93
87
  """
94
88
 
95
89
  @model_validator(mode="after")
96
- def validate_email_settings(self):
90
+ def validate_email_settings(self: Self) -> Self:
97
91
  """
98
92
  Set `self.public`.
99
93
  """
@@ -119,49 +113,18 @@ class EmailSettings(BaseSettings):
119
113
  use_starttls = self.FRACTAL_EMAIL_USE_STARTTLS == "true"
120
114
  use_login = self.FRACTAL_EMAIL_USE_LOGIN == "true"
121
115
 
122
- if use_login:
123
- if self.FRACTAL_EMAIL_PASSWORD is None:
124
- raise ValueError(
125
- "'FRACTAL_EMAIL_USE_LOGIN' is 'true' but "
126
- "'FRACTAL_EMAIL_PASSWORD' is not provided."
127
- )
128
- if self.FRACTAL_EMAIL_PASSWORD_KEY is None:
129
- raise ValueError(
130
- "'FRACTAL_EMAIL_USE_LOGIN' is 'true' but "
131
- "'FRACTAL_EMAIL_PASSWORD_KEY' is not provided."
132
- )
133
- try:
134
- (
135
- Fernet(
136
- self.FRACTAL_EMAIL_PASSWORD_KEY.get_secret_value()
137
- )
138
- .decrypt(
139
- self.FRACTAL_EMAIL_PASSWORD.get_secret_value()
140
- )
141
- .decode("utf-8")
142
- )
143
- except Exception as e:
144
- raise ValueError(
145
- "Invalid pair (FRACTAL_EMAIL_PASSWORD, "
146
- "FRACTAL_EMAIL_PASSWORD_KEY). "
147
- f"Original error: {str(e)}."
148
- )
149
- password = self.FRACTAL_EMAIL_PASSWORD.get_secret_value()
150
- else:
151
- password = None
152
-
153
- if self.FRACTAL_EMAIL_PASSWORD_KEY is not None:
154
- key = self.FRACTAL_EMAIL_PASSWORD_KEY.get_secret_value()
155
- else:
156
- key = None
116
+ if use_login and self.FRACTAL_EMAIL_PASSWORD is None:
117
+ raise ValueError(
118
+ "'FRACTAL_EMAIL_USE_LOGIN' is 'true' but "
119
+ "'FRACTAL_EMAIL_PASSWORD' is not provided."
120
+ )
157
121
 
158
122
  self.public = PublicEmailSettings(
159
123
  sender=self.FRACTAL_EMAIL_SENDER,
160
124
  recipients=self.FRACTAL_EMAIL_RECIPIENTS.split(","),
161
125
  smtp_server=self.FRACTAL_EMAIL_SMTP_SERVER,
162
126
  port=self.FRACTAL_EMAIL_SMTP_PORT,
163
- encrypted_password=password,
164
- encryption_key=key,
127
+ password=self.FRACTAL_EMAIL_PASSWORD,
165
128
  instance_name=self.FRACTAL_EMAIL_INSTANCE_NAME,
166
129
  use_starttls=use_starttls,
167
130
  use_login=use_login,
@@ -1,20 +1,12 @@
1
1
  import logging
2
2
  from typing import Literal
3
- from typing import TypeVar
4
3
 
4
+ from pydantic import HttpUrl
5
5
  from pydantic import SecretStr
6
6
  from pydantic_settings import BaseSettings
7
7
  from pydantic_settings import SettingsConfigDict
8
8
 
9
9
  from ._settings_config import SETTINGS_CONFIG_DICT
10
- from fractal_server.types import AbsolutePathStr
11
-
12
-
13
- class FractalConfigurationError(ValueError):
14
- pass
15
-
16
-
17
- T = TypeVar("T")
18
10
 
19
11
 
20
12
  class Settings(BaseSettings):
@@ -26,7 +18,6 @@ class Settings(BaseSettings):
26
18
 
27
19
  model_config = SettingsConfigDict(**SETTINGS_CONFIG_DICT)
28
20
 
29
- # JWT TOKEN
30
21
  JWT_EXPIRE_SECONDS: int = 180
31
22
  """
32
23
  JWT token lifetime, in seconds.
@@ -40,7 +31,6 @@ class Settings(BaseSettings):
40
31
  it.
41
32
  """
42
33
 
43
- # COOKIE TOKEN
44
34
  COOKIE_EXPIRE_SECONDS: int = 86400
45
35
  """
46
36
  Cookie token lifetime, in seconds.
@@ -72,50 +62,7 @@ class Settings(BaseSettings):
72
62
  Waiting time for the shutdown phase of executors
73
63
  """
74
64
 
75
- FRACTAL_VIEWER_AUTHORIZATION_SCHEME: Literal[
76
- "viewer-paths", "users-folders", "none"
77
- ] = "none"
78
- """
79
- Defines how the list of allowed viewer paths is built.
80
-
81
- This variable affects the `GET /auth/current-user/allowed-viewer-paths/`
82
- response, which is then consumed by
83
- [fractal-vizarr-viewer](https://github.com/fractal-analytics-platform/fractal-vizarr-viewer).
84
-
85
- Options:
86
-
87
- - "viewer-paths": The list of allowed viewer paths will include the user's
88
- `project_dir` along with any path defined in user groups' `viewer_paths`
89
- attributes.
90
- - "users-folders": The list will consist of the user's `project_dir` and a
91
- user-specific folder. The user folder is constructed by concatenating
92
- the base folder `FRACTAL_VIEWER_BASE_FOLDER` with the user's
93
- `slurm_user`.
94
- - "none": An empty list will be returned, indicating no access to
95
- viewer paths. Useful when vizarr viewer is not used.
96
- """
97
-
98
- FRACTAL_VIEWER_BASE_FOLDER: AbsolutePathStr | None = None
65
+ FRACTAL_HELP_URL: HttpUrl | None = None
99
66
  """
100
- Base path to Zarr files that will be served by fractal-vizarr-viewer;
101
- This variable is required and used only when
102
- FRACTAL_VIEWER_AUTHORIZATION_SCHEME is set to "users-folders".
67
+ The URL of an instance-specific Fractal help page.
103
68
  """
104
-
105
- def check(self):
106
- """
107
- Make sure that required variables are set
108
-
109
- This method must be called before the server starts
110
- """
111
- # FRACTAL_VIEWER_BASE_FOLDER is required when
112
- # FRACTAL_VIEWER_AUTHORIZATION_SCHEME is set to "users-folders"
113
- # and it must be an absolute path
114
- if self.FRACTAL_VIEWER_AUTHORIZATION_SCHEME == "users-folders":
115
- viewer_base_folder = self.FRACTAL_VIEWER_BASE_FOLDER
116
- if viewer_base_folder is None:
117
- raise FractalConfigurationError(
118
- "FRACTAL_VIEWER_BASE_FOLDER is required when "
119
- "FRACTAL_VIEWER_AUTHORIZATION_SCHEME is set to "
120
- "users-folders"
121
- )
@@ -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 = "*****"
@@ -0,0 +1,67 @@
1
+ """user-settings-related
2
+
3
+ Revision ID: f65ee53991e3
4
+ Revises: 90f6508c6379
5
+ Create Date: 2025-10-22 15:16:42.217910
6
+
7
+ """
8
+ import sqlalchemy as sa
9
+ from alembic import op
10
+ from sqlalchemy.dialects import postgresql
11
+
12
+ # revision identifiers, used by Alembic.
13
+ revision = "f65ee53991e3"
14
+ down_revision = "90f6508c6379"
15
+ branch_labels = None
16
+ depends_on = None
17
+
18
+
19
+ def upgrade() -> None:
20
+ # ### commands auto generated by Alembic - please adjust! ###
21
+ with op.batch_alter_table("user_oauth", schema=None) as batch_op:
22
+ batch_op.add_column(
23
+ sa.Column(
24
+ "project_dir",
25
+ sa.String(),
26
+ server_default="/PLACEHOLDER",
27
+ nullable=False,
28
+ )
29
+ )
30
+ batch_op.add_column(
31
+ sa.Column(
32
+ "slurm_accounts",
33
+ postgresql.ARRAY(sa.String()),
34
+ server_default="{}",
35
+ nullable=True,
36
+ )
37
+ )
38
+ batch_op.drop_constraint(
39
+ batch_op.f("fk_user_oauth_user_settings_id_user_settings"),
40
+ type_="foreignkey",
41
+ )
42
+ batch_op.drop_column("user_settings_id")
43
+
44
+ # ### end Alembic commands ###
45
+
46
+
47
+ def downgrade() -> None:
48
+ # ### commands auto generated by Alembic - please adjust! ###
49
+ with op.batch_alter_table("user_oauth", schema=None) as batch_op:
50
+ batch_op.add_column(
51
+ sa.Column(
52
+ "user_settings_id",
53
+ sa.INTEGER(),
54
+ autoincrement=False,
55
+ nullable=True,
56
+ )
57
+ )
58
+ batch_op.create_foreign_key(
59
+ batch_op.f("fk_user_oauth_user_settings_id_user_settings"),
60
+ "user_settings",
61
+ ["user_settings_id"],
62
+ ["id"],
63
+ )
64
+ batch_op.drop_column("slurm_accounts")
65
+ batch_op.drop_column("project_dir")
66
+
67
+ # ### end Alembic commands ###
@@ -87,7 +87,7 @@ class BaseSlurmRunner(BaseRunner):
87
87
  python_worker_interpreter: str,
88
88
  poll_interval: int,
89
89
  common_script_lines: list[str] | None = None,
90
- user_cache_dir: str | None = None, # FIXME: make required?
90
+ user_cache_dir: str,
91
91
  slurm_account: str | None = None,
92
92
  ):
93
93
  self.slurm_runner_type = slurm_runner_type
@@ -136,7 +136,7 @@ class SlurmConfig(BaseModel):
136
136
 
137
137
  def to_sbatch_preamble(
138
138
  self,
139
- remote_export_dir: str | None = None,
139
+ remote_export_dir: str,
140
140
  ) -> list[str]:
141
141
  """
142
142
  Compile `SlurmConfig` object into the preamble of a SLURM submission
@@ -189,13 +189,10 @@ class SlurmConfig(BaseModel):
189
189
  for line in self._sorted_extra_lines():
190
190
  lines.append(line)
191
191
 
192
- if self.user_local_exports != {} and remote_export_dir is None:
193
- raise ValueError(
194
- f"{remote_export_dir=} but {self.user_local_exports=}"
195
- )
196
- for key, value in self.user_local_exports.items():
197
- tmp_value = str(Path(remote_export_dir) / value)
198
- lines.append(f"export {key}={tmp_value}")
192
+ if self.user_local_exports:
193
+ for key, value in self.user_local_exports.items():
194
+ tmp_value = str(Path(remote_export_dir) / value)
195
+ lines.append(f"export {key}={tmp_value}")
199
196
 
200
197
  """
201
198
  FIXME export SRUN_CPUS_PER_TASK
@@ -31,7 +31,7 @@ class SlurmSSHRunner(BaseSlurmRunner):
31
31
  # Specific
32
32
  slurm_account: str | None = None,
33
33
  profile: Profile,
34
- user_cache_dir: str | None = None,
34
+ user_cache_dir: str,
35
35
  fractal_ssh: FractalSSH,
36
36
  ) -> None:
37
37
  """
@@ -54,7 +54,7 @@ class SudoSlurmRunner(BaseSlurmRunner):
54
54
  resource: Resource,
55
55
  # Specific
56
56
  profile: Profile,
57
- user_cache_dir: str | None = None, # FIXME: make required?
57
+ user_cache_dir: str,
58
58
  slurm_account: str | None = None,
59
59
  ) -> None:
60
60
  """
@@ -50,7 +50,7 @@ def process_workflow(
50
50
  fractal_ssh: FractalSSH | None = None,
51
51
  slurm_account: str | None = None,
52
52
  worker_init: str | None = None,
53
- user_cache_dir: str | None = None,
53
+ user_cache_dir: str,
54
54
  ) -> None:
55
55
  """
56
56
  Run a workflow through a `slurm_ssh` backend.
@@ -105,6 +105,7 @@ def process_workflow(
105
105
  resource=resource,
106
106
  profile=profile,
107
107
  common_script_lines=worker_init,
108
+ user_cache_dir=user_cache_dir,
108
109
  ) as runner:
109
110
  execute_tasks_v2(
110
111
  wf_task_list=workflow.task_list[
@@ -44,7 +44,7 @@ def process_workflow(
44
44
  user_id: int,
45
45
  resource: Resource,
46
46
  profile: Profile,
47
- user_cache_dir: str | None = None,
47
+ user_cache_dir: str,
48
48
  slurm_account: str | None = None,
49
49
  worker_init: str | None = None,
50
50
  fractal_ssh: FractalSSH | None = None,
@@ -52,6 +52,7 @@ class ProcessWorkflowType(Protocol):
52
52
  user_id: int,
53
53
  resource: Resource,
54
54
  profile: Profile,
55
+ user_cache_dir: str,
55
56
  ) -> None:
56
57
  ...
57
58
 
@@ -84,10 +85,10 @@ def submit_workflow(
84
85
  dataset_id: int,
85
86
  job_id: int,
86
87
  user_id: int,
87
- worker_init: str | None = None,
88
- user_cache_dir: str | None = None, # FIXME: review this
88
+ user_cache_dir: str,
89
89
  resource: Resource,
90
90
  profile: Profile,
91
+ worker_init: str | None = None,
91
92
  fractal_ssh: FractalSSH | None = None,
92
93
  ) -> None:
93
94
  """
@@ -110,8 +111,10 @@ def submit_workflow(
110
111
  Custom executor parameters that get parsed before the execution of
111
112
  each task.
112
113
  user_cache_dir:
113
- Cache directory (namely a path where the user can write); for the
114
- slurm backend, this is used as a base directory for FIXME.
114
+ Cache directory (namely a path where the user can write). For
115
+ `slurm_sudo` backend, this is both a base directory for
116
+ `job.working_dir_user`. For `slurm_sudo` and `slurm_ssh` backends,
117
+ this is used for `user_local_exports`.
115
118
  resource:
116
119
  Computational resource to be used for this job (e.g. a SLURM
117
120
  cluster).
@@ -224,22 +227,18 @@ def submit_workflow(
224
227
  job_working_dir = job.working_dir
225
228
 
226
229
  try:
230
+ process_workflow: ProcessWorkflowType
227
231
  match resource.type:
228
232
  case ResourceType.LOCAL:
229
- process_workflow: ProcessWorkflowType = local_process_workflow
233
+ process_workflow = local_process_workflow
230
234
  backend_specific_kwargs = {}
231
235
  case ResourceType.SLURM_SUDO:
232
- process_workflow: ProcessWorkflowType = (
233
- slurm_sudo_process_workflow
234
- )
236
+ process_workflow = slurm_sudo_process_workflow
235
237
  backend_specific_kwargs = dict(
236
238
  slurm_account=job.slurm_account,
237
- user_cache_dir=user_cache_dir,
238
239
  )
239
240
  case ResourceType.SLURM_SSH:
240
- process_workflow: ProcessWorkflowType = (
241
- slurm_ssh_process_workflow
242
- )
241
+ process_workflow = slurm_ssh_process_workflow
243
242
  backend_specific_kwargs = dict(
244
243
  fractal_ssh=fractal_ssh,
245
244
  slurm_account=job.slurm_account,
@@ -260,6 +259,7 @@ def submit_workflow(
260
259
  job_type_filters=job.type_filters,
261
260
  resource=resource,
262
261
  profile=profile,
262
+ user_cache_dir=user_cache_dir,
263
263
  **backend_specific_kwargs,
264
264
  )
265
265
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fractal-server
3
- Version: 2.17.0a4
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
@@ -12,20 +12,18 @@ Classifier: Programming Language :: Python :: 3.11
12
12
  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
- Requires-Dist: cryptography (>=46.0.0,<47.0.0)
16
15
  Requires-Dist: fabric (>=3.2.2,<3.3.0)
17
- Requires-Dist: fastapi (>=0.118.0,<0.119.0)
18
- 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)
19
18
  Requires-Dist: gunicorn (>=23.0,<24.0)
20
19
  Requires-Dist: packaging (>=25.0.0,<26.0.0)
21
20
  Requires-Dist: psycopg[binary] (>=3.1.0,<4.0.0)
22
21
  Requires-Dist: pydantic (>=2.12.0,<2.13.0)
23
22
  Requires-Dist: pydantic-settings (==2.11.0)
24
- Requires-Dist: python-dotenv (>=1.1.0,<1.2.0)
25
23
  Requires-Dist: sqlalchemy[asyncio] (>=2.0.23,<2.1)
26
24
  Requires-Dist: sqlmodel (==0.0.27)
27
25
  Requires-Dist: tomli_w (>=1.2.0,<1.3.0)
28
- Requires-Dist: uvicorn (>=0.37.0,<0.38.0)
26
+ Requires-Dist: uvicorn (>=0.38.0,<0.39.0)
29
27
  Requires-Dist: uvicorn-worker (==0.4.0)
30
28
  Project-URL: Documentation, https://fractal-analytics-platform.github.io/fractal-server
31
29
  Project-URL: Homepage, https://github.com/fractal-analytics-platform/fractal-server