even MORE code review
stateful to not deadhang, graph context -> output, more explicit state errors, other misc changes idfk any of those good thing theyre fixed tho
This commit is contained in:
@@ -10,6 +10,7 @@ from wf_core.runtime.foreach_state import (
|
||||
ForeachBarrierState,
|
||||
ItemErrorRecord,
|
||||
PendingItemResult,
|
||||
_state_write_from_metadata,
|
||||
)
|
||||
from wf_core.runtime.lineage import LineageStateView, lineage_writes_for_frame
|
||||
from wf_core.runtime.ops.state import StatePatch
|
||||
@@ -88,6 +89,21 @@ def test_foreach_barrier_state_round_trips_reducer_write_records() -> None:
|
||||
assert write.reducer.name == "wf.std.add"
|
||||
|
||||
|
||||
def test_pending_write_metadata_preserves_invalid_reducer_detail() -> None:
|
||||
with pytest.raises(WorkflowExecutionError, match="mutually exclusive"):
|
||||
_state_write_from_metadata(
|
||||
{
|
||||
"path": {"root": "state", "parts": ["count"]},
|
||||
"incoming_value": 1,
|
||||
"visible_value": 1,
|
||||
"reducer": {
|
||||
"name": "wf.std.add",
|
||||
"ref": {"source": "wf.std", "capability_key": "add"},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def test_lineage_state_view_materializes_visible_values_without_mutating_base() -> None:
|
||||
base_state = {"count": 2, "nested": {"value": "old"}}
|
||||
view = LineageStateView(
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
|
||||
from wf_core import (
|
||||
END,
|
||||
Edge,
|
||||
@@ -9,6 +11,7 @@ from wf_core import (
|
||||
StateField,
|
||||
StateSchema,
|
||||
Workflow,
|
||||
WorkflowExecutionError,
|
||||
)
|
||||
from wf_core.models.reducers import ReducerRef
|
||||
from wf_core.paths import StatePath
|
||||
@@ -158,6 +161,14 @@ def test_state_view_for_frame_overlays_writes_onto_frame_scope_state() -> None:
|
||||
assert run.state["value"] == "root"
|
||||
|
||||
|
||||
def test_lineage_state_view_rejects_corrupt_parent_cycle() -> None:
|
||||
run = create_run_state(_minimal_workflow(), {"value": "root"})
|
||||
run.lineages["root"].parent_id = "root"
|
||||
|
||||
with pytest.raises(WorkflowExecutionError, match="cycle"):
|
||||
lineage_state_view(run, scope_id="root", lineage_id="root")
|
||||
|
||||
|
||||
def test_lineage_state_view_handles_deep_ancestry_without_recursion() -> None:
|
||||
run = create_run_state(_minimal_workflow(), {"value": "root"})
|
||||
parent_id = "root"
|
||||
|
||||
@@ -24,8 +24,9 @@ from wf_core import (
|
||||
resume_workflow_async,
|
||||
resume_workflow,
|
||||
)
|
||||
from wf_core.models.steps import InputPathBinding, Step
|
||||
from wf_core.paths import GraphSourcePath, LocalPath
|
||||
from wf_core.validation.issues import ValidationIssueCode
|
||||
from wf_core.models.steps import Step
|
||||
|
||||
|
||||
def test_subgraph_step_validates_boundary_bindings_and_outcomes() -> None:
|
||||
@@ -158,6 +159,34 @@ def test_subgraph_step_executes_caller_prepared_saved_child_ref() -> None:
|
||||
assert run.trace[-1].step_type == "subgraph"
|
||||
|
||||
|
||||
def test_subgraph_step_projects_child_context_output() -> None:
|
||||
child = Workflow(
|
||||
name="context_child",
|
||||
input_schema=_schema({"text": {"type": "string"}}),
|
||||
state_schema=StateSchema.from_field_map({}),
|
||||
output_schema=_schema({"answer": {"type": "string"}}),
|
||||
output=[
|
||||
InputPathBinding(
|
||||
target=LocalPath.of("answer"),
|
||||
path=GraphSourcePath.parse("context.scope_id"),
|
||||
)
|
||||
],
|
||||
outcomes=["ok"],
|
||||
start="done",
|
||||
nodes=[EndNode(id="done", type="end", outcome="ok")],
|
||||
edges=[],
|
||||
)
|
||||
|
||||
run = execute_workflow(
|
||||
_workflow(output_schema=_schema({"answer": {"type": "string"}})),
|
||||
{"text": "hello"},
|
||||
{},
|
||||
subgraphs={"child.workflow": PreparedSubgraph(workflow=child, registry={})},
|
||||
)
|
||||
|
||||
assert run.output["answer"] == "root:subgraph:child"
|
||||
|
||||
|
||||
def test_subgraph_step_executes_prepared_async_child() -> None:
|
||||
async def answer(payload: dict[str, object], _ctx: object) -> dict[str, object]:
|
||||
return {"answer": f"async:{payload['text']}"}
|
||||
|
||||
Reference in New Issue
Block a user