Pandera is a data validation library for Python that provides a flexible, expressive API for validating dataframes and series across multiple backends. It supports pandas, polars, pyspark, ibis, dask, modin, and geopandas.
- License: MIT
- Python: >= 3.10 (tested on 3.10-3.14)
- Docs: https://pandera.readthedocs.io
- Repo: https://github.com/pandera-dev/pandera
pandera/ # Main package
├── api/ # Public validation API (backend-specific schemas/models)
│ ├── base/ # Abstract base classes (BaseSchema, BaseCheck, etc.)
│ ├── pandas/ # Pandas DataFrameSchema, Column, Index, DataFrameModel
│ ├── geopandas/ # GeoDataFrameSchema, GeoDataFrameModel (pandas-backed)
│ ├── polars/ # Polars schema and model implementations
│ ├── pyspark/ # PySpark schema and model implementations
│ ├── ibis/ # Ibis schema and model implementations
│ ├── dataframe/ # Shared dataframe components
│ ├── checks.py # Check class (ge, le, isin, str_matches, etc.)
│ └── hypotheses.py # Hypothesis-based statistical testing
├── backends/ # Validation logic implementations per backend
│ ├── base/ # Abstract backend + builtin check/hypothesis impls
│ ├── pandas/ # Pandas backend (checks, components, container, etc.)
│ ├── polars/ # Polars backend
│ ├── pyspark/ # PySpark backend
│ └── ibis/ # Ibis backend
├── engines/ # Type system and dtype handling per backend
│ ├── engine.py # Engine metaclass and type registry
│ ├── pandas_engine.py # Pandas dtype definitions
│ ├── numpy_engine.py # NumPy dtype definitions
│ ├── polars_engine.py # Polars dtype definitions
│ ├── pyspark_engine.py # PySpark dtype definitions
│ ├── ibis_engine.py # Ibis dtype definitions
│ ├── pyarrow_engine.py # PyArrow dtype definitions
│ └── geopandas_engine.py
├── typing/ # Type stubs for mypy integration
├── strategies/ # Hypothesis strategies: import ``pandera.strategies.pandas_strategies`` etc. (``strategies`` package does not import backends)
├── schema_inference/ # Infer schemas from data
├── schema_statistics/ # Statistical validation helpers
├── io/ # Serialization: ``pandera.io.pandas_io``, ``polars_io``, ``pyspark_sql_io``, ``ibis_io``, ``xarray_io`` (``pandera.io`` package has no imports)
├── accessors/ # Pandas/PySpark accessor extensions (.pandera)
├── config.py # PanderaConfig, ValidationDepth, ValidationScope
├── decorators.py # @check_input, @check_output, @check_io, @check_types
├── dtypes.py # Abstract data type definitions
├── errors.py # SchemaError, SchemaInitError, ParserError, etc.
├── extensions.py # Custom check/parser extension mechanism
├── pandas.py # Pandas entry point: `import pandera.pandas as pa`
├── geopandas.py # GeoPandas entry (`pg`): pandas API + GeoDataFrameSchema/Model
├── polars.py # Polars entry point: `import pandera.polars as pa`
├── pyspark.py # PySpark entry point: `import pandera.pyspark as pa`
└── ibis.py # Ibis entry point: `import pandera.ibis as pa`
tests/ # Test suite (mirrors backend structure)
├── base/ # Core tests (no backend-specific deps)
├── pandas/ # Pandas backend tests (~38 files)
├── polars/ # Polars backend tests
├── pyspark/ # PySpark backend tests
├── ibis/ # Ibis backend tests
├── dask/ # Dask integration tests
├── modin/ # Modin integration tests
├── geopandas/ # GeoPandas tests
├── strategies/ # Hypothesis strategy tests
├── hypotheses/ # Statistical hypothesis tests
├── io/ # Serialization tests
├── fastapi/ # FastAPI integration tests
├── mypy/ # MyPy type-checking tests
└── conftest.py # Shared pytest fixtures
docs/source/ # Sphinx documentation (MyST markdown + RST)
- API layer (
pandera/api/): Defines schemas, models, checks, and parsers. Each backend has its own subpackage inheriting frombase/. - Backend layer (
pandera/backends/): Implements actual validation logic. Backends are registered viaBaseSchema.BACKEND_REGISTRYand discovered at runtime. - Engine layer (
pandera/engines/): Manages dtype registration and coercion. Uses anEnginemetaclass pattern for pluggable type systems.
- Backend registry: Backends register themselves at import time. The schema objects delegate validation to the registered backend.
- Engine metaclass: Each engine (pandas, polars, etc.) uses a metaclass that
maintains a dtype registry. Types are registered with
@Engine.register_dtype. - DataFrameModel: Pydantic-style class-based schema definitions using type
annotations and
Field()descriptors. - Lazy validation: Pass
lazy=Truetoschema.validate()to collect all errors instead of failing on the first one.
Users import backend-specific modules:
import pandera.pandas as pa # Pandas
import pandera.polars as pa # Polars
import pandera.pyspark as pa # PySpark
import pandera.ibis as pa # IbisThe top-level import pandera falls back to the pandas API for backward
compatibility.
# Install uv and sync all extras
make setup
# macOS (uses polars-lts-cpu)
make setup-macosThis runs uv sync --all-extras which installs all optional dependencies and
dev/testing groups.
Tests are organized by backend. Each backend's tests live in tests/<backend>/.
# Run core + pandas tests
pytest tests/core tests/pandas
# Run a specific backend's tests
pytest tests/polars/
pytest tests/pyspark/
pytest tests/ibis/
# Run all tests with coverage
pytest --cov=pandera --cov-report=term-missing tests/
# Run via nox (parameterized across Python/pandas/pydantic/polars versions)
nox -db uv -s tests
# Run a specific nox session
nox -db uv -s "tests(extra='polars', pandas=None, pydantic=None, polars='1.33.1')"The nox tests session maps extras to test directories: extra=None runs
tests/base/, extra='pandas' runs tests/pandas/, etc.
- Python: 3.10, 3.11, 3.12, 3.13, 3.14
- Pandas: 2.1.1, 2.3.3
- Pydantic: 1.10.11, 2.12.3
- Polars: 0.20.0, 1.33.1
- Ruff: Linting (
I,UPrules) and formatting. Line length: 79. - isort: Import sorting (line length 79).
- mypy: Static type checking (v1.10.0). Config in
mypy.ini. - pyupgrade: Python 3.9+ syntax upgrades.
- flynt: f-string conversion.
- codespell: Spell checking.
prek hooks enforce all of the above. Run manually:
prek run --all-files- Line length: 79 characters
- Target Python version: 3.10+
- Use f-strings (enforced by flynt)
- Use modern Python syntax:
X | Yunions, etc. (enforced by pyupgrade/ruff) - Ruff ignores
UP007(X | Y in annotations — kept for runtime typing compat)
packaging,pydantic,typeguard,typing_extensions,typing_inspect
| Extra | Key packages |
|---|---|
pandas |
numpy, pandas >= 2.1.1 |
polars |
polars >= 0.20.0 |
pyspark |
pyspark[connect] >= 3.2.0 |
ibis |
ibis-framework >= 9.0.0 |
dask |
dask[dataframe], distributed |
modin |
modin, ray, dask |
geopandas |
geopandas, shapely |
strategies |
hypothesis >= 6.92.7 |
hypotheses |
scipy |
io |
pyyaml |
fastapi |
fastapi |
mypy |
pandas-stubs, scipy-stubs |
all |
Everything above |
# Full build with doctests (cleans first)
make docs
# Quick build (no clean, no -W flag)
make quick-docs
# Via nox
nox -db uv -s docsDocumentation uses Sphinx with MyST (markdown) and RST. Source is in
docs/source/. API reference is auto-generated into
docs/source/reference/generated/.
SchemaError— Raised when data fails validationSchemaErrors— Container for multiple errors (lazy validation)SchemaInitError— Raised when a schema is defined incorrectlyParserError— Raised when data parsing/coercion failsBackendNotFoundError— Raised when a required backend is not installed
- For builtin checks, add to
pandera/backends/base/builtin_checks.pyand register in each backend'schecks.py. - For custom checks via extensions, use
pandera.extensions.register_check_method. - Add corresponding tests in the relevant
tests/<backend>/directory.
- Create
pandera/api/<backend>/with schema, model, and component classes inheriting frompandera/api/base/. - Create
pandera/backends/<backend>/with validation implementations inheriting frompandera/backends/base/. - Create
pandera/engines/<backend>_engine.pywith dtype registrations. - Create a top-level entry point
pandera/<backend>.py. - Add tests in
tests/<backend>/. - Register the backend in the appropriate
register.pyfile.
- GitHub Actions:
.github/workflows/ci-tests.ymlruns linting, unit tests across all backends/platforms, coverage, and mypy. - Publishing:
.github/workflows/publish.ymlhandles PyPI releases. - Versioning: Automatic via
setuptools_scmfrom git tags. Version file atpandera/_version.py.