73 lines
2.3 KiB
Python
73 lines
2.3 KiB
Python
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
from pathlib import Path
|
|
from typing import Any, Dict, List, Mapping, Optional
|
|
|
|
import yaml
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class Outcome:
|
|
when: Mapping[str, Any]
|
|
to: Optional[str] = None
|
|
emit: Optional[Mapping[str, Any]] = None
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class Transition:
|
|
event_id: str
|
|
stage: str
|
|
desc: str
|
|
from_states: List[str]
|
|
outcomes: List[Outcome]
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class StateMachineConfig:
|
|
path: Path
|
|
raw: Mapping[str, Any]
|
|
transitions: Mapping[str, Transition]
|
|
invariants: Mapping[str, Mapping[str, Any]]
|
|
|
|
@staticmethod
|
|
def load(path: Path) -> "StateMachineConfig":
|
|
with path.open("r", encoding="utf-8") as f:
|
|
raw = yaml.safe_load(f)
|
|
|
|
if not isinstance(raw, dict):
|
|
raise TypeError(f"Invalid state machine yaml: {path}")
|
|
|
|
transitions_raw = raw.get("transitions")
|
|
if not isinstance(transitions_raw, dict):
|
|
raise TypeError("'transitions' must be a mapping")
|
|
|
|
parsed: Dict[str, Transition] = {}
|
|
for event_id, tdef in transitions_raw.items():
|
|
if not isinstance(tdef, dict):
|
|
continue
|
|
outcomes: List[Outcome] = []
|
|
for o in tdef.get("outcomes", []):
|
|
if not isinstance(o, dict):
|
|
continue
|
|
when = o.get("when", {})
|
|
if not isinstance(when, dict):
|
|
continue
|
|
outcomes.append(
|
|
Outcome(
|
|
when=when,
|
|
to=o.get("to") if isinstance(o.get("to"), str) else None,
|
|
emit=o.get("emit") if isinstance(o.get("emit"), dict) else None,
|
|
)
|
|
)
|
|
parsed[str(event_id)] = Transition(
|
|
event_id=str(event_id),
|
|
stage=str(tdef.get("stage", "")),
|
|
desc=str(tdef.get("desc", "")),
|
|
from_states=[s for s in tdef.get("from", []) if isinstance(s, str)],
|
|
outcomes=outcomes,
|
|
)
|
|
|
|
invariants = raw.get("invariants") if isinstance(raw.get("invariants"), dict) else {}
|
|
return StateMachineConfig(path=path, raw=raw, transitions=parsed, invariants=invariants)
|