Skip to main content

castiron

A schema→typed-code compiler for Python.

Point castiron at a schema source — a Supabase URL, your SQL migrations, or a live database — and get typed models (and, soon, a typed client for tables, views, and RPCs). A check mode fails CI when your committed generated code drifts from the schema. No database connection required for the OpenAPI and migrations sources.

"It's cast-iron. It doesn't care." — and neither should your types drift.

📖 Documentation


🚧 Status: pre-alpha. castiron is on PyPI and installable, but it is young and moving fast: the pipeline, sources, and emitters are still being built out, and APIs may change between releases. It is the successor to supabase-pydantic, carrying forward its schema-fidelity engine on a source-agnostic architecture.

Quickstart

uv add cast-iron       # or: pip install cast-iron
castiron --version     # the command has no hyphen

You install the hyphenated cast-iron and run the unhyphenated castiron. PyPI does not allow castiron as a distribution name, so the hyphen belongs to the distribution and nothing else — the command, the import package (import castiron), and this repository all stay unhyphenated.

Generate typed Pydantic models from a Supabase project — one command, no database connection, no driver, no connection string:

export CASTIRON_KEY='eyJhbGciOi...'
castiron gen --from https://abcdefgh.supabase.co --emit pydantic
castiron: read 6 tables, 1 enum and 4 functions from https://abcdefgh.supabase.co/rest/v1/
castiron: wrote schema.py (14.2 kB)

--from also takes a path, so a saved OpenAPI document regenerates offline — useful in CI and air-gapped builds:

castiron gen --from ./openapi.json --emit pydantic --output src/myapp/models

You get one file with Row, Insert, Update and operational models, enum classes, and nested foreign-key relationships:

class Orders(OrdersBaseSchema):
    """Orders Schema for Pydantic.

    Customer orders.

    Inherits from OrdersBaseSchema. Add any customization here.
    """

    # Foreign Keys
    user: Users | None = Field(default=None)
    order_items: list[OrderItems] | None = Field(default=None)

Every file opens with a two-line header recording the castiron version that wrote it — no timestamp, no source URL. Output is deterministic: the same schema, the same options and the same castiron version produce the same bytes, every time, and it is lint-clean as emitted under ruff's F, UP and I rules at ruff's own defaults. See The generated code for that promise, its limits, the header's exact format, and how enum member names are derived.

Put your settings in pyproject.toml and the flags go away (the API key is deliberately rejected there — that file gets committed):

[tool.castiron]
from = "https://abcdefgh.supabase.co"
emit = ["pydantic"]
output = "src/myapp/models"

Full walkthrough: Quickstart · CLI reference · Configuration

The idea

flowchart LR
    S1["OpenAPI / PostgREST"] --> IR
    S2["SQL migrations<br/>(planned)"] --> IR
    S3["Live database<br/>(planned)"] --> IR
    IR["Schema IR<br/>one typed, formal model"] --> E1["Pydantic v2"]
    IR --> E2["SQLAlchemy<br/>(planned)"]
    IR --> E3["Typed Supabase client<br/>(planned)"]
    IR --> CHK["check<br/>drift guard in CI"]

Pluggable sources parse a schema into one formalized Schema IR; pluggable emitters turn the IR into typed code. check re-emits in memory, compares against the files you committed, and exits 3 if they have drifted — writing nothing, ever.

Honest about what it knows

The OpenAPI source needs no database credentials and sees everything your API key can see — column types, nullability, primary keys, single-column foreign keys, enums, and RPC signatures. It cannot see unique or check constraints, identity/generated columns, exact integer widths below bigint, or function return types. castiron does not guess at them; it documents them and warns when one is about to change your output.

Read What the OpenAPI source can and cannot see before you trust a generated constraint.

Why "castiron"

Cast iron is durable, low-maintenance, and does one job for decades. It also puns on type casting — casting an untyped schema into hard, checked types.

Development

castiron uses uv and hatchling.

uv sync                 # create the environment and install dev deps
uv run castiron --version
make validate           # ruff + vulture + mypy + pytest (the pre-push gate)
make serve-docs         # preview the documentation site

See CONTRIBUTING.md.

License

MIT © Kevin Boehm

Metadata

Release files for cast-iron 0.6.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for cast-iron 0.6.0
File Size Uploaded Provenance Actions
cast_iron-0.6.0.tar.gz 769.9 kB With provenance Details for cast_iron-0.6.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for cast-iron 0.6.0
File Interpreter ABI Platform Actions
cast_iron-0.6.0-py3-none-any.whl Python 3 none any Details for cast_iron-0.6.0-py3-none-any.whl

Total release size: 940.9 kB

Release files / cast_iron-0.6.0.tar.gz

Download URL cast_iron-0.6.0.tar.gz
Size 769.9 kB
Tags Source
SHA-256 checksum
How to use checksums
625ff1a35676cbe82702b17f104a50b92c39cf3129990663cd7a32bd8a38e459
BLAKE2b-256 checksum
How to use checksums
6bb8a10635c13d52a2645dd2d4531dbe1c5da67565f224cb75b976660428ffe6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 Aug 13, 2026.

Transparency log

Release files / cast_iron-0.6.0-py3-none-any.whl

Download URL cast_iron-0.6.0-py3-none-any.whl
Size 171.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b30b9e8ae8ee8cf90a41899f1b7d5fed433458cc135b2fa3eb6c455658d1d549
BLAKE2b-256 checksum
How to use checksums
240aa1776ce1a64abe37a8d40eeca4ffbe6ab18cd13b5cc647413bbdbfd9c208
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 Aug 13, 2026.

Transparency log

Security for cast-iron 0.6.0

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 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for cast_iron-0.6.0.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 Aug 13, 2026.

Transparency log

A 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.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page