Skip to main content

Bring Pydantic's power to Marshmallow: type annotations, validators, and automatic schema generation

Project description

pydantic-marshmallow

CI PyPI version Python 3.10+ License: MIT

Bridge Pydantic's power with Marshmallow's ecosystem. Use Pydantic models for validation with full Marshmallow compatibility.

📖 Documentation | 🐙 GitHub

Features

  • Pydantic Validation: Leverage Pydantic's Rust-powered validation engine
  • Marshmallow Compatibility: Works with Flask-Marshmallow, webargs, apispec, SQLAlchemy, and more
  • Zero Drift: Single source of truth - Pydantic model defines the schema
  • Full Hook Support: @pre_load, @post_load, @pre_dump, @post_dump
  • Validators: @validates("field") and @validates_schema decorators
  • Partial Loading: partial=True or partial=('field1', 'field2')
  • Unknown Fields: unknown=RAISE/EXCLUDE/INCLUDE
  • Computed Fields: Pydantic @computed_field support in serialization

Installation

pip install pydantic-marshmallow

Quick Start

Basic Usage

from pydantic import BaseModel, EmailStr, Field
from pydantic_marshmallow import PydanticSchema

class User(BaseModel):
    name: str = Field(min_length=1)
    email: EmailStr
    age: int = Field(ge=0)

class UserSchema(PydanticSchema[User]):
    class Meta:
        model = User

# Use like any Marshmallow schema
schema = UserSchema()
user = schema.load({"name": "Alice", "email": "alice@example.com", "age": 30})
print(user.name)  # "Alice" - it's a Pydantic User instance!

# Serialize back
data = schema.dump(user)
# {"name": "Alice", "email": "alice@example.com", "age": 30}

Using the Decorator

from pydantic_marshmallow import pydantic_schema

@pydantic_schema
class User(BaseModel):
    name: str
    email: EmailStr

# .Schema attribute is automatically added
schema = User.Schema()
user = schema.load({"name": "Alice", "email": "alice@example.com"})

Factory Function

from pydantic_marshmallow import schema_for

UserSchema = schema_for(User)
schema = UserSchema()

Marshmallow Hooks

All standard Marshmallow hooks work:

from marshmallow import pre_load, post_load, validates

class UserSchema(PydanticSchema[User]):
    class Meta:
        model = User

    @pre_load
    def normalize_email(self, data, **kwargs):
        if "email" in data:
            data["email"] = data["email"].lower().strip()
        return data

    @post_load
    def log_user(self, user, **kwargs):
        print(f"Loaded user: {user.name}")
        return user

    @validates("name")
    def validate_name(self, value):
        if value.lower() == "admin":
            raise ValidationError("Cannot use 'admin' as name")

Partial Loading

# Allow all missing required fields
user = schema.load({"name": "Alice"}, partial=True)

# Allow specific missing fields
user = schema.load({"name": "Alice"}, partial=("email", "age"))

Unknown Field Handling

from marshmallow import EXCLUDE, INCLUDE, RAISE

# Reject unknown fields (default)
schema = UserSchema(unknown=RAISE)

# Ignore unknown fields
schema = UserSchema(unknown=EXCLUDE)

# Include unknown fields in result
schema = UserSchema(unknown=INCLUDE)

Field Filtering

# Only include specific fields
schema = UserSchema(only=("name", "email"))

# Exclude specific fields
schema = UserSchema(exclude=("age",))

# Load-only fields (not in dump output)
schema = UserSchema(load_only=("password",))

# Dump-only fields (not in load input)
schema = UserSchema(dump_only=("created_at",))

Computed Fields

from pydantic import computed_field

class User(BaseModel):
    first: str
    last: str

    @computed_field
    @property
    def full_name(self) -> str:
        return f"{self.first} {self.last}"

schema = schema_for(User)()
user = User(first="Alice", last="Smith")
data = schema.dump(user)
# {"first": "Alice", "last": "Smith", "full_name": "Alice Smith"}

Dump Options

# Exclude None values
schema.dump(user, exclude_none=True)

# Exclude unset fields
schema.dump(user, exclude_unset=True)

# Exclude fields with default values
schema.dump(user, exclude_defaults=True)

Flask-Marshmallow Integration

from flask import Flask
from flask_marshmallow import Marshmallow
from pydantic_marshmallow import schema_for

app = Flask(__name__)
ma = Marshmallow(app)

UserSchema = schema_for(User)

@app.route("/users", methods=["POST"])
def create_user():
    schema = UserSchema()
    user = schema.load(request.json)
    # user is a Pydantic User instance
    return schema.dump(user)

webargs Integration

from webargs.flaskparser import use_args
from pydantic_marshmallow import schema_for

UserSchema = schema_for(User)

@app.route("/users", methods=["POST"])
@use_args(UserSchema(), location="json")
def create_user(user):
    # user is a Pydantic User instance
    return {"message": f"Created {user.name}"}

apispec Integration

from apispec import APISpec
from apispec.ext.marshmallow import MarshmallowPlugin

spec = APISpec(
    title="My API",
    version="1.0.0",
    openapi_version="3.0.0",
    plugins=[MarshmallowPlugin()],
)

spec.components.schema("User", schema=UserSchema)

HybridModel

For models that need both Pydantic and Marshmallow APIs:

from pydantic_marshmallow import HybridModel

class User(HybridModel):
    name: str
    email: EmailStr

# Use as Pydantic model
user = User(name="Alice", email="alice@example.com")

# Use Marshmallow-style loading
user = User.ma_load({"name": "Alice", "email": "alice@example.com"})

# Get the Marshmallow schema class
schema_class = User.marshmallow_schema()

Error Handling

Validation errors are raised as BridgeValidationError, which extends Marshmallow's ValidationError:

from pydantic_marshmallow import BridgeValidationError

try:
    user = schema.load({"name": "", "email": "invalid"})
except BridgeValidationError as e:
    print(e.messages)
    # {'name': ['String should have at least 1 character'],
    #  'email': ['value is not a valid email address']}
    print(e.valid_data)
    # {} - fields that passed validation

API Reference

PydanticSchema

A Marshmallow schema backed by a Pydantic model.

Class Methods:

  • from_model(model, **meta_options) - Create a schema class from a Pydantic model

Instance Methods:

  • load(data, *, many, partial, unknown, return_instance) - Deserialize data
  • dump(obj, *, many, exclude_none, exclude_unset, exclude_defaults) - Serialize data
  • validate(data, *, many, partial) - Validate without deserializing

Hooks:

  • on_bind_field(field_name, field_obj) - Called when a field is bound
  • handle_error(error, data, *, many) - Custom error handling

Factory Functions

  • schema_for(model, **meta_options) - Create a schema class from a model
  • pydantic_schema - Decorator that adds .Schema to a model

HybridModel

A Pydantic model with built-in Marshmallow support.

Class Methods:

  • marshmallow_schema() - Get the Marshmallow schema class
  • ma_load(data, **kwargs) - Load using Marshmallow
  • ma_loads(json_str, **kwargs) - Load from JSON string

Instance Methods:

  • ma_dump(**kwargs) - Dump using Marshmallow
  • ma_dumps(**kwargs) - Dump to JSON string

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

pydantic_marshmallow-1.0.0.tar.gz (265.1 kB view details)

Uploaded Source

Built Distribution

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

pydantic_marshmallow-1.0.0-py3-none-any.whl (24.7 kB view details)

Uploaded Python 3

File details

Details for the file pydantic_marshmallow-1.0.0.tar.gz.

File metadata

  • Download URL: pydantic_marshmallow-1.0.0.tar.gz
  • Upload date:
  • Size: 265.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pydantic_marshmallow-1.0.0.tar.gz
Algorithm Hash digest
SHA256 33c4e1fd3cd715a4dc1dcfeb7aef8d4930cabc80cdd5e39b9529640cdec57a21
MD5 fdff9a4cc8e9b5d1492344e9df7e9745
BLAKE2b-256 52ab7cfc539853eada7c2b9c73e52e1409fd9ed09b979ac9d31ce85f5cc49117

See more details on using hashes here.

Provenance

The following attestation bundles were made for pydantic_marshmallow-1.0.0.tar.gz:

Publisher: release.yml on mockodin/pydantic-marshmallow

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

File details

Details for the file pydantic_marshmallow-1.0.0-py3-none-any.whl.

File metadata

File hashes

Hashes for pydantic_marshmallow-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7e909093ca304e77169e421f4f817c4992d1398af3b3ac4df98ecf07d733967a
MD5 dbce273f0539b7f6e0b90a718b0531f5
BLAKE2b-256 812ba3b56acdc1949b36c326058b923b1bb15bbbd88bd2fc4dbc0fa3b57e217c

See more details on using hashes here.

Provenance

The following attestation bundles were made for pydantic_marshmallow-1.0.0-py3-none-any.whl:

Publisher: release.yml on mockodin/pydantic-marshmallow

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

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