Skip to main content

Automatic Pydantic Schemas for SQLAlchemy models

Project description

schemap

Automatic Pydantic v2 schemas from SQLAlchemy 2.0 ORM models. Define your model once. The schemas come automatically.

Python License DeepWiki

pip install schemap

Why Schemap

Writing Pydantic schemas for SQLAlchemy models is repetitive work. You maintain four schemas per model: full, create, update, and public. Each schema must stay synchronized with column changes, nullability updates, and new constraints. Schemap eliminates this duplication by generating all four schemas directly from your model definition.

The library reads your SQLAlchemy columns and translates them into Pydantic fields. A primary key becomes excluded from CreateSchema. A server default becomes excluded from write operations. A nullable column becomes an Optional field. You focus on your model. Schemap handles the validation layer.

Quick Start

Schemap gives you three ways to attach schemas to your models. All three produce identical schemas.

AutoBase — inherit from the ready-made declarative base:

from schemap import AutoBase
from sqlalchemy.orm import Mapped, mapped_column

class User(AutoBase):
    __tablename__ = "users"

    id: Mapped[int] = mapped_column(primary_key=True)
    name: Mapped[str]
    email: Mapped[str]

@auto_schema — decorate any existing model without changing its base class:

from schemap import auto_schema
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column

class Base(DeclarativeBase):
    pass

@auto_schema
class User(Base):
    __tablename__ = "users"

    id: Mapped[int] = mapped_column(primary_key=True)
    name: Mapped[str]
    email: Mapped[str]

Both approaches give you the same four schemas and conversion methods:

User.Schema         # all columns
User.CreateSchema   # excludes primary keys and server defaults
User.UpdateSchema   # all fields optional for partial updates
User.PublicSchema   # excludes fields starting with __

# Convert between ORM and Pydantic
data = User.CreateSchema(name="Alice", email="alice@example.com")
user = User.from_schema(data)
schema = user.to_schema()

The decorator also accepts a config argument:

@auto_schema(config=SchemaConfig(exclude_public=["email"]))
class User(Base):
    ...

SchemaConfig

Customize generated schemas per model using the __schema_config__ attribute.

from schemap import AutoBase, SchemaConfig
from sqlalchemy.orm import Mapped, mapped_column

class User(AutoBase):
    __tablename__ = "users"
    __schema_config__ = SchemaConfig(
        exclude_public=["email"],
        exclude_create=["internal_id"],
    )

    id: Mapped[int] = mapped_column(primary_key=True)
    name: Mapped[str]
    email: Mapped[str]
    internal_id: Mapped[int]

The SchemaConfig class supports several exclusion options. exclude_always removes a field from all schemas. exclude_create, exclude_update, and exclude_public target specific schema variants. field_overrides lets you change a field's Python type. required_always and optional_always override nullability rules.

Built-in Mixins

Schemap includes two reusable mixins for common model patterns.

TimestampMixin adds created_at and updated_at columns. The timestamps set automatically on insert and update.

SoftDeleteMixin adds a deleted_at column, a soft_delete() method, and an active() classmethod filter for excluding deleted records.

from schemap import AutoBase, TimestampMixin, SoftDeleteMixin

class User(AutoBase, TimestampMixin):
    __tablename__ = "users"
    name: Mapped[str]

class Post(AutoBase, SoftDeleteMixin):
    __tablename__ = "posts"
    title: Mapped[str]

Custom Validators

Attach validation functions to any field using extra_validators in SchemaConfig. The validator receives the field value and must return it or raise ValueError.

from schemap import AutoBase, SchemaConfig

def validate_positive(value: int) -> int:
    if value <= 0:
        raise ValueError("Value must be positive")
    return value

class Product(AutoBase):
    __tablename__ = "products"
    __schema_config__ = SchemaConfig(extra_validators={"price": validate_positive})
    
    price: Mapped[float]

Standalone Usage

Use build_schema directly when you need a schema without modifying the model class.

from schemap import build_schema
from schemap.config import SchemaConfig

UserSchema = build_schema(User, schema_type="create", config=SchemaConfig(exclude_create=["internal_id"]))

Decorator API

Use @auto_schema to attach schemas to any SQLAlchemy model without inheritance.

from schemap import auto_schema, SchemaConfig

# Bare decorator — all defaults
@auto_schema
class User(Base):
    __tablename__ = "users"
    ...

# With config
@auto_schema(config=SchemaConfig(exclude_public=["email"]))
class User(Base):
    ...

The decorator runs after the class body and attaches .Schema, .CreateSchema, .UpdateSchema, .PublicSchema, .from_schema(), and .to_schema() directly to your class. Your model's inheritance chain stays unchanged.

Requirements

Python 3.12 or later, SQLAlchemy 2.0.49 or later, Pydantic 2.13.4 or later.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

schemap-0.5.1.tar.gz (17.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

schemap-0.5.1-py3-none-any.whl (13.4 kB view details)

Uploaded Python 3

File details

Details for the file schemap-0.5.1.tar.gz.

File metadata

  • Download URL: schemap-0.5.1.tar.gz
  • Upload date:
  • Size: 17.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.5

File hashes

Hashes for schemap-0.5.1.tar.gz
Algorithm Hash digest
SHA256 340442e03153e8062b3eb35004e3d8eaa30880c0345e2c0a407c0ad4a2608d26
MD5 9d4f7444198cbd672191c41ab2835433
BLAKE2b-256 bc5b89ca3ec6e60429bf1099cfc9ec47fd08191c60aed7ee5c57058083526ab8

See more details on using hashes here.

File details

Details for the file schemap-0.5.1-py3-none-any.whl.

File metadata

  • Download URL: schemap-0.5.1-py3-none-any.whl
  • Upload date:
  • Size: 13.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.5

File hashes

Hashes for schemap-0.5.1-py3-none-any.whl
Algorithm Hash digest
SHA256 2630782417b5ab11c4c54ba6e8128188f8e67032cf26621ccd67b151c0a3a676
MD5 f64730523bf0741c7658c057db6b6c29
BLAKE2b-256 3fc99d35960930bc75c44d0f73a264ef18b9eedb7a075f920236197eb4c2ba44

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page