mostlyright.core.result
ProvenancedFrame — backend-neutral provenance wrapper.
Polars frames have no .attrs, so stamping df.attrs["source"] /
df.attrs["retrieved_at"] cannot survive the polars backend.
ProvenancedFrame carries the provenance separately from the frame so
both pandas and polars callers preserve source-identity invariants without
.attrs writes.
Validator, KnowledgeView, and LeakageDetector accept either a raw
DataFrame or a ProvenancedFrame; they unwrap the wrapper via
frame_as_pandas() and the validation logic runs unchanged.
Classes
Section titled “Classes”| Class | Description |
|---|---|
ProvenancedFrame(frame, source, retrieved_at) | Backend-neutral provenance wrapper for a DataFrame-returning call. |
class mostlyright.core.result.ProvenancedFrame(frame, source, retrieved_at, schema_id=None, quality_control=None, data_version=None)
Section titled “class mostlyright.core.result.ProvenancedFrame(frame, source, retrieved_at, schema_id=None, quality_control=None, data_version=None)”Bases: object
Backend-neutral provenance wrapper for a DataFrame-returning call.
Both pandas-backend and polars-backend adapters return the same
wrapper shape. frame holds the native frame; the remaining fields
carry the provenance that pandas callers also find on df.attrs.
- Parameters:
The underlying DataFrame (pandas or polars). The polars
type is type-hinted via TYPE_CHECKING so the default
install does not require polars.
source
Section titled “source”The canonical source identifier (e.g. "iem.live",
"awc.live", "noaa_bdp"). Mirrors the
df.attrs["source"] contract.
retrieved_at
Section titled “retrieved_at”UTC timestamp of the fetch. Must be tz-aware.
schema_id
Section titled “schema_id”Optional canonical schema ID (e.g.
"schema.observation.v1"). None if the call returns
heterogeneous rows (e.g. research() pairs).
quality_control
Section titled “quality_control”Optional QC summary (rules_fired counts,
sidecar_paths) when the caller requested QC. Mirrors
df.attrs["quality_control"].
data_version
Section titled “data_version”Optional DataVersion token for reproducibility.
Examples
Section titled “Examples”>>> import pandas as pd>>> from datetime import datetime, timezone>>> from mostlyright.core.result import ProvenancedFrame>>> df = pd.DataFrame({"date": ["2025-01-01"], "value": [42]})>>> result = ProvenancedFrame(... frame=df,... source="iem.live",... retrieved_at=datetime(2025, 1, 1, tzinfo=timezone.utc),... )>>> result.source'iem.live'>>> result.frame_as_pandas().iloc[0]["value"]42data_version: DataVersion | None
Section titled “data_version: DataVersion | None”frame: DataFrame | DataFrame
Section titled “frame: DataFrame | DataFrame”frame_as_pandas()
Section titled “frame_as_pandas()”Return the underlying frame as a pandas DataFrame.
Pandas frames pass through unchanged. Polars frames are converted
via pl.DataFrame.to_pandas(). Modules whose output is pinned by
the parity fixtures call this before running their pandas-only
pipelines.
Polars→pandas conversion may shift datetime resolution (us → ns)
and may change nullable-int storage. Callers that need a
byte-equivalent round-trip across backends should consult the
coercion rules in tests/fixtures/parity/coerce_pd3.py.
- Return type:
DataFrame
quality_control: dict[str, Any] | None
Section titled “quality_control: dict[str, Any] | None”retrieved_at: datetime
Section titled “retrieved_at: datetime”schema_id: str | None
Section titled “schema_id: str | None”source: str
Section titled “source: str”to_dataframe()
Section titled “to_dataframe()”Return the underlying frame as a pandas DataFrame, schema-stamped.
Routes through the same finalizer the direct DataFrame path uses
(mostlyright._internal._finalize), so the wrapper path and the
return_type="dataframe" path emit identical
mostlyright_schema_id / mostlyright_schema_version attrs.
When schema_id is None (a heterogeneous-row wrapper) the
stamp is skipped — there is no single schema to name.
- Return type:
DataFrame
to_dict()
Section titled “to_dict()”JSON-safe dict representation for v0.2 MCP JSON-RPC serialization.
Excludes the frame body — callers that need to ship rows over MCP
should serialize the frame via mostlyright.core.formats.* writers
and attach the provenance via this method’s output.