(De)serialization for contract operations.
The op models are already pydantic under an op-discriminated union, but the
union was only ever used as a type annotation: there was no way to load a
heterogeneous list of ops from YAML, so change sets could not be stored,
transported or replayed. This module closes that gap.
RevisionOp is ManifestOp minus
:class:~graflo.architecture.evolution.ops.ComposeManifestsOp, which is binary
(two manifests in, one out) and is rejected by the unary dispatcher anyway. A
revision applies to exactly one manifest, so composition is not a revision op.
is_revision_op(op)
Whether op may appear in a revision (i.e. is not binary).
Source code in graflo/architecture/evolution/codec.py
| def is_revision_op(op: ManifestOp) -> bool:
"""Whether *op* may appear in a revision (i.e. is not binary)."""
return type(op).__name__ != "ComposeManifestsOp"
|
op_from_dict(payload)
Validate one op payload into its concrete model, keyed by op.
Source code in graflo/architecture/evolution/codec.py
| def op_from_dict(payload: dict[str, Any]) -> Any:
"""Validate one op payload into its concrete model, keyed by ``op``."""
return _op_adapter.validate_python(payload)
|
op_to_dict(op)
Serialize one op to a payload that is guaranteed to load back.
Compact form first (defaults dropped), then verified by re-validating
it. That check is not paranoia: a nested discriminated union whose tag has
a default — IdentityTarget.mode is one — loses its tag under
exclude_defaults and becomes unloadable. Rather than special-casing
every such field, fall back to the full form whenever the compact one does
not reproduce the op.
A change set exists to be replayed exactly; silently emitting something
that cannot be read back is the one failure this layer must not have.
Source code in graflo/architecture/evolution/codec.py
| def op_to_dict(op: Any) -> dict[str, Any]:
"""Serialize one op to a payload that is guaranteed to load back.
Compact form first (defaults dropped), then **verified** by re-validating
it. That check is not paranoia: a nested discriminated union whose tag has
a default — ``IdentityTarget.mode`` is one — loses its tag under
``exclude_defaults`` and becomes unloadable. Rather than special-casing
every such field, fall back to the full form whenever the compact one does
not reproduce the op.
A change set exists to be replayed exactly; silently emitting something
that cannot be read back is the one failure this layer must not have.
"""
compact = op.to_dict(skip_defaults=True) | {"op": op.op}
try:
if _op_adapter.validate_python(compact) == op:
return compact
except Exception:
# Any validation failure means the compact form is not loadable.
pass
return op.to_dict(skip_defaults=False) | {"op": op.op}
|
ops_from_dicts(payloads)
Validate a heterogeneous list of op payloads.
Source code in graflo/architecture/evolution/codec.py
| def ops_from_dicts(payloads: list[dict[str, Any]]) -> list[Any]:
"""Validate a heterogeneous list of op payloads."""
return _op_list_adapter.validate_python(payloads)
|
ops_from_yaml(source)
Load ops from a YAML file path, or from a YAML string.
Accepts either a bare list of op mappings or a mapping with an ops key.
Source code in graflo/architecture/evolution/codec.py
| def ops_from_yaml(source: str | Any) -> list[Any]:
"""Load ops from a YAML file path, or from a YAML string.
Accepts either a bare list of op mappings or a mapping with an ``ops`` key.
"""
if isinstance(source, str) and ("\n" in source or source.lstrip().startswith("-")):
import yaml
payload = yaml.safe_load(source)
else:
payload = FileHandle.load(source)
if isinstance(payload, dict):
payload = payload.get("ops", [])
if not isinstance(payload, list):
raise ValueError(
"expected a list of operations, or a mapping with an 'ops' key; "
f"got {type(payload).__name__}"
)
return ops_from_dicts(payload)
|
ops_to_dicts(ops)
Serialize ops to plain dicts that load back identically.
Source code in graflo/architecture/evolution/codec.py
| def ops_to_dicts(ops: list[Any]) -> list[dict[str, Any]]:
"""Serialize ops to plain dicts that load back identically."""
return [op_to_dict(op) for op in ops]
|
ops_to_yaml_str(ops)
Serialize ops to a YAML list.
Source code in graflo/architecture/evolution/codec.py
| def ops_to_yaml_str(ops: list[Any]) -> str:
"""Serialize ops to a YAML list."""
import yaml
return yaml.safe_dump(ops_to_dicts(ops), sort_keys=False, default_flow_style=False)
|