Skip to main content

schemap

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

Python License Documentation DeepWiki PyPI

pip install schemap

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

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.

What makes schemap unique

1. Four-variant generation as a first-class concept. No other library auto-generates full, create, update, and public schemas with intelligent exclusion rules out of the box. Primary keys are excluded from create. All fields become optional in update. Private fields are filtered from public. These rules are not something you configure; they are built in.

2. Strict separation between ORM and validation. SQLAlchemy stays pure SQLAlchemy. Pydantic stays Pydantic. Schemap never fuses them into a single class. Your ORM models remain unaware of your API layer. You can swap Pydantic versions, switch validation libraries, or use your models outside of FastAPI without touching a single column definition.

3. Three API modes. Use AutoBase inheritance for new projects. Use SchemaMixin to mix into your own declarative base. Use @auto_schema to decorate existing models without changing their base class. All three produce identical results.

4. Per-model customization via SchemaConfig. Attach a SchemaConfig to any model to override field types, exclude fields from specific variants, force required or optional status, and add custom validators. The model itself stays clean; the configuration lives in one place.

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. Best for new projects where you have no existing 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]

SchemaMixin: mix into your own declarative base. Best when you already have a custom DeclarativeBase and want to keep it:

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

class Base(SchemaMixin, DeclarativeBase):
    pass

class User(Base):
    __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. Best when you cannot change the model's base (third-party models, large codebases):

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]

All three 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 ships with nine 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.

CreatedByMixin and UpdatedByMixin add audit trail fields with foreign keys and relationships to a users table. Override user_table on subclasses to target a different table.

StatusMixin adds a status column with activate() and deactivate() methods.

ArchivableMixin adds an archived_at timestamp with archive() and restore() methods.

VersionMixin adds a version int column with increment_version() for optimistic locking.

UUIDPrimaryKeyMixin and IntPrimaryKeyMixin provide standard primary key columns.

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.

License

MIT

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.7.0.tar.gz (27.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.7.0-py3-none-any.whl (20.6 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: schemap-0.7.0.tar.gz
  • Upload date:
  • Size: 27.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for schemap-0.7.0.tar.gz
Algorithm Hash digest
SHA256 83373bcffb72a824163518d04a1f98ea65cbe368c35a2085065d3ceba015b784
MD5 25df8a9824cc8f42535057765561edf5
BLAKE2b-256 7017a4a4477ab06b27aaf373920e0f44e42de7582efe9f0a1b76ad9908210552

See more details on using hashes here.

Provenance

The following attestation bundles were made for schemap-0.7.0.tar.gz:

Publisher: publishing.yml on emiliano-go/schemap

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

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

File metadata

  • Download URL: schemap-0.7.0-py3-none-any.whl
  • Upload date:
  • Size: 20.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for schemap-0.7.0-py3-none-any.whl
Algorithm Hash digest
SHA256 8d05fd16463d135fec6e2ec71d708e9c5e2981e7168eca56a1c8e8ea584614d5
MD5 1989200b0bd24dcccec5e4e0fa79205c
BLAKE2b-256 9f9547147029a0987ceecd5deac710dbd13b2d683d484a6ccd3bb87659915820

See more details on using hashes here.

Provenance

The following attestation bundles were made for schemap-0.7.0-py3-none-any.whl:

Publisher: publishing.yml on emiliano-go/schemap

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.7.0 This release

2 files

0.6.1

2 files

0.5.2

2 files

0.5.1

2 files

0.5.0

2 files

0.4.0

2 files

0.3.0

2 files

0.2.0

2 files

0.1.0

2 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