Configuration Examples¶
Practical examples for multi-source configuration management.
Overview¶
The configuration module provides powerful, flexible configuration loading from multiple sources with automatic validation and type safety.
Examples¶
1. Basic Configuration¶
File: examples/config/01_basic_config.py
Introduction to configuration loading.
Topics:
- Loading from dictionaries (DictSource)
- Loading from files (YAML, JSON, TOML)
- Using default values
- Convenience methods (load_from_file, load_from_env)
- Nested configuration structures
- Automatic validation with Pydantic
- Type coercion
Key Concepts: - Simple, type-safe configuration - Multiple file format support - Automatic validation
Run:
2. Multi-Source Configuration¶
File: examples/config/02_multi_source_config.py
Advanced multi-source patterns.
Topics: - Source priority (later sources override earlier) - Deep merge of nested configuration - Layered configuration (Defaults → File → Environment) - Optional configuration files - Multi-format configuration - Environment-specific configuration
Key Concepts: - Flexible configuration composition - Environment-based overrides - Secrets management
Run:
3. Deployment Patterns¶
File: examples/config/03_deployment_patterns.py
Real-world deployment scenarios.
Topics: - Docker Compose: Environment variable based config - Kubernetes: ConfigMap + Secrets pattern - AWS ECS/Fargate: ECS Task Definition + Secrets Manager - Cloud-Native: Multi-source layered config - 12-Factor App: Pure environment variable config
Key Concepts: - Container orchestration patterns - Cloud platform integration - Secrets management best practices - 12-factor methodology
Run:
4. Validation Patterns¶
File: examples/config/04_validation_patterns.py
Advanced validation with Pydantic.
Topics: - Field Constraints: Ranges, lengths, patterns - String Patterns: Email, URL, regex patterns - Enum Validation: Fixed choices - Custom Validators: Business logic validation - Conditional Validation: Cross-field validation - Type Aliases: Reusable validation rules
Key Concepts: - Data validation at load time - Custom business rules - Helpful error messages - Type safety
Run:
Quick Start¶
from dspu.config import Config, FileSource, EnvSource
from pydantic import BaseModel
class AppConfig(BaseModel):
app_name: str
debug: bool = False
api_key: str
# Load from file with environment overrides
config = Config.load(
AppConfig,
sources=[
FileSource("config.yaml"),
EnvSource(prefix="APP_"),
],
)
print(f"App: {config.app_name}")
print(f"Debug: {config.debug}")
Common Patterns¶
Pattern 1: Local Development¶
config = Config.load(
AppConfig,
sources=[
FileSource("config.yaml"), # Base config
FileSource("config.local.yaml", required=False), # Local overrides
EnvSource(prefix="APP_"), # Environment overrides
],
)
Pattern 2: Docker Compose¶
Pattern 3: Kubernetes¶
config = Config.load(
AppConfig,
sources=[
FileSource("/config/app.yaml"), # ConfigMap
EnvSource(prefix="", separator="__"), # Secrets
],
)
Pattern 4: Environment-Specific¶
import os
env = os.getenv("ENV", "development")
config = Config.load(
AppConfig,
sources=[
FileSource("config.yaml"), # Base
FileSource(f"config.{env}.yaml"), # Environment-specific
],
)
Configuration Layers¶
Best practice is to layer your configuration:
Example¶
from pydantic import BaseModel, Field
class DatabaseConfig(BaseModel):
host: str = "localhost" # Default in code
port: int = 5432 # Default in code
name: str
password: str
config = Config.load(
DatabaseConfig,
sources=[
FileSource("config.yaml"), # host, port, name
FileSource(f"config.{env}.yaml"), # Override host
EnvSource(prefix="DB_", separator="__"), # password from DB_PASSWORD
],
)
Supported Formats¶
| Format | Extensions | Use Case |
|---|---|---|
| YAML | .yaml, .yml |
Human-readable, common for configs |
| JSON | .json |
Machine-readable, APIs |
| TOML | .toml |
Python ecosystem (pyproject.toml) |
| HOCON | .conf, .hocon |
Akka, complex hierarchical configs |
| ENV | .env |
Secrets, Docker, simple key=value |
Format Auto-Detection¶
DSPU automatically detects the format from the file extension:
config = Config.load_from_file(AppConfig, "config.yaml") # Auto-detects YAML
config = Config.load_from_file(AppConfig, "config.json") # Auto-detects JSON
config = Config.load_from_file(AppConfig, "config.toml") # Auto-detects TOML
Or specify explicitly:
Environment Variables¶
Nested Keys¶
Use double underscore __ for nested keys:
# Configuration model
class DatabaseConfig(BaseModel):
host: str
port: int
class AppConfig(BaseModel):
database: DatabaseConfig
# Load
config = Config.load(
AppConfig,
sources=[EnvSource(prefix="APP_", separator="__")],
)
Prefixes¶
Use prefixes to namespace environment variables:
Validation¶
Basic Validation¶
from pydantic import BaseModel, Field
class AppConfig(BaseModel):
port: int = Field(ge=1, le=65535) # Port range
workers: int = Field(ge=1, le=100) # Worker count
timeout: float = Field(gt=0) # Positive timeout
String Patterns¶
from pydantic import BaseModel, EmailStr, HttpUrl
class AppConfig(BaseModel):
email: EmailStr # Valid email
api_url: HttpUrl # Valid URL
api_key: str = Field(min_length=32) # Minimum length
Custom Validators¶
from pydantic import BaseModel, field_validator
class AppConfig(BaseModel):
database_url: str
@field_validator("database_url")
@classmethod
def validate_database_url(cls, v: str) -> str:
if not v.startswith(("postgresql://", "mysql://")):
raise ValueError("Invalid database URL scheme")
return v
Best Practices¶
✅ DO:
- Layer your configuration (defaults → file → env → secrets)
- Use Pydantic models for validation
- Use prefixes for environment variables
- Make local overrides optional (required=False)
- Provide sensible defaults
- Document required vs optional settings
❌ DON'T: - Never commit secrets to version control - Don't use loose types (use validation) - Don't skip validation (fail fast) - Don't hardcode environment-specific values
Security¶
Never Commit Secrets¶
Use Environment Variables for Secrets¶
# config.yaml (committed)
database:
host: localhost
port: 5432
name: myapp
# Environment variables (not committed)
export DB_PASSWORD=secret123
export API_KEY=sk_live_abc123
Use Secret Managers in Production¶
from dspu.config import Config, FileSource, EnvSource
from dspu.security import SecretManager
# Load base config
config = Config.load(AppConfig, sources=[FileSource("config.yaml")])
# Load secrets from AWS Secrets Manager
secrets = SecretManager.from_aws(region="us-east-1")
config.database.password = secrets.get("database/password")
Troubleshooting¶
Common Issues¶
Issue: ValidationError: Field required
- Solution: Provide the required field or add a default value
Issue: ConfigurationError: Configuration file not found
- Solution: Check file path or use required=False for optional files
Issue: Environment variables not being picked up - Solution: Check prefix and separator match your env var names
Issue: Values not overriding as expected - Solution: Check source order - later sources override earlier ones