more half-ass async migrations + basedpyright warning

This commit is contained in:
lda
2026-06-12 08:07:15 +07:00 Verified
parent 862d3340da
commit 510590239a
8 changed files with 206 additions and 179 deletions
+2 -2
View File
@@ -96,7 +96,7 @@ def test_openapi_source_can_be_registered_and_inspected_by_service(
)
def test_source_node_passes_operation_config_and_payload_to_execution(
async def test_source_node_passes_operation_config_and_payload_to_execution(
monkeypatch,
) -> None:
captured: dict[str, Any] = {}
@@ -137,7 +137,7 @@ def test_source_node_passes_operation_config_and_payload_to_execution(
RuntimeContext(current_node_id="petstore.default.get_pet"),
)
asyncio.run(run_handler())
await run_handler()
operation = captured["operation"]
config = captured["config"]
+24 -23
View File
@@ -7,6 +7,8 @@ from dataclasses import replace
from pathlib import Path
from typing import Any, cast
import pytest
from tests.wf_mcp.test_support import echo_tool
from wf_api.deployments import WorkflowDeploymentApi
from wf_artifacts import (
@@ -96,13 +98,12 @@ def _deployment_api(
context = context_from_service(service)
return WorkflowDeploymentApi(context), service
def test_save_deployment_stores_and_returns_stable_fields(tmp_path: Path) -> None:
@pytest.mark.asyncio
async def test_save_deployment_stores_and_returns_stable_fields(tmp_path: Path) -> None:
artifact_store = FileWorkflowArtifactStore(tmp_path / "deploy_save")
api, _service = _deployment_api(artifact_store)
result = asyncio.run(
api.save_deployment(
result = await api.save_deployment(
WorkflowDeployment(
id="echo.personal",
artifact_id="echo",
@@ -112,15 +113,14 @@ def test_save_deployment_stores_and_returns_stable_fields(tmp_path: Path) -> Non
],
).model_dump(mode="json")
)
)
assert result["saved"] is True
assert result["deployment_id"] == "echo.personal"
assert result["artifact_id"] == "echo"
assert result["artifact_version"] == 1
def test_list_deployments_returns_compact_summaries(tmp_path: Path) -> None:
@pytest.mark.asyncio
async def test_list_deployments_returns_compact_summaries(tmp_path: Path) -> None:
artifact_store = FileWorkflowArtifactStore(tmp_path / "deploy_list")
api, _service = _deployment_api(artifact_store)
artifact_store.save_deployment(
@@ -132,7 +132,7 @@ def test_list_deployments_returns_compact_summaries(tmp_path: Path) -> None:
)
)
result = asyncio.run(api.list_deployments())
result = await api.list_deployments()
assert len(result["deployments"]) == 1
assert result["deployments"][0]["id"] == "echo.personal"
@@ -140,18 +140,20 @@ def test_list_deployments_returns_compact_summaries(tmp_path: Path) -> None:
assert "bindings" not in result["deployments"][0]
def test_list_deployments_returns_empty_without_artifact_store(tmp_path: Path) -> None:
@pytest.mark.asyncio
async def test_list_deployments_returns_empty_without_artifact_store(tmp_path: Path) -> None:
artifact_store = FileWorkflowArtifactStore(tmp_path / "deploy_no_store")
_api, service = _deployment_api(artifact_store)
context = replace(context_from_service(service), artifact_store=None)
api = WorkflowDeploymentApi(context)
result = asyncio.run(api.list_deployments())
result = await api.list_deployments()
assert result["deployments"] == []
def test_delete_deployment_removes_one(tmp_path: Path) -> None:
@pytest.mark.asyncio
async def test_delete_deployment_removes_one(tmp_path: Path) -> None:
artifact_store = FileWorkflowArtifactStore(tmp_path / "deploy_delete")
api, _service = _deployment_api(artifact_store)
artifact_store.save_deployment(
@@ -163,14 +165,15 @@ def test_delete_deployment_removes_one(tmp_path: Path) -> None:
)
)
result = asyncio.run(api.delete_deployment(deployment_id="echo.personal"))
result = await api.delete_deployment(deployment_id="echo.personal")
assert result["deployment_id"] == "echo.personal"
assert result["deleted"] is True
assert artifact_store.list_deployments() == []
def test_validate_deployment_returns_runnable_for_valid_binding(tmp_path: Path) -> None:
@pytest.mark.asyncio
async def test_validate_deployment_returns_runnable_for_valid_binding(tmp_path: Path) -> None:
artifact_store = FileWorkflowArtifactStore(tmp_path / "deploy_validate_runnable")
api, service = _deployment_api(artifact_store, register_echo=True)
artifact_store.save_artifact(_echo_artifact())
@@ -183,9 +186,7 @@ def test_validate_deployment_returns_runnable_for_valid_binding(tmp_path: Path)
)
)
result = asyncio.run(
api.validate_deployment(deployment_id="echo.personal", live_check=False)
)
result = await api.validate_deployment(deployment_id="echo.personal", live_check=False)
assert result["status"] == "runnable"
assert result["diagnostics"] == []
@@ -200,7 +201,8 @@ class FailingLivenessAdapter:
raise OSError("stdio process exited")
def test_validate_deployment_live_check_calls_live_checker(tmp_path: Path) -> None:
@pytest.mark.asyncio
async def test_validate_deployment_live_check_calls_live_checker(tmp_path: Path) -> None:
artifact_store = FileWorkflowArtifactStore(tmp_path / "deploy_validate_live")
api, service = _deployment_api(artifact_store, register_echo=True)
artifact_store.save_artifact(_echo_artifact())
@@ -217,15 +219,14 @@ def test_validate_deployment_live_check_calls_live_checker(tmp_path: Path) -> No
cast(BackendAdapter, FailingLivenessAdapter()),
)
result = asyncio.run(
api.validate_deployment(deployment_id="echo.personal", live_check=True)
)
result = await api.validate_deployment(deployment_id="echo.personal", live_check=True)
assert result["status"] == "unrunnable"
assert result["diagnostics"][0]["code"] == "source_unreachable"
def test_handler_delegation_for_validate_deployment(tmp_path: Path) -> None:
@pytest.mark.asyncio
async def test_handler_delegation_for_validate_deployment(tmp_path: Path) -> None:
"""WorkflowSurfaceHandlers.validate_deployment delegates to WorkflowDeploymentApi."""
artifact_store = FileWorkflowArtifactStore(tmp_path / "deploy_delegation")
service = WfMcpService(
@@ -246,8 +247,8 @@ def test_handler_delegation_for_validate_deployment(tmp_path: Path) -> None:
context = context_from_service(service)
api = WorkflowDeploymentApi(context)
handler_result = asyncio.run(h.validate_deployment(deployment_id="echo.personal"))
api_result = asyncio.run(api.validate_deployment(deployment_id="echo.personal"))
handler_result = await h.validate_deployment(deployment_id="echo.personal")
api_result = await api.validate_deployment(deployment_id="echo.personal")
assert handler_result["status"] == api_result["status"]
assert len(handler_result["diagnostics"]) == len(api_result["diagnostics"])
+7 -6
View File
@@ -3,6 +3,8 @@ from __future__ import annotations
import asyncio
from pathlib import Path
import pytest
from tests.wf_mcp.test_support import echo_tool
from wf_api import WorkflowApi
from wf_api.artifacts import WorkflowArtifactApi
@@ -40,14 +42,13 @@ def test_workflow_api_composes_domain_services(tmp_path: Path) -> None:
assert not hasattr(api, "backend")
def test_workflow_api_direct_capability_call(tmp_path: Path) -> None:
@pytest.mark.asyncio
async def test_workflow_api_direct_capability_call(tmp_path: Path) -> None:
api = _api(tmp_path / "wf_api_direct_composition")
result = asyncio.run(
api.call_capability(
qualified_name="demo.personal.echo_tool",
payload={"text": "hello"},
)
result = await api.call_capability(
qualified_name="demo.personal.echo_tool",
payload={"text": "hello"},
)
assert result["kind"] == "node_spec"
+112 -128
View File
@@ -4,6 +4,8 @@ import asyncio
from pathlib import Path
from typing import Any
import pytest
from tests.wf_mcp.test_support import echo_tool
from wf_api.drafts import WorkflowDraftApi
from wf_artifacts import FileDraftWorkspaceStore, FileWorkflowArtifactStore
@@ -70,21 +72,20 @@ def _draft_api(
return WorkflowDraftApi(context), service
def test_patch_draft_applies_json_patch(tmp_path: Path) -> None:
@pytest.mark.asyncio
async def test_patch_draft_applies_json_patch(tmp_path: Path) -> None:
artifact_store = FileWorkflowArtifactStore(tmp_path / "drafts_patch")
api, _service = _draft_api(artifact_store)
result = asyncio.run(
api.patch_draft(
draft=_echo_draft(),
patch=[
{
"op": "replace",
"path": "/steps/echo/input/0/target/parts/0",
"value": "message",
}
],
)
result = await api.patch_draft(
draft=_echo_draft(),
patch=[
{
"op": "replace",
"path": "/steps/echo/input/0/target/parts/0",
"value": "message",
}
],
)
assert result["status"] == "valid"
@@ -94,49 +95,45 @@ def test_patch_draft_applies_json_patch(tmp_path: Path) -> None:
}
def test_create_draft_workspace_creates_workspace(tmp_path: Path) -> None:
@pytest.mark.asyncio
async def test_create_draft_workspace_creates_workspace(tmp_path: Path) -> None:
artifact_store = FileWorkflowArtifactStore(tmp_path / "drafts_create_workspace")
api, _service = _draft_api(artifact_store)
result = asyncio.run(
api.create_draft_workspace(
workspace_id="echo_ws",
title="Echo Workspace",
draft=_echo_draft(),
)
result = await api.create_draft_workspace(
workspace_id="echo_ws",
title="Echo Workspace",
draft=_echo_draft(),
)
assert result["workspace_id"] == "echo_ws"
assert result["revision"] == 1
fetched = asyncio.run(
api.get_draft_workspace(workspace_id="echo_ws", include_draft=True)
)
fetched = await api.get_draft_workspace(workspace_id="echo_ws", include_draft=True)
assert fetched["workspace_id"] == "echo_ws"
assert fetched["title"] == "Echo Workspace"
assert fetched["draft"]["steps"]["echo"]["use"] == "demo.personal.echo_tool"
def test_list_draft_workspaces_returns_sorted_summaries_without_drafts(
@pytest.mark.asyncio
async def test_list_draft_workspaces_returns_sorted_summaries_without_drafts(
tmp_path: Path,
) -> None:
artifact_store = FileWorkflowArtifactStore(tmp_path / "drafts_list_workspaces")
api, _service = _draft_api(artifact_store)
asyncio.run(
api.create_draft_workspace(
workspace_id="b_draft",
title="B Draft",
draft=_echo_draft(),
)
)
asyncio.run(
api.create_draft_workspace(
workspace_id="a_draft",
title="A Draft",
draft=_echo_draft(),
)
await api.create_draft_workspace(
workspace_id="b_draft",
title="B Draft",
draft=_echo_draft(),
)
result = asyncio.run(api.list_draft_workspaces())
await api.create_draft_workspace(
workspace_id="a_draft",
title="A Draft",
draft=_echo_draft(),
)
result = await api.list_draft_workspaces()
assert [workspace["workspace_id"] for workspace in result["workspaces"]] == [
"a_draft",
@@ -146,19 +143,18 @@ def test_list_draft_workspaces_returns_sorted_summaries_without_drafts(
assert "draft" not in result["workspaces"][0]
def test_delete_draft_workspace_is_idempotent(tmp_path: Path) -> None:
@pytest.mark.asyncio
async def test_delete_draft_workspace_is_idempotent(tmp_path: Path) -> None:
artifact_store = FileWorkflowArtifactStore(tmp_path / "drafts_delete_workspace")
api, _service = _draft_api(artifact_store)
asyncio.run(
api.create_draft_workspace(
workspace_id="echo_ws",
draft=_echo_draft(),
)
await api.create_draft_workspace(
workspace_id="echo_ws",
draft=_echo_draft(),
)
deleted = asyncio.run(api.delete_draft_workspace(workspace_id="echo_ws"))
deleted_again = asyncio.run(api.delete_draft_workspace(workspace_id="echo_ws"))
listed = asyncio.run(api.list_draft_workspaces())
deleted = await api.delete_draft_workspace(workspace_id="echo_ws")
deleted_again = await api.delete_draft_workspace(workspace_id="echo_ws")
listed = await api.list_draft_workspaces()
assert deleted["workspace_id"] == "echo_ws"
assert deleted["deleted"] is True
@@ -169,75 +165,62 @@ def test_delete_draft_workspace_is_idempotent(tmp_path: Path) -> None:
assert listed["workspaces"] == []
def test_patch_draft_workspace_updates_revision(tmp_path: Path) -> None:
@pytest.mark.asyncio
async def test_patch_draft_workspace_updates_revision(tmp_path: Path) -> None:
artifact_store = FileWorkflowArtifactStore(tmp_path / "drafts_patch_workspace")
api, _service = _draft_api(artifact_store)
asyncio.run(
api.create_draft_workspace(
workspace_id="echo_ws",
draft=_echo_draft(),
)
await api.create_draft_workspace(
workspace_id="echo_ws",
draft=_echo_draft(),
)
patched = asyncio.run(
api.patch_draft_workspace(
workspace_id="echo_ws",
revision=1,
patch=[{"op": "replace", "path": "/name", "value": "echo_v2"}],
)
patched = await api.patch_draft_workspace(
workspace_id="echo_ws",
revision=1,
patch=[{"op": "replace", "path": "/name", "value": "echo_v2"}],
)
assert patched["revision"] == 2
assert patched["status"] == "valid"
def test_draft_workspace_patch_helpers_update_revision_and_bindings(
@pytest.mark.asyncio
async def test_draft_workspace_patch_helpers_update_revision_and_bindings(
tmp_path: Path,
) -> None:
artifact_store = FileWorkflowArtifactStore(tmp_path / "drafts_patch_helpers")
api, _service = _draft_api(artifact_store)
asyncio.run(
api.create_draft_workspace(
workspace_id="echo_ws",
draft=_echo_draft(),
)
await api.create_draft_workspace(
workspace_id="echo_ws",
draft=_echo_draft(),
)
named = asyncio.run(
api.set_draft_name(
workspace_id="echo_ws",
revision=1,
name="echo_v2",
)
named = await api.set_draft_name(
workspace_id="echo_ws",
revision=1,
name="echo_v2",
)
routed = asyncio.run(
api.set_draft_route(
workspace_id="echo_ws",
revision=2,
step_id="echo",
outcome="error",
target="__end__",
)
routed = await api.set_draft_route(
workspace_id="echo_ws",
revision=2,
step_id="echo",
outcome="error",
target="__end__",
)
input_mapped = asyncio.run(
api.set_step_input_map(
workspace_id="echo_ws",
revision=3,
step_id="echo",
input_map={"input.text": "message"},
)
input_mapped = await api.set_step_input_map(
workspace_id="echo_ws",
revision=3,
step_id="echo",
input_map={"input.text": "message"},
)
output_mapped = asyncio.run(
api.set_step_output_map(
workspace_id="echo_ws",
revision=4,
step_id="echo",
output_map={"echoed": "state.echoed"},
)
)
fetched = asyncio.run(
api.get_draft_workspace(workspace_id="echo_ws", include_draft=True)
output_mapped = await api.set_step_output_map(
workspace_id="echo_ws",
revision=4,
step_id="echo",
output_map={"echoed": "state.echoed"},
)
fetched = await api.get_draft_workspace(workspace_id="echo_ws", include_draft=True)
assert named["revision"] == 2
assert routed["revision"] == 3
@@ -259,20 +242,19 @@ def test_draft_workspace_patch_helpers_update_revision_and_bindings(
]
def test_validate_draft_workspace_refreshes_status(tmp_path: Path) -> None:
@pytest.mark.asyncio
async def test_validate_draft_workspace_refreshes_status(tmp_path: Path) -> None:
artifact_store = FileWorkflowArtifactStore(tmp_path / "drafts_validate_workspace")
api, service = _draft_api(artifact_store, register_echo=True)
draft = _echo_draft()
draft["routes"]["echo"] = {"typo": "__end__"}
asyncio.run(
api.create_draft_workspace(
workspace_id="echo_ws",
draft=draft,
)
await api.create_draft_workspace(
workspace_id="echo_ws",
draft=draft,
)
payload = asyncio.run(api.validate_draft_workspace(workspace_id="echo_ws"))
fetched = asyncio.run(api.get_draft_workspace(workspace_id="echo_ws"))
payload = await api.validate_draft_workspace(workspace_id="echo_ws")
fetched = await api.get_draft_workspace(workspace_id="echo_ws")
assert payload["revision"] == 1
assert payload["status"] == "invalid"
@@ -280,40 +262,42 @@ def test_validate_draft_workspace_refreshes_status(tmp_path: Path) -> None:
assert fetched["status"] == "invalid"
def test_create_minimal_draft_workspace_minimal_success_path(tmp_path: Path) -> None:
@pytest.mark.asyncio
async def test_create_minimal_draft_workspace_minimal_success_path(
tmp_path: Path,
) -> None:
artifact_store = FileWorkflowArtifactStore(tmp_path / "drafts_minimal_workspace")
api, _service = _draft_api(artifact_store, register_echo=True)
result = asyncio.run(
api.create_minimal_draft_workspace(
workspace_id="echo_minimal",
name="echo",
capability_name="demo.personal.echo_tool",
input_schema={
"type": "object",
"properties": {"text": {"type": "string"}},
"required": ["text"],
},
state_schema={"fields": {"echoed": {"type": "string"}}},
output_schema={
"type": "object",
"properties": {"echoed": {"type": "string"}},
"required": ["echoed"],
},
input_map={"input.text": "text"},
output_map={"echoed": "state.echoed"},
)
result = await api.create_minimal_draft_workspace(
workspace_id="echo_minimal",
name="echo",
capability_name="demo.personal.echo_tool",
input_schema={
"type": "object",
"properties": {"text": {"type": "string"}},
"required": ["text"],
},
state_schema={"fields": {"echoed": {"type": "string"}}},
output_schema={
"type": "object",
"properties": {"echoed": {"type": "string"}},
"required": ["echoed"],
},
input_map={"input.text": "text"},
output_map={"echoed": "state.echoed"},
)
assert result["workspace_id"] == "echo_minimal"
fetched = asyncio.run(
api.get_draft_workspace(workspace_id="echo_minimal", include_draft=True)
fetched = await api.get_draft_workspace(
workspace_id="echo_minimal", include_draft=True
)
assert fetched["draft"]["routes"]["call"]["ok"] == "__end__"
assert fetched["draft"]["steps"]["call"]["use"] == "demo.personal.echo_tool"
def test_delegation_smoke_validate_draft_equivalence(tmp_path: Path) -> None:
@pytest.mark.asyncio
async def test_delegation_smoke_validate_draft_equivalence(tmp_path: Path) -> None:
"""WorkflowSurfaceHandlers.validate_draft delegates to WorkflowDraftApi."""
artifact_store = FileWorkflowArtifactStore(tmp_path / "drafts_delegation_smoke")
mcp_root = artifact_store.root / "delegation_mcp"
@@ -332,8 +316,8 @@ def test_delegation_smoke_validate_draft_equivalence(tmp_path: Path) -> None:
api = WorkflowDraftApi(context)
draft = _echo_draft()
handler_result = asyncio.run(h.validate_draft(draft=draft))
api_result = asyncio.run(api.validate_draft(draft=draft))
handler_result = await h.validate_draft(draft=draft)
api_result = await api.validate_draft(draft=draft)
assert handler_result["status"] == api_result["status"]
assert handler_result["diagnostics"] == api_result["diagnostics"]