fractal-server 2.3.0a0__py3-none-any.whl → 2.3.0a2__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.3.0a0"
1
+ __VERSION__ = "2.3.0a2"
@@ -49,15 +49,33 @@ async def collect_task_custom(
49
49
  status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
50
50
  detail="Cannot infer 'package_root' with 'slurm_ssh' backend.",
51
51
  )
52
+ package_name_underscore = task_collect.package_name.replace("-", "_")
53
+ # Note that python_command is then used as part of a subprocess.run
54
+ # statement: be careful with mixing `'` and `"`.
55
+ python_command = (
56
+ "import importlib.util; "
57
+ "from pathlib import Path; "
58
+ "init_path=importlib.util.find_spec"
59
+ f'("{package_name_underscore}").origin; '
60
+ "print(Path(init_path).parent.as_posix())"
61
+ )
62
+ logger.debug(
63
+ f"Now running {python_command=} through "
64
+ "{task_collect.python_interpreter}."
65
+ )
52
66
  res = subprocess.run( # nosec
53
67
  shlex.split(
54
- f"{task_collect.python_interpreter} "
55
- f"-m pip show {task_collect.package_name}"
68
+ f"{task_collect.python_interpreter} -c '{python_command}'"
56
69
  ),
57
70
  capture_output=True,
58
71
  encoding="utf8",
59
72
  )
60
- if res.returncode != 0:
73
+
74
+ if (
75
+ res.returncode != 0
76
+ or res.stdout is None
77
+ or ("\n" in res.stdout.strip("\n"))
78
+ ):
61
79
  raise HTTPException(
62
80
  status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
63
81
  detail=(
@@ -66,23 +84,7 @@ async def collect_task_custom(
66
84
  f"Original error: {res.stderr}"
67
85
  ),
68
86
  )
69
- try:
70
- package_root_dir = next(
71
- it.split()[1]
72
- for it in res.stdout.split("\n")
73
- if it.startswith("Location")
74
- )
75
- except Exception as e:
76
- raise HTTPException(
77
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
78
- detail=(
79
- "Command 'pip show' gave an unexpected response:\n"
80
- "the output should contain 'Location /path/to/package', "
81
- f"instead returned: {res.stdout}.\n"
82
- f"Original error: {str(e)}"
83
- ),
84
- )
85
- package_root = Path(package_root_dir) / task_collect.package_name
87
+ package_root = Path(res.stdout.strip("\n"))
86
88
  else:
87
89
  package_root = Path(task_collect.package_root)
88
90
 
@@ -113,23 +115,25 @@ async def collect_task_custom(
113
115
  res = db.execute(stm)
114
116
  overlapping_sources_v2 = res.scalars().all()
115
117
  if overlapping_sources_v2:
118
+ overlapping_tasks_v2_source_and_id = [
119
+ f"TaskV2 with ID {task.id} already has source='{task.source}'"
120
+ for task in overlapping_sources_v2
121
+ ]
116
122
  raise HTTPException(
117
123
  status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
118
- detail=(
119
- "Some sources already used by some TaskV2: "
120
- f"{overlapping_sources_v2}"
121
- ),
124
+ detail="\n".join(overlapping_tasks_v2_source_and_id),
122
125
  )
123
126
  stm = select(TaskV1).where(TaskV1.source.in_(sources))
124
127
  res = db.execute(stm)
125
128
  overlapping_sources_v1 = res.scalars().all()
126
129
  if overlapping_sources_v1:
130
+ overlapping_tasks_v1_source_and_id = [
131
+ f"TaskV1 with ID {task.id} already has source='{task.source}'\n"
132
+ for task in overlapping_sources_v1
133
+ ]
127
134
  raise HTTPException(
128
135
  status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
129
- detail=(
130
- "Some sources already used by some TaskV1: "
131
- f"{overlapping_sources_v1}"
132
- ),
136
+ detail="\n".join(overlapping_tasks_v1_source_and_id),
133
137
  )
134
138
 
135
139
  task_list_db: list[TaskV2] = _insert_tasks(
@@ -56,15 +56,16 @@ class TaskCollectPipV2(BaseModel):
56
56
  python_version: Optional[Literal["3.9", "3.10", "3.11", "3.12"]] = None
57
57
  pinned_package_versions: Optional[dict[str, str]] = None
58
58
 
59
+ _package = validator("package", allow_reuse=True)(valstr("package"))
60
+ _package_version = validator("package_version", allow_reuse=True)(
61
+ valstr("package_version")
62
+ )
59
63
  _pinned_package_versions = validator(
60
64
  "pinned_package_versions", allow_reuse=True
61
65
  )(valdictkeys("pinned_package_versions"))
62
66
  _package_extras = validator("package_extras", allow_reuse=True)(
63
67
  valstr("package_extras")
64
68
  )
65
- _python_version = validator("python_version", allow_reuse=True)(
66
- valstr("python_version")
67
- )
68
69
 
69
70
  @validator("package")
70
71
  def package_validator(cls, value):
@@ -114,10 +115,25 @@ class TaskCollectCustomV2(BaseModel):
114
115
  package_name: Optional[str]
115
116
  version: Optional[str]
116
117
 
118
+ # Valstr
119
+ _python_interpreter = validator("python_interpreter", allow_reuse=True)(
120
+ valstr("python_interpreter")
121
+ )
122
+ _source = validator("source", allow_reuse=True)(valstr("source"))
123
+ _package_root = validator("package_root", allow_reuse=True)(
124
+ valstr("package_root", accept_none=True)
125
+ )
126
+ _package_name = validator("package_name", allow_reuse=True)(
127
+ valstr("package_name", accept_none=True)
128
+ )
129
+ _version = validator("version", allow_reuse=True)(
130
+ valstr("version", accept_none=True)
131
+ )
132
+
117
133
  @root_validator(pre=True)
118
134
  def one_of_package_root_or_name(cls, values):
119
- package_root = values["package_root"]
120
- package_name = values["package_name"]
135
+ package_root = values.get("package_root")
136
+ package_name = values.get("package_name")
121
137
  if (package_root is None and package_name is None) or (
122
138
  package_root is not None and package_name is not None
123
139
  ):
@@ -154,21 +170,6 @@ class TaskCollectCustomV2(BaseModel):
154
170
  )
155
171
  return value
156
172
 
157
- # Valstr
158
- _python_interpreter = validator("python_interpreter", allow_reuse=True)(
159
- valstr("python_interpreter")
160
- )
161
- _source = validator("source", allow_reuse=True)(valstr("source"))
162
- _package_root = validator("package_root", allow_reuse=True)(
163
- valstr("package_root", accept_none=True)
164
- )
165
- _package_name = validator("package_name", allow_reuse=True)(
166
- valstr("package_name", accept_none=True)
167
- )
168
- _version = validator("version", allow_reuse=True)(
169
- valstr("version", accept_none=True)
170
- )
171
-
172
173
 
173
174
  class CollectionStateReadV2(BaseModel):
174
175
 
@@ -112,7 +112,7 @@ def _customize_and_run_template(
112
112
  return stdout
113
113
 
114
114
 
115
- async def background_collect_pip_ssh(
115
+ def background_collect_pip_ssh(
116
116
  state_id: int,
117
117
  task_pkg: _TaskCollectPip,
118
118
  connection: Connection,
@@ -122,6 +122,10 @@ async def background_collect_pip_ssh(
122
122
 
123
123
  This function is run as a background task, therefore exceptions must be
124
124
  handled.
125
+
126
+ NOTE: by making this function sync, it will run within a thread - due to
127
+ starlette/fastapi handling of background tasks (see
128
+ https://github.com/encode/starlette/blob/master/starlette/background.py).
125
129
  """
126
130
  # Work within a temporary folder, where also logs will be placed
127
131
  with TemporaryDirectory() as tmpdir:
@@ -10,7 +10,7 @@ PACKAGE_ENV_DIR=__PACKAGE_ENV_DIR__
10
10
  PACKAGE_NAME=__PACKAGE_NAME__
11
11
  PACKAGE=__PACKAGE__
12
12
  PYTHON=__PYTHON__
13
- INSTALL_STRING=__INSTAL_STRING__
13
+ INSTALL_STRING=__INSTALL_STRING__
14
14
 
15
15
  TIME_START=$(date +%s)
16
16
 
@@ -12,7 +12,7 @@ PACKAGE_ENV_DIR=__PACKAGE_ENV_DIR__
12
12
  PACKAGE_NAME=__PACKAGE_NAME__
13
13
  PACKAGE=__PACKAGE__
14
14
  PYTHON=__PYTHON__
15
- INSTALL_STRING=__INSTAL_STRING__
15
+ INSTALL_STRING=__INSTALL_STRING__
16
16
 
17
17
 
18
18
 
@@ -11,7 +11,7 @@ PACKAGE_ENV_DIR=__PACKAGE_ENV_DIR__
11
11
  PACKAGE_NAME=__PACKAGE_NAME__
12
12
  PACKAGE=__PACKAGE__
13
13
  PYTHON=__PYTHON__
14
- INSTALL_STRING=__INSTAL_STRING__
14
+ INSTALL_STRING=__INSTALL_STRING__
15
15
 
16
16
 
17
17
  TIME_START=$(date +%s)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fractal-server
3
- Version: 2.3.0a0
3
+ Version: 2.3.0a2
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
@@ -1,4 +1,4 @@
1
- fractal_server/__init__.py,sha256=NUiWXbKdkjhFPGUHB9xqD5jxggU6mBVYu1Kp1n3xVOA,24
1
+ fractal_server/__init__.py,sha256=-7gSN0r8k13Hgml0ZA7i3bfRDaNoC2Xlx1lqiv1d1uY,24
2
2
  fractal_server/__main__.py,sha256=CocbzZooX1UtGqPi55GcHGNxnrJXFg5tUU5b3wyFCyo,4958
3
3
  fractal_server/alembic.ini,sha256=MWwi7GzjzawI9cCAK1LW7NxIBQDUqD12-ptJoq5JpP0,3153
4
4
  fractal_server/app/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -45,7 +45,7 @@ fractal_server/app/routes/api/v2/status.py,sha256=osLexiMOSqmYcEV-41tlrwt9ofyFbt
45
45
  fractal_server/app/routes/api/v2/submit.py,sha256=bgGDGPT57oVlUgoI0p3cBuSBim8PqCGLZw8VPEbqjZs,8732
46
46
  fractal_server/app/routes/api/v2/task.py,sha256=bRTtGgL8BBGbT7csVeRB-a54clgU2xHydi5XpcByDxg,8297
47
47
  fractal_server/app/routes/api/v2/task_collection.py,sha256=AvUb6_JVxuxtaa3Nk1qN1x7D_gb13xkfVOXhgEGLwWk,10743
48
- fractal_server/app/routes/api/v2/task_collection_custom.py,sha256=eGCUN2Qr6iSTD5YMM-v_tMSXD7HpLlo5XIxULJHcJT0,4950
48
+ fractal_server/app/routes/api/v2/task_collection_custom.py,sha256=3DclNe_AaG01ktBaVy5X6PjnceKgBBwXvKcvHV-9P9A,5196
49
49
  fractal_server/app/routes/api/v2/task_collection_ssh.py,sha256=UJDk2ijGRbB314HbscoU5SEkb9C63gV7HME7JiBB7Qw,3809
50
50
  fractal_server/app/routes/api/v2/task_legacy.py,sha256=P_VJv9v0yzFUBuS-DQHhMVSOe20ecGJJcFBqiiFciOM,1628
51
51
  fractal_server/app/routes/api/v2/workflow.py,sha256=2GlcYNjpvCdjwC_Kn7y0UP16B3pOLSNXBvIVsVDtDKM,11863
@@ -135,7 +135,7 @@ fractal_server/app/schemas/v2/manifest.py,sha256=N37IWohcfO3_y2l8rVM0h_1nZq7m4Iz
135
135
  fractal_server/app/schemas/v2/project.py,sha256=u7S4B-bote1oGjzAGiZ-DuQIyeRAGqJsI71Tc1EtYE0,736
136
136
  fractal_server/app/schemas/v2/status.py,sha256=SQaUpQkjFq5c5k5J4rOjNhuQaDOEg8lksPhkKmPU5VU,332
137
137
  fractal_server/app/schemas/v2/task.py,sha256=7IfxiZkaVqlARy7WYE_H8m7j_IEcuQaZORUrs6b5YuY,4672
138
- fractal_server/app/schemas/v2/task_collection.py,sha256=U_3Tjr-oPoM276sQfqDtyckDp6FIO-j5cv1DNlekMdU,6045
138
+ fractal_server/app/schemas/v2/task_collection.py,sha256=8PG1bOqkfQqORMN0brWf6mHDmijt0bBW-mZsF7cSxUs,6129
139
139
  fractal_server/app/schemas/v2/workflow.py,sha256=Zzx3e-qgkH8le0FUmAx9UrV5PWd7bj14PPXUh_zgZXM,1827
140
140
  fractal_server/app/schemas/v2/workflowtask.py,sha256=atVuVN4aXsVEOmSd-vyg-8_8OnPmqx-gT75rXcn_AlQ,6552
141
141
  fractal_server/app/security/__init__.py,sha256=2-QbwuR-nsuHM_uwKS_WzYvkhnuhO5jUv8UVROetyVk,11169
@@ -182,18 +182,18 @@ fractal_server/tasks/v2/_TaskCollectPip.py,sha256=kWQNMNZ8OEddkYhmhsk3E6ArcaD7qe
182
182
  fractal_server/tasks/v2/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
183
183
  fractal_server/tasks/v2/_venv_pip.py,sha256=xm4XClWYbhXQRqDxYxM9cP7ZCnx-8b078fuVUL12D2M,6286
184
184
  fractal_server/tasks/v2/background_operations.py,sha256=dfKH467G0tln9EKiDRzN2WW_eD1SvT3PJrMu4FyTCBs,11497
185
- fractal_server/tasks/v2/background_operations_ssh.py,sha256=KQIulabP9B4ACSzpbAfmPNheAuxz31-A9XFrk0qyRvs,11805
185
+ fractal_server/tasks/v2/background_operations_ssh.py,sha256=yTD4U4HtOF3cWGun6C5vtWEUQOwXL0MoP0l0RX-WzOY,12011
186
186
  fractal_server/tasks/v2/endpoint_operations.py,sha256=gT38pl5TEH6WNWOtg4Itegt2lTJJI6YRa7fEj9Y4x2s,4226
187
187
  fractal_server/tasks/v2/templates/_1_create_venv.sh,sha256=_Lr1UCWQycqea07YZFICxiwQVz9YZHYS-AaVFjNLUyQ,993
188
- fractal_server/tasks/v2/templates/_2_upgrade_pip.sh,sha256=TT1hdgnyuuB5IkqtQE222S8BezvpqsX7aKYQ6McWqmg,625
188
+ fractal_server/tasks/v2/templates/_2_upgrade_pip.sh,sha256=45CPrRxxNBq1ujDA8m1_LWt6QaN1G29mda_LbW2EjN8,626
189
189
  fractal_server/tasks/v2/templates/_3_pip_install.sh,sha256=ViAf3KKtk8YnEkrhybPV8ZZdmZJ0g2l4zkoVnmXbAKw,664
190
- fractal_server/tasks/v2/templates/_4_pip_freeze.sh,sha256=_UA2Ckke_JApi4NFciYslEhU-QpMfoIj0Iac4ZTn558,371
191
- fractal_server/tasks/v2/templates/_5_pip_show.sh,sha256=8E7gHPyd_4dmURNeoy9THzBB63c-gObBY4jcNlbWmaw,1824
190
+ fractal_server/tasks/v2/templates/_4_pip_freeze.sh,sha256=SHndmLn5daT_lg6rnhNPMrRiPAIbGUlMUBIDDLniVOg,372
191
+ fractal_server/tasks/v2/templates/_5_pip_show.sh,sha256=3onbKZ0PJkkYronP4_tdMBoAe3GqxVQFH-L4dUqSkQY,1825
192
192
  fractal_server/tasks/v2/utils.py,sha256=JOyCacb6MNvrwfLNTyLwcz8y79J29YuJeJ2MK5kqXRM,1657
193
193
  fractal_server/urls.py,sha256=5o_qq7PzKKbwq12NHSQZDmDitn5RAOeQ4xufu-2v9Zk,448
194
194
  fractal_server/utils.py,sha256=b7WwFdcFZ8unyT65mloFToYuEDXpQoHRcmRNqrhd_dQ,2115
195
- fractal_server-2.3.0a0.dist-info/LICENSE,sha256=QKAharUuhxL58kSoLizKJeZE3mTCBnX6ucmz8W0lxlk,1576
196
- fractal_server-2.3.0a0.dist-info/METADATA,sha256=T97rFL8LsA21n54Zdfl8OAANAH5hOMc7KPu23c86Ek4,4427
197
- fractal_server-2.3.0a0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
198
- fractal_server-2.3.0a0.dist-info/entry_points.txt,sha256=8tV2kynvFkjnhbtDnxAqImL6HMVKsopgGfew0DOp5UY,58
199
- fractal_server-2.3.0a0.dist-info/RECORD,,
195
+ fractal_server-2.3.0a2.dist-info/LICENSE,sha256=QKAharUuhxL58kSoLizKJeZE3mTCBnX6ucmz8W0lxlk,1576
196
+ fractal_server-2.3.0a2.dist-info/METADATA,sha256=hUMPCeItWLj1fcMcRSLAJmyJuO7uspL2pzgx_XyJlRQ,4427
197
+ fractal_server-2.3.0a2.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
198
+ fractal_server-2.3.0a2.dist-info/entry_points.txt,sha256=8tV2kynvFkjnhbtDnxAqImL6HMVKsopgGfew0DOp5UY,58
199
+ fractal_server-2.3.0a2.dist-info/RECORD,,