envsmith
A modern, production-ready solution for loading, validating, and managing environment variables in Python using a schema-first approach.
🚀 How It Works
envsmith is a Python package that provides a robust way to manage environment variables with the following workflow:
-
Schema Definition: You define a YAML or JSON schema that specifies:
- Which environment variables are required
- What data types they should have
- Default values for optional variables
- Validation rules
-
Environment Loading: The package loads variables from multiple sources:
.envfiles- System environment variables
- Custom dictionaries
- Priority: System > .env file > defaults
-
Validation & Type Casting: Each variable is validated against the schema:
- Required variables are checked for presence
- Values are cast to the specified types (str, int, float, bool)
- Helpful error messages for missing/invalid variables
-
Integration: Seamlessly integrates with FastAPI and Django applications
🔧 Technical Architecture
Core Processing Pipeline
class EnvSmith(dict):
def __init__(self, schema_path, env_file=".env", env=None):
# Step 1: Load .env file into environment
load_dotenv(env_file)
# Step 2: Parse schema file (YAML/JSON)
self.schema = load_schema(schema_path)
# Step 3: Get environment (system + .env merged)
self.env = env or dict(os.environ)
# Step 4: Validate and cast types
validated = validate_env(self.env, self.schema)
# Step 5: Update the dictionary
self.update(validated)
Data Flow & Priority System
- Schema Loading: YAML/JSON → Python dict with validation rules
- Environment Merging: System env + .env files + custom dicts
- Priority Chain: System > .env > Schema defaults
- Type Casting: Automatic conversion (str, int, float, bool)
- Validation: Required checks + type validation + error collection
Key Components
core.py: Main engine that orchestrates the entire processschema_loader.py: Parses YAML/JSON schema filesvalidation.py: Type casting and validation logicintegrations/: Framework-specific adapters (FastAPI, Django)cli.py: Command-line interface for common operations
📊 Comparison with Other Tools
| Feature | envsmith | python-dotenv | pydantic-settings | dynaconf | python-decouple |
|---|---|---|---|---|---|
| Schema Validation | ✅ YAML/JSON | ❌ None | ✅ Pydantic models | ✅ TOML/YAML | ❌ None |
| Type Casting | ✅ Automatic | ❌ Strings only | ✅ Pydantic types | ✅ Basic | ❌ Strings only |
| Framework Integration | ✅ FastAPI/Django | ❌ None | ✅ Pydantic ecosystem | ✅ Multiple | ❌ None |
| CLI Tools | ✅ Built-in | ❌ None | ❌ None | ✅ Rich CLI | ❌ None |
| Priority System | ✅ System > .env > defaults | ❌ .env only | ✅ Environment > .env | ✅ Multiple sources | ✅ .env > env |
| Error Handling | ✅ Comprehensive | ❌ Basic | ✅ Pydantic errors | ✅ Good | ❌ Basic |
| Production Ready | ✅ Logging, testing | ⚠️ Basic | ✅ Enterprise | ✅ Enterprise | ⚠️ Basic |
Why Choose envsmith?
vs python-dotenv
- python-dotenv: Only loads
.envfiles, no validation, no type casting - envsmith: Full validation, type safety, multiple sources, framework integration
vs pydantic-settings
- pydantic-settings: Requires Pydantic knowledge, more complex setup
- envsmith: Simple YAML/JSON schemas, easier to understand and maintain
vs dynaconf
- dynaconf: More complex, multiple config formats, overkill for simple apps
- envsmith: Focused on environment variables, simple and lightweight
vs python-decouple
- python-decouple: Basic .env loading, no validation, no type safety
- envsmith: Full validation suite, type casting, production features
Performance Characteristics
- Startup Time: Fast - single pass validation
- Memory Usage: Minimal - only stores validated variables
- Runtime Overhead: Zero - all processing happens at initialization
- Error Reporting: Comprehensive - all issues reported at once
Use Cases Where envsmith Excels
✅ Web Applications: FastAPI, Django, Flask ✅ Microservices: Environment-based configuration ✅ Docker Containers: Environment variable validation ✅ CI/CD Pipelines: Configuration validation ✅ Team Development: Clear schema documentation ✅ Production Deployments: Early error detection
✨ Features
- Schema-First: Define your environment structure in YAML/JSON
- Multiple Sources: Load from
.env, system, or custom dicts - Type Safety: Automatic type casting and validation
- Framework Integration: FastAPI and Django support
- CLI Tools: Command-line interface for common tasks
- Secrets Management: Mock interface for external secret providers
- Production Ready: Logging, error handling, and comprehensive testing
📦 Installation
pip install envsmith
With optional extras:
pip install envsmith[fastapi,django]
🎯 Quick Start
1. Create a Schema
Create a schema.yaml file:
DATABASE_URL:
type: str
required: true
description: "Database connection string"
SECRET_KEY:
type: str
required: true
description: "Application secret key"
DEBUG:
type: bool
default: false
description: "Debug mode"
PORT:
type: int
default: 8000
description: "Server port"
API_TIMEOUT:
type: float
default: 30.0
description: "API timeout in seconds"
2. Create Environment File
Create a .env file:
DATABASE_URL=postgresql://user:pass@localhost:5432/mydb
SECRET_KEY=your-super-secret-key-here
DEBUG=true
PORT=8080
API_TIMEOUT=45.0
3. Use in Python
from envsmith import EnvSmith
# Load with schema validation
settings = EnvSmith(schema_path="schema.yaml", env_file=".env")
# Access validated variables
print(settings["DATABASE_URL"]) # postgresql://user:pass@localhost:5432/mydb
print(settings["DEBUG"]) # True (bool)
print(settings["PORT"]) # 8080 (int)
print(settings["API_TIMEOUT"]) # 45.0 (float)
# Get with default fallback
print(settings.get("NONEXISTENT", "default_value"))
🛠️ CLI Usage
Initialize Project
Create .env and schema.yaml files:
python3 -m envsmith init
Validate Environment
Check if your .env file matches the schema:
python3 -m envsmith validate
Export Environment
Export validated variables in different formats:
# Export as JSON
python3 -m envsmith export --format json
# Export as YAML
python3 -m envsmith export --format yaml
🔌 Framework Integrations
FastAPI Integration
from fastapi import FastAPI, Depends
from envsmith.integrations.fastapi import get_settings
app = FastAPI()
@app.get("/config")
def get_config(settings = Depends(get_settings)):
return {
"database_url": settings["DATABASE_URL"],
"debug": settings["DEBUG"],
"port": settings["PORT"]
}
@app.get("/health")
def health_check(settings = Depends(get_settings)):
return {
"status": "healthy",
"environment": settings.get("ENV", "development")
}
Django Integration
In your settings.py:
from envsmith.integrations.django import load_envsmith
# Load environment variables with schema validation
load_envsmith(schema_path="schema.yaml")
# Now you can use them directly
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': DATABASE_NAME,
'USER': DATABASE_USER,
'PASSWORD': DATABASE_PASSWORD,
'HOST': DATABASE_HOST,
'PORT': DATABASE_PORT,
}
}
SECRET_KEY = SECRET_KEY
DEBUG = DEBUG
ALLOWED_HOSTS = ALLOWED_HOSTS.split(',') if ALLOWED_HOSTS else []
🔐 Secrets Management
For production environments, you can integrate with external secret providers:
from envsmith.secrets import SecretProvider
# Mock interface (replace with actual AWS, Vault, etc.)
secrets = SecretProvider()
# Get secret from external provider
api_key = secrets.get_secret("API_KEY")
# Fallback to local secret
fallback_key = secrets.get_local_secret("API_KEY")
📋 Schema Reference
Supported Types
- str: String values
- int: Integer values
- float: Floating-point values
- bool: Boolean values (accepts: true/false, yes/no, 1/0, on/off)
Schema Structure
VARIABLE_NAME:
type: str|int|float|bool
required: true|false
default: "default_value"
description: "Human-readable description"
Example Schema
# Database Configuration
DATABASE_URL:
type: str
required: true
description: "PostgreSQL connection string"
DATABASE_POOL_SIZE:
type: int
default: 10
description: "Database connection pool size"
# Application Settings
DEBUG:
type: bool
default: false
description: "Enable debug mode"
LOG_LEVEL:
type: str
default: "INFO"
description: "Logging level"
# API Configuration
API_TIMEOUT:
type: float
default: 30.0
description: "API request timeout in seconds"
MAX_REQUESTS:
type: int
default: 1000
description: "Maximum concurrent requests"
🧪 Testing
Run the test suite:
# Install test dependencies
pip install pytest pytest-cov
# Run tests with coverage
python3 -m pytest --cov=envsmith
# Run specific test file
python3 -m pytest tests/test_core.py
🚀 Development
Project Structure
envsmith/
├── envsmith/ # Main package
│ ├── __init__.py # Package initialization
│ ├── core.py # Core loader and validation
│ ├── cli.py # Command-line interface
│ ├── validation.py # Schema validation logic
│ ├── schema_loader.py # YAML/JSON schema loading
│ ├── secrets.py # Secrets management
│ ├── _types.py # Type definitions
│ └── integrations/ # Framework integrations
│ ├── fastapi.py # FastAPI integration
│ └── django.py # Django integration
├── tests/ # Test suite
├── examples/ # Usage examples
└── docs/ # Documentation
Adding New Features
- Type Support: Add new types in
validation.py - Framework Integration: Create new integration modules
- CLI Commands: Extend
cli.pywith new subcommands - Secrets Providers: Implement actual secret provider interfaces
📝 Examples
Check the examples/ directory for complete working examples:
demo_fastapi.py- FastAPI application with envsmithdemo_django.py- Django settings with envsmithenv.example- Example environment file
🤝 Contributing
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests for new functionality
- Ensure all tests pass
- Submit a pull request
Development Setup
# Clone the repository
git clone https://github.com/PeymanSohi/envsmith.git
cd envsmith
# Create virtual environment
python3 -m venv .venv
source .venv/bin/activate # On Windows: .venv\Scripts\activate
# Install in development mode
pip install -e ".[fastapi,django]"
# Install test dependencies
pip install pytest pytest-cov
# Run tests
python3 -m pytest
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
🆘 Support
- Issues: GitHub Issues
- Documentation: README
- Examples: Check the
examples/directory
🔄 Changelog
See CHANGELOG.md for a detailed history of changes and releases.
Metadata
Release files for envsmith 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| envsmith-0.1.0.tar.gz | 16.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| envsmith-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 29.7 kB
Release files / envsmith-0.1.0.tar.gz
| Download URL | envsmith-0.1.0.tar.gz |
|---|---|
| Size | 16.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
7da6d8e50bde173156d4d55e4e83ceb5b3ff4a0f0c5e334021ea4421b7d6f108
|
|
BLAKE2b-256 checksum How to use checksums |
afdd9f7841e9b8268bc69d82b3d6e4eda5035e827000dc701edb5f28381e0f14
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.12.9
|
Release files / envsmith-0.1.0-py3-none-any.whl
| Download URL | envsmith-0.1.0-py3-none-any.whl |
|---|---|
| Size | 12.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
817ad2255819c5c27a935f215391df3182c0a11f06185b108da6b20c19452121
|
|
BLAKE2b-256 checksum How to use checksums |
1588197e895ca84cd632a8df67320cc423d750abde9eb3fafc2d6bbcc93a5c9a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.12.9
|