feat: deliver Python workflow client
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any, cast
|
||||
|
||||
from wf_client.capabilities import CapabilityResult, RemoteCapability
|
||||
from wf_client.deployments import Deployment, DeploymentValidation
|
||||
from wf_client.protocols import WorkflowClientPort
|
||||
from wf_client.runs import Run, TracePage
|
||||
from wf_client.workflows import (
|
||||
ArtifactRef,
|
||||
WorkflowDiagnostic,
|
||||
WorkflowValidation,
|
||||
)
|
||||
from wf_core import ValidationReport
|
||||
from wf_platform import CapabilityRef
|
||||
|
||||
|
||||
class _Port:
|
||||
"""A port that records accidental representation-time remote operations."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.calls: list[tuple[str, dict[str, Any]]] = []
|
||||
|
||||
def __getattr__(self, name: str) -> Any:
|
||||
async def operation(**params: Any) -> object:
|
||||
self.calls.append((name, params))
|
||||
return {}
|
||||
|
||||
return operation
|
||||
|
||||
|
||||
def _port() -> _Port:
|
||||
return _Port()
|
||||
|
||||
|
||||
def test_capability_html_repr_is_bounded_and_does_not_call_port() -> None:
|
||||
port = _port()
|
||||
remote = RemoteCapability(
|
||||
_port=cast(WorkflowClientPort, port),
|
||||
ref=CapabilityRef.parse("app.default.search"),
|
||||
qualified_name="app.default.search",
|
||||
description="Search things <carefully>",
|
||||
input_schema={"type": "object", "properties": {"query": {"type": "string"}}},
|
||||
output_schema={"type": "object", "properties": {"items": {"type": "array"}}},
|
||||
outcomes=("ok",),
|
||||
is_async=False,
|
||||
)
|
||||
|
||||
rendered = remote._repr_html_()
|
||||
|
||||
assert "app.default.search" in rendered
|
||||
assert "input schema" in rendered.lower()
|
||||
assert "<carefully>" in rendered
|
||||
assert port.calls == []
|
||||
|
||||
|
||||
def test_rich_representations_bound_large_values_and_redact_secret_like_fields() -> (
|
||||
None
|
||||
):
|
||||
port = _port()
|
||||
result = CapabilityResult(
|
||||
outcome="ok",
|
||||
output={"token": "do-not-show", "items": ["x" * 400] * 20},
|
||||
diagnostics=(),
|
||||
)
|
||||
run = Run(
|
||||
_port=cast(WorkflowClientPort, port),
|
||||
run_id="run-1",
|
||||
deployment_id="deployment-1",
|
||||
status="completed",
|
||||
outcome="ok",
|
||||
output=result.output,
|
||||
interrupt=None,
|
||||
diagnostics=(),
|
||||
trace_count=1000,
|
||||
)
|
||||
|
||||
rendered = repr(run)
|
||||
html = run._repr_html_()
|
||||
|
||||
assert len(rendered) <= 1_201
|
||||
assert len(html) <= 2_500
|
||||
assert "do-not-show" not in rendered
|
||||
assert "do-not-show" not in html
|
||||
assert "1000 frames" in rendered
|
||||
assert port.calls == []
|
||||
|
||||
|
||||
def test_all_rich_objects_render_without_port_access() -> None:
|
||||
port = cast(WorkflowClientPort, _port())
|
||||
diagnostic = WorkflowDiagnostic("error", "bad", "state.x", "broken")
|
||||
local = ValidationReport()
|
||||
objects = [
|
||||
ArtifactRef("artifact", 1),
|
||||
diagnostic,
|
||||
WorkflowValidation(local, "valid", (diagnostic,)),
|
||||
CapabilityResult("ok", {"value": 1}, ()),
|
||||
DeploymentValidation("deployment", "artifact", 1, "runnable", ()),
|
||||
TracePage(0, 25, (), False, 0),
|
||||
]
|
||||
|
||||
for value in objects:
|
||||
assert repr(value)
|
||||
assert value._repr_html_()
|
||||
assert repr(
|
||||
Deployment.from_payload(
|
||||
port,
|
||||
{
|
||||
"id": "deployment",
|
||||
"artifact_id": "artifact",
|
||||
"artifact_version": 1,
|
||||
"bindings": [],
|
||||
"drift_policy": "block",
|
||||
},
|
||||
)
|
||||
)
|
||||
assert port.calls == []
|
||||
Reference in New Issue
Block a user