Skip to main content

sqlalchemy-annotate

Rails annotate_models for modern SQLAlchemy 2.x + Alembic projects.

It keeps a Schema Information comment block alongside every model class, in sync with your actual SQLAlchemy metadata, so reviewers and editors see the table shape without opening a database or a migration. The block sits below the class by default; flip position = "top" to put it above instead.

class User(Base):
    __tablename__ = "users"
    ...

# == Schema Information
#
# Table name: users
#
# id         : integer, primary key
# email      : varchar, not null
# created_at : timestamp
#
# Indexes
#   ix_users_email (email) UNIQUE
#
# Foreign Keys
#   profile_id -> profiles.id (ON DELETE CASCADE)
#
# == End Schema Information

Why it is safe

  • No database required. Everything is read from Base.metadata / __table__. A connection URL, if you pass one, is parsed only for its dialect so types compile correctly offline. No engine is ever connected.
  • No regex rewriting. Files are edited through a single libcst transformer. Imports, comments, blank lines and Black formatting are preserved byte-for-byte; only the region between the markers is touched.
  • Idempotent. Running generate twice produces no diff, which is what makes check reliable in CI and pre-commit.

Install

pip install sqlalchemy-annotate      # or: uv pip install sqlalchemy-annotate

Usage

sqlalchemy-annotate generate
sqlalchemy-annotate generate --models app.models --engine postgresql://localhost/db
sqlalchemy-annotate check        # exit 1 if stale (CI)
sqlalchemy-annotate remove       # strip every block
sqlalchemy-annotate generate --dry-run     # show the diff, write nothing

--models points at the dotted package path. Subpackages are imported recursively (app/models/user.py, app/models/post.py, ...), so every model registers regardless of how many files you split them across. A broken or circularly-importing module is reported as a warning and skipped, never fatal.

Configuration

Put defaults in pyproject.toml; CLI flags override them.

[tool.sqlalchemy-annotate]
models = "app.models"
engine = "postgresql+asyncpg://..."   # dialect only, never connected
include_indexes = true
include_foreign_keys = true
include_relationships = false
normalize_types = false               # true -> Rails-style (bigint, varchar(255))
sort = "definition"                   # or "alphabetical"
position = "bottom"                   # or "top" to place the block above the class
exclude = ["audit_*", "*_history"]

Type rendering

By default types are truthful: rendered exactly as SQLAlchemy compiles them for the resolved dialect (Mapped[int] PK -> integer, Mapped[str] -> varchar). Set normalize_types = true for Rails-style fabrication (autoincrement int PK -> bigint, unlengthed string -> varchar(255)).

The dialect is --dialect if given, else the backend of engine (async drivers collapse to their sync backend), else PostgreSQL.

Alembic / pre-commit

Run it right after a schema change:

alembic revision --autogenerate -m "add users"
alembic upgrade head
sqlalchemy-annotate generate

.pre-commit-config.yaml:

repos:
  - repo: https://github.com/abhinavs/sqlalchemy-annotate
    rev: v0.1.1
    hooks:
      - id: sqlalchemy-annotate

CI gate:

- run: sqlalchemy-annotate check

How it works

Module Responsibility
discovery.py import-walk the package, collect mapped classes -> files
schema.py Table/Mapper -> ModelSchema value objects (pure)
formatter.py ModelSchema -> comment lines (pure, pluggable renderer)
parser.py libcst helpers: build lines, locate the existing block
writer.py one libcst transformer: insert / replace / remove
config.py defaults <- pyproject.toml <- CLI
cli.py typer commands; heavy imports stay lazy

Roadmap (designed, not built)

The formatter is already a swappable Renderer behind the sqlalchemy_annotate.renderers entry-point group, leaving room for: Markdown schema export, ER diagram generation, a schema diff command, watch mode, and an IDE/VSCode integration.

Project

License

MIT (c) 2026 Abhinav Saxena

Metadata

Release files for sqlalchemy-annotate 0.1.1

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

Source distribution (sdist)

Source distribution for sqlalchemy-annotate 0.1.1
File Size Uploaded
sqlalchemy_annotate-0.1.1.tar.gz 23.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for sqlalchemy-annotate 0.1.1
File Interpreter ABI Platform
sqlalchemy_annotate-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 44.1 kB

Release files / sqlalchemy_annotate-0.1.1.tar.gz

Download URL sqlalchemy_annotate-0.1.1.tar.gz
Size 23.6 kB
Tags Source
SHA-256 checksum
How to use checksums
d1695360994fd04e3886a2f798e76bf1c143e35022241246035fd295e1d8e959
BLAKE2b-256 checksum
How to use checksums
7238d6b346e481bf1ffec781ebe040fcdee050b2b51c1316044c76e29fa8f564
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

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 Jun 3, 2026.

Transparency log

Release files / sqlalchemy_annotate-0.1.1-py3-none-any.whl

Download URL sqlalchemy_annotate-0.1.1-py3-none-any.whl
Size 20.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
009b422d65ae111101c84d926592a3c11290cef5d7498982524e3ebd22e50631
BLAKE2b-256 checksum
How to use checksums
c3d644023b3dfa729a9557abfc004da002c0821c8da59abb803e8aa21f0f7aa4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

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 Jun 3, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files

0.1.0

2 release files

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