Easily serialize dataclasses to and from JSON.
—
Fine-grained control over field-level serialization behavior. The configuration system allows customization of individual fields through encoders, decoders, naming conventions, exclusion rules, and marshmallow integration.
The config function creates metadata dictionaries that control how individual dataclass fields are serialized and deserialized.
def config(
metadata: Optional[dict] = None,
*,
encoder: Optional[Callable] = None,
decoder: Optional[Callable] = None,
mm_field: Optional[marshmallow.fields.Field] = None,
letter_case: Optional[Union[Callable[[str], str], LetterCase]] = None,
undefined: Optional[Union[str, Undefined]] = None,
field_name: Optional[str] = None,
exclude: Optional[Callable] = None
) -> Dict[str, dict]:
"""
Configure field-level serialization options.
Parameters:
- metadata: Existing metadata dict to extend
- encoder: Custom function to encode this field's value
- decoder: Custom function to decode this field's value
- mm_field: Marshmallow field instance for validation
- letter_case: Case conversion for this field's name
- undefined: Undefined parameter handling for this field
- field_name: Custom name for this field in JSON
- exclude: Function to determine if field should be excluded
Returns:
Metadata dictionary for use with dataclass field()
"""Usage example:
from dataclasses import dataclass, field
from dataclasses_json import dataclass_json, config
from datetime import datetime
@dataclass_json
@dataclass
class Event:
name: str
# Custom field name in JSON
event_date: datetime = field(metadata=config(field_name="date"))
# Custom encoder/decoder
priority: int = field(metadata=config(
encoder=lambda x: "high" if x > 5 else "low",
decoder=lambda x: 10 if x == "high" else 1
))The LetterCase enum provides standard case conversion strategies for field names.
class LetterCase(Enum):
"""
Enumeration of supported letter case conversions for field names.
"""
CAMEL = camelcase # fieldName
KEBAB = spinalcase # field-name
SNAKE = snakecase # field_name
PASCAL = pascalcase # FieldNameCase conversion functions:
def camelcase(string: str) -> str:
"""Convert string to camelCase format."""
def snakecase(string: str) -> str:
"""Convert string to snake_case format."""
def spinalcase(string: str) -> str:
"""Convert string to spinal-case (kebab-case) format."""
def pascalcase(string: str) -> str:
"""Convert string to PascalCase format."""
def capitalcase(string: str) -> str:
"""Convert string to capital case (first letter uppercase)."""
def uplowcase(string: str, case: str) -> str:
"""Convert string to upper or lower case.
Parameters:
- string: String to convert
- case: 'up' for uppercase, 'low' for lowercase
"""Usage examples:
from dataclasses import dataclass, field
from dataclasses_json import dataclass_json, config, LetterCase
# Global case conversion
@dataclass_json(letter_case=LetterCase.CAMEL)
@dataclass
class Product:
product_name: str # Becomes "productName" in JSON
unit_price: float # Becomes "unitPrice" in JSON
# Per-field case conversion
@dataclass_json
@dataclass
class Order:
order_id: str
# Override global case for this field
customer_name: str = field(metadata=config(letter_case=LetterCase.SNAKE))Control which fields are included in serialization based on dynamic conditions.
class Exclude:
"""
Pre-defined exclusion predicates for field-level control.
"""
ALWAYS: Callable[[object], bool] = lambda _: True
NEVER: Callable[[object], bool] = lambda _: FalseUsage example:
from dataclasses import dataclass, field
from dataclasses_json import dataclass_json, config, Exclude
@dataclass_json
@dataclass
class User:
username: str
email: str
# Always exclude this field from serialization
password_hash: str = field(metadata=config(exclude=Exclude.ALWAYS))
# Conditionally exclude based on value
admin: bool = field(metadata=config(
exclude=lambda obj: not obj.admin # Only include if user is admin
))Implement custom serialization logic for specific fields or types.
# Encoder: Python value -> JSON-serializable value
EncoderFunc = Callable[[Any], Any]
# Decoder: JSON value -> Python value
DecoderFunc = Callable[[Any], Any]Usage examples:
from dataclasses import dataclass, field
from dataclasses_json import dataclass_json, config
from datetime import datetime, date
from decimal import Decimal
def date_encoder(dt: date) -> str:
"""Encode date as ISO string."""
return dt.isoformat()
def date_decoder(s: str) -> date:
"""Decode ISO string to date."""
return datetime.fromisoformat(s).date()
def decimal_encoder(d: Decimal) -> str:
"""Encode Decimal as string."""
return str(d)
def decimal_decoder(s: str) -> Decimal:
"""Decode string to Decimal."""
return Decimal(s)
@dataclass_json
@dataclass
class Invoice:
invoice_date: date = field(metadata=config(
encoder=date_encoder,
decoder=date_decoder
))
amount: Decimal = field(metadata=config(
encoder=decimal_encoder,
decoder=decimal_decoder
))
# Enum encoding
status: str = field(metadata=config(
encoder=lambda x: x.upper(),
decoder=lambda x: x.lower()
))Use marshmallow fields directly for advanced validation and transformation.
# Marshmallow field types that can be used
from marshmallow import fields
# Common field types:
# fields.String, fields.Integer, fields.Float, fields.Boolean
# fields.DateTime, fields.Date, fields.Time
# fields.List, fields.Dict, fields.Nested
# fields.Email, fields.Url, fields.UUIDUsage example:
from dataclasses import dataclass, field
from dataclasses_json import dataclass_json, config
from marshmallow import fields
from typing import List
@dataclass_json
@dataclass
class Contact:
# Email validation
email: str = field(metadata=config(mm_field=fields.Email()))
# URL validation
website: str = field(metadata=config(mm_field=fields.Url()))
# List with validation
tags: List[str] = field(metadata=config(
mm_field=fields.List(fields.String(validate=lambda x: len(x) > 0))
))
# Custom validation
age: int = field(metadata=config(
mm_field=fields.Integer(validate=lambda x: 0 <= x <= 150)
))from dataclasses import dataclass, field
from dataclasses_json import dataclass_json, config, LetterCase
from marshmallow import fields
@dataclass_json
@dataclass
class AdvancedConfig:
# Multiple config options on one field
created_at: datetime = field(metadata=config(
field_name="timestamp",
encoder=lambda dt: int(dt.timestamp()),
decoder=lambda ts: datetime.fromtimestamp(ts),
mm_field=fields.Integer(validate=lambda x: x > 0)
))# Base configuration can be extended
base_config = config(letter_case=LetterCase.CAMEL)
@dataclass_json
@dataclass
class BaseModel:
created_at: datetime = field(metadata=config(
base_config, # Extend base config
encoder=lambda dt: dt.isoformat()
))import os
# Environment-based configuration
DEBUG_MODE = os.getenv('DEBUG', 'false').lower() == 'true'
@dataclass_json
@dataclass
class ApiResponse:
data: dict
# Include debug info only in debug mode
debug_info: dict = field(metadata=config(
exclude=lambda obj: not DEBUG_MODE
))Install with Tessl CLI
npx tessl i tessl/pypi-dataclasses-json