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.0.tar.gz (17.2 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.0-py3-none-any.whl (13.4 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: schemap-0.5.0.tar.gz
  • Upload date:
  • Size: 17.2 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.0.tar.gz
Algorithm Hash digest
SHA256 2245dc065d4c165a6fc71e1325a4a75f9ca7e49d2610cf7f59e2e9ce1ae8c75d
MD5 e42ef5e150077a64afc2dbfcdcc57ced
BLAKE2b-256 4e054c9ab540b8355d51ebc502a92247352df2607a39b3090e0963f99893c472

See more details on using hashes here.

File details

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

File metadata

  • Download URL: schemap-0.5.0-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.0-py3-none-any.whl
Algorithm Hash digest
SHA256 2de60fabb52b4609f0f5481c4b66136853bad5694cf6c65bc867813675b4da97
MD5 8000034c719c71d92708f7656da138da
BLAKE2b-256 5d7e90afb17b658be120ab9748bcd59c64433399ea4ae5933158cc6511300a8c

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