Peaceful, type-safe Python configuration with strict separation from code
Project description
๐ง DotZen
Peaceful, type-safe Python configuration that just works.
๐ Overview
DotZen brings zen to Python configuration management. Load settings from environment variables, .env files, JSON, YAML, or cloud secret managers with automatic type casting, validation, and a beautiful fluent API.
No more config chaos. Just pure zen. ๐งโโ๏ธโจ
โจ Key Highlights
from dotzen import config
# Simple, elegant, type-safe
DEBUG = config('DEBUG', cast=bool, default=False)
PORT = config('PORT', cast=int, default=8000)
DATABASE_URL = config('DATABASE_URL')
ALLOWED_HOSTS = config('ALLOWED_HOSTS', cast=list)
Why Choose DotZen?
| Traditional Config | ๐ซ | DotZen | โจ |
|---|---|---|---|
| Scattered sources | Multiple libraries needed | Unified API | One interface for all sources |
| String soup | Manual type conversion everywhere | Type Safety | Automatic casting & validation |
| Runtime failures | Errors only in production | Early Validation | Catch issues at startup |
| Copy-paste code | Boilerplate in every project | Design Patterns | Elegant, reusable architecture |
| Hardcoded secrets | Security nightmares | Cloud-Native | First-class secrets support |
๐ Quick Start
Installation
# Core library (zero dependencies)
pip install dotzen
# With cloud provider support
pip install dotzen[aws] # AWS Secrets Manager
pip install dotzen[gcp] # Google Cloud Secret Manager
pip install dotzen[azure] # Azure Key Vault
pip install dotzen[cloud] # All cloud providers
# Everything included
pip install dotzen[all]
Basic Usage
from dotzen import config
# Get configuration values with automatic type casting
API_KEY = config('API_KEY')
DEBUG = config('DEBUG', cast=bool, default=False)
MAX_CONNECTIONS = config('MAX_CONNECTIONS', cast=int, default=100)
ALLOWED_ORIGINS = config('ALLOWED_ORIGINS', cast=list)
Advanced Usage with Builder Pattern
from dotzen import ConfigBuilder
# Build a configuration with multiple sources
config = (ConfigBuilder()
.add_environment('APP_') # Env vars with prefix
.add_dotenv('.env') # .env file
.add_json('config.json') # JSON config
.add_secrets('/run/secrets') # Docker secrets
.build())
# Type-safe access with convenience methods
debug = config.get_bool('DEBUG', default=False)
port = config.get_int('PORT', default=8000)
timeout = config.get_float('TIMEOUT', default=30.0)
hosts = config.get_list('ALLOWED_HOSTS')
๐ฏ Features
๐ Multi-Source Configuration
DotZen implements a Chain of Responsibility pattern, checking sources in priority order:
config = (ConfigBuilder()
.add_environment() # 1๏ธโฃ Highest priority
.add_dotenv('.env') # 2๏ธโฃ
.add_json('config.json') # 3๏ธโฃ
.add_aws_secrets('prod') # 4๏ธโฃ
.build()) # 5๏ธโฃ Default values (lowest priority)
๐ก๏ธ Type Safety & Automatic Casting
# Automatic type conversion with validation
DEBUG = config.get_bool('DEBUG') # str โ bool
PORT = config.get_int('PORT') # str โ int
RATE_LIMIT = config.get_float('RATE') # str โ float
SERVERS = config.get_list('SERVERS') # str โ list
# Boolean casting supports multiple formats
# True: "true", "yes", "1", "on", "t", "y"
# False: "false", "no", "0", "off", "f", "n"
โ Built-in Validation
from dotzen import ConfigBuilder
from dotzen.validators import URLValidator, RangeValidator, RegexValidator
config = (ConfigBuilder()
.add_environment()
.with_validator(URLValidator('DATABASE_URL'))
.with_validator(RangeValidator('PORT', 1024, 65535))
.with_validator(RegexValidator('API_KEY', r'^[A-Za-z0-9]{32}$'))
.build())
# Configuration is validated at build time
# Errors are caught before your app starts! ๐
๐ Cloud Secrets Support
# AWS Secrets Manager
config = (ConfigBuilder()
.add_environment()
.add_aws_secrets('prod/myapp', region='us-east-1')
.build())
# Google Cloud Secret Manager
config = (ConfigBuilder()
.add_environment()
.add_gcp_secrets('projects/my-project/secrets')
.build())
# Azure Key Vault
config = (ConfigBuilder()
.add_environment()
.add_azure_keyvault('https://myvault.vault.azure.net')
.build())
# HashiCorp Vault
config = (ConfigBuilder()
.add_environment()
.add_vault_secrets('secret/myapp', url='https://vault.example.com')
.build())
๐จ Fluent API Design
DotZen uses the Builder Pattern for an intuitive, chainable API:
config = (ConfigBuilder()
.add_environment('MYAPP_')
.add_dotenv('.env')
.add_dotenv('.env.local', override=True)
.add_json('config.json')
.add_yaml('settings.yaml')
.with_validator(URLValidator('DATABASE_URL'))
.with_type('MAX_WORKERS', int)
.build())
๐ญ Auto-Detection Factory
Let DotZen automatically detect your configuration files:
from dotzen import ConfigFactory
# Automatically finds and loads:
# - .env
# - config.json
# - settings.json
config = ConfigFactory.auto_config()
๐ Real-World Examples
Django Settings
# settings.py
from dotzen import config
# Core settings
DEBUG = config('DEBUG', cast=bool, default=False)
SECRET_KEY = config('SECRET_KEY')
ALLOWED_HOSTS = config('ALLOWED_HOSTS', cast=list, default=[])
# Database configuration
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': config('DB_NAME'),
'USER': config('DB_USER'),
'PASSWORD': config('DB_PASSWORD'),
'HOST': config('DB_HOST', default='localhost'),
'PORT': config('DB_PORT', cast=int, default=5432),
}
}
# Email configuration
EMAIL_HOST = config('EMAIL_HOST', default='smtp.gmail.com')
EMAIL_PORT = config('EMAIL_PORT', cast=int, default=587)
EMAIL_USE_TLS = config('EMAIL_USE_TLS', cast=bool, default=True)
EMAIL_HOST_USER = config('EMAIL_HOST_USER')
EMAIL_HOST_PASSWORD = config('EMAIL_HOST_PASSWORD')
# Redis cache
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.redis.RedisCache',
'LOCATION': config('REDIS_URL', default='redis://127.0.0.1:6379/1'),
}
}
FastAPI Application
from fastapi import FastAPI, Depends
from dotzen import ConfigBuilder
# Build configuration at startup
config = (ConfigBuilder()
.add_environment()
.add_dotenv()
.add_json('config.json')
.build())
app = FastAPI(
title=config('APP_NAME', default='My API'),
debug=config.get_bool('DEBUG', default=False),
version=config('VERSION', default='1.1.0'),
)
# Dependency injection
def get_database_url():
return config('DATABASE_URL')
@app.get("/health")
async def health_check():
return {
"status": "healthy",
"environment": config('ENVIRONMENT', default='development'),
"version": config('VERSION', default='1.1.0'),
}
@app.get("/config")
async def get_config_info():
return {
"debug_mode": config.get_bool('DEBUG', False),
"max_connections": config.get_int('MAX_CONNECTIONS', 100),
"timeout": config.get_float('TIMEOUT', 30.0),
}
Flask Application
from flask import Flask
from dotzen import config
app = Flask(__name__)
# Configure Flask from DotZen
app.config['DEBUG'] = config('DEBUG', cast=bool, default=False)
app.config['SECRET_KEY'] = config('SECRET_KEY')
app.config['SQLALCHEMY_DATABASE_URI'] = config('DATABASE_URL')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# Custom settings
app.config['MAX_CONTENT_LENGTH'] = config('MAX_UPLOAD_SIZE', cast=int, default=16 * 1024 * 1024)
app.config['UPLOAD_FOLDER'] = config('UPLOAD_FOLDER', default='uploads')
@app.route('/config')
def show_config():
return {
'debug': app.config['DEBUG'],
'environment': config('ENVIRONMENT', default='development'),
}
Microservices with Docker Secrets
# docker-compose.yml provides secrets in /run/secrets/
from dotzen import ConfigBuilder
config = (ConfigBuilder()
.add_environment()
.add_secrets('/run/secrets') # Docker secrets
.add_dotenv('.env')
.build())
# Access secrets seamlessly
DB_PASSWORD = config('db_password')
API_KEY = config('api_key')
JWT_SECRET = config('jwt_secret')
# Regular config
SERVICE_NAME = config('SERVICE_NAME', default='my-service')
PORT = config.get_int('PORT', default=8000)
Multi-Environment Configuration
import os
from dotzen import ConfigBuilder
# Determine environment
ENVIRONMENT = os.getenv('ENVIRONMENT', 'development')
# Load environment-specific configuration
config = (ConfigBuilder()
.add_environment()
.add_dotenv(f'.env.{ENVIRONMENT}') # .env.development, .env.production
.add_json(f'config.{ENVIRONMENT}.json')
.add_dotenv('.env.local', override=True) # Local overrides
.build())
# Configuration adapts to environment automatically
DEBUG = config.get_bool('DEBUG')
DATABASE_URL = config('DATABASE_URL')
LOG_LEVEL = config('LOG_LEVEL', default='INFO')
Pydantic Integration
from pydantic import BaseModel, Field
from dotzen importfig
class DatabaseSettings(BaseModel):
host: str = Field(default_factory=lambda: config('DB_HOST', default='localhost'))
port: int = Field(default_factory=lambda: config('DB_PORT', cast=int, default=5432))
user: str = Field(default_factory=lambda: config('DB_USER'))
password: str = Field(default_factory=lambda: config('DB_PASSWORD'))
database: str = Field(default_factory=lambda: config('DB_NAME'))
class AppSettings(BaseModel):
debug: bool = Field(default_factory=lambda: config('DEBUG', cast=bool, default=False))
secret_key: str = Field(default_factory=lambda: config('SECRET_KEY'))
database: DatabaseSettings = Field(default_factory=DatabaseSettings)
allowed_hosts: list = Field(default_factory=lambda: config('ALLOWED_HOSTS', cast=list, default=[]))
# Create settings instance
settings = AppSettings()
๐๏ธ Architecture & Design Patterns
DotZen is built on proven Gang of Four design patterns:
Design Patterns Used
| Pattern | Purpose | Implementation |
|---|---|---|
| Strategy | Pluggable config sources | ConfigSource abstract base class |
| Chain of Responsibility | Priority-based resolution | ConfigChain tries sources in order |
| Builder | Fluent construction | ConfigBuilder for chainable API |
| Factory | Auto-detection | ConfigFactory.auto_config() |
| Singleton | Global instance | ConfigSingleton for app-wide access |
| Facade | Simple interface | Config class hides complexity |
| Null Object | Graceful defaults | NullSource for missing configs |
| Sentinel | Undefined values | UNDEFINED marker object |
Architecture Diagram
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ConfigBuilder โ
โ (Builder Pattern) โ
โโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ builds
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Config โ
โ (Facade Pattern) โ
โโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ uses
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ConfigChain โ
โ (Chain of Responsibility Pattern) โ
โโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ coordinates
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ConfigSource (Strategy) โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ EnvironmentSource โ DotEnvSource โ JsonSourceโ โ
โ โ YamlSource โ SecretSource โ AwsSecretsSource โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
๐ Comparison with Alternatives
Feature Comparison Matrix
| Feature | DotZen | python-decouple | pydantic-settings | dynaconf | python-dotenv |
|---|---|---|---|---|---|
| Type Safety | โ Full | โ ๏ธ Basic | โ Full | โ Full | โ None |
| Cloud Secrets | โ Native | โ No | โ ๏ธ Limited | โ Yes | โ No |
| Fluent API | โ Yes | โ No | โ No | โ ๏ธ Limited | โ No |
| Validation | โ Built-in | โ ๏ธ Basic | โ Pydantic | โ Yes | โ No |
| Multi-Source | โ Yes | โ ๏ธ Limited | โ ๏ธ Limited | โ Yes | โ Env only |
| Zero Core Deps | โ Yes | โ Yes | โ No | โ No | โ Yes |
| Design Patterns | โ 8 patterns | โ None | โ ๏ธ Some | โ ๏ธ Some | โ None |
| Docker Secrets | โ Native | โ No | โ No | โ No | โ No |
| Auto-Detection | โ Yes | โ No | โ ๏ธ Limited | โ Yes | โ No |
| Custom Sources | โ Easy | โ No | โ ๏ธ Complex | โ ๏ธ Complex | โ No |
When to Use DotZen
Perfect for:
- ๐ Modern cloud-native applications
- ๐ข Microservices architectures
- ๐ฆ 12-factor app compliance
- ๐ Applications requiring cloud secrets
- ๐ฅ Teams valuing clean, maintainable code
- ๐ฏ Projects needing validated configuration
Consider alternatives if:
- You only need basic
.envfile parsing โpython-dotenv - You're heavily invested in Pydantic โ
pydantic-settings - You need legacy Python 2.7 support โ
python-decouple
๐ Documentation
Core Concepts
Configuration Sources
from dotzen import ConfigBuilder
# Available sources
builder = ConfigBuilder()
builder.add_environment() # Environment variables
builder.add_environment('APP_') # With prefix
builder.add_dotenv('.env') # .env file
builder.add_json('config.json') # JSON file
builder.add_yaml('config.yaml') # YAML file (requires dotzen[yaml])
builder.add_toml('config.toml') # TOML file (requires dotzen[toml])
builder.add_secrets('/run/secrets') # Docker secrets
builder.add_aws_secrets('prod/myapp') # AWS Secrets Manager
builder.add_gcp_secrets('projects/x') # GCP Secret Manager
builder.add_azure_keyvault('url') # Azure Key Vault
builder.add_vault_secrets('path') # HashiCorp Vault
Type Casting
# Automatic casting
value = config.get('KEY', cast=int)
value = config.get('KEY', cast=bool)
value = config.get('KEY', cast=float)
value = config.get('KEY', cast=list)
# Convenience methods
value = config.get_int('KEY', default=0)
value = config.get_bool('KEY', default=False)
value = config.get_float('KEY', default=0.0)
value = config.get_list('KEY', default=[])
# Custom casting
def parse_json(value):
import json
return json.loads(value)
value = config.get('JSON_DATA', cast=parse_json)
Error Handling
from dotzen import UndefinedValueError, ValidationError, ConfigError
try:
api_key = config('API_KEY')
except UndefinedValueError:
print("API_KEY not found in configuration")
try:
port = config.get_int('PORT')
except ValidationError as e:
print(f"Invalid PORT value: {e}")
# Or use defaults
api_key = config('API_KEY', default='dev-key')
port = config.get_int('PORT', default=8000)
Advanced Usage
Custom Configuration Sources
from dotzen import ConfigSource
class RedisSource(ConfigSource):
"""Load configuration from Redis"""
def __init__(self, redis_client, prefix='config:'):
self.redis = redis_client
self.prefix = prefix
def load(self) -> Dict[str, str]:
keys = self.redis.keys(f'{self.prefix}*')
data = {}
for key in keys:
clean_key = key.decode().replace(self.prefix, '')
data[clean_key] = self.redis.get(key).decode()
return data
def exists(self) -> bool:
return self.redis.ping()
# Use custom source
import redis
redis_client = redis.Redis(host='localhost', port=6379)
config = (ConfigBuilder()
.add_custom_source(RedisSource(redis_client))
.build())
Custom Validators
from dotzen import ConfigBuilder, ValidationError
def email_validator(key: str, value: str):
"""Validate email format"""
if '@' not in value:
raise ValidationError(f"{key} must be a valid email")
def port_validator(key: str, value: int):
"""Validate port number"""
if not (1024 <= value <= 65535):
raise ValidationError(f"{key} must be between 1024 and 65535")
config = (ConfigBuilder()
.add_environment()
.with_validator(email_validator)
.with_type('PORT', int)
.with_validator(port_validator)
.build())
Testing Configuration
import pytest
from dotzen import ConfigBuilder, ConfigSingleton
def test_config():
"""Test configuration loading"""
# Reset singleton for testing
ConfigSingleton.reset()
# Create test config
config = (ConfigBuilder()
.add_environment()
.build())
# Test values
assert config.get_bool('DEBUG', False) == False
assert config.get_int('PORT', 8000) == 8000
@pytest.fixture
def test_config():
"""Fixture providing test configuration"""
ConfigSingleton.reset()
return (ConfigBuilder()
.add_dotenv('.env.test')
.build())
๐ง Installation Extras
Available Extras
# Cloud providers
pip install dotzen[aws] # AWS Secrets Manager (boto3)
pip install dotzen[gcp] # Google Cloud Secret Manager
pip install dotzen[azure] # Azure Key Vault
pip install dotzen[vault] # HashiCorp Vault
pip install dotzen[cloud] # All cloud providers
# File formats
pip install dotzen[yaml] # YAML support (PyYAML)
pip install dotzen[toml] # TOML support
pip install dotzen[json5] # JSON5 support
pip install dotzen[formats] # All formats
# Development
pip install dotzen[dev] # Testing and dev tools
pip install dotzen[docs] # Documentation building
pip install dotzen[test] # Testing with cloud mocks
# Everything
pip install dotzen[all] # All features
๐ค Contributing
We welcome contributions! Here's how to get started:
Development Setup
# Clone the repository
git clone https://github.com/carrington-dev/dotzen.git
cd dotzen
# Create virtual environment
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
# Install development dependencies
pip install -e ".[dev,test,all]"
# Install pre-commit hooks
pre-commit install
# Run tests
pytest
# Run type checking
mypy dotzen
# Format code
black dotzen tests
ruff check dotzen tests
Running Tests
# Run all tests
pytest
# Run with coverage
pytest --cov=dotzen --cov-report=html
# Run specific test file
pytest tests/test_dotzen.py
# Run with verbose output
pytest -v
# Run only fast tests (skip cloud integration)
pytest -m "not integration"
Pull Request Process
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes
- Add tests for new functionality
- Ensure all tests pass (
pytest) - Format code (
black .andruff check --fix .) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Please use our PR templates for:
- ๐ Bug fixes
- โจ New features
- ๐ Documentation
๐ License
DotZen is released under the MIT License. See LICENSE for details.
MIT License
Copyright (c) 2025 Carrington Muleya
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
๐ Acknowledgments
- Inspired by the 12-factor app methodology
- Built with insights from "Design Patterns" by Gang of Four
- Thanks to all contributors
๐ Project Stats
๐ Links & Resources
- ๐ฆ PyPI Package: pypi.org/project/dotzen
- ๐ Documentation: dotzen.readthedocs.io
- ๐ป Source Code: github.com/carrington-dev/dotzen
- ๐ Issue Tracker: github.com/carrington-dev/dotzen/issues
- ๐ฌ Discussions: github.com/carrington-dev/dotzen/discussions
- ๐ Changelog: CHANGELOG.md
- ๐ค Contributing: CONTRIBUTING.md
๐ฌ Community & Support
- ๐ Star this repository if you find it helpful
- ๐ Report bugs via GitHub Issues
- ๐ก Request features in Discussions
- ๐ง Contact: carrington.muleya@outlook.com
- ๐ฆ Twitter: @carrington_dev (if applicable)
Made with ๐ง and โค๏ธ by Carrington Muleya
Find your configuration zen. Try DotZen today!
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file dotzen-1.1.0.tar.gz.
File metadata
- Download URL: dotzen-1.1.0.tar.gz
- Upload date:
- Size: 39.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.19
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ff49dfb969c9ff91231982feb6117e859cd17187e2d5f6a50960d69bce030c0d
|
|
| MD5 |
4b99419ba89c62214957ef1e53fb7094
|
|
| BLAKE2b-256 |
9018ecc3e188a23480ec48241023cc4d0037de3ae56bebaa9ddf2cdba81f9457
|
File details
Details for the file dotzen-1.1.0-py3-none-any.whl.
File metadata
- Download URL: dotzen-1.1.0-py3-none-any.whl
- Upload date:
- Size: 18.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.19
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5c0d175c810eaa6c4e45930b4e6e9b2cab83e1d8b0ba7852b025fcf37bcf3bad
|
|
| MD5 |
6b7675d41e7b7f5d08cc490a9511a0ad
|
|
| BLAKE2b-256 |
486325b65e2db1e1783c17ea53548171789b8d9637677331735ba8e4a4a0c4e2
|