The dynamic configurator for your Python Project
—
Comprehensive validation framework with required field checking, type validation, range constraints, custom conditions, and combinatorial validators for ensuring configuration integrity. The validation system helps maintain data quality and provides clear error reporting.
Create validation rules for configuration values.
class Validator:
"""Validation rule for configuration values."""
def __init__(
self,
*names, # Variable names or patterns to validate
must_exist=False, # Require the value to exist
required=None, # Alias for must_exist
condition=None, # Custom validation function
when=None, # Conditional validator
env=None, # Environment(s) to validate in
messages=None, # Custom error messages
cast=None, # Type casting function
default=None, # Default value or callable
description=None, # Description string
apply_default_on_none=False, # Apply default when value is None
# Validation operations
eq=None, # Equal to
ne=None, # Not equal to
gt=None, # Greater than
lt=None, # Less than
gte=None, # Greater than or equal
lte=None, # Less than or equal
is_type_of=None, # Type validation
is_in=None, # Value in list/set
is_not_in=None, # Value not in list/set
identity=None, # Identity check (is)
cont=None, # Contains substring/element
len_eq=None, # Length equal
len_ne=None, # Length not equal
len_min=None, # Minimum length
len_max=None, # Maximum length
**kwargs
): ...Usage examples:
from dynaconf import Validator
# Basic required field
Validator("DATABASE_URL", must_exist=True)
# Type validation with default
Validator("DEBUG", default=False, is_type_of=bool)
# Range validation
Validator("PORT", default=8000, gte=1000, lte=9999)
# Multiple conditions
Validator("LOG_LEVEL", is_in=["DEBUG", "INFO", "WARNING", "ERROR"])
# Custom validation function
Validator("EMAIL", condition=lambda x: "@" in x, must_exist=True)Run validation rules against settings.
def validate(
self,
settings, # Settings instance to validate
only=None, # Validate only specific validators
exclude=None, # Exclude specific validators
only_current_env=False # Validate only current environment
):
"""
Run validation against settings.
Raises:
ValidationError: If validation fails
"""
...Combine validators with logical operations.
def __or__(self, other):
"""OR operation - either validator can pass."""
...
def __and__(self, other):
"""AND operation - both validators must pass."""
...Usage examples:
# OR combination - either condition passes
email_or_phone = (
Validator("EMAIL", condition=lambda x: "@" in x) |
Validator("PHONE", condition=lambda x: x.isdigit())
)
# AND combination - both conditions must pass
secure_password = (
Validator("PASSWORD", len_min=8) &
Validator("PASSWORD", condition=lambda x: any(c.isupper() for c in x))
)Handle validation failures with detailed error information.
class ValidationError(Exception):
"""Exception raised when validation fails."""
def __init__(self, message: str, details=None): ...
@property
def message(self) -> str:
"""Error message."""
...
@property
def details(self) -> list:
"""List of detailed error information."""
...Manage collections of validators.
class ValidatorList:
"""Container for managing multiple validators."""
def __init__(self, settings=None, validators=None): ...
def register(self, *args, **kwargs):
"""Register new validators."""
...
def validate(
self,
only=None, # Validate only specific validators
exclude=None, # Exclude specific validators
only_current_env=False # Validate only current environment
):
"""
Run all validators.
Raises:
ValidationError: If any validation fails
"""
...
def validate_all(
self,
only=None,
exclude=None,
only_current_env=False
) -> list:
"""
Run all validators and collect all errors.
Returns:
list: List of validation errors (empty if all pass)
"""
...
def descriptions(self, flat=False) -> dict:
"""Get validator descriptions."""
...Specialized validator classes for logical combinations.
class OrValidator:
"""At least one of the validators must pass."""
def __init__(self, *validators): ...
def validate(self, settings, only=None, exclude=None, only_current_env=False): ...
class AndValidator:
"""All validators must pass."""
def __init__(self, *validators): ...
def validate(self, settings, only=None, exclude=None, only_current_env=False): ...Validate values only when certain conditions are met.
# Validate SSL settings only when HTTPS is enabled
Validator(
"SSL_CERTIFICATE",
must_exist=True,
when=Validator("USE_HTTPS", eq=True)
)
# Environment-specific validation
Validator("DEBUG", eq=False, env="production")Create complex validation logic with custom functions.
def validate_database_url(url):
"""Custom database URL validation."""
return url.startswith(("postgresql://", "mysql://", "sqlite:///"))
def validate_email_list(emails):
"""Validate list of email addresses."""
if not isinstance(emails, list):
return False
return all("@" in email for email in emails)
# Use custom validators
Validator("DATABASE_URL", condition=validate_database_url)
Validator("ADMIN_EMAILS", condition=validate_email_list)Combine validation with automatic type conversion.
# Cast to integer and validate range
Validator("WORKER_COUNT", cast=int, gte=1, lte=10, default=4)
# Cast to boolean with validation
Validator("ENABLE_CACHE", cast=bool, default=True)
# Cast to list and validate contents
Validator("ALLOWED_HOSTS", cast=list, len_min=1)Provide clear error messages and documentation.
Validator(
"API_KEY",
must_exist=True,
messages={
"must_exist_true": "API key is required for external service access"
},
description="Authentication key for third-party API integration"
)from dynaconf import Dynaconf, Validator
settings = Dynaconf(
validators=[
# Database configuration
Validator("DATABASE_URL", must_exist=True),
Validator("DB_POOL_SIZE", cast=int, gte=1, lte=100, default=10),
# Security settings
Validator("SECRET_KEY", must_exist=True, len_min=32),
Validator("DEBUG", cast=bool, default=False),
Validator("ALLOWED_HOSTS", cast=list, len_min=1),
# External services
Validator("REDIS_URL", condition=lambda x: x.startswith("redis://")),
Validator("EMAIL_BACKEND", is_in=["smtp", "sendgrid", "ses"]),
# Environment-specific
Validator("DEBUG", eq=False, env="production"),
Validator("SSL_REQUIRED", eq=True, env="production"),
]
)
# Validate all settings
try:
settings.validators.validate()
print("All settings are valid!")
except ValidationError as e:
print(f"Validation failed: {e.message}")
for detail in e.details:
print(f" - {detail}")validators = [
# Server configuration
Validator("HOST", default="localhost"),
Validator("PORT", cast=int, gte=1000, lte=65535, default=8000),
Validator("WORKERS", cast=int, gte=1, lte=20, default=4),
# API configuration
Validator("API_VERSION", is_in=["v1", "v2", "v3"], default="v2"),
Validator("RATE_LIMIT", cast=int, gte=10, lte=10000, default=1000),
# Authentication
Validator("JWT_SECRET", must_exist=True, len_min=64),
Validator("TOKEN_EXPIRY", cast=int, gte=300, lte=86400, default=3600),
# Monitoring
Validator("METRICS_ENABLED", cast=bool, default=True),
Validator("LOG_LEVEL", is_in=["DEBUG", "INFO", "WARNING", "ERROR"], default="INFO"),
]
settings = Dynaconf(validators=validators)Install with Tessl CLI
npx tessl i tessl/pypi-dynaconf