Python data validation library for validating nested data structures with comprehensive error reporting
—
String transformation utilities, default value handling, value setting, and collection conversion utilities. These transformers modify data during validation rather than just validating it.
Functions that transform strings while validating them.
def Lower(v):
"""
Transform string to lowercase.
Parameters:
- v: String to transform
Returns:
Lowercase version of input string
Raises:
Invalid: If input cannot be converted to string
"""
def Upper(v):
"""
Transform string to uppercase.
Parameters:
- v: String to transform
Returns:
Uppercase version of input string
Raises:
Invalid: If input cannot be converted to string
"""
def Capitalize(v):
"""
Capitalize first letter of string.
Parameters:
- v: String to transform
Returns:
String with first letter capitalized, rest lowercase
Raises:
Invalid: If input cannot be converted to string
"""
def Title(v):
"""
Transform string to title case (each word capitalized).
Parameters:
- v: String to transform
Returns:
String in title case
Raises:
Invalid: If input cannot be converted to string
"""
def Strip(v):
"""
Remove leading and trailing whitespace from string.
Parameters:
- v: String to transform
Returns:
String with whitespace stripped
Raises:
Invalid: If input cannot be converted to string
"""Usage Examples:
from voluptuous import Schema, All, Lower, Upper, Capitalize, Title, Strip, Length
# Data normalization
user_schema = Schema({
'username': All(str, Strip, Lower), # Clean and lowercase username
'name': All(str, Strip, Title), # Clean and title case name
'email': All(str, Strip, Lower), # Clean and lowercase email
'country': All(str, Strip, Upper), # Clean and uppercase country code
})
# Text processing pipeline
text_processor = All(
str, # Ensure string
Strip, # Remove whitespace
lambda s: s if s else None, # Convert empty strings to None
)
# Combined with validation
clean_name = All(
str,
Strip, # Remove whitespace
Title, # Title case
Length(min=1, max=100), # Validate length
)
# Usage examples:
user_schema({
'username': ' JohnDoe ', # -> 'johndoe'
'name': ' john doe ', # -> 'John Doe'
'email': ' JOHN@EXAMPLE.COM ', # -> 'john@example.com'
'country': ' usa ', # -> 'USA'
})Set default values when input is None or missing.
class DefaultTo:
def __init__(self, default_value, msg=None):
"""
Set default value when input is None.
Parameters:
- default_value: Value to use when input is None (can be callable for factory)
- msg: Custom error message (rarely used)
Returns:
Input value if not None, otherwise default_value (or result of calling it)
Note:
If default_value is callable, it will be called each time to generate the default
"""Usage Examples:
from voluptuous import Schema, DefaultTo, Required, Optional
# Simple default values
config_schema = Schema({
Required('host', default='localhost'): str, # Default host
Required('port', default=8080): int, # Default port
Required('debug', default=False): bool, # Default debug mode
})
# Factory functions for dynamic defaults
import datetime
session_schema = Schema({
'user_id': str,
'created_at': DefaultTo(datetime.datetime.now), # Current time as default
'expires_at': DefaultTo(lambda: datetime.datetime.now() + datetime.timedelta(hours=24)),
'permissions': DefaultTo(list), # Empty list as default
'metadata': DefaultTo(dict), # Empty dict as default
})
# Conditional defaults
def default_config():
return {'theme': 'light', 'language': 'en'}
user_prefs_schema = Schema({
'username': str,
'config': DefaultTo(default_config), # Function returns dict
})
# Usage examples:
config_schema({'host': None}) # -> {'host': 'localhost', 'port': 8080, 'debug': False}
session_schema({'user_id': '123'}) # Adds timestamps and empty collectionsAlways set specific values regardless of input.
class SetTo:
def __init__(self, value):
"""
Always set to specific value, ignoring input.
Parameters:
- value: Value to always return (can be callable for factory)
Returns:
The specified value (or result of calling it if callable)
Note:
Completely ignores the input value
"""Usage Examples:
from voluptuous import Schema, SetTo, Any, All
import uuid
import datetime
# Always set specific values
audit_schema = Schema({
'data': dict, # User data
'created_by': SetTo('system'), # Always 'system'
'created_at': SetTo(datetime.datetime.now), # Always current time
'id': SetTo(lambda: str(uuid.uuid4())), # Always new UUID
'version': SetTo(1), # Always version 1
})
# Conditional value setting
def status_based_priority(data):
if data.get('status') == 'urgent':
return SetTo(1) # High priority
elif data.get('status') == 'low':
return SetTo(5) # Low priority
else:
return SetTo(3) # Medium priority
task_schema = Schema({
'title': str,
'status': str,
'priority': status_based_priority, # Set based on status
})
# Default or override pattern
flexible_schema = Schema({
'name': str,
'type': Any(str, SetTo('default')), # Use provided or default to 'default'
})
# Usage examples:
audit_result = audit_schema({'data': {'key': 'value'}})
# Result includes system-generated fields regardless of input
task_result = task_schema({'title': 'Fix bug', 'status': 'urgent'})
# Result: {'title': 'Fix bug', 'status': 'urgent', 'priority': 1}Convert between different collection types.
class Set:
def __init__(self, msg=None):
"""
Convert iterable to Python set.
Parameters:
- msg: Custom error message if conversion fails
Returns:
Set containing unique elements from input iterable
Raises:
TypeInvalid: If input cannot be converted to set (not iterable or contains unhashable types)
"""Usage Examples:
from voluptuous import Schema, Set, All, Length
# Remove duplicates by converting to set
unique_tags_schema = Schema({
'tags': All([str], Set()), # Convert list to set (removes duplicates)
})
# Validate set properties
permissions_schema = Schema(All(
[str], # Start with list of strings
Set(), # Convert to set
lambda s: len(s) >= 2, # Must have at least 2 unique permissions
))
# Combined with other validation
category_schema = Schema(All(
[str], # List of strings
lambda lst: [s.strip().lower() for s in lst], # Normalize
Set(), # Remove duplicates
lambda s: len(s) <= 10, # Max 10 unique categories
))
# Usage examples:
unique_tags_schema({'tags': ['python', 'web', 'python', 'api']})
# Result: {'tags': {'python', 'web', 'api'}}
permissions_schema(['read', 'write', 'read', 'admin'])
# Result: {'read', 'write', 'admin'}Validate exact literal values with custom comparison.
class Literal:
def __init__(self, lit):
"""
Validate exact literal value match.
Parameters:
- lit: Literal value that input must exactly match
Returns:
The literal value if input matches exactly
Raises:
LiteralInvalid: If input doesn't match literal value exactly
"""Usage Examples:
from voluptuous import Schema, Literal, Any
# API version validation
api_schema = Schema({
'version': Literal('v1'), # Must be exactly 'v1'
'format': Literal('json'), # Must be exactly 'json'
})
# Multiple literal options
status_schema = Schema({
'status': Any(
Literal('active'),
Literal('inactive'),
Literal('pending'),
),
})
# Configuration flags
feature_flags = Schema({
'new_ui': Any(Literal(True), Literal(False)), # Boolean literals
'api_version': Any(Literal(1), Literal(2)), # Integer literals
'mode': Any(Literal('dev'), Literal('prod')), # String literals
})
# Null/None validation
nullable_field = Schema({
'optional_field': Any(str, Literal(None)), # String or exactly None
})
# Usage examples:
api_schema({'version': 'v1', 'format': 'json'}) # Valid
# api_schema({'version': 'v2', 'format': 'json'}) # Invalid - wrong version
status_schema({'status': 'active'}) # Valid
feature_flags({'new_ui': True, 'api_version': 1, 'mode': 'prod'}) # ValidComplex data transformation patterns using multiple transformers.
Text Normalization Pipeline:
from voluptuous import Schema, All, Strip, Lower, Replace, Length
import re
# Complete text normalization
normalize_text = All(
str, # Ensure string
Strip, # Remove leading/trailing whitespace
lambda s: re.sub(r'\s+', ' ', s), # Normalize internal whitespace
Lower, # Convert to lowercase
lambda s: s if s else None, # Convert empty strings to None
)
# URL slug generation
create_slug = All(
str,
Strip,
Lower,
Replace(r'[^\w\s-]', ''), # Remove special characters
Replace(r'\s+', '-'), # Replace spaces with hyphens
Replace(r'-+', '-'), # Collapse multiple hyphens
lambda s: s.strip('-'), # Remove leading/trailing hyphens
)
# Usage:
normalize_text(' Hello World ') # -> 'hello world'
create_slug('My Blog Post Title!') # -> 'my-blog-post-title'Data Cleaning Pipeline:
from voluptuous import Schema, All, DefaultTo, Strip, Coerce
# Clean and validate user input
clean_user_data = Schema({
'name': All(str, Strip, DefaultTo('Anonymous')),
'age': All(Any(int, str), Coerce(int), Range(min=0, max=150)),
'email': All(str, Strip, Lower, Any(Email(), DefaultTo(None))),
'tags': All(
Any(list, str), # Accept list or comma-separated string
lambda x: x.split(',') if isinstance(x, str) else x, # Split if string
[All(str, Strip)], # Clean each tag
lambda tags: [t for t in tags if t], # Remove empty tags
Set(), # Remove duplicates
),
})Configuration Processing:
from voluptuous import Schema, All, DefaultTo, Coerce, Any
# Process configuration with defaults and coercion
config_processor = Schema({
'database': {
'host': All(str, Strip, DefaultTo('localhost')),
'port': All(Any(int, str), Coerce(int), Range(min=1024, max=65535), DefaultTo(5432)),
'name': All(str, Strip),
'ssl': All(Any(bool, str), Boolean, DefaultTo(True)),
},
'cache': {
'enabled': All(Any(bool, str), Boolean, DefaultTo(False)),
'ttl': All(Any(int, str), Coerce(int), Range(min=1), DefaultTo(3600)),
},
'features': All(
Any([str], str), # List or comma-separated string
lambda x: x.split(',') if isinstance(x, str) else x,
[All(str, Strip, Lower)], # Normalize feature names
Set(), # Remove duplicates
DefaultTo(set()), # Default to empty set
),
})Flexible Data Transformation:
from voluptuous import Schema, All, Any, SetTo
def smart_transform(field_name, transforms):
"""Apply different transformations based on field name or value."""
def transformer(value):
for condition, transform in transforms:
if condition(field_name, value):
return transform(value)
return value
return transformer
# Dynamic field processing
dynamic_schema = Schema({
'username': smart_transform('username', [
(lambda f, v: isinstance(v, str), All(Strip, Lower)),
(lambda f, v: True, SetTo('anonymous')), # Fallback
]),
'created_at': smart_transform('created_at', [
(lambda f, v: v is None, SetTo(datetime.datetime.now)),
(lambda f, v: isinstance(v, str), lambda s: datetime.datetime.fromisoformat(s)),
(lambda f, v: True, lambda x: x), # Pass through
]),
})Install with Tessl CLI
npx tessl i tessl/pypi-voluptuous