Spaces:
Sleeping
Sleeping
File size: 1,439 Bytes
116524e | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | """Immutable step context — the single object that flows through every step."""
from __future__ import annotations
import dataclasses
from dataclasses import dataclass, field
from types import MappingProxyType
from typing import Any, Self
@dataclass(frozen=True)
class StepContext:
"""Frozen context object passed from step to step.
The pipeline engine only requires ``sample`` and ``metadata``. All
domain-specific fields are added by subclassing — the engine never reads
anything beyond these two fields.
Consuming applications subclass ``StepContext`` to add named fields for
concepts shared across their pipelines. Integration-specific data goes
in ``metadata`` to prevent field accumulation on the subclass.
Steps never mutate the incoming context — they call ``.replace()`` to
produce a new one.
"""
sample: Any = None
metadata: MappingProxyType = field(default_factory=lambda: MappingProxyType({}))
def __post_init__(self) -> None:
# Coerce plain dict → MappingProxyType so mutation is a hard runtime error
if not isinstance(self.metadata, MappingProxyType):
object.__setattr__(self, "metadata", MappingProxyType(self.metadata))
def replace(self, **changes: Any) -> Self:
"""Return a new context with the given fields replaced."""
return dataclasses.replace(self, **changes)
|