fractal-server 1.4.0a7__py3-none-any.whl → 1.4.0a9__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__ = "1.4.0a7"
1
+ __VERSION__ = "1.4.0a9"
@@ -63,7 +63,9 @@ class DB:
63
63
  connect_args={"check_same_thread": False},
64
64
  )
65
65
  else:
66
- engine_kwargs_async = {}
66
+ engine_kwargs_async = {
67
+ "pool_pre_ping": True,
68
+ }
67
69
  engine_kwargs_sync = {}
68
70
 
69
71
  cls._engine_async = create_async_engine(
@@ -80,11 +82,17 @@ class DB:
80
82
  )
81
83
 
82
84
  cls._async_session_maker = sessionmaker(
83
- cls._engine_async, class_=AsyncSession, expire_on_commit=False
85
+ cls._engine_async,
86
+ class_=AsyncSession,
87
+ expire_on_commit=False,
88
+ future=True,
84
89
  )
85
90
 
86
91
  cls._sync_session_maker = sessionmaker(
87
- bind=cls._engine_sync, autocommit=False, autoflush=False
92
+ bind=cls._engine_sync,
93
+ autocommit=False,
94
+ autoflush=False,
95
+ future=True,
88
96
  )
89
97
 
90
98
  @event.listens_for(cls._engine_sync, "connect")
@@ -15,8 +15,12 @@ from .....config import get_settings
15
15
  from .....syringe import Inject
16
16
  from ....db import AsyncSession
17
17
  from ....db import get_db
18
+ from ....models import ApplyWorkflow
18
19
  from ....runner._common import SHUTDOWN_FILENAME
19
20
  from ....schemas import ApplyWorkflowRead
21
+ from ....schemas import ApplyWorkflowUpdate
22
+ from ....schemas import JobStatusType
23
+ from ....security import current_active_superuser
20
24
  from ....security import current_active_user
21
25
  from ....security import User
22
26
  from ._aux_functions import _get_job_check_owner
@@ -196,3 +200,39 @@ async def stop_job(
196
200
  f.write(f"Trigger executor shutdown for {job.id=}, {project_id=}.")
197
201
 
198
202
  return Response(status_code=status.HTTP_204_NO_CONTENT)
203
+
204
+
205
+ @router.patch(
206
+ "/job/{job_id}/",
207
+ response_model=ApplyWorkflowRead,
208
+ )
209
+ async def update_job(
210
+ job_update: ApplyWorkflowUpdate,
211
+ job_id: int,
212
+ user: User = Depends(current_active_superuser),
213
+ db: AsyncSession = Depends(get_db),
214
+ ) -> Optional[ApplyWorkflowRead]:
215
+ """
216
+ Change the status of an existing job.
217
+
218
+ This endpoint is only open to superusers, and it does not apply
219
+ project-based access-control to jobs.
220
+ """
221
+ job = await db.get(ApplyWorkflow, job_id)
222
+ if job is None:
223
+ raise HTTPException(
224
+ status_code=status.HTTP_404_NOT_FOUND,
225
+ detail=f"Job {job_id} not found",
226
+ )
227
+
228
+ if job_update.status != JobStatusType.FAILED:
229
+ raise HTTPException(
230
+ status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
231
+ detail=f"Cannot set job status to {job_update.status}",
232
+ )
233
+
234
+ setattr(job, "status", job_update.status)
235
+ await db.commit()
236
+ await db.refresh(job)
237
+ await db.close()
238
+ return job
@@ -3,6 +3,11 @@ Definition of `/auth` routes.
3
3
  """
4
4
  from fastapi import APIRouter
5
5
  from fastapi import Depends
6
+ from fastapi import HTTPException
7
+ from fastapi import status
8
+ from fastapi_users import exceptions
9
+ from fastapi_users import schemas
10
+ from fastapi_users.router.common import ErrorCode
6
11
  from sqlalchemy.ext.asyncio import AsyncSession
7
12
  from sqlmodel import select
8
13
 
@@ -13,12 +18,14 @@ from ..models.security import UserOAuth as User
13
18
  from ..schemas.user import UserCreate
14
19
  from ..schemas.user import UserRead
15
20
  from ..schemas.user import UserUpdate
21
+ from ..schemas.user import UserUpdateStrict
16
22
  from ..security import cookie_backend
17
23
  from ..security import current_active_superuser
18
24
  from ..security import current_active_user
19
25
  from ..security import fastapi_users
26
+ from ..security import get_user_manager
20
27
  from ..security import token_backend
21
-
28
+ from ..security import UserManager
22
29
 
23
30
  router_auth = APIRouter()
24
31
 
@@ -33,18 +40,22 @@ router_auth.include_router(
33
40
  fastapi_users.get_register_router(UserRead, UserCreate),
34
41
  dependencies=[Depends(current_active_superuser)],
35
42
  )
36
- router_auth.include_router(
37
- fastapi_users.get_reset_password_router(),
38
- )
39
- router_auth.include_router(
40
- fastapi_users.get_verify_router(UserRead),
41
- )
42
43
 
43
- # Include users routes, after removing DELETE endpoint (ref
44
- # https://github.com/fastapi-users/fastapi-users/discussions/606)
45
44
  users_router = fastapi_users.get_users_router(UserRead, UserUpdate)
45
+
46
+ # We remove `/auth/users/me` endpoints to implement our own
47
+ # at `/auth/current-user/`.
48
+ # We also remove `DELETE /auth/users/{user_id}`
49
+ # (ref https://github.com/fastapi-users/fastapi-users/discussions/606)
46
50
  users_router.routes = [
47
- route for route in users_router.routes if route.name != "users:delete_user"
51
+ route
52
+ for route in users_router.routes
53
+ if route.name
54
+ not in [
55
+ "users:current_user",
56
+ "users:delete_user",
57
+ "users:patch_current_user",
58
+ ]
48
59
  ]
49
60
  router_auth.include_router(
50
61
  users_router,
@@ -53,17 +64,37 @@ router_auth.include_router(
53
64
  )
54
65
 
55
66
 
56
- @router_auth.get("/whoami", response_model=UserRead)
57
- async def whoami(
58
- user: User = Depends(current_active_user),
67
+ @router_auth.patch("/current-user/", response_model=UserRead)
68
+ async def patch_current_user(
69
+ user_update: UserUpdateStrict,
70
+ current_user: User = Depends(current_active_user),
71
+ user_manager: UserManager = Depends(get_user_manager),
59
72
  ):
73
+
74
+ update = UserUpdate(**user_update.dict(exclude_unset=True))
75
+
76
+ try:
77
+ user = await user_manager.update(update, current_user, safe=True)
78
+ except exceptions.InvalidPasswordException as e:
79
+ raise HTTPException(
80
+ status_code=status.HTTP_400_BAD_REQUEST,
81
+ detail={
82
+ "code": ErrorCode.UPDATE_USER_INVALID_PASSWORD,
83
+ "reason": e.reason,
84
+ },
85
+ )
86
+ return schemas.model_validate(User, user)
87
+
88
+
89
+ @router_auth.get("/current-user/", response_model=UserRead)
90
+ async def get_current_user(user: User = Depends(current_active_user)):
60
91
  """
61
92
  Return current user
62
93
  """
63
94
  return user
64
95
 
65
96
 
66
- @router_auth.get("/userlist", response_model=list[UserRead])
97
+ @router_auth.get("/users/", response_model=list[UserRead])
67
98
  async def list_users(
68
99
  user: User = Depends(current_active_superuser),
69
100
  db: AsyncSession = Depends(get_db),
@@ -3,6 +3,7 @@ Schemas for API request/response bodies
3
3
  """
4
4
  from .applyworkflow import ApplyWorkflowCreate # noqa: F401
5
5
  from .applyworkflow import ApplyWorkflowRead # noqa: F401
6
+ from .applyworkflow import ApplyWorkflowUpdate # noqa: F401
6
7
  from .applyworkflow import JobStatusType # noqa: F401
7
8
  from .dataset import DatasetCreate # noqa: F401
8
9
  from .dataset import DatasetRead # noqa: F401
@@ -146,3 +146,14 @@ class ApplyWorkflowRead(_ApplyWorkflowBase):
146
146
  d["start_timestamp"] = str(self.start_timestamp)
147
147
  d["end_timestamp"] = str(self.end_timestamp)
148
148
  return d
149
+
150
+
151
+ class ApplyWorkflowUpdate(BaseModel):
152
+ """
153
+ Class for updating a job status.
154
+
155
+ Attributes:
156
+ status: New job status.
157
+ """
158
+
159
+ status: JobStatusType
@@ -1,6 +1,8 @@
1
1
  from typing import Optional
2
2
 
3
3
  from fastapi_users import schemas
4
+ from pydantic import BaseModel
5
+ from pydantic import Extra
4
6
  from pydantic import validator
5
7
 
6
8
  from ._validators import val_absolute_path
@@ -52,6 +54,31 @@ class UserUpdate(schemas.BaseUserUpdate):
52
54
  val_absolute_path("cache_dir")
53
55
  )
54
56
 
57
+ @validator(
58
+ "is_active",
59
+ "is_verified",
60
+ "is_superuser",
61
+ "email",
62
+ "password",
63
+ always=False,
64
+ )
65
+ def cant_set_none(cls, v, field):
66
+ if v is None:
67
+ raise ValueError(f"Cannot set {field.name}=None")
68
+ return v
69
+
70
+
71
+ class UserUpdateStrict(BaseModel, extra=Extra.forbid):
72
+ """
73
+ Attributes that every user can self-edit
74
+ """
75
+
76
+ cache_dir: Optional[str]
77
+
78
+ _cache_dir = validator("cache_dir", allow_reuse=True)(
79
+ val_absolute_path("cache_dir")
80
+ )
81
+
55
82
 
56
83
  class UserCreate(schemas.BaseUserCreate):
57
84
  """
@@ -35,8 +35,6 @@ from typing import Type
35
35
 
36
36
  from fastapi import Depends
37
37
  from fastapi import HTTPException
38
- from fastapi import Request
39
- from fastapi import Response
40
38
  from fastapi import status
41
39
  from fastapi_users import BaseUserManager
42
40
  from fastapi_users import FastAPIUsers
@@ -46,6 +44,7 @@ from fastapi_users.authentication import BearerTransport
46
44
  from fastapi_users.authentication import CookieTransport
47
45
  from fastapi_users.authentication import JWTStrategy
48
46
  from fastapi_users.db.base import BaseUserDatabase
47
+ from fastapi_users.exceptions import InvalidPasswordException
49
48
  from fastapi_users.models import ID
50
49
  from fastapi_users.models import OAP
51
50
  from fastapi_users.models import UP
@@ -176,17 +175,17 @@ async def get_user_db(
176
175
 
177
176
 
178
177
  class UserManager(IntegerIDMixin, BaseUserManager[User, int]):
179
- async def on_after_login(
180
- self,
181
- user: User,
182
- request: Optional[Request] = None,
183
- response: Optional[Response] = None,
184
- ) -> None:
185
- """
186
- Perform logic after user login.
187
- *You should overload this method to add your own logic.*
188
- """
189
- pass
178
+ async def validate_password(self, password: str, user: User) -> None:
179
+ # check password length
180
+ min_length, max_length = 4, 100
181
+ if len(password) < min_length:
182
+ raise InvalidPasswordException(
183
+ f"The password is too short (minimum length: {min_length})."
184
+ )
185
+ elif len(password) > max_length:
186
+ raise InvalidPasswordException(
187
+ f"The password is too long (maximum length: {min_length})."
188
+ )
190
189
 
191
190
 
192
191
  async def get_user_manager(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fractal-server
3
- Version: 1.4.0a7
3
+ Version: 1.4.0a9
4
4
  Summary: Server component of the Fractal analytics platform
5
5
  Home-page: https://github.com/fractal-analytics-platform/fractal-server
6
6
  License: BSD-3-Clause
@@ -12,12 +12,13 @@ Classifier: Programming Language :: Python :: 3
12
12
  Classifier: Programming Language :: Python :: 3.9
13
13
  Classifier: Programming Language :: Python :: 3.10
14
14
  Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
15
16
  Provides-Extra: gunicorn
16
17
  Provides-Extra: postgres
17
18
  Provides-Extra: slurm
18
19
  Requires-Dist: aiosqlite (>=0.17.0,<0.18.0)
19
20
  Requires-Dist: alembic (>=1.9.1,<2.0.0)
20
- Requires-Dist: asyncpg (>=0.27.0,<0.28.0) ; extra == "postgres"
21
+ Requires-Dist: asyncpg (>=0.29.0,<0.30.0) ; extra == "postgres"
21
22
  Requires-Dist: cloudpickle (>=2.2.1,<2.3.0) ; extra == "slurm"
22
23
  Requires-Dist: clusterfutures (>=0.5,<0.6) ; extra == "slurm"
23
24
  Requires-Dist: fastapi (>=0.103.0,<0.104.0)
@@ -26,8 +27,8 @@ Requires-Dist: gunicorn (>=20.1.0,<21.0.0) ; extra == "gunicorn"
26
27
  Requires-Dist: psycopg2 (>=2.9.5,<3.0.0) ; extra == "postgres"
27
28
  Requires-Dist: pydantic (>=1.10.8,<2)
28
29
  Requires-Dist: python-dotenv (>=0.20.0,<0.21.0)
29
- Requires-Dist: sqlalchemy[asyncio] (>=1.4,<2.0)
30
- Requires-Dist: sqlmodel (>=0.0.11,<0.0.12)
30
+ Requires-Dist: sqlalchemy[asyncio] (>=2.0.23,<2.1)
31
+ Requires-Dist: sqlmodel (>=0.0.12,<0.0.13)
31
32
  Requires-Dist: uvicorn (>=0.20.0,<0.21.0)
32
33
  Project-URL: Changelog, https://github.com/fractal-analytics-platform/fractal-server/blob/main/CHANGELOG.md
33
34
  Project-URL: Documentation, https://fractal-analytics-platform.github.io/fractal-server
@@ -1,8 +1,8 @@
1
- fractal_server/__init__.py,sha256=N2MagRx5dIspHCzA8pKzYWpIRqjQogIOXNJvb_S8HJ8,24
1
+ fractal_server/__init__.py,sha256=IneygUCsbuvssacaRSvCjbRcp6R_sPRDaCi7xtY7xSY,24
2
2
  fractal_server/__main__.py,sha256=znijcImbcEC4P26ICOhEJ9VY3_5vWdMwQcl-WP25sYA,2202
3
3
  fractal_server/alembic.ini,sha256=MWwi7GzjzawI9cCAK1LW7NxIBQDUqD12-ptJoq5JpP0,3153
4
4
  fractal_server/app/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
- fractal_server/app/db/__init__.py,sha256=KWmQiO9CZ3f16RpKcnLa1BvpTwFv7WUpeMn6LmAe6KA,3629
5
+ fractal_server/app/db/__init__.py,sha256=gJCmPYNVg8UEjvtPWLupM3yzZRpt3wvHjZuUsn1DBXk,3781
6
6
  fractal_server/app/models/__init__.py,sha256=RuxWH8fsmkTWsjLhYjrxSt-mvk74coCilAQlX2Q6OO0,353
7
7
  fractal_server/app/models/dataset.py,sha256=fcZkb2y7PXlFJAyZtndJ7Gf4c8VpkWjZe47iMybv1aE,2109
8
8
  fractal_server/app/models/job.py,sha256=DbX7OMx88eC-232C_OdYOpNeyN0tma7p8J3x7HB43os,2768
@@ -18,13 +18,13 @@ fractal_server/app/routes/api/__init__.py,sha256=EVyZrEq3I_1643QGTPCC5lgCp4xH_au
18
18
  fractal_server/app/routes/api/v1/__init__.py,sha256=V4nhYyMIqhlJxbotLTYikq_ghb6KID0ZKOOYaOq7C-g,944
19
19
  fractal_server/app/routes/api/v1/_aux_functions.py,sha256=qaeTsfSk78FHSsMVNkGdPIPBjeKOEd1sq0KhY0SQ1l0,10095
20
20
  fractal_server/app/routes/api/v1/dataset.py,sha256=_P8SUXEs5Gh-a82QR06xyZ_F6eX6R_CxmBduNXEeERY,14968
21
- fractal_server/app/routes/api/v1/job.py,sha256=07nrsWvPcV-DkFybiMKgHLVDp_CFeFx6pnEKnBNrvL4,5382
21
+ fractal_server/app/routes/api/v1/job.py,sha256=9jEoIYnUvtc3oB52yRhFd_NYJk8tGK3qorDOjcgiN1I,6554
22
22
  fractal_server/app/routes/api/v1/project.py,sha256=uP-p9rghQBQ_vRZ2hUw_bT21WVLpqdgJNdxN6z367YI,11417
23
23
  fractal_server/app/routes/api/v1/task.py,sha256=iT45B_NXvBilp-aclWuONsNAWvpczrEWO21K9DOJsZ0,5504
24
24
  fractal_server/app/routes/api/v1/task_collection.py,sha256=bMnhrMkI_45Bttd6J9j_CEmpjQZCV5mTy8_j1Ca8xQg,11724
25
25
  fractal_server/app/routes/api/v1/workflow.py,sha256=rXU-wyU8SFJ7t6tNl2dCiugXzMjFpYV_ljTcYQrC8NE,9819
26
26
  fractal_server/app/routes/api/v1/workflowtask.py,sha256=ZXmZBymcQgt838Bywoxcy6M0l1z2uatHJxq_e45-8T0,5432
27
- fractal_server/app/routes/auth.py,sha256=XEerBzlHE7b4XfB6Bk0qYj6edRM6yFZr3UosLzjfvt8,3816
27
+ fractal_server/app/routes/auth.py,sha256=aBR0ZICrbJpOgPO972HN5lJ1YqfkrO0avwdrSRvI9aQ,4873
28
28
  fractal_server/app/runner/.gitignore,sha256=ytzN_oyHWXrGU7iFAtoHSTUbM6Rn6kG0Zkddg0xZk6s,16
29
29
  fractal_server/app/runner/__init__.py,sha256=WNMxT9XFEocPOdJRN6FfMek-LecOpBYXfJxmxupMRUE,13597
30
30
  fractal_server/app/runner/_common.py,sha256=p8T-fUD357vaBXPwNPZOHptRRT3c3scnhzgHYoxFNro,22649
@@ -43,9 +43,9 @@ fractal_server/app/runner/_slurm/executor.py,sha256=ao5YuWtjsIfTYUucE1SvNS8a99Sg
43
43
  fractal_server/app/runner/_slurm/remote.py,sha256=wLziIsGdSMiO-jIXM8x77JRK82g_2hx0iBKTiMghuIo,5852
44
44
  fractal_server/app/runner/common.py,sha256=nz0ZuIro0iwZm-OV-e-Y-PrtgKcLK0d7BrzebWyEWEk,9496
45
45
  fractal_server/app/runner/handle_failed_job.py,sha256=PKgJARHjXyv33sDsl7oTINdcTu7EwmFmIkp38RqAE3Q,4641
46
- fractal_server/app/schemas/__init__.py,sha256=th51Dzbe94xatOIMVheqlq0rVFy8oI1CHRfzCbjiTSg,1859
46
+ fractal_server/app/schemas/__init__.py,sha256=UciI1WXCtZbGj9rSBFN388_oaJACzNY0yJulxbMR17w,1920
47
47
  fractal_server/app/schemas/_validators.py,sha256=7YEbgrnGRpzkLMfZzQNfczEmcNnO__SmVOaBHhzaiXE,1819
48
- fractal_server/app/schemas/applyworkflow.py,sha256=zzQy_vxWjzUE0WnZHQWQBU7GB0a8ZkBczZidl32WOY0,3911
48
+ fractal_server/app/schemas/applyworkflow.py,sha256=8GLvfhfsH3CbFShkiihqYhQ89gA0vbvx-DT9zGHWGRo,4080
49
49
  fractal_server/app/schemas/dataset.py,sha256=PPqGTsRQ5JEwkiM4NcjPYFckxnCdi_Zov-bWXDm1LUk,3092
50
50
  fractal_server/app/schemas/json_schemas/manifest.json,sha256=yXYKHbYXPYSkSXMTLfTpfCUGBtmQuPTk1xuSXscdba4,1787
51
51
  fractal_server/app/schemas/manifest.py,sha256=xxTd39dAXMK9Ox1y-p3gbyg0zd5udW99pV4JngCUGwM,3819
@@ -53,9 +53,9 @@ fractal_server/app/schemas/project.py,sha256=qfVqDeQPIyb1QiT6oUJNcF6gXcSfjsj3BJE
53
53
  fractal_server/app/schemas/state.py,sha256=CS8Rs5qF21TsnqmyzUHLqRaX1b61Oc6Yra6POYpYSQY,762
54
54
  fractal_server/app/schemas/task.py,sha256=2TBE5Ne9tO_-a2-Es0PRXMT8ZddSInTOPMor7u8-gx0,3671
55
55
  fractal_server/app/schemas/task_collection.py,sha256=mPk6E1LK2UvnHkhIQWHmTztsVT99iHZn-UZy7mGNjUk,2965
56
- fractal_server/app/schemas/user.py,sha256=zhB-2WfJ30hNcHaW2V126v5i7rHl66fX_SRmIWCQrjM,1587
56
+ fractal_server/app/schemas/user.py,sha256=vxoxojcnCngjGlAzNtd1rp4zw_mWsBije0AJR2le1Ik,2187
57
57
  fractal_server/app/schemas/workflow.py,sha256=oFoO62JH5hfMJjKoicdpyC5hd2O9XgqoAm5RN9YjXAI,4238
58
- fractal_server/app/security/__init__.py,sha256=dnLkDpzduB9pS5dNeUZhEb0z6ZDb7dPreE57uCtxOBE,7998
58
+ fractal_server/app/security/__init__.py,sha256=_h50FYHMBn70_F2qV54rewairdllmwEK_Z9jU6e7fWM,8189
59
59
  fractal_server/config.py,sha256=zekTDA_FhQG_RYgOWEIxT6KyJKRpMge-pB-iYRr4sIY,14447
60
60
  fractal_server/logger.py,sha256=keri8i960WHT8Zz9Rm2MwfnrA2dw9TsrfCmojqtGDLs,4562
61
61
  fractal_server/main.py,sha256=N82d-bq0TxOItUBwo5MZO693oL9lklu5-chk2McB8Eo,6662
@@ -76,8 +76,8 @@ fractal_server/syringe.py,sha256=3qSMW3YaMKKnLdgnooAINOPxnCOxP7y2jeAQYB21Gdo,278
76
76
  fractal_server/tasks/__init__.py,sha256=Wzuxf5EoH1v0fYzRpAZHG_S-Z9f6DmbIsuSvllBCGvc,72
77
77
  fractal_server/tasks/collection.py,sha256=POKvQyS5G5ySybH0r0v21I_ZQ5AREe9kAqr_uFfGyaU,17627
78
78
  fractal_server/utils.py,sha256=b7WwFdcFZ8unyT65mloFToYuEDXpQoHRcmRNqrhd_dQ,2115
79
- fractal_server-1.4.0a7.dist-info/LICENSE,sha256=QKAharUuhxL58kSoLizKJeZE3mTCBnX6ucmz8W0lxlk,1576
80
- fractal_server-1.4.0a7.dist-info/METADATA,sha256=TSSUg_-pl8slsQ6suxXi5J2aR9uiThGFOQX7Jiad4WA,3773
81
- fractal_server-1.4.0a7.dist-info/WHEEL,sha256=Zb28QaM1gQi8f4VCBhsUklF61CTlNYfs9YAZn-TOGFk,88
82
- fractal_server-1.4.0a7.dist-info/entry_points.txt,sha256=8tV2kynvFkjnhbtDnxAqImL6HMVKsopgGfew0DOp5UY,58
83
- fractal_server-1.4.0a7.dist-info/RECORD,,
79
+ fractal_server-1.4.0a9.dist-info/LICENSE,sha256=QKAharUuhxL58kSoLizKJeZE3mTCBnX6ucmz8W0lxlk,1576
80
+ fractal_server-1.4.0a9.dist-info/METADATA,sha256=ES4pTFqvvpmuYSrpQlW0YyOIFN2M2RvoxAQYAJAwTvc,3827
81
+ fractal_server-1.4.0a9.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
82
+ fractal_server-1.4.0a9.dist-info/entry_points.txt,sha256=8tV2kynvFkjnhbtDnxAqImL6HMVKsopgGfew0DOp5UY,58
83
+ fractal_server-1.4.0a9.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 1.6.1
2
+ Generator: poetry-core 1.8.1
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any