Python data validation library for validating nested data structures with comprehensive error reporting
—
Type conversion and coercion with error handling, truth value validation, and human-readable boolean conversion. These validators handle type transformations and validate type-specific conditions.
Convert values to specified types with graceful error handling.
class Coerce:
def __init__(self, type, msg=None):
"""
Convert value to specified type.
Parameters:
- type: Target type to convert to (int, float, str, etc.)
- msg: Custom error message if coercion fails
Returns:
Value converted to target type
Raises:
CoerceInvalid: If conversion fails (ValueError/TypeError from type constructor)
"""Usage Examples:
from voluptuous import Schema, Coerce, All, Range
# Convert strings to numbers
numeric_schema = Schema({
'age': Coerce(int), # "25" -> 25
'price': Coerce(float), # "19.99" -> 19.99
'active': Coerce(bool), # "true" -> True, "false" -> False
})
# Combined with validation
validated_age = Schema(All(
Coerce(int), # Convert to int first
Range(min=0, max=150), # Then validate range
))
# Custom types
from decimal import Decimal
decimal_price = Schema(All(
Coerce(Decimal), # Convert to Decimal
lambda x: x >= 0, # Validate non-negative
))Convert human-readable values to boolean with comprehensive string recognition.
def Boolean(v):
"""
Convert human-readable values to boolean.
Parameters:
- v: Value to convert to boolean
Accepted truthy values:
'1', 'true', 'yes', 'on', 'enable', 1, True (case-insensitive for strings)
Accepted falsy values:
'0', 'false', 'no', 'off', 'disable', 0, False (case-insensitive for strings)
Returns:
True or False
Raises:
BooleanInvalid: If value cannot be converted to boolean
"""Usage Examples:
from voluptuous import Schema, Boolean
# Flexible boolean conversion
settings_schema = Schema({
'debug': Boolean, # Accepts 'true', 'yes', '1', True, etc.
'logging': Boolean, # Accepts 'false', 'no', '0', False, etc.
'ssl_enabled': Boolean,
})
# Valid inputs:
settings_schema({
'debug': 'true', # -> True
'logging': 'no', # -> False
'ssl_enabled': 1, # -> True
})
settings_schema({
'debug': 'YES', # -> True (case-insensitive)
'logging': 'disable', # -> False
'ssl_enabled': '0', # -> False
})Validate whether values are truthy or falsy in Python's sense.
def IsTrue(v):
"""
Assert value is truthy in Python sense.
Parameters:
- v: Value to test for truthiness
Returns:
Original value if truthy
Raises:
TrueInvalid: If value is falsy (False, None, 0, '', [], {}, etc.)
"""
def IsFalse(v):
"""
Assert value is falsy in Python sense.
Parameters:
- v: Value to test for falsiness
Returns:
Original value if falsy
Raises:
FalseInvalid: If value is truthy
"""Usage Examples:
from voluptuous import Schema, IsTrue, IsFalse, Any
# Validate required fields are not empty
data_schema = Schema({
'name': IsTrue, # Must be non-empty string
'items': IsTrue, # Must be non-empty list
'settings': IsTrue, # Must be non-empty dict
})
# Valid data
data_schema({
'name': 'John', # Truthy string
'items': [1, 2, 3], # Non-empty list
'settings': {'debug': True}, # Non-empty dict
})
# Invalid data would fail:
# data_schema({'name': '', 'items': [], 'settings': {}}) # All falsy
# Validate disabled features
feature_schema = Schema({
'legacy_mode': IsFalse, # Must be disabled/falsy
'deprecated_api': IsFalse, # Must be disabled/falsy
})
# Accept various ways of expressing "disabled"
feature_schema({
'legacy_mode': False, # Explicitly False
'deprecated_api': None, # None is falsy
})Convert arbitrary boolean functions into validators.
def truth(f):
"""
Decorator to convert truth functions into validators.
Parameters:
- f: Function that returns True/False for validation
Returns:
Validator function that raises ValueError if f returns False
Usage:
Decorate any function that returns boolean to create a validator
"""Usage Examples:
from voluptuous import Schema, truth
import os.path
# Convert existing boolean functions to validators
@truth
def is_file(path):
return os.path.isfile(path)
@truth
def is_even(n):
return n % 2 == 0
@truth
def is_valid_email_domain(email):
return email.split('@')[1] in ['company.com', 'partner.org']
# Use in schemas
file_schema = Schema(is_file) # Validates file exists
number_schema = Schema(is_even) # Validates even numbers
email_schema = Schema(is_valid_email_domain) # Validates email domain
# Combined validation
config_schema = Schema({
'log_file': is_file, # Must be existing file
'port': is_even, # Must be even number
'admin_email': is_valid_email_domain, # Must be company email
})Common patterns for type validation and conversion.
Flexible Type Acceptance:
from voluptuous import Schema, Any, Coerce, All
# Accept multiple representations of the same data
flexible_id = Any(
int, # Already an integer
All(str, Coerce(int)), # String representation of integer
All(str, Match(r'^\d+$'), Coerce(int)), # Ensure string is numeric first
)
# Flexible timestamp handling
timestamp_validator = Any(
int, # Unix timestamp
float, # Fractional timestamp
All(str, Coerce(float)), # String timestamp
datetime.datetime, # Datetime object
)Safe Type Coercion:
from voluptuous import Schema, Coerce, All, message
@message("Invalid number format")
def safe_int(value):
"""Safely convert to int with better error messages."""
if isinstance(value, int):
return value
if isinstance(value, str) and value.strip():
try:
return int(value.strip())
except ValueError:
# Try float first, then int
try:
float_val = float(value.strip())
if float_val.is_integer():
return int(float_val)
except ValueError:
pass
raise ValueError("Cannot convert to integer")
# Safer than plain Coerce(int)
safe_number_schema = Schema(safe_int)Conditional Type Conversion:
from voluptuous import Schema, Any, All, Coerce
def smart_coerce(target_type):
"""Intelligently coerce values based on their current type."""
def coercer(value):
if isinstance(value, target_type):
return value
if target_type == bool:
return Boolean(value)
elif target_type in (int, float):
if isinstance(value, str) and not value.strip():
raise ValueError("Empty string cannot be converted to number")
return target_type(value)
else:
return target_type(value)
return coercer
# Smart coercion with fallbacks
smart_schema = Schema({
'count': smart_coerce(int),
'rate': smart_coerce(float),
'enabled': smart_coerce(bool),
})Type Validation with Constraints:
from voluptuous import Schema, All, Coerce, Range, Length
# Ensure type and constraints in one step
constrained_string = All(
str, # Must be string
Length(min=1, max=100), # Must have reasonable length
lambda s: s.strip() == s, # Must not have leading/trailing whitespace
)
constrained_number = All(
Any(int, float, Coerce(float)), # Accept various numeric types
Range(min=0), # Must be non-negative
lambda x: x == x, # Must not be NaN (NaN != NaN)
)
# Use in schema
validated_schema = Schema({
'name': constrained_string,
'amount': constrained_number,
})Install with Tessl CLI
npx tessl i tessl/pypi-voluptuous