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.
🚧 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
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file cast_iron-0.6.0.tar.gz.
File metadata
- Download URL: cast_iron-0.6.0.tar.gz
- Upload date:
- Size: 769.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
625ff1a35676cbe82702b17f104a50b92c39cf3129990663cd7a32bd8a38e459
|
|
| MD5 |
b38c13ef25c62ed26cf1fc0a34197898
|
|
| BLAKE2b-256 |
6bb8a10635c13d52a2645dd2d4531dbe1c5da67565f224cb75b976660428ffe6
|
Provenance
The following attestation bundles were made for cast_iron-0.6.0.tar.gz:
Publisher:
release.yml on kmbhm1/castiron
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cast_iron-0.6.0.tar.gz -
Subject digest:
625ff1a35676cbe82702b17f104a50b92c39cf3129990663cd7a32bd8a38e459 - Sigstore transparency entry: 2453100294
- Sigstore integration time:
-
Permalink:
kmbhm1/castiron@83ebb05ca8d66ce37785bb5ab916b93c7bac2708 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/kmbhm1
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@83ebb05ca8d66ce37785bb5ab916b93c7bac2708 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file cast_iron-0.6.0-py3-none-any.whl.
File metadata
- Download URL: cast_iron-0.6.0-py3-none-any.whl
- Upload date:
- Size: 171.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b30b9e8ae8ee8cf90a41899f1b7d5fed433458cc135b2fa3eb6c455658d1d549
|
|
| MD5 |
b9ae0f50867e69d843c367318a856c01
|
|
| BLAKE2b-256 |
240aa1776ce1a64abe37a8d40eeca4ffbe6ab18cd13b5cc647413bbdbfd9c208
|
Provenance
The following attestation bundles were made for cast_iron-0.6.0-py3-none-any.whl:
Publisher:
release.yml on kmbhm1/castiron
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cast_iron-0.6.0-py3-none-any.whl -
Subject digest:
b30b9e8ae8ee8cf90a41899f1b7d5fed433458cc135b2fa3eb6c455658d1d549 - Sigstore transparency entry: 2453100367
- Sigstore integration time:
-
Permalink:
kmbhm1/castiron@83ebb05ca8d66ce37785bb5ab916b93c7bac2708 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/kmbhm1
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@83ebb05ca8d66ce37785bb5ab916b93c7bac2708 -
Trigger Event:
workflow_dispatch
-
Statement type: