splime 0.2.5__tar.gz → 0.3.0__tar.gz
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.
- {splime-0.2.5/src/splime.egg-info → splime-0.3.0}/PKG-INFO +3 -1
- {splime-0.2.5 → splime-0.3.0}/pyproject.toml +8 -3
- {splime-0.2.5 → splime-0.3.0}/src/spl/_client.py +32 -119
- {splime-0.2.5 → splime-0.3.0}/src/spl/_http.py +9 -2
- {splime-0.2.5 → splime-0.3.0}/src/spl/_views.py +28 -61
- {splime-0.2.5 → splime-0.3.0}/src/spl/core/__init__.py +1 -6
- {splime-0.2.5 → splime-0.3.0}/src/spl/core/_common.py +76 -120
- splime-0.3.0/src/spl/core/entities/adapter.py +176 -0
- splime-0.3.0/src/spl/core/entities/artifact.py +112 -0
- splime-0.3.0/src/spl/core/entities/control.py +44 -0
- splime-0.3.0/src/spl/core/entities/distribution.py +56 -0
- splime-0.3.0/src/spl/core/entities/function.py +257 -0
- {splime-0.2.5 → splime-0.3.0}/src/spl/core/entities/local_function.py +27 -33
- {splime-0.2.5 → splime-0.3.0}/src/spl/core/entities/misc.py +3 -3
- splime-0.3.0/src/spl/core/entities/module.py +82 -0
- splime-0.3.0/src/spl/core/entities/node.py +289 -0
- splime-0.3.0/src/spl/core/entities/node_function.py +71 -0
- splime-0.3.0/src/spl/core/entities/node_remote.py +298 -0
- splime-0.3.0/src/spl/core/entities/pipeline.py +366 -0
- splime-0.3.0/src/spl/core/entities/scalar.py +48 -0
- splime-0.3.0/src/spl/core/ir/common.py +42 -0
- {splime-0.2.5 → splime-0.3.0}/src/spl/core/ir/parse.py +18 -18
- splime-0.3.0/src/spl/core/ir/unparse.py +38 -0
- splime-0.3.0/src/spl/core/ir/utils.py +157 -0
- {splime-0.2.5 → splime-0.3.0}/src/spl/daemon/canonical.py +6 -20
- {splime-0.2.5 → splime-0.3.0}/src/spl/daemon/cli.py +5 -15
- {splime-0.2.5 → splime-0.3.0}/src/spl/daemon/docker_environment.py +6 -21
- {splime-0.2.5 → splime-0.3.0}/src/spl/daemon/docker_pool.py +5 -20
- {splime-0.2.5 → splime-0.3.0}/src/spl/daemon/doctor.py +71 -12
- splime-0.3.0/src/spl/daemon/environment.py +429 -0
- {splime-0.2.5 → splime-0.3.0}/src/spl/daemon/environment_base.py +6 -19
- {splime-0.2.5 → splime-0.3.0}/src/spl/daemon/heartbeat_service.py +1 -5
- splime-0.3.0/src/spl/daemon/interpreter_visibility.py +69 -0
- {splime-0.2.5 → splime-0.3.0}/src/spl/daemon/metadata.py +12 -37
- {splime-0.2.5 → splime-0.3.0}/src/spl/daemon/remote_client.py +126 -117
- {splime-0.2.5 → splime-0.3.0}/src/spl/daemon/repositories/env.py +27 -20
- {splime-0.2.5 → splime-0.3.0}/src/spl/daemon/repositories/library.py +3 -12
- {splime-0.2.5 → splime-0.3.0}/src/spl/daemon/repositories/object.py +138 -176
- {splime-0.2.5 → splime-0.3.0}/src/spl/daemon/repositories/run.py +32 -8
- {splime-0.2.5 → splime-0.3.0}/src/spl/daemon/repositories/server_connection.py +11 -25
- {splime-0.2.5 → splime-0.3.0}/src/spl/daemon/routes/_helpers.py +38 -20
- {splime-0.2.5 → splime-0.3.0}/src/spl/daemon/routes/artifacts.py +5 -13
- {splime-0.2.5 → splime-0.3.0}/src/spl/daemon/routes/diagnostics.py +57 -11
- {splime-0.2.5 → splime-0.3.0}/src/spl/daemon/routes/envs.py +3 -5
- {splime-0.2.5 → splime-0.3.0}/src/spl/daemon/routes/libraries.py +2 -2
- {splime-0.2.5 → splime-0.3.0}/src/spl/daemon/routes/objects.py +12 -21
- {splime-0.2.5 → splime-0.3.0}/src/spl/daemon/routes/remote.py +2 -2
- {splime-0.2.5 → splime-0.3.0}/src/spl/daemon/routes/runs.py +3 -7
- {splime-0.2.5 → splime-0.3.0}/src/spl/daemon/routes/server_connections.py +3 -6
- {splime-0.2.5 → splime-0.3.0}/src/spl/daemon/run_progress.py +5 -0
- {splime-0.2.5 → splime-0.3.0}/src/spl/daemon/runtime_backend.py +85 -12
- {splime-0.2.5 → splime-0.3.0}/src/spl/daemon/runtime_config.py +3 -12
- {splime-0.2.5 → splime-0.3.0}/src/spl/daemon/runtime_dependencies.py +13 -0
- {splime-0.2.5 → splime-0.3.0}/src/spl/daemon/secret_store.py +3 -6
- {splime-0.2.5 → splime-0.3.0}/src/spl/daemon/server.py +138 -148
- {splime-0.2.5 → splime-0.3.0}/src/spl/daemon/server_connection.py +2 -7
- {splime-0.2.5 → splime-0.3.0}/src/spl/daemon/services/sync.py +3 -14
- {splime-0.2.5 → splime-0.3.0}/src/spl/daemon/signature.py +15 -38
- splime-0.3.0/src/spl/daemon/spl_free_generator.py +241 -0
- splime-0.3.0/src/spl/daemon/spl_free_runner.py +216 -0
- {splime-0.2.5 → splime-0.3.0}/src/spl/daemon/storage_base.py +43 -93
- {splime-0.2.5 → splime-0.3.0}/src/spl/daemon/store.py +5 -3
- {splime-0.2.5 → splime-0.3.0}/src/spl/daemon/worker.py +49 -79
- splime-0.3.0/src/spl/daemon/worker_runtime_marker.py +3 -0
- {splime-0.2.5 → splime-0.3.0}/src/spl/daemon_client.py +189 -121
- {splime-0.2.5 → splime-0.3.0}/src/spl/pipeline_widget.py +45 -38
- {splime-0.2.5 → splime-0.3.0}/src/spl/server_client.py +17 -33
- {splime-0.2.5 → splime-0.3.0/src/splime.egg-info}/PKG-INFO +3 -1
- {splime-0.2.5 → splime-0.3.0}/src/splime.egg-info/SOURCES.txt +4 -0
- {splime-0.2.5 → splime-0.3.0}/src/splime.egg-info/requires.txt +2 -0
- splime-0.2.5/src/spl/core/entities/adapter.py +0 -210
- splime-0.2.5/src/spl/core/entities/artifact.py +0 -140
- splime-0.2.5/src/spl/core/entities/control.py +0 -45
- splime-0.2.5/src/spl/core/entities/distribution.py +0 -65
- splime-0.2.5/src/spl/core/entities/function.py +0 -257
- splime-0.2.5/src/spl/core/entities/module.py +0 -88
- splime-0.2.5/src/spl/core/entities/node.py +0 -286
- splime-0.2.5/src/spl/core/entities/node_function.py +0 -79
- splime-0.2.5/src/spl/core/entities/node_remote.py +0 -349
- splime-0.2.5/src/spl/core/entities/pipeline.py +0 -436
- splime-0.2.5/src/spl/core/entities/scalar.py +0 -55
- splime-0.2.5/src/spl/core/ir/common.py +0 -34
- splime-0.2.5/src/spl/core/ir/unparse.py +0 -29
- splime-0.2.5/src/spl/core/ir/utils.py +0 -163
- splime-0.2.5/src/spl/daemon/environment.py +0 -269
- {splime-0.2.5 → splime-0.3.0}/LICENSE +0 -0
- {splime-0.2.5 → splime-0.3.0}/NOTICE +0 -0
- {splime-0.2.5 → splime-0.3.0}/README.md +0 -0
- {splime-0.2.5 → splime-0.3.0}/setup.cfg +0 -0
- {splime-0.2.5 → splime-0.3.0}/src/spl/__init__.py +0 -0
- {splime-0.2.5 → splime-0.3.0}/src/spl/_deprecate.py +0 -0
- {splime-0.2.5 → splime-0.3.0}/src/spl/client.py +0 -0
- {splime-0.2.5 → splime-0.3.0}/src/spl/core/common.py +0 -0
- {splime-0.2.5 → splime-0.3.0}/src/spl/core/entities/__init__.py +0 -0
- {splime-0.2.5 → splime-0.3.0}/src/spl/core/ir/__init__.py +0 -0
- {splime-0.2.5 → splime-0.3.0}/src/spl/daemon/__init__.py +0 -0
- {splime-0.2.5 → splime-0.3.0}/src/spl/daemon/__main__.py +0 -0
- {splime-0.2.5 → splime-0.3.0}/src/spl/daemon/client.py +0 -0
- {splime-0.2.5 → splime-0.3.0}/src/spl/daemon/repositories/__init__.py +0 -0
- {splime-0.2.5 → splime-0.3.0}/src/spl/daemon/repositories/sync_event.py +0 -0
- {splime-0.2.5 → splime-0.3.0}/src/spl/daemon/routes/__init__.py +0 -0
- {splime-0.2.5 → splime-0.3.0}/src/spl/daemon/services/__init__.py +0 -0
- {splime-0.2.5 → splime-0.3.0}/src/spl/py.typed +0 -0
- {splime-0.2.5 → splime-0.3.0}/src/splime.egg-info/dependency_links.txt +0 -0
- {splime-0.2.5 → splime-0.3.0}/src/splime.egg-info/entry_points.txt +0 -0
- {splime-0.2.5 → splime-0.3.0}/src/splime.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: splime
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Reuse Python functions across projects without rewriting or redeploying them.
|
|
5
5
|
Author-email: Yastrebov Kirill <yastrebovks@gmail.com>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -42,6 +42,8 @@ Requires-Dist: pyexpect; extra == "test"
|
|
|
42
42
|
Requires-Dist: mypy==2.1.0; extra == "test"
|
|
43
43
|
Requires-Dist: pytest==9.1.1; extra == "test"
|
|
44
44
|
Requires-Dist: pytest-asyncio; extra == "test"
|
|
45
|
+
Requires-Dist: ruff==0.15.20; extra == "test"
|
|
46
|
+
Requires-Dist: types-PyYAML==6.0.12.20260518; extra == "test"
|
|
45
47
|
Provides-Extra: docs
|
|
46
48
|
Requires-Dist: sphinx==9.1.0; extra == "docs"
|
|
47
49
|
Requires-Dist: sphinx-rtd-theme==3.1.0; extra == "docs"
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "splime"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.3.0"
|
|
8
8
|
|
|
9
9
|
description = "Reuse Python functions across projects without rewriting or redeploying them."
|
|
10
10
|
readme = "README.md"
|
|
@@ -55,7 +55,9 @@ test = [
|
|
|
55
55
|
"pyexpect",
|
|
56
56
|
"mypy==2.1.0",
|
|
57
57
|
"pytest==9.1.1",
|
|
58
|
-
"pytest-asyncio"
|
|
58
|
+
"pytest-asyncio",
|
|
59
|
+
"ruff==0.15.20",
|
|
60
|
+
"types-PyYAML==6.0.12.20260518"]
|
|
59
61
|
|
|
60
62
|
docs = [
|
|
61
63
|
"sphinx==9.1.0",
|
|
@@ -105,7 +107,7 @@ strict = true
|
|
|
105
107
|
line-length = 120
|
|
106
108
|
|
|
107
109
|
[tool.ruff.lint]
|
|
108
|
-
select = []
|
|
110
|
+
select = ["E4", "E7", "E9", "F"]
|
|
109
111
|
ignore = []
|
|
110
112
|
|
|
111
113
|
# Scoped, justified allowances. These silence rules only where the pattern is
|
|
@@ -125,6 +127,9 @@ ignore = []
|
|
|
125
127
|
"S603", "S607", "S310", "S104", "S108", "S608",
|
|
126
128
|
"S105", "B904", "S110", "S112", "N818",
|
|
127
129
|
]
|
|
130
|
+
# The legacy worker must repair sys.path before importing packages that can be
|
|
131
|
+
# shadowed by the daemon checkout injected through PYTHONPATH.
|
|
132
|
+
"src/spl/daemon/worker.py" = ["E402"]
|
|
128
133
|
# The CLI and daemon bootstrap print to the console on purpose.
|
|
129
134
|
"src/spl/daemon/cli.py" = ["T201"]
|
|
130
135
|
"src/spl/daemon/server.py" = ["T201"]
|
|
@@ -18,6 +18,7 @@ dependencies imported yet.
|
|
|
18
18
|
|
|
19
19
|
from __future__ import annotations
|
|
20
20
|
|
|
21
|
+
import builtins
|
|
21
22
|
from dataclasses import dataclass, field, replace
|
|
22
23
|
from html import escape
|
|
23
24
|
from pathlib import Path
|
|
@@ -70,10 +71,7 @@ def _preview(value: Any, *, limit: int = 80) -> str:
|
|
|
70
71
|
|
|
71
72
|
|
|
72
73
|
def _is_missing_server_connection(exc: Exception) -> bool:
|
|
73
|
-
return (
|
|
74
|
-
isinstance(exc, ClientError)
|
|
75
|
-
and _NO_SERVER_CONNECTION_MESSAGE in str(exc)
|
|
76
|
-
)
|
|
74
|
+
return isinstance(exc, ClientError) and _NO_SERVER_CONNECTION_MESSAGE in str(exc)
|
|
77
75
|
|
|
78
76
|
|
|
79
77
|
def _progress_callback(progress: ProgressOption) -> RunStateCallback | None:
|
|
@@ -141,10 +139,7 @@ class PublishedObject:
|
|
|
141
139
|
"entrypoint": self.entrypoint,
|
|
142
140
|
}
|
|
143
141
|
body = "".join(
|
|
144
|
-
"<tr>"
|
|
145
|
-
f"<th style='text-align:left'>{escape(key)}</th>"
|
|
146
|
-
f"<td><code>{escape(value)}</code></td>"
|
|
147
|
-
"</tr>"
|
|
142
|
+
f"<tr><th style='text-align:left'>{escape(key)}</th><td><code>{escape(value)}</code></td></tr>"
|
|
148
143
|
for key, value in rows.items()
|
|
149
144
|
)
|
|
150
145
|
return f"<table><tbody>{body}</tbody></table>"
|
|
@@ -170,11 +165,7 @@ def _catalog_rows(
|
|
|
170
165
|
rows: list[dict[str, str]] = []
|
|
171
166
|
for record in records:
|
|
172
167
|
library = record.get("library")
|
|
173
|
-
library_name = (
|
|
174
|
-
library.get("display_name") or library.get("slug")
|
|
175
|
-
if isinstance(library, dict)
|
|
176
|
-
else library
|
|
177
|
-
)
|
|
168
|
+
library_name = library.get("display_name") or library.get("slug") if isinstance(library, dict) else library
|
|
178
169
|
version_value = record.get("version")
|
|
179
170
|
if version_value is None:
|
|
180
171
|
current = record.get("current_version")
|
|
@@ -197,28 +188,16 @@ def _catalog_rows(
|
|
|
197
188
|
def _rows_to_text(rows: list[dict[str, str]], title: str) -> str:
|
|
198
189
|
if not rows:
|
|
199
190
|
return f"{title}: (empty)"
|
|
200
|
-
widths = {
|
|
201
|
-
header: max(len(header), *(len(row[header]) for row in rows))
|
|
202
|
-
for header in _CATALOG_HEADERS
|
|
203
|
-
}
|
|
191
|
+
widths = {header: max(len(header), *(len(row[header]) for row in rows)) for header in _CATALOG_HEADERS}
|
|
204
192
|
head = " ".join(header.ljust(widths[header]) for header in _CATALOG_HEADERS)
|
|
205
|
-
body = "\n".join(
|
|
206
|
-
" ".join(row[header].ljust(widths[header]) for header in _CATALOG_HEADERS)
|
|
207
|
-
for row in rows
|
|
208
|
-
)
|
|
193
|
+
body = "\n".join(" ".join(row[header].ljust(widths[header]) for header in _CATALOG_HEADERS) for row in rows)
|
|
209
194
|
return f"{title} ({len(rows)}):\n{head}\n{body}"
|
|
210
195
|
|
|
211
196
|
|
|
212
197
|
def _rows_to_html(rows: list[dict[str, str]], title: str) -> str:
|
|
213
|
-
head = "".join(
|
|
214
|
-
f"<th style='text-align:left'>{escape(header)}</th>"
|
|
215
|
-
for header in _CATALOG_HEADERS
|
|
216
|
-
)
|
|
198
|
+
head = "".join(f"<th style='text-align:left'>{escape(header)}</th>" for header in _CATALOG_HEADERS)
|
|
217
199
|
body = "".join(
|
|
218
|
-
"<tr>"
|
|
219
|
-
+ "".join(f"<td>{escape(row[header])}</td>" for header in _CATALOG_HEADERS)
|
|
220
|
-
+ "</tr>"
|
|
221
|
-
for row in rows
|
|
200
|
+
"<tr>" + "".join(f"<td>{escape(row[header])}</td>" for header in _CATALOG_HEADERS) + "</tr>" for row in rows
|
|
222
201
|
)
|
|
223
202
|
return (
|
|
224
203
|
f"<div><b>{escape(title)}</b> ({len(rows)})"
|
|
@@ -258,14 +237,10 @@ class ObjectCatalog(dict[str, Any]):
|
|
|
258
237
|
"""Local+server catalog that prints per-scope tables; ``.raw`` is a plain dict."""
|
|
259
238
|
|
|
260
239
|
def __repr__(self) -> str:
|
|
261
|
-
return "\n\n".join(
|
|
262
|
-
_rows_to_text(_catalog_rows(value), str(key)) for key, value in self.items()
|
|
263
|
-
)
|
|
240
|
+
return "\n\n".join(_rows_to_text(_catalog_rows(value), str(key)) for key, value in self.items())
|
|
264
241
|
|
|
265
242
|
def _repr_html_(self) -> str:
|
|
266
|
-
return "".join(
|
|
267
|
-
_rows_to_html(_catalog_rows(value), str(key)) for key, value in self.items()
|
|
268
|
-
)
|
|
243
|
+
return "".join(_rows_to_html(_catalog_rows(value), str(key)) for key, value in self.items())
|
|
269
244
|
|
|
270
245
|
@property
|
|
271
246
|
def raw(self) -> dict[str, Any]:
|
|
@@ -343,10 +318,7 @@ class RemoteResult:
|
|
|
343
318
|
"artifacts": str(len(self.artifacts)),
|
|
344
319
|
}
|
|
345
320
|
body = "".join(
|
|
346
|
-
"<tr>"
|
|
347
|
-
f"<th style='text-align:left'>{escape(key)}</th>"
|
|
348
|
-
f"<td><code>{escape(value)}</code></td>"
|
|
349
|
-
"</tr>"
|
|
321
|
+
f"<tr><th style='text-align:left'>{escape(key)}</th><td><code>{escape(value)}</code></td></tr>"
|
|
350
322
|
for key, value in rows.items()
|
|
351
323
|
)
|
|
352
324
|
return f"<table><tbody>{body}</tbody></table>"
|
|
@@ -375,13 +347,13 @@ class RemoteRun:
|
|
|
375
347
|
def id(self) -> str:
|
|
376
348
|
"""Return the daemon run id."""
|
|
377
349
|
|
|
378
|
-
return self.state["id"]
|
|
350
|
+
return cast(str, self.state["id"])
|
|
379
351
|
|
|
380
352
|
@property
|
|
381
353
|
def status(self) -> str:
|
|
382
354
|
"""Return the last known daemon status."""
|
|
383
355
|
|
|
384
|
-
return self.state["status"]
|
|
356
|
+
return cast(str, self.state["status"])
|
|
385
357
|
|
|
386
358
|
@property
|
|
387
359
|
def mode(self) -> str:
|
|
@@ -490,17 +462,10 @@ class RemoteRun:
|
|
|
490
462
|
)
|
|
491
463
|
if final_state["status"] != "succeeded":
|
|
492
464
|
error = final_state.get("error") or "run returned no error message"
|
|
493
|
-
raise RuntimeError(
|
|
494
|
-
f"{self.mode} run {self.id!r} ended as "
|
|
495
|
-
f"{final_state.get('status')!r}: {error}"
|
|
496
|
-
)
|
|
465
|
+
raise RuntimeError(f"{self.mode} run {self.id!r} ended as {final_state.get('status')!r}: {error}")
|
|
497
466
|
|
|
498
467
|
payload = self.result()
|
|
499
|
-
downloaded = (
|
|
500
|
-
self.download_artifacts(artifacts_dir)
|
|
501
|
-
if artifacts_dir is not None
|
|
502
|
-
else {}
|
|
503
|
-
)
|
|
468
|
+
downloaded = self.download_artifacts(artifacts_dir) if artifacts_dir is not None else {}
|
|
504
469
|
return RemoteResult(
|
|
505
470
|
run=final_state,
|
|
506
471
|
payload=payload,
|
|
@@ -593,7 +558,7 @@ class _LibraryAdmin:
|
|
|
593
558
|
grantee: str,
|
|
594
559
|
*,
|
|
595
560
|
grantee_type: str = "user",
|
|
596
|
-
scopes: list[str] | None = None,
|
|
561
|
+
scopes: builtins.list[str] | None = None,
|
|
597
562
|
) -> dict[str, Any]:
|
|
598
563
|
"""Grant a user or team access to one central-server library."""
|
|
599
564
|
|
|
@@ -779,11 +744,7 @@ class SPLClient:
|
|
|
779
744
|
)
|
|
780
745
|
conn = self.current_server_connection()
|
|
781
746
|
connection = conn.get("connection")
|
|
782
|
-
nested_url = (
|
|
783
|
-
connection.get("server_url")
|
|
784
|
-
if isinstance(connection, dict)
|
|
785
|
-
else None
|
|
786
|
-
)
|
|
747
|
+
nested_url = connection.get("server_url") if isinstance(connection, dict) else None
|
|
787
748
|
server_url = conn.get("server_url") or nested_url or DEFAULT_SERVER_URL
|
|
788
749
|
return SPLServerClient(token=self._user_token, base_url=server_url)
|
|
789
750
|
|
|
@@ -800,9 +761,7 @@ class SPLClient:
|
|
|
800
761
|
state = self._daemon.server_connection()
|
|
801
762
|
except Exception as exc:
|
|
802
763
|
if _is_missing_server_connection(exc):
|
|
803
|
-
return ConnectionStatusView(
|
|
804
|
-
{"connected": False, "offline": False, "connection": None}
|
|
805
|
-
)
|
|
764
|
+
return ConnectionStatusView({"connected": False, "offline": False, "connection": None})
|
|
806
765
|
raise
|
|
807
766
|
state.setdefault("connected", bool(state.get("server_url")))
|
|
808
767
|
return ConnectionStatusView(state)
|
|
@@ -819,9 +778,7 @@ class SPLClient:
|
|
|
819
778
|
|
|
820
779
|
if not self._has_server_connection():
|
|
821
780
|
return LibraryListView([])
|
|
822
|
-
return LibraryListView(
|
|
823
|
-
self._daemon.server_libraries(include_accessible=include_accessible)
|
|
824
|
-
)
|
|
781
|
+
return LibraryListView(self._daemon.server_libraries(include_accessible=include_accessible))
|
|
825
782
|
|
|
826
783
|
# The flat library aliases (create_library, get_library, update_library,
|
|
827
784
|
# delete_library, grant_library, revoke_library_grant, add_reference,
|
|
@@ -1018,11 +975,7 @@ class SPLClient:
|
|
|
1018
975
|
"""
|
|
1019
976
|
|
|
1020
977
|
if scope == "auto":
|
|
1021
|
-
scope = (
|
|
1022
|
-
"server"
|
|
1023
|
-
if owner is not None or library is not None or self._has_server_connection()
|
|
1024
|
-
else "local"
|
|
1025
|
-
)
|
|
978
|
+
scope = "server" if owner is not None or library is not None or self._has_server_connection() else "local"
|
|
1026
979
|
if scope == "local":
|
|
1027
980
|
if owner is not None or library is not None:
|
|
1028
981
|
raise ValueError("owner/library require scope='server', scope='all', or scope='auto'")
|
|
@@ -1220,9 +1173,7 @@ class SPLClient:
|
|
|
1220
1173
|
"""Return normalized function/node/link metadata for one object."""
|
|
1221
1174
|
|
|
1222
1175
|
if self._is_node_remote(name):
|
|
1223
|
-
return DecompositionView(
|
|
1224
|
-
self._remote_decomposition_response(name, version=version)["decomposition"]
|
|
1225
|
-
)
|
|
1176
|
+
return DecompositionView(self._remote_decomposition_response(name, version=version)["decomposition"])
|
|
1226
1177
|
if owner is not None or library is not None:
|
|
1227
1178
|
response = self._remote_decomposition_response(
|
|
1228
1179
|
{
|
|
@@ -1269,11 +1220,7 @@ class SPLClient:
|
|
|
1269
1220
|
record = response.get("object") or {}
|
|
1270
1221
|
remote = response.get("remote") or {}
|
|
1271
1222
|
object_name = (
|
|
1272
|
-
title
|
|
1273
|
-
or record.get("display_name")
|
|
1274
|
-
or record.get("name")
|
|
1275
|
-
or remote.get("name")
|
|
1276
|
-
or pipeline.name
|
|
1223
|
+
title or record.get("display_name") or record.get("name") or remote.get("name") or pipeline.name
|
|
1277
1224
|
)
|
|
1278
1225
|
return PipelineGraphWidget(
|
|
1279
1226
|
decomposition,
|
|
@@ -1328,10 +1275,7 @@ class SPLClient:
|
|
|
1328
1275
|
theme=theme,
|
|
1329
1276
|
)
|
|
1330
1277
|
|
|
1331
|
-
raise TypeError(
|
|
1332
|
-
"pipeline_widget expects an object name, PublishedObject, "
|
|
1333
|
-
"spl.core Pipeline, or NodeRemote"
|
|
1334
|
-
)
|
|
1278
|
+
raise TypeError("pipeline_widget expects an object name, PublishedObject, spl.core Pipeline, or NodeRemote")
|
|
1335
1279
|
|
|
1336
1280
|
def draw_pipeline(
|
|
1337
1281
|
self,
|
|
@@ -1371,20 +1315,11 @@ class SPLClient:
|
|
|
1371
1315
|
function=function,
|
|
1372
1316
|
)
|
|
1373
1317
|
display_name = signature.get("display_name") or signature["name"]
|
|
1374
|
-
lines = [
|
|
1375
|
-
(
|
|
1376
|
-
f"{display_name} "
|
|
1377
|
-
f"v{signature['version']} ({signature['kind']})"
|
|
1378
|
-
)
|
|
1379
|
-
]
|
|
1318
|
+
lines = [(f"{display_name} v{signature['version']} ({signature['kind']})")]
|
|
1380
1319
|
if signature.get("description"):
|
|
1381
1320
|
lines.append(signature["description"])
|
|
1382
1321
|
|
|
1383
|
-
if (
|
|
1384
|
-
function is None
|
|
1385
|
-
and signature.get("kind") == "pipeline"
|
|
1386
|
-
and signature.get("internal_functions")
|
|
1387
|
-
):
|
|
1322
|
+
if function is None and signature.get("kind") == "pipeline" and signature.get("internal_functions"):
|
|
1388
1323
|
lines.append("Functions:")
|
|
1389
1324
|
for item in signature["internal_functions"]:
|
|
1390
1325
|
lines.append(f" - {item['name']}")
|
|
@@ -1393,29 +1328,16 @@ class SPLClient:
|
|
|
1393
1328
|
if signature["inputs"]:
|
|
1394
1329
|
for item in signature["inputs"]:
|
|
1395
1330
|
required = "required" if item["required"] else "optional"
|
|
1396
|
-
default =
|
|
1397
|
-
|
|
1398
|
-
if item["default"] is None
|
|
1399
|
-
else f", default={item['default']}"
|
|
1400
|
-
)
|
|
1401
|
-
lines.append(
|
|
1402
|
-
f" - {item['name']}: {item['type'] or 'Any'} "
|
|
1403
|
-
f"({required}{default})"
|
|
1404
|
-
)
|
|
1331
|
+
default = "" if item["default"] is None else f", default={item['default']}"
|
|
1332
|
+
lines.append(f" - {item['name']}: {item['type'] or 'Any'} ({required}{default})")
|
|
1405
1333
|
else:
|
|
1406
1334
|
lines.append(" - none")
|
|
1407
1335
|
|
|
1408
1336
|
lines.append("Outputs:")
|
|
1409
1337
|
if signature["outputs"]:
|
|
1410
1338
|
for item in signature["outputs"]:
|
|
1411
|
-
selector =
|
|
1412
|
-
|
|
1413
|
-
if item["selector"] is not None
|
|
1414
|
-
else "no output selector"
|
|
1415
|
-
)
|
|
1416
|
-
lines.append(
|
|
1417
|
-
f" - {item['name']}: {selector}; read {item['read']}"
|
|
1418
|
-
)
|
|
1339
|
+
selector = f'output="{item["selector"]}"' if item["selector"] is not None else "no output selector"
|
|
1340
|
+
lines.append(f" - {item['name']}: {selector}; read {item['read']}")
|
|
1419
1341
|
else:
|
|
1420
1342
|
lines.append(" - none")
|
|
1421
1343
|
|
|
@@ -1628,11 +1550,7 @@ class SPLClient:
|
|
|
1628
1550
|
*,
|
|
1629
1551
|
version: int | None = None,
|
|
1630
1552
|
) -> dict[str, Any]:
|
|
1631
|
-
ref = (
|
|
1632
|
-
self._remote_node_payload(remote, version=version)
|
|
1633
|
-
if self._is_node_remote(remote)
|
|
1634
|
-
else dict(remote)
|
|
1635
|
-
)
|
|
1553
|
+
ref = self._remote_node_payload(remote, version=version) if self._is_node_remote(remote) else dict(remote)
|
|
1636
1554
|
if version is not None:
|
|
1637
1555
|
ref["version"] = version
|
|
1638
1556
|
return self._daemon.resolve_remote_decomposition(ref)
|
|
@@ -1735,11 +1653,7 @@ def export_objects_to_yaml(xs: list[Any], *, frame_offset: int = 2) -> str:
|
|
|
1735
1653
|
|
|
1736
1654
|
top_level_deps = get_top_level_deps(frame_offset, xs)
|
|
1737
1655
|
|
|
1738
|
-
mapping = {
|
|
1739
|
-
root: DSPLSelfImport(name=cast(Any, root).name)
|
|
1740
|
-
for (root, _) in top_level_deps
|
|
1741
|
-
if hasattr(root, "name")
|
|
1742
|
-
}
|
|
1656
|
+
mapping = {root: DSPLSelfImport(name=cast(Any, root).name) for (root, _) in top_level_deps if hasattr(root, "name")}
|
|
1743
1657
|
|
|
1744
1658
|
normalized_deps = {
|
|
1745
1659
|
root: [mapping.get(dependency, dependency) for dependency in dependencies]
|
|
@@ -1762,8 +1676,7 @@ def prepare_export_object(obj: Any, entrypoint: str | None) -> tuple[Any, str]:
|
|
|
1762
1676
|
if entrypoint is None:
|
|
1763
1677
|
if obj.name is None:
|
|
1764
1678
|
raise ValueError(
|
|
1765
|
-
"unnamed pipeline requires entrypoint; "
|
|
1766
|
-
"use pipeline.render(name) or publish(..., entrypoint='name')"
|
|
1679
|
+
"unnamed pipeline requires entrypoint; use pipeline.render(name) or publish(..., entrypoint='name')"
|
|
1767
1680
|
)
|
|
1768
1681
|
return obj, obj.name
|
|
1769
1682
|
return replace(obj, name=entrypoint), entrypoint
|
|
@@ -7,6 +7,9 @@ from functools import lru_cache
|
|
|
7
7
|
from typing import Any
|
|
8
8
|
from urllib.request import Request, urlopen
|
|
9
9
|
|
|
10
|
+
DEFAULT_HTTP_TIMEOUT_SECONDS = 60.0
|
|
11
|
+
DEFAULT_FILE_TRANSFER_TIMEOUT_SECONDS = 300.0
|
|
12
|
+
|
|
10
13
|
|
|
11
14
|
@lru_cache(maxsize=1)
|
|
12
15
|
def verified_https_context() -> ssl.SSLContext:
|
|
@@ -17,7 +20,11 @@ def verified_https_context() -> ssl.SSLContext:
|
|
|
17
20
|
return ssl.create_default_context(cafile=certifi.where())
|
|
18
21
|
|
|
19
22
|
|
|
20
|
-
def urlopen_verified(
|
|
23
|
+
def urlopen_verified(
|
|
24
|
+
request: Request,
|
|
25
|
+
*,
|
|
26
|
+
timeout: float | None = DEFAULT_HTTP_TIMEOUT_SECONDS,
|
|
27
|
+
) -> Any:
|
|
21
28
|
"""Open a URL request with the bundled certifi CA bundle."""
|
|
22
29
|
|
|
23
|
-
return urlopen(request, context=verified_https_context())
|
|
30
|
+
return urlopen(request, context=verified_https_context(), timeout=timeout)
|
|
@@ -11,7 +11,7 @@ from __future__ import annotations
|
|
|
11
11
|
from collections.abc import Mapping
|
|
12
12
|
from html import escape
|
|
13
13
|
from pathlib import Path
|
|
14
|
-
from typing import Any
|
|
14
|
+
from typing import Any, cast
|
|
15
15
|
|
|
16
16
|
_EMPTY = "—"
|
|
17
17
|
_DEFAULT_CELL_LIMIT = 72
|
|
@@ -40,10 +40,7 @@ def details_to_text(title: str, rows: list[tuple[str, Any]]) -> str:
|
|
|
40
40
|
if not rows:
|
|
41
41
|
return f"{title}: (empty)"
|
|
42
42
|
width = max(len(label) for label, _ in rows)
|
|
43
|
-
body = "\n".join(
|
|
44
|
-
f"{label.ljust(width)}: {preview(value, limit=100)}"
|
|
45
|
-
for label, value in rows
|
|
46
|
-
)
|
|
43
|
+
body = "\n".join(f"{label.ljust(width)}: {preview(value, limit=100)}" for label, value in rows)
|
|
47
44
|
return f"{title}:\n{body}"
|
|
48
45
|
|
|
49
46
|
|
|
@@ -57,10 +54,7 @@ def details_to_html(title: str, rows: list[tuple[str, Any]]) -> str:
|
|
|
57
54
|
"</tr>"
|
|
58
55
|
for label, value in rows
|
|
59
56
|
)
|
|
60
|
-
return (
|
|
61
|
-
f"<div><b>{escape(title)}</b>"
|
|
62
|
-
f"<table><tbody>{body}</tbody></table></div>"
|
|
63
|
-
)
|
|
57
|
+
return f"<div><b>{escape(title)}</b><table><tbody>{body}</tbody></table></div>"
|
|
64
58
|
|
|
65
59
|
|
|
66
60
|
def table_to_text(
|
|
@@ -72,19 +66,10 @@ def table_to_text(
|
|
|
72
66
|
|
|
73
67
|
if not rows:
|
|
74
68
|
return f"{title}: (empty)"
|
|
75
|
-
normalized = [
|
|
76
|
-
|
|
77
|
-
for row in rows
|
|
78
|
-
]
|
|
79
|
-
widths = {
|
|
80
|
-
header: max(len(header), *(len(row[header]) for row in normalized))
|
|
81
|
-
for header in headers
|
|
82
|
-
}
|
|
69
|
+
normalized = [{header: preview(row.get(header), limit=_DEFAULT_CELL_LIMIT) for header in headers} for row in rows]
|
|
70
|
+
widths = {header: max(len(header), *(len(row[header]) for row in normalized)) for header in headers}
|
|
83
71
|
head = " ".join(header.ljust(widths[header]) for header in headers)
|
|
84
|
-
body = "\n".join(
|
|
85
|
-
" ".join(row[header].ljust(widths[header]) for header in headers)
|
|
86
|
-
for row in normalized
|
|
87
|
-
)
|
|
72
|
+
body = "\n".join(" ".join(row[header].ljust(widths[header]) for header in headers) for row in normalized)
|
|
88
73
|
return f"{title} ({len(rows)}):\n{head}\n{body}"
|
|
89
74
|
|
|
90
75
|
|
|
@@ -95,16 +80,9 @@ def table_to_html(
|
|
|
95
80
|
) -> str:
|
|
96
81
|
"""Render a compact HTML table for notebooks."""
|
|
97
82
|
|
|
98
|
-
head = "".join(
|
|
99
|
-
f"<th style='text-align:left'>{escape(header)}</th>" for header in headers
|
|
100
|
-
)
|
|
83
|
+
head = "".join(f"<th style='text-align:left'>{escape(header)}</th>" for header in headers)
|
|
101
84
|
body = "".join(
|
|
102
|
-
"<tr>"
|
|
103
|
-
+ "".join(
|
|
104
|
-
f"<td>{escape(preview(row.get(header), limit=160))}</td>"
|
|
105
|
-
for header in headers
|
|
106
|
-
)
|
|
107
|
-
+ "</tr>"
|
|
85
|
+
"<tr>" + "".join(f"<td>{escape(preview(row.get(header), limit=160))}</td>" for header in headers) + "</tr>"
|
|
108
86
|
for row in rows
|
|
109
87
|
)
|
|
110
88
|
return (
|
|
@@ -169,7 +147,7 @@ class CompactDict(dict[str, Any]):
|
|
|
169
147
|
|
|
170
148
|
@property
|
|
171
149
|
def raw(self) -> dict[str, Any]:
|
|
172
|
-
return plain(dict(self))
|
|
150
|
+
return cast(dict[str, Any], plain(dict(self)))
|
|
173
151
|
|
|
174
152
|
def _summary_rows(self) -> list[tuple[str, Any]]:
|
|
175
153
|
return [(str(key), value) for key, value in list(self.items())[:8]]
|
|
@@ -193,7 +171,7 @@ class CompactList(list[Any]):
|
|
|
193
171
|
|
|
194
172
|
@property
|
|
195
173
|
def raw(self) -> list[Any]:
|
|
196
|
-
return plain(list(self))
|
|
174
|
+
return cast(list[Any], plain(list(self)))
|
|
197
175
|
|
|
198
176
|
def _table_rows(self) -> list[dict[str, Any]]:
|
|
199
177
|
return [{"item": item} for item in self]
|
|
@@ -209,32 +187,27 @@ class HealthView(CompactDict):
|
|
|
209
187
|
title = "health"
|
|
210
188
|
|
|
211
189
|
def _summary_rows(self) -> list[tuple[str, Any]]:
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
)
|
|
220
|
-
|
|
190
|
+
counts_value = self.get("counts")
|
|
191
|
+
db_value = self.get("db")
|
|
192
|
+
server_value = self.get("server")
|
|
193
|
+
builds_value = self.get("environment_builds")
|
|
194
|
+
counts = counts_value if isinstance(counts_value, Mapping) else {}
|
|
195
|
+
db = db_value if isinstance(db_value, Mapping) else {}
|
|
196
|
+
server = server_value if isinstance(server_value, Mapping) else {}
|
|
197
|
+
builds = builds_value if isinstance(builds_value, Mapping) else {}
|
|
198
|
+
by_status_value = builds.get("by_status")
|
|
199
|
+
by_status = by_status_value if isinstance(by_status_value, Mapping) else {}
|
|
221
200
|
return [
|
|
222
201
|
("ok", self.get("ok")),
|
|
223
202
|
("db", f"{db.get('path', _EMPTY)} (exists={db.get('exists', _EMPTY)})"),
|
|
224
203
|
("server", "connected" if server.get("connected") else "offline"),
|
|
225
204
|
(
|
|
226
205
|
"counts",
|
|
227
|
-
", ".join(
|
|
228
|
-
f"{key}={value}" for key, value in sorted(counts.items())
|
|
229
|
-
)
|
|
230
|
-
or _EMPTY,
|
|
206
|
+
", ".join(f"{key}={value}" for key, value in sorted(counts.items())) or _EMPTY,
|
|
231
207
|
),
|
|
232
208
|
(
|
|
233
209
|
"env builds",
|
|
234
|
-
", ".join(
|
|
235
|
-
f"{key}={value}" for key, value in sorted((by_status or {}).items())
|
|
236
|
-
)
|
|
237
|
-
or _EMPTY,
|
|
210
|
+
", ".join(f"{key}={value}" for key, value in sorted((by_status or {}).items())) or _EMPTY,
|
|
238
211
|
),
|
|
239
212
|
]
|
|
240
213
|
|
|
@@ -424,7 +397,8 @@ class SignatureView(CompactDict):
|
|
|
424
397
|
title = "signature"
|
|
425
398
|
|
|
426
399
|
def _summary_rows(self) -> list[tuple[str, Any]]:
|
|
427
|
-
|
|
400
|
+
call_value = self.get("call")
|
|
401
|
+
call = call_value if isinstance(call_value, Mapping) else {}
|
|
428
402
|
return [
|
|
429
403
|
("name", _name(self)),
|
|
430
404
|
("kind", self.get("kind")),
|
|
@@ -489,11 +463,7 @@ class OutputListView(CompactList):
|
|
|
489
463
|
ports = item.get("ports")
|
|
490
464
|
output_type = None
|
|
491
465
|
if isinstance(ports, list) and ports:
|
|
492
|
-
output_type = ",".join(
|
|
493
|
-
str(port.get("type") or "Any")
|
|
494
|
-
for port in ports
|
|
495
|
-
if isinstance(port, Mapping)
|
|
496
|
-
)
|
|
466
|
+
output_type = ",".join(str(port.get("type") or "Any") for port in ports if isinstance(port, Mapping))
|
|
497
467
|
rows.append(
|
|
498
468
|
{
|
|
499
469
|
"name": item.get("name"),
|
|
@@ -510,7 +480,8 @@ class DecompositionView(CompactDict):
|
|
|
510
480
|
headers = ("node", "kind", "inputs", "outputs")
|
|
511
481
|
|
|
512
482
|
def _node_rows(self) -> list[dict[str, Any]]:
|
|
513
|
-
|
|
483
|
+
nodes_value = self.get("nodes")
|
|
484
|
+
nodes = nodes_value if isinstance(nodes_value, list) else []
|
|
514
485
|
return [
|
|
515
486
|
{
|
|
516
487
|
"node": item.get("name") or item.get("function") or item.get("node_id"),
|
|
@@ -528,11 +499,7 @@ class DecompositionView(CompactDict):
|
|
|
528
499
|
("functions", len(self.get("functions") or [])),
|
|
529
500
|
("links", len(self.get("links") or [])),
|
|
530
501
|
]
|
|
531
|
-
return (
|
|
532
|
-
details_to_text(self.title, rows)
|
|
533
|
-
+ "\n\n"
|
|
534
|
-
+ table_to_text("nodes", self.headers, self._node_rows())
|
|
535
|
-
)
|
|
502
|
+
return details_to_text(self.title, rows) + "\n\n" + table_to_text("nodes", self.headers, self._node_rows())
|
|
536
503
|
|
|
537
504
|
def _repr_html_(self) -> str:
|
|
538
505
|
rows = [
|
|
@@ -16,9 +16,4 @@ import spl.core.entities.scalar # noqa: F401
|
|
|
16
16
|
from spl.core.entities.node_remote import NodeRemote
|
|
17
17
|
from spl.core.ir.utils import spl_export_to_dir, spl_export_to_file, spl_import_from_file
|
|
18
18
|
|
|
19
|
-
__all__ = [
|
|
20
|
-
'NodeRemote',
|
|
21
|
-
'spl_export_to_dir',
|
|
22
|
-
'spl_export_to_file',
|
|
23
|
-
'spl_import_from_file'
|
|
24
|
-
]
|
|
19
|
+
__all__ = ["NodeRemote", "spl_export_to_dir", "spl_export_to_file", "spl_import_from_file"]
|