A lightweight library for converting complex datatypes to and from native Python datatypes
—
Marshmallow provides structured exception types for error handling and utility functions for data manipulation, type checking, and advanced use cases.
Comprehensive exception hierarchy for handling validation and processing errors.
class MarshmallowError(Exception):
"""
Base exception class for all marshmallow-related errors.
"""
class ValidationError(MarshmallowError):
"""
Main exception raised when validation fails during deserialization.
Attributes:
- messages: dict/list/str, validation error messages
- field_name: str, name of the field where error occurred (if applicable)
- data: dict, raw input data that caused the error
- valid_data: dict, successfully validated data (if any)
"""
def __init__(self, message, field_name="_schema", data=None, valid_data=None, **kwargs):
"""
Initialize ValidationError.
Parameters:
- message: str/list/dict, error message(s)
- field_name: str, field name where error occurred (default: "_schema")
- data: dict, input data that failed validation
- valid_data: dict, any data that passed validation
"""
@property
def messages_dict(self):
"""
Get error messages as a dictionary.
Returns:
dict: error messages organized by field name
"""
class RegistryError(MarshmallowError):
"""
Raised for invalid schema registry operations.
"""
class StringNotCollectionError(ValidationError):
"""
Raised when a string is passed where a collection is expected.
"""SCHEMA = "_schema" # Key used for schema-level validation errorsHelper functions for data manipulation and object introspection.
def get_value(obj, key, default=missing):
"""
Get a value from an object by key with fallback support.
Parameters:
- obj: object to get value from (dict-like or object with attributes)
- key: str, key or attribute name (supports dot notation for nested access)
- default: default value if key is not found
Returns:
The value at the specified key, or default if not found
"""
def set_value(dct, key, value):
"""
Set a value in a dictionary using dot notation for nested keys.
Parameters:
- dct: dict, dictionary to modify
- key: str, key name (supports dot notation like 'user.profile.name')
- value: value to set
"""
def pluck(dictlist, key):
"""
Extract a list of values by key from a list of dictionaries.
Parameters:
- dictlist: list of dict, list of dictionaries
- key: str, key to extract from each dictionary
Returns:
list: values extracted from each dictionary
"""Functions for runtime type checking and validation.
def is_collection(obj):
"""
Check if an object is a collection type (but not string/bytes).
Parameters:
- obj: object to check
Returns:
bool: True if object is a collection, False otherwise
"""
def is_iterable_but_not_string(obj):
"""
Check if an object is iterable but not a string or bytes.
Parameters:
- obj: object to check
Returns:
bool: True if iterable and not string/bytes
"""
def is_sequence_but_not_string(obj):
"""
Check if an object is a sequence but not a string or bytes.
Parameters:
- obj: object to check
Returns:
bool: True if sequence and not string/bytes
"""
def is_generator(obj):
"""
Check if an object is a generator.
Parameters:
- obj: object to check
Returns:
bool: True if object is a generator
"""
def callable_or_raise(obj):
"""
Check if an object is callable, raise TypeError if not.
Parameters:
- obj: object to check
Raises:
TypeError: if object is not callable
"""Functions for datetime conversion and manipulation.
def is_aware(dt):
"""
Check if a datetime object is timezone-aware.
Parameters:
- dt: datetime object to check
Returns:
bool: True if datetime is timezone-aware
"""
def from_timestamp(value):
"""
Convert a POSIX timestamp to a datetime object.
Parameters:
- value: numeric timestamp (seconds since epoch)
Returns:
datetime: datetime object in UTC
"""
def from_timestamp_ms(value):
"""
Convert a millisecond timestamp to a datetime object.
Parameters:
- value: numeric timestamp (milliseconds since epoch)
Returns:
datetime: datetime object in UTC
"""
def timestamp(value):
"""
Convert a datetime object to a POSIX timestamp.
Parameters:
- value: datetime object
Returns:
float: timestamp in seconds since epoch
"""
def timestamp_ms(value):
"""
Convert a datetime object to a millisecond timestamp.
Parameters:
- value: datetime object
Returns:
int: timestamp in milliseconds since epoch
"""
def timedelta_to_microseconds(value):
"""
Convert a timedelta to total microseconds.
Parameters:
- value: timedelta object
Returns:
int: total microseconds
"""Functions for text processing and encoding.
def ensure_text_type(val):
"""
Ensure a value is a text/string type.
Parameters:
- val: value to convert
Returns:
str: string representation of the value
"""class OrderedSet:
"""
Set that maintains insertion order (similar to dict keys in Python 3.7+).
Provides standard set operations while preserving the order elements were added.
"""
def add(self, item):
"""Add an item to the set."""
def discard(self, item):
"""Remove an item from the set if present."""
def pop(self):
"""Remove and return the last item."""
def clear(self):
"""Remove all items from the set."""
def __contains__(self, item):
"""Check if item is in the set."""
def __iter__(self):
"""Iterate over items in insertion order."""
def __len__(self):
"""Return the number of items."""from marshmallow import Schema, fields, ValidationError
class UserSchema(Schema):
username = fields.Str(required=True)
email = fields.Email(required=True)
age = fields.Int(validate=lambda x: x >= 18)
schema = UserSchema()
try:
result = schema.load({
'username': '',
'email': 'invalid-email',
'age': 15
})
except ValidationError as err:
print("Validation failed:")
print(f"Messages: {err.messages}")
print(f"Field errors: {err.messages_dict}")
print(f"Valid data: {err.valid_data}")
# Handle specific field errors
if 'email' in err.messages:
print("Email validation failed")
# Access nested error structure
for field, errors in err.messages.items():
print(f"{field}: {errors}")from marshmallow.utils import get_value, set_value, pluck
# Working with nested data
user_data = {
'profile': {
'personal': {
'name': 'John Doe'
}
}
}
# Get nested values with dot notation
name = get_value(user_data, 'profile.personal.name') # 'John Doe'
missing_value = get_value(user_data, 'profile.work.title', 'N/A') # 'N/A'
# Set nested values
set_value(user_data, 'profile.personal.age', 30)
# user_data now has: {'profile': {'personal': {'name': 'John Doe', 'age': 30}}}
# Extract values from list of dictionaries
users = [
{'name': 'Alice', 'age': 25},
{'name': 'Bob', 'age': 30},
{'name': 'Charlie', 'age': 35}
]
names = pluck(users, 'name') # ['Alice', 'Bob', 'Charlie']from marshmallow.utils import is_collection, is_sequence_but_not_string
# Type checking examples
print(is_collection([1, 2, 3])) # True
print(is_collection({'a': 1})) # True
print(is_collection('string')) # False
print(is_collection({1, 2, 3})) # True
print(is_sequence_but_not_string([1, 2, 3])) # True
print(is_sequence_but_not_string('string')) # False
print(is_sequence_but_not_string((1, 2, 3))) # True
print(is_sequence_but_not_string({1, 2, 3})) # False (set is not sequence)from datetime import datetime, timezone
from marshmallow.utils import timestamp, from_timestamp, is_aware
# Convert datetime to timestamp
dt = datetime(2023, 1, 1, 12, 0, 0, tzinfo=timezone.utc)
ts = timestamp(dt) # Unix timestamp
# Convert timestamp back to datetime
dt_from_ts = from_timestamp(ts)
# Check timezone awareness
naive_dt = datetime(2023, 1, 1, 12, 0, 0)
aware_dt = datetime(2023, 1, 1, 12, 0, 0, tzinfo=timezone.utc)
print(is_aware(naive_dt)) # False
print(is_aware(aware_dt)) # Truefrom marshmallow import Schema, fields, ValidationError, validates_schema
class CustomValidationSchema(Schema):
data = fields.Dict()
@validates_schema
def custom_validation(self, data, **kwargs):
"""Custom validation with detailed error reporting."""
errors = {}
# Complex validation logic
if 'required_field' not in data.get('data', {}):
errors['data'] = ['Missing required_field in data object']
# Multiple error conditions
value = data.get('data', {}).get('value')
if value is not None:
if not isinstance(value, (int, float)):
errors.setdefault('data', []).append('Value must be numeric')
elif value < 0:
errors.setdefault('data', []).append('Value must be positive')
if errors:
raise ValidationError(errors)
# Usage
schema = CustomValidationSchema()
try:
result = schema.load({'data': {'value': -5}})
except ValidationError as err:
# Handle multiple validation errors
for field, field_errors in err.messages.items():
for error in field_errors:
print(f"Error in {field}: {error}")from marshmallow.orderedset import OrderedSet
# Create ordered set
tags = OrderedSet()
tags.add('python')
tags.add('marshmallow')
tags.add('validation')
tags.add('python') # Duplicate ignored
# Maintains insertion order
print(list(tags)) # ['python', 'marshmallow', 'validation']
# Standard set operations
tags.discard('python')
print('python' in tags) # False
print(len(tags)) # 2Install with Tessl CLI
npx tessl i tessl/pypi-marshmallow