Configuration management for Python projects with dataclass-based schemas
Clevis provides type-safe configuration management for Python applications:
- Dataclass schemas — Define config structure with Python dataclasses
- TOML support — Load from
.tomlfiles - Env vars —
${VAR}interpolation (with envtoml/tomlev) - CLI generation — Auto-generate argparse from dataclass
- Layered config — User config < project config < CLI args
A clevis is a U-shaped mechanical fastener that connects components while allowing pivoting. It's used in everything from agricultural equipment to aerospace control systems — a simple, robust connector that provides flexibility without compromising strength.
This library follows the same principle: it connects multiple configuration sources (TOML files, environment variables, CLI arguments) into a single, cohesive interface. Just as a mechanical clevis allows articulation, Clevis allows your configuration to flex and adapt — user-level defaults, project-level settings, and runtime overrides all pivot around a single dataclass schema.
# Install (Python 3.11+)
pip install clevis
# Or with env var support
pip install clevis[envtoml]from dataclasses import dataclass
from clevis import get_config
@dataclass
class Config:
name: str = "MyApp"
debug: bool = False
config = get_config(Config, name="app")Choose your TOML parser based on needs:
| Extra | Features | Use When |
|---|---|---|
| (none) | Stdlib tomllib |
Python 3.11+, minimal deps |
tomli |
Pure Python TOML | Python 3.10 compatibility |
envtoml |
${VAR} interpolation |
Environment-based config |
tomlev |
${VAR|default} syntax |
Env vars with defaults |
# Python 3.11+ - no extras needed
pip install clevis
# Python 3.10
pip install clevis[tomli]
# Environment variable support
pip install clevis[envtoml]from dataclasses import dataclass, field
@dataclass
class DatabaseConfig:
host: str = "localhost"
port: int = 5432
user: str | None = None
password: str | None = None
@dataclass
class AppConfig:
name: str = "MyApp"
debug: bool = False
database: DatabaseConfig = field(default_factory=DatabaseConfig)from clevis import get_config
# Load from ~/.myapp.toml and ./myapp.toml
config = get_config(AppConfig, name="myapp")Configuration layers (lowest to highest priority):
- Dataclass defaults
- User-level TOML —
~/.{name}.toml - Project-level TOML —
./{name}.toml - CLI arguments —
--database-host,--debug
Create myapp.toml:
name = "Production App"
debug = true
[database]
host = "db.example.com"
port = 5432With env var support (clevis[envtoml] or clevis[tomlev]):
[database]
password = "${DB_PASSWORD}" # envtoml
host = "${DB_HOST|localhost}" # tomlev (with default)Clevis auto-generates CLI arguments:
python app.py --database-host localhost
python app.py --database-port 5432
python app.py --debugNested dataclasses become dashed arguments: database.host → --database-host
# Run tests
make test
# Run with coverage
make test-covWhen using Clevis as a library (not a CLI app), you can disable CLI parsing:
from clevis import get_config
# Library mode - skip sys.argv parsing
config = get_config(Config, name="myapp", cli=False)
# Programmatic control with explicit args
config = get_config(Config, name="myapp", cli=False, args=["--debug"])
# Testing
def test_my_config():
config = get_config(TestConfig, cli=False, user=False, project=False)
assert config.name == "default"Using cli=False instead of args=[]:
- Clear Intent: Explicitly signals library usage
- Better Errors: Error messages omit CLI suggestions when not applicable
- No Overhead: Skips argparse parser creation entirely
Load configuration from TOML files and CLI arguments.
Parameters:
data_class— The dataclass type to populatename— Config file name (without.toml)user— Load user-level config (~/.{name}.toml)project— Load project-level config (./{name}.toml)cli— Parse CLI arguments fromsys.argv(default:True)args— CLI arguments (defaults tosys.argv[1:]whencli=True)
Returns: Instance of the dataclass with merged configuration
Raises:
ConfigError— Missing required fields or wrong typesImportError— No TOML parser available
Clevis provides helpful, actionable errors:
When using CLI (default):
======================================================================
Configuration Error
======================================================================
Field: database.host
Issue: Required field has no value
Provide this value in one of these ways:
1. Project config: ./project.toml
[database]
host = "your_value"
2. User config: ~/.project.toml
(same format as above)
3. CLI argument: --database-host <value>
======================================================================
When using library mode (cli=False):
======================================================================
Configuration Error
======================================================================
Field: database.host
Issue: Required field has no value
Provide this value in one of these ways:
1. Project config: ./project.toml
[database]
host = "your_value"
2. User config: ~/.project.toml
(same format as above)
======================================================================
Clevis builds on excellent work from the Python community:
- tomllib — Python 3.11+ stdlib
- tomli — Pure Python TOML 1.0
- envtoml — Env var interpolation
- tomlev — Env vars with defaults
- dacite — Dict-to-dataclass conversion
MIT