Data Validation & Quality
Schema and statistical checks at pipeline boundaries catch bad ingests before they pollute marts - Pandera for Python DataFrames, Great Expectations for documented data contracts.
Search across all documentation pages
Schema and statistical checks at pipeline boundaries catch bad ingests before they pollute marts - Pandera for Python DataFrames, Great Expectations for documented data contracts.
Quick-reference recipe card - copy-paste ready.
import pandera.pandas as pa
schema = pa.DataFrameSchema({
"order_id": pa.Column(int, unique=True, nullable=False),
"revenue": pa.Column(float, pa.Check.ge(0)),
"region": pa.Column(str, pa.Check.isin(["East", "West", "Central"])),
})
def validate_orders(df):
return schema.validate(df, lazy=True)When to reach for this:
import pandas as pd
import pandera.pandas as pa
from pandera import Check, Column, DataFrameSchema
orders_schema = DataFrameSchema(
{
"order_id": Column(int, unique=True, nullable=False),
"revenue": Column(float, checks=Check.ge(0)),
"region": Column(str, checks=Check.isin(["East", "West", "Central"])),
"ordered_at": Column("datetime64[ns, UTC]", nullable=False),
},
strict=False,
coerce=True,
)
def load_orders(path: str) -> pd.DataFrame:
df = pd.read_parquet(path)
try:
return orders_schema.validate(df, lazy=True)
except pa.errors.SchemaErrors as err:
# Quarantine bad rows for inspection
failure_cases = err.failure_cases
failure_cases.to_csv("quarantine/schema_failures.csv", index=False)
raise
# Great Expectations style check (conceptual GE API)
def gx_style_checks(df: pd.DataFrame) -> None:
assert len(df) > 0, "empty batch"
assert df["order_id"].is_unique.all()
assert df["revenue"].between(0, 1_000_000).mean() > 0.99What this demonstrates:
| Type | Example |
|---|---|
| Structural | column exists, dtype, unique |
| Range | revenue >= 0 |
| Set membership | region in allowed list |
| Statistical | row count within 3 sigma of 7-day median |
# Polars with pandera.polars
import polars as pl
import pandera.polars as pa
schema = pa.DataFrameSchema({"id": pa.Column(int)})
schema.validate(pl.DataFrame({"id": [1, 2]}))@task before write.lazy=True for full failure report.
| Alternative | Use When | Don't Use When |
|---|---|---|
| dbt tests | Warehouse-native transforms | Pre-load pandas cleaning |
| Soda Core | YAML checks across warehouses | Already standardized on GE |
| Pydantic models | JSON API events before DataFrame | Columnar file bulk loads |
| Manual assert | Tiny scripts | Any shared production pipeline |
import pytest
import pandera.errors
def test_rejects_negative_revenue(bad_df):
with pytest.raises(pandera.errors.SchemaError):
orders_schema.validate(bad_df)Stack versions: This page was written for Python 3.14.0 (stable 3.14, maintenance 3.13), FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, and uv 0.6+.
Reviewed by Chris St. John·Last updated Jul 19, 2026