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.2.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.2-py3-none-any.whl (13.4 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: schemap-0.5.2.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.2.tar.gz
Algorithm Hash digest
SHA256 089d9ba97a4b5931e2ae91a478c2e3eb45bb129c10f0bebf780a727b59302626
MD5 eb9d7cf4a239cdfcbe69e34dfdcd18c5
BLAKE2b-256 98981076416cea92634939d70ff2f59b3a2912eafe17c2f3477c1d5e4874a229

See more details on using hashes here.

File details

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

File metadata

  • Download URL: schemap-0.5.2-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.2-py3-none-any.whl
Algorithm Hash digest
SHA256 567972ecc4bcef9fe68869cfeb435c90de370bc856ef85905ba95cbf1de25016
MD5 ba936ebb9cab6d570b6e87a0e9b63dfe
BLAKE2b-256 95f6b11788662484b5e328b61181d22428557c9be073e23c4b4da701637d0a95

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