sched: add typed occurrence expression kind for schedule inputs (T04)
This commit is contained in:
@@ -10,16 +10,22 @@ values through a faked graph ``context`` mapping.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Iterator, Mapping
|
||||
from collections.abc import Iterator, Mapping, Sequence
|
||||
from typing import Any, Protocol
|
||||
|
||||
from wf_core.errors import WorkflowExecutionError
|
||||
from wf_core.local_paths import LocalPathError, has_overlapping_paths, set_local_value
|
||||
from wf_core.models.input_bindings import (
|
||||
ArrayExpression,
|
||||
InputExpression,
|
||||
LiteralExpression,
|
||||
ObjectExpression,
|
||||
OccurrenceExpression,
|
||||
PathExpression,
|
||||
ScheduleArrayExpression,
|
||||
ScheduleExpression,
|
||||
ScheduleInputBinding,
|
||||
ScheduleObjectExpression,
|
||||
)
|
||||
from wf_core.models.json_values import JsonValue, validate_strict_json_value
|
||||
from wf_core.paths import GraphSourcePath, resolve_graph_path
|
||||
@@ -114,6 +120,81 @@ def resolve_composed_expression(
|
||||
raise WorkflowExecutionError(f"unsupported input expression for {label} {location}")
|
||||
|
||||
|
||||
def resolve_schedule_expression(
|
||||
expression: ScheduleExpression,
|
||||
*,
|
||||
occurrence: Mapping[str, Any],
|
||||
label: str,
|
||||
location: str,
|
||||
) -> JsonValue:
|
||||
"""Resolve one schedule-side expression against the occurrence environment.
|
||||
|
||||
Composition (literal/array/object) is shared with the graph traversal
|
||||
above; leaves are typed occurrence fields only. Graph paths are invalid
|
||||
here and never reach ``GraphSourcePath``.
|
||||
"""
|
||||
if isinstance(expression, LiteralExpression):
|
||||
return expression.value
|
||||
if isinstance(expression, OccurrenceExpression):
|
||||
try:
|
||||
if expression.field not in occurrence:
|
||||
raise WorkflowExecutionError(
|
||||
f"unknown occurrence field {expression.field!r}"
|
||||
)
|
||||
return validate_strict_json_value(occurrence[expression.field])
|
||||
except (ValueError, WorkflowExecutionError) as exc:
|
||||
raise WorkflowExecutionError(f"{label} {location}: {exc}") from exc
|
||||
if isinstance(expression, ScheduleArrayExpression):
|
||||
return [
|
||||
resolve_schedule_expression(
|
||||
item,
|
||||
occurrence=occurrence,
|
||||
label=label,
|
||||
location=f"{location}[{index}]",
|
||||
)
|
||||
for index, item in enumerate(expression.items)
|
||||
]
|
||||
if isinstance(expression, ScheduleObjectExpression):
|
||||
return {
|
||||
field: resolve_schedule_expression(
|
||||
value,
|
||||
occurrence=occurrence,
|
||||
label=label,
|
||||
location=f"{location}.{field}",
|
||||
)
|
||||
for field, value in expression.fields.items()
|
||||
}
|
||||
raise WorkflowExecutionError(
|
||||
f"unsupported schedule expression for {label} {location}"
|
||||
)
|
||||
|
||||
|
||||
def resolve_schedule_input_bindings(
|
||||
bindings: Sequence[ScheduleInputBinding],
|
||||
*,
|
||||
occurrence: Mapping[str, Any],
|
||||
label: str,
|
||||
) -> dict[str, Any]:
|
||||
"""Build one workflow-input object from schedule-side bindings."""
|
||||
targets = [str(binding.target) for binding in bindings]
|
||||
if has_overlapping_paths(targets):
|
||||
raise WorkflowExecutionError(f"{label}: schedule targets overlap: {targets!r}")
|
||||
payload: dict[str, Any] = {}
|
||||
for binding in bindings:
|
||||
location = str(binding.target)
|
||||
value = resolve_schedule_expression(
|
||||
binding.expression,
|
||||
occurrence=occurrence,
|
||||
label=label,
|
||||
location=location,
|
||||
)
|
||||
try:
|
||||
set_local_value(payload, binding.target, value)
|
||||
except LocalPathError as exc:
|
||||
raise WorkflowExecutionError(f"{label} {location}: {exc}") from exc
|
||||
return payload
|
||||
|
||||
|
||||
def walk_expression_paths(
|
||||
expression: InputExpression,
|
||||
) -> Iterator[tuple[GraphSourcePath, str]]:
|
||||
|
||||
Reference in New Issue
Block a user