fractal-server 2.16.1__py3-none-any.whl → 2.16.2a0__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.16.1"
1
+ __VERSION__ = "2.16.2a0"
fractal_server/config.py CHANGED
@@ -18,16 +18,19 @@ import sys
18
18
  from os import environ
19
19
  from os import getenv
20
20
  from pathlib import Path
21
+ from typing import Annotated
21
22
  from typing import Literal
22
23
  from typing import TypeVar
23
24
 
24
25
  from cryptography.fernet import Fernet
25
26
  from dotenv import load_dotenv
27
+ from pydantic import AfterValidator
26
28
  from pydantic import BaseModel
27
29
  from pydantic import EmailStr
28
30
  from pydantic import Field
29
31
  from pydantic import field_validator
30
32
  from pydantic import model_validator
33
+ from pydantic import PositiveInt
31
34
  from pydantic import SecretStr
32
35
  from pydantic_settings import BaseSettings
33
36
  from pydantic_settings import SettingsConfigDict
@@ -36,6 +39,7 @@ from sqlalchemy.engine import URL
36
39
  import fractal_server
37
40
  from fractal_server.types import AbsolutePathStr
38
41
  from fractal_server.types import DictStrStr
42
+ from fractal_server.types import NonEmptyStr
39
43
 
40
44
 
41
45
  class MailSettings(BaseModel):
@@ -64,6 +68,47 @@ class MailSettings(BaseModel):
64
68
  use_login: bool
65
69
 
66
70
 
71
+ def _check_pixi_slurm_memory(mem: str) -> str:
72
+ if mem[-1] not in ["K", "M", "G", "T"]:
73
+ raise ValueError(
74
+ f"Invalid memory requirement {mem=} for `pixi`, "
75
+ "please set a K/M/G/T units suffix."
76
+ )
77
+ return mem
78
+
79
+
80
+ class PixiSLURMConfig(BaseModel):
81
+ """
82
+ Parameters that are passed directly to a `sbatch` command.
83
+
84
+ See https://slurm.schedmd.com/sbatch.html.
85
+ """
86
+
87
+ partition: NonEmptyStr
88
+ """
89
+ `-p, --partition=<partition_names>`
90
+ """
91
+ cpus: PositiveInt
92
+ """
93
+ `-c, --cpus-per-task=<ncpus>
94
+ """
95
+ mem: Annotated[NonEmptyStr, AfterValidator(_check_pixi_slurm_memory)]
96
+ """
97
+ `--mem=<size>[units]` (examples: `"10M"`, `"10G"`).
98
+ From `sbatch` docs: Specify the real memory required per node. Default
99
+ units are megabytes. Different units can be specified using the suffix
100
+ [K|M|G|T].
101
+ """
102
+ time: NonEmptyStr
103
+ """
104
+ `-t, --time=<time>`.
105
+ From `sbatch` docs: "A time limit of zero requests that no time limit be
106
+ imposed. Acceptable time formats include "minutes", "minutes:seconds",
107
+ "hours:minutes:seconds", "days-hours", "days-hours:minutes" and
108
+ "days-hours:minutes:seconds".
109
+ """
110
+
111
+
67
112
  class PixiSettings(BaseModel):
68
113
  """
69
114
  Configuration for Pixi Task collection.
@@ -130,9 +175,15 @@ class PixiSettings(BaseModel):
130
175
  """
131
176
  DEFAULT_ENVIRONMENT: str = "default"
132
177
  """
178
+ Default pixi environment name.
133
179
  """
134
180
  DEFAULT_PLATFORM: str = "linux-64"
135
181
  """
182
+ Default platform for pixi.
183
+ """
184
+ SLURM_CONFIG: PixiSLURMConfig | None = None
185
+ """
186
+ Required when using pixi in a SSH/SLURM deployment.
136
187
  """
137
188
 
138
189
  @model_validator(mode="after")
@@ -784,6 +835,10 @@ class Settings(BaseSettings):
784
835
  raise FractalConfigurationError(
785
836
  f"Must set FRACTAL_SLURM_WORKER_PYTHON when {info}"
786
837
  )
838
+ if self.pixi and self.pixi.SLURM_CONFIG is None:
839
+ raise FractalConfigurationError(
840
+ "Pixi config must include SLURM_CONFIG."
841
+ )
787
842
 
788
843
  from fractal_server.app.runner.executors.slurm_common._slurm_config import ( # noqa: E501
789
844
  load_slurm_config_file,
@@ -0,0 +1,115 @@
1
+ import os
2
+ import time
3
+ from pathlib import Path
4
+
5
+ from fractal_server.config import get_settings
6
+ from fractal_server.config import PixiSLURMConfig
7
+ from fractal_server.logger import get_logger
8
+ from fractal_server.ssh._fabric import FractalSSH
9
+ from fractal_server.syringe import Inject
10
+
11
+
12
+ # https://slurm.schedmd.com/squeue.html#lbAG
13
+ STATES_FINISHED = {
14
+ "BOOT_FAIL",
15
+ "CANCELLED",
16
+ "COMPLETED",
17
+ "DEADLINE",
18
+ "FAILED",
19
+ "NODE_FAIL",
20
+ "OUT_OF_MEMORY",
21
+ "PREEMPTED",
22
+ "SPECIAL_EXIT",
23
+ "TIMEOUT",
24
+ }
25
+
26
+
27
+ def run_script_on_remote_slurm(
28
+ *,
29
+ script_path: str,
30
+ slurm_config: PixiSLURMConfig,
31
+ fractal_ssh: FractalSSH,
32
+ logger_name: str,
33
+ prefix: str,
34
+ ):
35
+ """
36
+ FIXME
37
+
38
+
39
+ NOTE: This is called from within a try/except, thus we can use exceptions
40
+ as a mechanism to propagate failure/errors.
41
+ """
42
+
43
+ logger = get_logger(logger_name=logger_name)
44
+ settings = Inject(get_settings)
45
+
46
+ # (1) Prepare remote submission script
47
+ workdir_remote = Path(script_path).parent.as_posix()
48
+ submission_script_remote = os.path.join(
49
+ workdir_remote, f"{prefix}-submit.sh"
50
+ )
51
+ stderr_remote = os.path.join(workdir_remote, f"{prefix}-err.txt")
52
+ stdout_remote = os.path.join(workdir_remote, f"{prefix}-out.txt")
53
+ success_file_remote = os.path.join(workdir_remote, f"{prefix}-success.txt")
54
+ script_lines = [
55
+ "#!/bin/bash",
56
+ f"#SBATCH --partition={slurm_config.partition}",
57
+ f"#SBATCH --cpus-per-task={slurm_config.cpus}",
58
+ f"#SBATCH --mem={slurm_config.mem}",
59
+ f"#SBATCH --time={slurm_config.time}",
60
+ f"#SBATCH --err={stderr_remote}",
61
+ f"#SBATCH --out={stdout_remote}",
62
+ f"#SBATCH -D {workdir_remote}",
63
+ "",
64
+ f"bash {script_path}",
65
+ f"touch {success_file_remote}",
66
+ "",
67
+ ]
68
+ script_contents = "\n".join(script_lines)
69
+ fractal_ssh.write_remote_file(
70
+ path=submission_script_remote,
71
+ content=script_contents,
72
+ )
73
+
74
+ # (2) Submit SLURM job
75
+ sbatch_cmd = f"sbatch --parsable {submission_script_remote} "
76
+ try:
77
+ stdout = fractal_ssh.run_command(cmd=sbatch_cmd)
78
+ except Exception as e:
79
+ logger.error(
80
+ f"Submission of {submission_script_remote} failed. "
81
+ f"Original error: {str(e)}"
82
+ )
83
+ raise e
84
+ logger.debug(f"Now submit job {submission_script_remote} to SLURM.")
85
+ job_id = int(stdout)
86
+ logger.debug(f"SLURM-job submission successful ({job_id=}).")
87
+
88
+ # (3) Monitor job
89
+ squeue_cmd = (
90
+ f"squeue --noheader --format='%i %T' --states=all --jobs={job_id}"
91
+ )
92
+ while True:
93
+ try:
94
+ stdout = fractal_ssh.run_command(cmd=squeue_cmd)
95
+ except Exception as e:
96
+ # FIXME: review this logic
97
+ logger.info(
98
+ f"`squeue` command failed (original error: {e}), "
99
+ "consider the job as complete."
100
+ )
101
+ break
102
+ state = stdout.strip().split()[1]
103
+ logger.debug(f"Status of SLURM job {job_id}: {state}")
104
+ if state in STATES_FINISHED:
105
+ logger.debug(f"Exit retrieval loop ({state=}).")
106
+ break
107
+ time.sleep(settings.FRACTAL_SLURM_POLL_INTERVAL)
108
+
109
+ if fractal_ssh.remote_exists(path=success_file_remote):
110
+ logger.info(f"{success_file_remote=} exists.")
111
+ else:
112
+ raise RuntimeError(
113
+ "SLURM job did not complete correctly "
114
+ f"({success_file_remote=} missing)."
115
+ )
@@ -17,29 +17,26 @@ from fractal_server.tasks.v2.utils_templates import customize_template
17
17
  logger = set_logger(__name__)
18
18
 
19
19
 
20
- def _customize_and_run_template(
20
+ def _customize_and_send_template(
21
21
  *,
22
22
  template_filename: str,
23
23
  replacements: set[tuple[str, str]],
24
24
  script_dir_local: str,
25
+ script_dir_remote: str,
25
26
  prefix: str,
26
27
  fractal_ssh: FractalSSH,
27
- script_dir_remote: str,
28
28
  logger_name: str,
29
- login_shell: bool = False,
30
29
  ) -> str:
31
30
  """
32
- Customize one of the template bash scripts, transfer it to the remote host
33
- via SFTP and then run it via SSH.
31
+ Customize a template bash scripts and transfer it to the remote host.
34
32
 
35
33
  Args:
36
34
  template_filename: Filename of the template file (ends with ".sh").
37
35
  replacements: Dictionary of replacements.
38
36
  script_dir_local: Local folder where the script will be placed.
37
+ script_dir_remote: Remote scripts directory
39
38
  prefix: Prefix for the script filename.
40
39
  fractal_ssh: FractalSSH object
41
- script_dir_remote: Remote scripts directory
42
- login_shell: If `True`, use `bash --login` for remote script execution.
43
40
  """
44
41
  logger = get_logger(logger_name=logger_name)
45
42
  logger.debug(f"_customize_and_run_template {template_filename} - START")
@@ -67,10 +64,46 @@ def _customize_and_run_template(
67
64
  local=script_path_local,
68
65
  remote=script_path_remote,
69
66
  )
67
+ return script_path_remote
68
+
69
+
70
+ def _customize_and_run_template(
71
+ *,
72
+ template_filename: str,
73
+ replacements: set[tuple[str, str]],
74
+ script_dir_local: str,
75
+ script_dir_remote: str,
76
+ prefix: str,
77
+ fractal_ssh: FractalSSH,
78
+ logger_name: str,
79
+ ) -> str:
80
+ """
81
+ Customize one of the template bash scripts, transfer it to the remote host
82
+ via SFTP and then run it via SSH.
83
+
84
+ Args:
85
+ template_filename: Filename of the template file (ends with ".sh").
86
+ replacements: Dictionary of replacements.
87
+ script_dir_remote: Remote scripts directory
88
+ script_dir_local: Local folder where the script will be placed.
89
+ prefix: Prefix for the script filename.
90
+ fractal_ssh: FractalSSH object
91
+ """
92
+ logger = get_logger(logger_name=logger_name)
93
+ logger.debug(f"_customize_and_run_template {template_filename} - START")
94
+
95
+ script_path_remote = _customize_and_send_template(
96
+ template_filename=template_filename,
97
+ replacements=replacements,
98
+ script_dir_local=script_dir_local,
99
+ script_dir_remote=script_dir_remote,
100
+ prefix=prefix,
101
+ fractal_ssh=fractal_ssh,
102
+ logger_name=logger_name,
103
+ )
70
104
 
71
105
  # Execute script remotely
72
- bash = "bash --login" if login_shell else "bash"
73
- cmd = f"{bash} {script_path_remote}"
106
+ cmd = f"bash {script_path_remote}"
74
107
  logger.debug(f"Now run '{cmd}' over SSH.")
75
108
  stdout = fractal_ssh.run_command(cmd=cmd)
76
109
 
@@ -8,6 +8,7 @@ from ..utils_background import prepare_tasks_metadata
8
8
  from ..utils_database import create_db_tasks_and_update_task_group_sync
9
9
  from ..utils_pixi import parse_collect_stdout
10
10
  from ..utils_pixi import SOURCE_DIR_NAME
11
+ from ._pixi_slurm_ssh import run_script_on_remote_slurm
11
12
  from ._utils import check_ssh_or_fail_and_cleanup
12
13
  from ._utils import edit_pyproject_toml_in_place_ssh
13
14
  from fractal_server.app.db import get_sync_db
@@ -22,6 +23,7 @@ from fractal_server.ssh._fabric import SingleUseFractalSSH
22
23
  from fractal_server.ssh._fabric import SSHConfig
23
24
  from fractal_server.syringe import Inject
24
25
  from fractal_server.tasks.v2.ssh._utils import _customize_and_run_template
26
+ from fractal_server.tasks.v2.ssh._utils import _customize_and_send_template
25
27
  from fractal_server.tasks.v2.utils_background import add_commit_refresh
26
28
  from fractal_server.tasks.v2.utils_background import get_current_log
27
29
  from fractal_server.tasks.v2.utils_templates import SCRIPTS_SUBFOLDER
@@ -201,16 +203,30 @@ def collect_ssh_pixi(
201
203
  pyproject_toml_path=pyproject_toml_path,
202
204
  )
203
205
 
204
- stdout = _customize_and_run_template(
206
+ # Run script 2 - run pixi-install command
207
+ remote_script2_path = _customize_and_send_template(
205
208
  template_filename="pixi_2_install.sh",
206
209
  replacements=replacements,
207
- login_shell=True,
208
210
  **common_args,
209
211
  )
210
- logger.debug(f"STDOUT: {stdout}")
212
+ logger.debug(
213
+ "Installation script written to "
214
+ f"{remote_script2_path=}."
215
+ )
216
+ activity.log = get_current_log(log_file_path)
217
+ activity = add_commit_refresh(obj=activity, db=db)
218
+
219
+ run_script_on_remote_slurm(
220
+ script_path=remote_script2_path,
221
+ slurm_config=settings.pixi.SLURM_CONFIG,
222
+ fractal_ssh=fractal_ssh,
223
+ logger_name=LOGGER_NAME,
224
+ prefix=common_args["prefix"],
225
+ )
211
226
  activity.log = get_current_log(log_file_path)
212
227
  activity = add_commit_refresh(obj=activity, db=db)
213
228
 
229
+ # Run script 3 - post-install
214
230
  stdout = _customize_and_run_template(
215
231
  template_filename="pixi_3_post_install.sh",
216
232
  replacements=replacements,
@@ -5,6 +5,7 @@ from tempfile import TemporaryDirectory
5
5
  from ..utils_background import fail_and_cleanup
6
6
  from ..utils_background import get_activity_and_task_group
7
7
  from ..utils_pixi import SOURCE_DIR_NAME
8
+ from ._pixi_slurm_ssh import run_script_on_remote_slurm
8
9
  from ._utils import check_ssh_or_fail_and_cleanup
9
10
  from ._utils import edit_pyproject_toml_in_place_ssh
10
11
  from fractal_server.app.db import get_sync_db
@@ -18,6 +19,7 @@ from fractal_server.ssh._fabric import SSHConfig
18
19
  from fractal_server.syringe import Inject
19
20
  from fractal_server.tasks.utils import get_log_path
20
21
  from fractal_server.tasks.v2.ssh._utils import _customize_and_run_template
22
+ from fractal_server.tasks.v2.ssh._utils import _customize_and_send_template
21
23
  from fractal_server.tasks.v2.utils_background import add_commit_refresh
22
24
  from fractal_server.tasks.v2.utils_background import get_current_log
23
25
  from fractal_server.tasks.v2.utils_templates import SCRIPTS_SUBFOLDER
@@ -187,13 +189,25 @@ def reactivate_ssh_pixi(
187
189
  )
188
190
 
189
191
  # Run script 2 - run pixi-install command
190
- stdout = _customize_and_run_template(
192
+ remote_script2_path = _customize_and_send_template(
191
193
  template_filename="pixi_2_install.sh",
192
194
  replacements=replacements,
193
- login_shell=True,
194
195
  **common_args,
195
196
  )
196
- logger.debug(f"STDOUT: {stdout}")
197
+ logger.debug(
198
+ "Installation script written to "
199
+ f"{remote_script2_path=}."
200
+ )
201
+ activity.log = get_current_log(log_file_path)
202
+ activity = add_commit_refresh(obj=activity, db=db)
203
+
204
+ run_script_on_remote_slurm(
205
+ script_path=remote_script2_path,
206
+ slurm_config=settings.pixi.SLURM_CONFIG,
207
+ fractal_ssh=fractal_ssh,
208
+ logger_name=LOGGER_NAME,
209
+ prefix=common_args["prefix"],
210
+ )
197
211
  activity.log = get_current_log(log_file_path)
198
212
  activity = add_commit_refresh(obj=activity, db=db)
199
213
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: fractal-server
3
- Version: 2.16.1
3
+ Version: 2.16.2a0
4
4
  Summary: Backend component of the Fractal analytics platform
5
5
  License: BSD-3-Clause
6
6
  Author: Tommaso Comparin
@@ -1,4 +1,4 @@
1
- fractal_server/__init__.py,sha256=Slaz4BSSaAhGoGVOZBGgBrBLlFksmPxY8vXizrOcKgE,23
1
+ fractal_server/__init__.py,sha256=ywvZY_b51fGszgBtc9wZwOVbz6O5w5tzfaYERx4Ui_s,25
2
2
  fractal_server/__main__.py,sha256=rkM8xjY1KeS3l63irB8yCrlVobR-73uDapC4wvrIlxI,6957
3
3
  fractal_server/alembic.ini,sha256=MWwi7GzjzawI9cCAK1LW7NxIBQDUqD12-ptJoq5JpP0,3153
4
4
  fractal_server/app/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -129,7 +129,7 @@ fractal_server/app/schemas/v2/workflowtask.py,sha256=6eweAMyziwaoMT-7R1fVJYunIeZ
129
129
  fractal_server/app/security/__init__.py,sha256=oJ8RVglpOvWPQY4RokiE2YA72Nqo42dZEjywWTt8xr8,14032
130
130
  fractal_server/app/security/signup_email.py,sha256=Xd6QYxcdmg0PHpDwmUE8XQmPcOj3Xjy5oROcIMhmltM,1472
131
131
  fractal_server/app/user_settings.py,sha256=OP1yiYKtPadxwM51_Q0hdPk3z90TCN4z1BLpQsXyWiU,1316
132
- fractal_server/config.py,sha256=EdgVC0uAEUKiLft7k-IQd9W_TxVGrBNi9TflKEcNKu8,29177
132
+ fractal_server/config.py,sha256=q0f1DsSgXKE9gyzty7y4NGiQyttV6H13LUMPZsOeGH8,30896
133
133
  fractal_server/data_migrations/2_14_10.py,sha256=jzMg2c1zNO8C_Nho_9_EZJD6kR1-gkFNpNrMR5Hr8hM,1598
134
134
  fractal_server/data_migrations/README.md,sha256=_3AEFvDg9YkybDqCLlFPdDmGJvr6Tw7HRI14aZ3LOIw,398
135
135
  fractal_server/data_migrations/tools.py,sha256=LeMeASwYGtEqd-3wOLle6WARdTGAimoyMmRbbJl-hAM,572
@@ -204,14 +204,15 @@ fractal_server/tasks/v2/local/delete.py,sha256=TbNcg0IhbJNXzXsO2Vgv6Dq4jWmFUVtSu
204
204
  fractal_server/tasks/v2/local/reactivate.py,sha256=Q43DOadNeFyyfgNP67lUqaXmZsS6onv67XwxH_-5ANA,5756
205
205
  fractal_server/tasks/v2/local/reactivate_pixi.py,sha256=IuxDRaj8i6Rc582TIbc9HVKQ9pOvR4IepyXSaJx2PfQ,7565
206
206
  fractal_server/tasks/v2/ssh/__init__.py,sha256=dPK6BtEZVh1GiFP05j1RKTEnZvjJez8o2KkMC2hWXaw,339
207
- fractal_server/tasks/v2/ssh/_utils.py,sha256=V8ZcjEMCNSHivUyu1rnGG_V96Ylq1RRvocQDN1n6BAw,5120
207
+ fractal_server/tasks/v2/ssh/_pixi_slurm_ssh.py,sha256=P-QyoKlQ9rbq3DPuG0DjgnbJ9KOCBXqbFcJZ2qB4VzA,3484
208
+ fractal_server/tasks/v2/ssh/_utils.py,sha256=AjbH4o6-ENe-ZiHvE_pGe_yw8e2lapGMYtLX7VuBkA8,6111
208
209
  fractal_server/tasks/v2/ssh/collect.py,sha256=WesUBtNaax9ST7CtgqAD2qd-ZII4t1JFPzRzltEOuM8,14333
209
- fractal_server/tasks/v2/ssh/collect_pixi.py,sha256=unZXs3qjBoWYBIa2xWiIKz2CVMVBAhcloQ_9YJ97n5k,14211
210
+ fractal_server/tasks/v2/ssh/collect_pixi.py,sha256=5CRr_XiuRaFjydZqxgfoMMj3p1TfT7aqNOxHcVxrOQI,15020
210
211
  fractal_server/tasks/v2/ssh/deactivate.py,sha256=7gJ2mOah0wKwUnK0S9QpaXg08_WE95P0rC-oExAGhLE,12438
211
212
  fractal_server/tasks/v2/ssh/deactivate_pixi.py,sha256=K0yK_NPUqhFMj6cp6G_0Kfn0Yo7oQux4kT5dFPulnos,4748
212
213
  fractal_server/tasks/v2/ssh/delete.py,sha256=9DCe5QXZ14pY8NRb_FCqpIr31r5Gboz6bnFrS8Oa044,4277
213
214
  fractal_server/tasks/v2/ssh/reactivate.py,sha256=NJIgMNFKaXMhbvK0iZOsMwMtsms6Boj9f8N4L01X9Bo,8271
214
- fractal_server/tasks/v2/ssh/reactivate_pixi.py,sha256=UOlG01wOv-eQCtUxSwphEY-Ey7OoUm5PMCSP9J-i1rY,10323
215
+ fractal_server/tasks/v2/ssh/reactivate_pixi.py,sha256=LZk7WaC2uCo3cHTwrpRcc4F_I7HUDA-8rE-RJ2agLZA,11020
215
216
  fractal_server/tasks/v2/templates/1_create_venv.sh,sha256=PK0jdHKtQpda1zULebBaVPORt4t6V17wa4N1ohcj5ac,548
216
217
  fractal_server/tasks/v2/templates/2_pip_install.sh,sha256=vN9DX-eucJjB-XCuQuZmkuATGBzL4FlDQJTQdVewJG8,2155
217
218
  fractal_server/tasks/v2/templates/3_pip_freeze.sh,sha256=JldREScEBI4cD_qjfX4UK7V4aI-FnX9ZvVNxgpSOBFc,168
@@ -235,8 +236,8 @@ fractal_server/types/validators/_workflow_task_arguments_validators.py,sha256=HL
235
236
  fractal_server/urls.py,sha256=QjIKAC1a46bCdiPMu3AlpgFbcv6a4l3ABcd5xz190Og,471
236
237
  fractal_server/utils.py,sha256=Vn35lApt1T1J8nc09sAVqd10Cy0sa3dLipcljI-hkuk,2185
237
238
  fractal_server/zip_tools.py,sha256=H0w7wS5yE4ebj7hw1_77YQ959dl2c-L0WX6J_ro1TY4,4884
238
- fractal_server-2.16.1.dist-info/LICENSE,sha256=QKAharUuhxL58kSoLizKJeZE3mTCBnX6ucmz8W0lxlk,1576
239
- fractal_server-2.16.1.dist-info/METADATA,sha256=eaTdwJo3-jLcC4s9w7iJgXLVjn6axnfpWBRgxhq1jRA,4334
240
- fractal_server-2.16.1.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
241
- fractal_server-2.16.1.dist-info/entry_points.txt,sha256=8tV2kynvFkjnhbtDnxAqImL6HMVKsopgGfew0DOp5UY,58
242
- fractal_server-2.16.1.dist-info/RECORD,,
239
+ fractal_server-2.16.2a0.dist-info/LICENSE,sha256=QKAharUuhxL58kSoLizKJeZE3mTCBnX6ucmz8W0lxlk,1576
240
+ fractal_server-2.16.2a0.dist-info/METADATA,sha256=6x9kEFUU9jQkukimP25U3iu8UKP1JY2bCA67qTSxx2I,4336
241
+ fractal_server-2.16.2a0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
242
+ fractal_server-2.16.2a0.dist-info/entry_points.txt,sha256=8tV2kynvFkjnhbtDnxAqImL6HMVKsopgGfew0DOp5UY,58
243
+ fractal_server-2.16.2a0.dist-info/RECORD,,