Python data validation library for validating nested data structures with comprehensive error reporting
—
The foundational validation system that defines data structure rules, manages field requirements, handles extra key policies, and enables complex validation composition through markers and schema extension.
The main validation class that defines and executes validation rules against data structures.
class Schema:
def __init__(self, schema, required=False, extra=PREVENT_EXTRA):
"""
Create a validation schema.
Parameters:
- schema: The validation rules (dict, list, callable, or value)
- required: Whether all keys are required by default (bool)
- extra: How to handle extra keys (PREVENT_EXTRA/ALLOW_EXTRA/REMOVE_EXTRA)
"""
def __call__(self, data):
"""
Validate data against the schema.
Parameters:
- data: Data to validate
Returns:
Validated and potentially transformed data
Raises:
Invalid: If validation fails
MultipleInvalid: If multiple validation errors occur
"""
def extend(self, schema, required=None, extra=None):
"""
Merge with another schema to create a new schema.
Parameters:
- schema: Schema to merge with
- required: Override required setting
- extra: Override extra key handling
Returns:
New Schema object with merged rules
"""
@classmethod
def infer(cls, data, **kwargs):
"""
Create a schema by inferring types from concrete data.
Parameters:
- data: Sample data to infer schema from
- kwargs: Additional options for schema creation
Returns:
New Schema object inferred from data types
"""Mark schema keys as required with optional default values.
class Required:
def __init__(self, schema, msg=None, default=UNDEFINED, description=None):
"""
Mark a schema key as required.
Parameters:
- schema: The key to mark as required
- msg: Custom error message
- default: Default value or factory function
- description: Human-readable description
"""Usage Example:
from voluptuous import Schema, Required, DefaultTo
schema = Schema({
Required('name'): str,
Required('age', default=0): int,
Required('config', default=dict): dict,
})
# Validates successfully with defaults applied
result = schema({'name': 'John'})
# Result: {'name': 'John', 'age': 0, 'config': {}}Mark schema keys as optional with optional default values.
class Optional:
def __init__(self, schema, msg=None, default=UNDEFINED, description=None):
"""
Mark a schema key as optional.
Parameters:
- schema: The key to mark as optional
- msg: Custom error message
- default: Default value or factory function
- description: Human-readable description
"""Usage Example:
from voluptuous import Schema, Required, Optional
schema = Schema({
Required('name'): str,
Optional('nickname'): str,
Optional('tags', default=list): [str],
})
# Both work:
schema({'name': 'John'}) # nickname omitted
schema({'name': 'John', 'nickname': 'Johnny'}) # nickname providedCreate mutually exclusive field groups where only one field from the group can be present.
class Exclusive:
def __init__(self, schema, group_of_exclusion, msg=None, description=None):
"""
Mark fields as mutually exclusive.
Parameters:
- schema: The key to mark as exclusive
- group_of_exclusion: Group identifier (string)
- msg: Custom error message
- description: Human-readable description
"""Usage Example:
from voluptuous import Schema, Exclusive
# Only one authentication method allowed
auth_schema = Schema({
Exclusive('username', 'auth'): str,
Exclusive('token', 'auth'): str,
Exclusive('api_key', 'auth'): str,
})
# Valid: only one auth method
auth_schema({'username': 'john'})
auth_schema({'token': 'abc123'})
# Invalid: multiple auth methods
# auth_schema({'username': 'john', 'token': 'abc123'}) # Raises ExclusiveInvalidCreate inclusive field groups where if any field from the group is present, all must be present.
class Inclusive:
def __init__(self, schema, group_of_inclusion, msg=None, description=None, default=UNDEFINED):
"""
Mark fields as inclusive (all-or-nothing).
Parameters:
- schema: The key to mark as inclusive
- group_of_inclusion: Group identifier (string)
- msg: Custom error message
- description: Human-readable description
- default: Default value if group is missing
"""Usage Example:
from voluptuous import Schema, Inclusive, Required
# Coordinates must be provided together
location_schema = Schema({
Required('name'): str,
Inclusive('latitude', 'coords'): float,
Inclusive('longitude', 'coords'): float,
})
# Valid: both coords or neither
location_schema({'name': 'Home'}) # No coordinates
location_schema({'name': 'Home', 'latitude': 40.7, 'longitude': -74.0}) # Both coordinates
# Invalid: only one coordinate
# location_schema({'name': 'Home', 'latitude': 40.7}) # Raises InclusiveInvalidMark fields for removal from validated output, treating validation failures as extra keys.
class Remove:
def __init__(self, schema, msg=None, description=None):
"""
Mark a field for removal from output.
Parameters:
- schema: The key to remove from output
- msg: Custom error message (rarely used)
- description: Human-readable description
"""Usage Example:
from voluptuous import Schema, Remove, Required
# Remove sensitive fields from output
schema = Schema({
Required('name'): str,
Required('email'): str,
Remove('password'): str, # Validated but not included in result
})
data = {'name': 'John', 'email': 'john@example.com', 'password': 'secret'}
result = schema(data)
# Result: {'name': 'John', 'email': 'john@example.com'}
# Password was validated but removed from outputValidate object attributes instead of dictionary keys, useful for class instances.
class Object(dict):
def __init__(self, schema, cls=UNDEFINED):
"""
Validate object attributes instead of dict keys.
Parameters:
- schema: Validation schema for object attributes
- cls: Expected class type (optional)
"""Usage Example:
from voluptuous import Schema, Object, Required
class User:
def __init__(self, name, age):
self.name = name
self.age = age
user_schema = Schema(Object({
Required('name'): str,
Required('age'): int,
}))
user = User('John', 30)
validated_user = user_schema(user) # Validates object attributesProvide custom error messages and exception types for validation failures.
class Msg:
def __init__(self, schema, msg, cls=None):
"""
Provide custom error message for validation.
Parameters:
- schema: The schema to validate
- msg: Custom error message
- cls: Custom exception class to raise (defaults to ValueError)
"""Usage Example:
from voluptuous import Schema, Msg, All, Length
password_schema = Schema(
Msg(All(str, Length(min=8)), 'Password must be at least 8 characters', ValueError)
)
try:
password_schema('short')
except ValueError as e:
print(e) # "Password must be at least 8 characters"Control how schema validation handles keys not defined in the schema.
PREVENT_EXTRA = 0 # Raise error for extra keys (default)
ALLOW_EXTRA = 1 # Include extra keys in output
REMOVE_EXTRA = 2 # Exclude extra keys from output
def Extra(_):
"""Placeholder function for allowing extra keys in schema definition."""Usage Example:
from voluptuous import Schema, Required, ALLOW_EXTRA, REMOVE_EXTRA
# Allow extra keys
flexible_schema = Schema({
Required('name'): str,
}, extra=ALLOW_EXTRA)
# Remove extra keys
strict_schema = Schema({
Required('name'): str,
}, extra=REMOVE_EXTRA)
data = {'name': 'John', 'extra_field': 'value'}
flexible_result = flexible_schema(data) # {'name': 'John', 'extra_field': 'value'}
strict_result = strict_schema(data) # {'name': 'John'}Helper functions for schema creation and validation.
def message(msg=None, cls=None):
"""
Decorator to add custom error messages to validator functions.
Parameters:
- msg: Custom error message
- cls: Custom exception class
"""
def validate(*a, **kw):
"""
Decorator for validating function arguments against a schema.
Parameters:
- *a: Positional argument schemas
- **kw: Keyword argument schemas
"""
def default_factory(value):
"""
Convert a value to a factory function for default values.
Parameters:
- value: Value to convert (if callable, returns as-is; otherwise wraps in lambda)
Returns:
Factory function that returns the value
"""
def raises(exc, msg=None, regex=None):
"""
Context manager for testing that an exception is raised.
Parameters:
- exc: Exception class that should be raised
- msg: Optional exact error message to match
- regex: Optional regex pattern to match against error message
Returns:
Context manager for use with 'with' statement
Raises:
AssertionError: If expected exception is not raised or message doesn't match
"""Message Decorator Example:
from voluptuous import message, Schema
@message("Value must be positive", ValueError)
def positive(value):
if value <= 0:
raise ValueError()
return value
schema = Schema(positive)Validate Decorator Example:
from voluptuous import validate, Schema, Required
@validate({'name': str, 'age': int})
def create_user(data):
return f"User: {data['name']}, Age: {data['age']}"
# Function arguments are automatically validated
create_user({'name': 'John', 'age': 30})Testing Utility Example:
from voluptuous import raises, Schema, Invalid, Range
# Test that validation raises expected exceptions
with raises(Invalid):
Schema(Range(min=0, max=10))(15) # Should raise Invalid
# Test with specific error message
with raises(Invalid, "value must be at most 10"):
Schema(Range(min=0, max=10))(15)
# Test with regex pattern
import re
with raises(Invalid, regex=re.compile(r"value must be at most \d+")):
Schema(Range(min=0, max=10))(15)Install with Tessl CLI
npx tessl i tessl/pypi-voluptuous