Bring Pydantic's power to Marshmallow: type annotations, validators, and automatic schema generation
Project description
pydantic-marshmallow
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_schemadecorators - Partial Loading:
partial=Trueorpartial=('field1', 'field2') - Unknown Fields:
unknown=RAISE/EXCLUDE/INCLUDE - Computed Fields: Pydantic
@computed_fieldsupport 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 datadump(obj, *, many, exclude_none, exclude_unset, exclude_defaults)- Serialize datavalidate(data, *, many, partial)- Validate without deserializing
Hooks:
on_bind_field(field_name, field_obj)- Called when a field is boundhandle_error(error, data, *, many)- Custom error handling
Factory Functions
schema_for(model, **meta_options)- Create a schema class from a modelpydantic_schema- Decorator that adds.Schemato a model
HybridModel
A Pydantic model with built-in Marshmallow support.
Class Methods:
marshmallow_schema()- Get the Marshmallow schema classma_load(data, **kwargs)- Load using Marshmallowma_loads(json_str, **kwargs)- Load from JSON string
Instance Methods:
ma_dump(**kwargs)- Dump using Marshmallowma_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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
33c4e1fd3cd715a4dc1dcfeb7aef8d4930cabc80cdd5e39b9529640cdec57a21
|
|
| MD5 |
fdff9a4cc8e9b5d1492344e9df7e9745
|
|
| BLAKE2b-256 |
52ab7cfc539853eada7c2b9c73e52e1409fd9ed09b979ac9d31ce85f5cc49117
|
Provenance
The following attestation bundles were made for pydantic_marshmallow-1.0.0.tar.gz:
Publisher:
release.yml on mockodin/pydantic-marshmallow
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pydantic_marshmallow-1.0.0.tar.gz -
Subject digest:
33c4e1fd3cd715a4dc1dcfeb7aef8d4930cabc80cdd5e39b9529640cdec57a21 - Sigstore transparency entry: 896660578
- Sigstore integration time:
-
Permalink:
mockodin/pydantic-marshmallow@20f4cfacd4f4b463e7a4d59f6ddbf59ec23cf4b7 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/mockodin
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@20f4cfacd4f4b463e7a4d59f6ddbf59ec23cf4b7 -
Trigger Event:
push
-
Statement type:
File details
Details for the file pydantic_marshmallow-1.0.0-py3-none-any.whl.
File metadata
- Download URL: pydantic_marshmallow-1.0.0-py3-none-any.whl
- Upload date:
- Size: 24.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7e909093ca304e77169e421f4f817c4992d1398af3b3ac4df98ecf07d733967a
|
|
| MD5 |
dbce273f0539b7f6e0b90a718b0531f5
|
|
| BLAKE2b-256 |
812ba3b56acdc1949b36c326058b923b1bb15bbbd88bd2fc4dbc0fa3b57e217c
|
Provenance
The following attestation bundles were made for pydantic_marshmallow-1.0.0-py3-none-any.whl:
Publisher:
release.yml on mockodin/pydantic-marshmallow
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pydantic_marshmallow-1.0.0-py3-none-any.whl -
Subject digest:
7e909093ca304e77169e421f4f817c4992d1398af3b3ac4df98ecf07d733967a - Sigstore transparency entry: 896660584
- Sigstore integration time:
-
Permalink:
mockodin/pydantic-marshmallow@20f4cfacd4f4b463e7a4d59f6ddbf59ec23cf4b7 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/mockodin
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@20f4cfacd4f4b463e7a4d59f6ddbf59ec23cf4b7 -
Trigger Event:
push
-
Statement type: