Claude Code for Marshmallow: Python Object Serialization — Claude Skills 360 Blog
Blog / AI / Claude Code for Marshmallow: Python Object Serialization
AI

Claude Code for Marshmallow: Python Object Serialization

Published: January 1, 2028
Read time: 5 min read
By: Claude Skills 360

Marshmallow serializes and deserializes Python objects. pip install marshmallow. Schema: from marshmallow import Schema, fields. Define: class UserSchema(Schema): name = fields.Str(required=True); email = fields.Email(required=True). Serialize (dump): schema = UserSchema(); result = schema.dump(user_obj). Deserialize (load): data = schema.load({"name":"Alice","email":"[email protected]"}). Many: schema.dump(users, many=True). schema.load(list_of_dicts, many=True). Validate only: schema.validate({"name":"","email":"bad"}) — returns error dict. Fields: fields.Int, fields.Float, fields.Bool, fields.DateTime(format="iso"), fields.Date, fields.Nested(OtherSchema), fields.List(fields.Str()), fields.Dict(values=fields.Int()). Optional: fields.Str(load_default=None). Dump only: fields.Str(dump_only=True). Load only: fields.Str(load_only=True). Rename: email = fields.Str(data_key="emailAddress"). Validators: from marshmallow import validate. fields.Str(validate=validate.Length(min=1,max=100)). validate.Range(min=0,max=100). validate.OneOf(["a","b","c"]). validate.Regexp(r"^\d{5}$"). validate.Email(). validate.URL(). Custom validator: @validates("password") def validate_password(self, value): if len(value)<8: raise ValidationError("Too short"). Cross-field: @validates_schema def check_dates(self, data, **kwargs): if data["end"]<data["start"]: raise ValidationError("end before start"). Hooks: @post_load def make_user(self, data, **kwargs): return User(**data). Meta: class Meta: unknown = EXCLUDE — ignore unknown fields. INCLUDE to keep them. RAISE (default) to error on unknown. marshmallow-dataclass: from marshmallow_dataclass import dataclass. @dataclass class User: name: str; email: str. UserSchema = User.Schema. marshmallow-sqlalchemy: from marshmallow_sqlalchemy import SQLAlchemyAutoSchema. class UserSchema(SQLAlchemyAutoSchema): class Meta: model = User. Claude Code generates marshmallow schemas, nested serializers, and SQLAlchemy auto-schemas.

CLAUDE.md for Marshmallow

## marshmallow Stack
- Version: marshmallow >= 3.21 | pip install marshmallow marshmallow-dataclass
- Schema: class S(Schema): field = fields.Str(required=True, validate=Length(min=1))
- Dump: schema.dump(obj) — serialize to dict | schema.dump(list, many=True)
- Load: schema.load(dict) — deserialize + validate | schema.validate(dict) only
- Meta: class Meta: unknown = EXCLUDE|INCLUDE|RAISE (default RAISE)
- Hook: @post_load def make_model(self, data, **kwargs): return Model(**data)
- Nested: fields.Nested(OtherSchema) | fields.List(fields.Nested(...))

Marshmallow Serialization Pipeline

# app/serializers.py — marshmallow schema definitions
from __future__ import annotations

import re
from datetime import datetime
from typing import Any

from marshmallow import (
    EXCLUDE,
    INCLUDE,
    RAISE,
    Schema,
    ValidationError,
    fields,
    post_dump,
    post_load,
    pre_load,
    validate,
    validates,
    validates_schema,
)


# ─────────────────────────────────────────────────────────────────────────────
# Data models (plain Python — no ORM required)
# ─────────────────────────────────────────────────────────────────────────────

class Address:
    def __init__(self, street, city, state, postal_code, country="US"):
        self.street      = street
        self.city        = city
        self.state       = state
        self.postal_code = postal_code
        self.country     = country


class User:
    def __init__(self, id, email, first_name, last_name, role,
                 is_active=True, address=None, created_at=None):
        self.id         = id
        self.email      = email
        self.first_name = first_name
        self.last_name  = last_name
        self.role       = role
        self.is_active  = is_active
        self.address    = address
        self.created_at = created_at or datetime.utcnow()
        self._password_hash = ""

    def set_password(self, raw: str) -> None:
        self._password_hash = f"hashed:{raw}"


class Product:
    def __init__(self, id, sku, name, price, stock, category, is_active=True):
        self.id        = id
        self.sku       = sku
        self.name      = name
        self.price     = price
        self.stock     = stock
        self.category  = category
        self.is_active = is_active


class OrderLine:
    def __init__(self, product_id, sku, quantity, unit_price):
        self.product_id = product_id
        self.sku        = sku
        self.quantity   = quantity
        self.unit_price = unit_price
        self.subtotal   = quantity * unit_price


class Order:
    def __init__(self, id, user_id, lines, status, total, created_at=None):
        self.id         = id
        self.user_id    = user_id
        self.lines      = lines
        self.status     = status
        self.total      = total
        self.created_at = created_at or datetime.utcnow()


# ─────────────────────────────────────────────────────────────────────────────
# Address schema
# ─────────────────────────────────────────────────────────────────────────────

class AddressSchema(Schema):
    street      = fields.Str(required=True, validate=validate.Length(min=1, max=200))
    city        = fields.Str(required=True, validate=validate.Length(min=1, max=100))
    state       = fields.Str(required=True, validate=validate.Length(min=2, max=2))
    postal_code = fields.Str(required=True, validate=validate.Regexp(r"^\d{5}(-\d{4})?$"))
    country     = fields.Str(load_default="US", validate=validate.Length(min=2, max=2))

    @post_load
    def make_address(self, data: dict, **kwargs) -> Address:
        data["state"]   = data["state"].upper()
        data["country"] = data["country"].upper()
        return Address(**data)


# ─────────────────────────────────────────────────────────────────────────────
# User schemas
# ─────────────────────────────────────────────────────────────────────────────

class UserSchema(Schema):
    """Response schema — safe to expose to clients."""

    class Meta:
        unknown = EXCLUDE   # silently drop unknown fields during deserialization

    id         = fields.Int(dump_only=True)
    email      = fields.Email(required=True)
    first_name = fields.Str(required=True, validate=validate.Length(min=1, max=100))
    last_name  = fields.Str(required=True, validate=validate.Length(min=1, max=100))
    role       = fields.Str(
        required=True,
        validate=validate.OneOf(["user", "moderator", "admin"]),
    )
    is_active  = fields.Bool(load_default=True)
    address    = fields.Nested(AddressSchema, load_default=None)
    created_at = fields.DateTime(format="iso", dump_only=True)

    # Computed field — only in serialized output
    full_name = fields.Method("get_full_name", dump_only=True)

    def get_full_name(self, obj: User) -> str:
        return f"{obj.first_name} {obj.last_name}"


class CreateUserSchema(Schema):
    """Request schema for POST /users — includes password input."""

    class Meta:
        unknown = RAISE   # reject unexpected fields from clients

    email      = fields.Email(required=True)
    first_name = fields.Str(required=True, validate=validate.Length(min=1, max=100))
    last_name  = fields.Str(required=True, validate=validate.Length(min=1, max=100))
    password   = fields.Str(
        required=True,
        load_only=True,   # never serialized in responses
        validate=validate.Length(min=8, max=72),
    )
    role       = fields.Str(load_default="user", validate=validate.OneOf(["user","moderator","admin"]))
    address    = fields.Nested(AddressSchema, required=False, load_default=None)

    @validates("password")
    def validate_password_complexity(self, value: str) -> None:
        if not re.search(r"[A-Z]", value):
            raise ValidationError("Password must contain at least one uppercase letter")
        if not re.search(r"\d", value):
            raise ValidationError("Password must contain at least one digit")

    @post_load
    def make_user(self, data: dict, **kwargs) -> User:
        password = data.pop("password")
        user = User(id=None, **data)
        user.set_password(password)
        return user


class UpdateUserSchema(Schema):
    """PATCH schema — all fields optional."""

    class Meta:
        unknown = RAISE

    first_name = fields.Str(required=False, validate=validate.Length(min=1, max=100))
    last_name  = fields.Str(required=False, validate=validate.Length(min=1, max=100))
    role       = fields.Str(required=False, validate=validate.OneOf(["user","moderator","admin"]))


# ─────────────────────────────────────────────────────────────────────────────
# Product schema
# ─────────────────────────────────────────────────────────────────────────────

class ProductSchema(Schema):
    id       = fields.Int(dump_only=True)
    sku      = fields.Str(required=True, validate=validate.Regexp(r"^[A-Z0-9]+-\d{4,}$"))
    name     = fields.Str(required=True, validate=validate.Length(min=1, max=200))
    price    = fields.Float(required=True, validate=validate.Range(min=0.01, max=100_000))
    stock    = fields.Int(required=True, validate=validate.Range(min=0))
    category = fields.Str(required=True, validate=validate.OneOf(
        ["Electronics", "Clothing", "Books", "Home", "Sports"]
    ))
    is_active = fields.Bool(load_default=True)

    @post_load
    def make_product(self, data: dict, **kwargs) -> Product:
        return Product(id=None, **data)


# ─────────────────────────────────────────────────────────────────────────────
# Order line and Order schemas — nested
# ─────────────────────────────────────────────────────────────────────────────

class OrderLineSchema(Schema):
    product_id = fields.Int(required=True, validate=validate.Range(min=1))
    sku        = fields.Str(dump_only=True)
    quantity   = fields.Int(required=True, validate=validate.Range(min=1, max=10_000))
    unit_price = fields.Float(dump_only=True)   # set server-side from product
    subtotal   = fields.Float(dump_only=True)


class CreateOrderSchema(Schema):
    user_id = fields.Int(required=True)
    lines   = fields.List(fields.Nested(OrderLineSchema), required=True,
                          validate=validate.Length(min=1))
    notes   = fields.Str(load_default=None, validate=validate.Length(max=500))

    @validates_schema
    def check_unique_products(self, data: dict, **kwargs) -> None:
        product_ids = [line["product_id"] for line in data.get("lines", [])]
        if len(product_ids) != len(set(product_ids)):
            raise ValidationError("Duplicate product_id in order lines", field_name="lines")


class OrderSchema(Schema):
    id         = fields.Int(dump_only=True)
    user_id    = fields.Int()
    lines      = fields.List(fields.Nested(OrderLineSchema))
    status     = fields.Str(validate=validate.OneOf(
        ["pending","paid","shipped","delivered","cancelled"]
    ))
    total      = fields.Float(dump_only=True)
    created_at = fields.DateTime(format="iso", dump_only=True)


# ─────────────────────────────────────────────────────────────────────────────
# Schema registry — access by name for generic endpoints
# ─────────────────────────────────────────────────────────────────────────────

SCHEMAS: dict[str, Schema] = {
    "user":         UserSchema(),
    "create_user":  CreateUserSchema(),
    "update_user":  UpdateUserSchema(),
    "product":      ProductSchema(),
    "order":        OrderSchema(),
    "create_order": CreateOrderSchema(),
}


def serialize(schema_name: str, obj: Any, many: bool = False) -> dict | list:
    return SCHEMAS[schema_name].dump(obj, many=many)


def deserialize(schema_name: str, data: dict | list, many: bool = False) -> Any:
    return SCHEMAS[schema_name].load(data, many=many)


if __name__ == "__main__":
    # Serialize a user object
    user = User(id=1, email="[email protected]",
                first_name="Alice", last_name="Smith", role="user")
    schema = UserSchema()
    serialized = schema.dump(user)
    print("Serialized:", serialized)

    # Deserialize + validate raw input
    try:
        new_user = CreateUserSchema().load({
            "email":      "[email protected]",
            "first_name": "Bob",
            "last_name":  "Jones",
            "password":   "SecurePass1",
        })
        print("Created user:", new_user.first_name)
    except ValidationError as e:
        print("Validation errors:", e.messages)

    # Many=True
    users = [
        User(id=1, email="[email protected]", first_name="A", last_name="B", role="user"),
        User(id=2, email="[email protected]", first_name="C", last_name="D", role="admin"),
    ]
    results = schema.dump(users, many=True)
    print(f"Serialized {len(results)} users")

For the Pydantic alternative — Pydantic v2 validates at instantiation time using Rust-compiled validators and is 5–20× faster than marshmallow for large payloads, but marshmallow’s @post_load def make_model(self, data, **kwargs): return MyClass(**data) deserializes directly into arbitrary Python classes without those classes extending BaseModel — useful for legacy codebases or third-party models, and @validates_schema can check relationships between fields (start < end, product quantities don’t exceed warehouse capacity) with access to the full validated dict before instantiation. For the plain json.loads + manual validation alternative — if "email" not in data or "@" not in data["email"]: in every endpoint is unmaintainable across 50 fields, while a single marshmallow Schema centralizes validation (field types, ranges, regex), serialization (dump_only / load_only), and transformation (@pre_load to normalize keys, @post_load to construct objects) in one place that can be tested independently of HTTP handlers. The Claude Skills 360 bundle includes marshmallow skill sets covering Schema field definitions, fields Nested/List/Method/DateTime, validate Length/Range/OneOf/Regexp/Email, @validates and @validates_schema cross-field checks, @post_load for object construction, Meta unknown EXCLUDE/RAISE, dump_only/load_only fields, many=True for collections, marshmallow-dataclass integration, and marshmallow-sqlalchemy auto-schema. Start with the free tier to try serialization code generation.

Keep Reading

AI

Claude Code for email.contentmanager: Python Email Content Accessors

Read and write EmailMessage body content with Python's email.contentmanager module and Claude Code — email contentmanager ContentManager for the class that maps content types to get and set handler functions allowing EmailMessage to support get_content and set_content with type-specific behaviour, email contentmanager raw_data_manager for the ContentManager instance that handles raw bytes and str payloads without any conversion, email contentmanager content_manager for the standard ContentManager instance used by email.policy.default that intelligently handles text plain text html multipart and binary content types, email contentmanager get_content_text for the handler that returns the decoded text payload of a text-star message part as a str, email contentmanager get_content_binary for the handler that returns the raw decoded bytes payload of a non-text message part, email contentmanager get_data_manager for the get-handler lookup used by EmailMessage get_content to find the right reader function for the content type, email contentmanager set_content text for the handler that creates and sets a text part correctly choosing charset and transfer encoding, email contentmanager set_content bytes for the handler that creates and sets a binary part with base64 encoding and optional filename Content-Disposition, email contentmanager EmailMessage get_content for the method that reads the message body using the registered content manager handlers, email contentmanager EmailMessage set_content for the method that sets the message body and MIME headers in one call, email contentmanager EmailMessage make_alternative make_mixed make_related for the methods that convert a simple message into a multipart container, email contentmanager EmailMessage add_attachment for the method that attaches a file or bytes to a multipart message, and email contentmanager integration with email.message and email.policy and email.mime and io for building high-level email readers attachment extractors text body accessors HTML readers and policy-aware MIME construction pipelines.

5 min read Feb 12, 2029
AI

Claude Code for email.charset: Python Email Charset Encoding

Control header and body encoding for international email with Python's email.charset module and Claude Code — email charset Charset for the class that wraps a character set name with the encoding rules for header encoding and body encoding describing how to encode text for that charset in email messages, email charset Charset header_encoding for the attribute specifying whether headers using this charset should use QP quoted-printable encoding BASE64 encoding or no encoding, email charset Charset body_encoding for the attribute specifying the Content-Transfer-Encoding to use for message bodies in this charset such as QP or BASE64, email charset Charset output_codec for the attribute giving the Python codec name used to encode the string to bytes for the wire format, email charset Charset input_codec for the attribute giving the Python codec name used to decode incoming bytes to str, email charset Charset get_output_charset for returning the output charset name, email charset Charset header_encode for encoding a header string using the charset's header_encoding method, email charset Charset body_encode for encoding body content using the charset's body_encoding, email charset Charset convert for converting a string from the input_codec to the output_codec, email charset add_charset for registering a new charset with custom encoding rules in the global charset registry, email charset add_alias for adding an alias name that maps to an existing registered charset, email charset add_codec for registering a codec name mapping for use by the charset machinery, and email charset integration with email.message and email.mime and email.policy and email.encoders for building international email senders non-ASCII header encoders Content-Transfer-Encoding selectors charset-aware message constructors and MIME encoding pipelines.

5 min read Feb 11, 2029
AI

Claude Code for email.utils: Python Email Address and Header Utilities

Parse and format RFC 2822 email addresses and dates with Python's email.utils module and Claude Code — email utils parseaddr for splitting a display-name plus angle-bracket address string into a realname and email address tuple, email utils formataddr for combining a realname and address string into a properly quoted RFC 2822 address with angle brackets, email utils getaddresses for parsing a list of raw address header strings each potentially containing multiple comma-separated addresses into a list of realname address tuples, email utils parsedate for parsing an RFC 2822 date string into a nine-tuple compatible with time.mktime, email utils parsedate_tz for parsing an RFC 2822 date string into a ten-tuple that includes the UTC offset timezone in seconds, email utils parsedate_to_datetime for parsing an RFC 2822 date string into an aware datetime object with timezone, email utils formatdate for formatting a POSIX timestamp or the current time as an RFC 2822 date string with optional usegmt and localtime flags, email utils format_datetime for formatting a datetime object as an RFC 2822 date string, email utils make_msgid for generating a globally unique Message-ID string with optional idstring and domain components, email utils decode_rfc2231 for decoding an RFC 2231 encoded parameter value into a tuple of charset language and value, email utils encode_rfc2231 for encoding a string as an RFC 2231 encoded parameter value, email utils collapse_rfc2231_value for collapsing a decoded RFC 2231 tuple to a Unicode string, and email utils integration with email.message and email.headerregistry and datetime and time for building address parsers date formatters message-id generators header extractors and RFC-compliant email construction utilities.

5 min read Feb 10, 2029

Put these ideas into practice

Claude Skills 360 gives you production-ready skills for everything in this article — and 2,350+ more. Start free or go all-in.

Back to Blog

Get 360 skills free