Source code for marivo.analysis.frames.delta

"""DeltaFrame and DeltaFrameMeta."""

from __future__ import annotations

from dataclasses import dataclass
from typing import TYPE_CHECKING, Any, Literal

from pydantic import ConfigDict, Field

from marivo.analysis.frames.base import BaseFrame, BaseFrameMeta, assert_semantic_shape

if TYPE_CHECKING:
    from marivo.analysis.frames.component import ComponentFrame
    from marivo.analysis.intents._shape import AttributionShape


class DeltaFrameMeta(BaseFrameMeta):
    model_config = ConfigDict(extra="forbid")

    kind: Literal["delta_frame"] = "delta_frame"
    metric_id: str
    unit: str | None = None
    source_current_ref: str
    source_baseline_ref: str
    alignment: dict[str, Any]
    semantic_kind: Literal["scalar", "time_series", "segmented", "panel"]
    semantic_model: str
    normalization: dict[str, Any] | None = None
    component_ref: str | None = None
    composition: dict[str, Any] | None = None
    fold: dict[str, Any] | None = None
    component_folds: list[dict[str, Any]] = Field(default_factory=list)


[docs] @dataclass(repr=False) class DeltaFrame(BaseFrame): meta: DeltaFrameMeta _NEXT_INTENTS = ("decompose", "discover", "transform") def _repr_identity(self) -> str: unit_part = f" unit={self.meta.unit}" if self.meta.unit else "" return ( f"DeltaFrame ref={self.meta.ref} metric={self.meta.metric_id}" f"{unit_part} rows={self.meta.row_count}" ) @property def semantic_shape(self) -> Literal["scalar", "time_series", "segmented", "panel"]: """The frame's semantic shape (distinct from .shape, the dataframe dims).""" return self.meta.semantic_kind def as_scalar(self) -> DeltaFrame: assert_semantic_shape( got=self.meta.semantic_kind, expected="scalar", frame_kind=self.meta.kind ) return self def as_time_series(self) -> DeltaFrame: assert_semantic_shape( got=self.meta.semantic_kind, expected="time_series", frame_kind=self.meta.kind ) return self def as_segmented(self) -> DeltaFrame: assert_semantic_shape( got=self.meta.semantic_kind, expected="segmented", frame_kind=self.meta.kind ) return self def as_panel(self) -> DeltaFrame: assert_semantic_shape( got=self.meta.semantic_kind, expected="panel", frame_kind=self.meta.kind ) return self
[docs] def predicted_attribution_shape(self) -> AttributionShape: """Predict the AttributionFrame shape decompose will produce for this delta. Reads this delta's component_ref + decomposition kind only (no component load); "sum" when not component-aware, else "ratio_mix"/"weighted_mix". """ from marivo.analysis.intents._shape import attribution_output_shape return attribution_output_shape(self.meta)
[docs] def components(self) -> ComponentFrame: """Load the linked ComponentFrame for component-aware deltas.""" from marivo.analysis.frames._component import _load_component_frame return _load_component_frame( parent_ref=self.ref, parent_kind=self.meta.kind, session_id=self.meta.session_id, project_root=self.meta.project_root, artifact_id=self.meta.artifact_id, component_ref=self.meta.component_ref, composition=self.meta.composition, advice="re-run compare() to regenerate it", )