polspec
One schema for your Polars data. Generate it, validate it, watch it drift.
Your tests need fixtures, and your pipeline needs a contract. Written separately, they drift apart. polspec lets you write the schema once, as a Polars class, and use it for both: realistic data to test against, and validation of the data that turns up.
import datetime as dt
import polars as pl
from polspec import ColSpec, FrameSpec
class Orders(FrameSpec):
order_id = ColSpec(pl.Int64, bounds=(1, 10**9), unique=True)
status = ColSpec(pl.Enum(["NEW", "PAID", "SHIPPED"]), weights=[0.2, 0.5, 0.3])
total = ColSpec(pl.Float64, bounds=(0, 5_000), distribution="lognormal",
distribution_params={"mean": 4, "std": 1})
placed = ColSpec(pl.Date, bounds=(dt.date(2025, 1, 1), dt.date(2025, 12, 31)),
nullable=True, null_probability=0.05)
email = ColSpec(pl.String, format="email")
orders = Orders.generate(1_000_000, seed=42) # a million rows in ~12 ms
Orders.validate(orders) # ~27 ms; raises on any breach
┌───────────┬────────┬────────────┬────────────┬───────────────────────┐
│ order_id ┆ status ┆ total ┆ placed ┆ email │
│ i64 ┆ enum ┆ f64 ┆ date ┆ str │
╞═══════════╪════════╪════════════╪════════════╪═══════════════════════╡
│ 830916752 ┆ PAID ┆ 9.187332 ┆ 2025-12-30 ┆ dupebca@xdcbivwq.dev │
│ 366447256 ┆ PAID ┆ 19.02604 ┆ 2025-11-28 ┆ hinro@ewzc.com │
│ 922459406 ┆ PAID ┆ 336.930617 ┆ 2025-04-11 ┆ jp5uo7@mgayhywoxn.com │
└───────────┴────────┴────────────┴────────────┴───────────────────────┘
What you get
- Fast. The generator is a Rust extension that fills columns in
parallel.
validate()compiles every check on every column into one Polars aggregation, so a wide table costs about what a narrow one does. Timings here are from a laptop; more are in Comparison. - Lazy and streaming.
scan()is aLazyFrame: filter and project it like any other. The sinks write Parquet, IPC, CSV or NDJSON in batches, never holding the frame in memory, and a unique column stays unique across every batch. - Every Polars dtype. Integers to 128 bits,
Decimal, time-zonedDatetime,Enum,Categorical, andList,ArrayandStructnested to any depth (plusMapon Polars 2). Bounds, choices with weights, distributions, formats such asemailanduuid4, uniqueness, nulls and NaNs are all declared per column. - Tables that relate. Foreign keys within and across specs, conditional rules, composite keys and hierarchies are generated to hold, and validated. Checks written as Polars expressions are enforced at validation.
- Validation as data.
inspect()returns every finding at once, with the offending rows a lazy filter away, and splits a frame into what passed and what to quarantine. - Learn from real data.
profile()turns a frame into a spec, finding formats, frequencies, distributions and null rates;synthesize()makes a stand-in with the same shape. - Drift with statistics behind it. A move is reported only when it is both significant and large, as breaking or compatible.
- Specs as files and docs. Save and load specs as YAML or Python. Render a Markdown data dictionary or a Mermaid ER diagram.
- A CLI for your pipeline.
polspec validate,generate,driftandsynthesize, with exit codes for CI. - Deterministic. The same seed gives the same data on every Polars from 1.39 to 2.x, on Windows, Linux and macOS, checked case by case in CI.
A quick tour
Generate lazily
scan() returns a LazyFrame, so Polars pushes filters and projections into it:
paid = (
Orders.scan(10_000_000, seed=1)
.filter(pl.col("status") == "PAID")
.select("order_id", "total")
.collect() # ~0.2 s
)
Orders.sink_parquet("orders.parquet", 1_000_000, seed=1) # streamed in batches
Validate and quarantine
inspect() never raises: it reports every finding, with the rows behind it.
broken = orders.with_columns(
pl.when(pl.col("order_id") % 1_000 == 0).then(-1.0).otherwise("total").alias("total")
)
report = Orders.inspect(broken) # 1 finding: 1,053 totals out of bounds
clean = report.passing_rows().collect() # the other 998,947 rows
Profile real data
from polspec import profile, synthesize
spec = profile(orders.head(100_000))
spec["total"].distribution # 'lognormal', fitted
fake = synthesize(orders.head(100_000), seed=1) # a stand-in with the same shape
Catch drift
print(Orders.drift(orders.filter(pl.col("status") != "NEW")))
Drift: 0 breaking, 2 compatible, DataFrame against 'Orders'
- [compatible] Column 'status': 1 of 3 declared value(s) never appear: ['NEW']
- [compatible] Column 'status': frequencies moved by 20.0% over 800,231 value(s): ...
From the command line
polspec schema infer orders.csv -o orders_spec.py
polspec validate orders_spec.py orders.csv --failing rejected.csv
polspec drift orders_spec.py orders.csv --markdown
polspec generate orders_spec.py -n 1000000 -o fixture.parquet --seed 1
Install
uv add polspec # or: pip install polspec
polspec works with Polars 1.39 and later, Polars 2 included, on Python 3.12 to 3.15 (on 3.15, Polars 2: Polars 1 does not run on it). Wheels are published for Linux (x86_64, aarch64), macOS (Intel and Apple silicon) and Windows (x86_64), so you don't need a Rust toolchain.
Pre-1.0. The API is settling toward a 1.0 with written stability promises. Until then, see Roadmap and stability, and Known limitations for what polspec does not do. Each limitation there is backed by a test that fails the moment it stops being true.
Documentation
maxwellb13.github.io/polspec: start with Getting started, find a task among the how-to guides, or look a name up in the API reference.
Contributing
Setting up a checkout, the checks CI runs and the release process are in CONTRIBUTING.md. What changed, and when, is in CHANGELOG.md.
License
MIT.
Metadata
Release files for polspec 0.21.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| polspec-0.21.1.tar.gz | 784.2 kB | With provenance | Details |
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| polspec-0.21.1-cp312-abi3-win_amd64.whl | CPython 3.12 | abi3 | Windows x86-64 | Details |
| polspec-0.21.1-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl | CPython 3.12 | abi3 | Linux glibc 2.17+ x86-64 | Details |
| polspec-0.21.1-cp312-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl | CPython 3.12 | abi3 | Linux glibc 2.17+ ARM64 | Details |
| polspec-0.21.1-cp312-abi3-macosx_11_0_arm64.whl | CPython 3.12 | abi3 | macOS 11.0+ ARM64 | Details |
| polspec-0.21.1-cp312-abi3-macosx_10_12_x86_64.whl | CPython 3.12 | abi3 | macOS 10.12+ x86-64 | Details |
Total release size: 31.1 MB
Release files / polspec-0.21.1.tar.gz
| Download URL | polspec-0.21.1.tar.gz |
|---|---|
| Size | 784.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
cbdda33116378828a5424a9c430cd9979018b8d41a81d42370e854d1836447f1
|
|
BLAKE2b-256 checksum How to use checksums |
44970b9b08b85674cf77864adc875e46cb7f7308453f53f3cc944759494ee243
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.
Transparency logRelease files / polspec-0.21.1-cp312-abi3-win_amd64.whl
| Download URL | polspec-0.21.1-cp312-abi3-win_amd64.whl |
|---|---|
| Size | 6.6 MB |
| Tags | CPython 3.12 Windows x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
c8b45735d0fd75c1510bac5da329a3e7ba0a12c1a2d4b2682e4ffbd8b9798f50
|
|
BLAKE2b-256 checksum How to use checksums |
1b888958fe01b2265c5b6adf365949a4940ca6d7e534b7fb85c7be024f255abc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.
Transparency logRelease files / polspec-0.21.1-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | polspec-0.21.1-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 6.3 MB |
| Tags | CPython 3.12 Linux glibc 2.17+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
13dd3fcf36b27f210fa5ba175d848c6ef649db24c0aebfe2d3f03dd094b486f2
|
|
BLAKE2b-256 checksum How to use checksums |
ee47031c05c0092aa0baa03b7eb9e540c9dc9ca8dd7a84e605d2a49d34dbbf78
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.
Transparency logRelease files / polspec-0.21.1-cp312-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
| Download URL | polspec-0.21.1-cp312-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl |
|---|---|
| Size | 5.8 MB |
| Tags | CPython 3.12 Linux glibc 2.17+ ARM64 abi3 |
|
SHA-256 checksum How to use checksums |
82ba60fe5a0c9862435f28ae8b297214c6fcb3af9cccc23fc737a9d75c44f85a
|
|
BLAKE2b-256 checksum How to use checksums |
ed9cc320342c649ba27d34e724db7b38feaf7c08053f365c37c3ffb3b390c211
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.
Transparency logRelease files / polspec-0.21.1-cp312-abi3-macosx_11_0_arm64.whl
| Download URL | polspec-0.21.1-cp312-abi3-macosx_11_0_arm64.whl |
|---|---|
| Size | 5.5 MB |
| Tags | CPython 3.12 abi3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
88be5203f3c1df45676f926a84ad15445f23378e4928b41a2f199cb7b2e55dad
|
|
BLAKE2b-256 checksum How to use checksums |
2c586956450cde00765977293c288312bf1313111c084abdbc2a2fac589dfb5e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.
Transparency logRelease files / polspec-0.21.1-cp312-abi3-macosx_10_12_x86_64.whl
| Download URL | polspec-0.21.1-cp312-abi3-macosx_10_12_x86_64.whl |
|---|---|
| Size | 6.2 MB |
| Tags | CPython 3.12 abi3 macOS 10.12+ x86-64 |
|
SHA-256 checksum How to use checksums |
b022f7825a39036152f0314a89d24173be266d3558c0bc5fecb9aabd6958297a
|
|
BLAKE2b-256 checksum How to use checksums |
8b8bf5e151e844756da8aa705246d3439971ef5fedc70c27cf43f9e0afc6c591
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.
Transparency logSecurity for polspec 0.21.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 6 files in this release have been uploaded with provenance metadata.
Attestation for polspec-0.21.1.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.