Schema-based environment variable management for Python projects
Project description
epicenv
Schema-based environment variable management for Python projects. Define your environment variables in pyproject.toml (or a dedicated .env.toml) with types, defaults, and help text. Use epicenv to create, validate, and manage .env files.
Table of Contents
- Installation
- Quick Start
- Why epicenv?
- CLI Commands
- Schema Basics
- Built-in Initializers
- Framework Examples
- Validation
- Documentation
Installation
# Run without installing
uvx epicenv create
# Or install as a dependency
uv add epicenv
# For Django projects (adds dj-database-url, dj-email-url support)
uv add epicenv[django]
Quick Start
1. Define your schema in pyproject.toml:
[tool.epicenv.variables]
SECRET_KEY = {
type = "str",
required = true,
help_text = "Secret key for cryptographic signing",
initial_func = "epicenv.initializers.url_safe_password"
}
DEBUG = { type = "bool", default = false, initial = "on" }
DATABASE_URL = { type = "str", default = "sqlite:///db.sqlite3" }
2. Generate your .env file:
uvx epicenv create
3. Use in your code:
from epicenv import Env
env = Env()
env.read_env()
SECRET_KEY = env.str("SECRET_KEY")
DEBUG = env.bool("DEBUG", default=False)
Why epicenv?
Traditional .env.example workflow |
With epicenv |
|---|---|
Copy .env.example to .env |
Run epicenv create |
| Manually generate secrets | Auto-generated via initializers |
| Templates get out of date | Schema is the single source of truth |
| Runtime errors from missing vars | epicenv validate catches mistakes early |
| No documentation for variables | Help text in schema, shown in .env |
CLI Commands
epicenv create # Create .env from schema
epicenv create --path config/.env # Create at specific path
epicenv create --no-backup # Don't backup existing file
epicenv diff # Compare .env with schema
epicenv validate # Validate environment against schema
epicenv validate --strict # Exit with error if validation fails
Schema Basics
Define variables in [tool.epicenv.variables]:
[tool.epicenv.variables]
MY_VAR = {
type = "str", # Required: str, bool, int, list, url, json, etc.
required = true, # Is this required? (default: true if no default)
default = "value", # Default for .env generation
help_text = "Description", # Shown in generated .env
initial = "value", # Static initial value
initial_func = "module.fn" # Dynamic initial value generator
}
Supported types: str, bool, int, float, list, dict, json, url, uuid, path, date, datetime, log_level, and Django types (dj_db_url, dj_email_url, dj_cache_url).
Schema location
For projects with many variables, keep pyproject.toml tidy by moving the schema into a dedicated .env.toml file next to pyproject.toml. It's auto-discovered — no pyproject.toml change needed:
# .env.toml
[variables]
DEBUG = { type = "bool", default = false, initial = "on" }
# Table form is nice for variables with several fields:
[variables.SECRET_KEY]
type = "str"
required = true
help_text = "Secret key for cryptographic signing"
initial_func = "epicenv.initializers.url_safe_password"
Or point at a custom path:
# pyproject.toml
[tool.epicenv]
config_file = "config/env-schema.toml"
See Schema Reference for complete field documentation and discovery rules.
Built-in Initializers
url_safe_password
Generate URL-safe random passwords:
SECRET_KEY = {
type = "str",
initial_func = "epicenv.initializers.url_safe_password"
}
# Custom length (default: 50)
API_TOKEN = {
type = "str",
initial_func = "epicenv.initializers.url_safe_password",
kwargs = { length = 32 }
}
1Password
Fetch secrets from 1Password CLI during .env generation:
STRIPE_API_KEY = {
type = "str",
initial_func = "epicenv.initializers.onepassword",
args = ["op://Production/Stripe/api_key"]
}
Requires 1Password CLI installed and signed in. Falls back to placeholder if unavailable.
See 1Password Integration for setup and troubleshooting.
Custom Initializers
Use any Python callable:
SECRET_KEY = { type = "str", initial_func = "secrets.token_urlsafe" }
DJANGO_KEY = { type = "str", initial_func = "django.core.management.utils.get_random_secret_key" }
CUSTOM = { type = "str", initial_func = "myapp.utils.generate_key" }
Framework Examples
Django
# pyproject.toml
[tool.epicenv.variables]
SECRET_KEY = { type = "str", required = true, initial_func = "django.core.management.utils.get_random_secret_key" }
DEBUG = { type = "bool", default = false, initial = "on" }
DATABASE_URL = { type = "dj_db_url", default = "sqlite:///db.sqlite3" }
# settings.py
from epicenv import Env
env = Env()
env.read_env()
SECRET_KEY = env.str("SECRET_KEY")
DEBUG = env.bool("DEBUG", default=False)
DATABASES = {"default": env.dj_db_url("DATABASE_URL", default="sqlite:///db.sqlite3")}
See Django Integration for complete setup including email and cache URLs.
FastAPI / Flask
# pyproject.toml
[tool.epicenv.variables]
APP_NAME = { type = "str", default = "My API" }
API_HOST = { type = "str", default = "0.0.0.0" }
API_PORT = { type = "int", default = 8000 }
DATABASE_URL = { type = "url", required = true }
LOG_LEVEL = { type = "log_level", default = "INFO" }
# config.py
from epicenv import Env
env = Env()
env.read_env()
APP_NAME = env.str("APP_NAME", default="My API")
DATABASE_URL = env.url("DATABASE_URL")
LOG_LEVEL = env.log_level("LOG_LEVEL", default="INFO")
Validation
epicenv validates that variables used in code are defined in your schema. Control with EPICENV_VALIDATE:
| Mode | Behavior |
|---|---|
auto (default) |
Validate when DEBUG=true |
strict |
Always validate, raise errors |
warn |
Always validate, warn only |
off |
Disable validation |
EPICENV_VALIDATE=strict python app.py # Always validate
Documentation
- Schema Reference - Complete field types and options
- 1Password Integration - Setup and troubleshooting
- Django Integration - Django-specific features and legacy commands
Contributing
Contributions are welcome! Please open an issue or submit a pull request.
Acknowledgments
epicenv is built on top of environs, which provides the core environment variable parsing functionality.
License
MIT License
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 epicenv-1.3.1.tar.gz.
File metadata
- Download URL: epicenv-1.3.1.tar.gz
- Upload date:
- Size: 52.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.14 {"installer":{"name":"uv","version":"0.11.14","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9f3f92c67c6d5d3e93509dd895844e5a727ea398654c2c2dfa44ffcf52fe256d
|
|
| MD5 |
281024e818c25d5b576de5a5517210ad
|
|
| BLAKE2b-256 |
a2c61a0f8be2076aea7e95031319e892dc7bd0b2ef4bca13ceaa6b61dfe8e5c3
|
File details
Details for the file epicenv-1.3.1-py3-none-any.whl.
File metadata
- Download URL: epicenv-1.3.1-py3-none-any.whl
- Upload date:
- Size: 20.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.14 {"installer":{"name":"uv","version":"0.11.14","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bc89d2ab6005f2d04d4fe9b8402b4431c6c5966e82514f3c2defa9c386a53bd6
|
|
| MD5 |
38d32483aa1c2c1bdabbd0613c8318e7
|
|
| BLAKE2b-256 |
f39d1537d20c566a49fee4c0d29bf8940101bd96f0ce54d9c08ddff881964ae3
|