Skip to content

christophevg/clevis

Repository files navigation

Clevis

PyPI Python CI Coverage License Agentic PACKAGE.md

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 .toml files
  • Env vars${VAR} interpolation (with envtoml/tomlev)
  • CLI generation — Auto-generate argparse from dataclass
  • Layered config — User config < project config < CLI args

About the Name

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.

Quick Start

# 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")

Installation

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]

Usage

Define Your Config

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)

Load Configuration

from clevis import get_config

# Load from ~/.myapp.toml and ./myapp.toml
config = get_config(AppConfig, name="myapp")

Configuration layers (lowest to highest priority):

  1. Dataclass defaults
  2. User-level TOML~/.{name}.toml
  3. Project-level TOML./{name}.toml
  4. CLI arguments--database-host, --debug

TOML Files

Create myapp.toml:

name = "Production App"
debug = true

[database]
host = "db.example.com"
port = 5432

With env var support (clevis[envtoml] or clevis[tomlev]):

[database]
password = "${DB_PASSWORD}"        # envtoml
host = "${DB_HOST|localhost}"       # tomlev (with default)

CLI Arguments

Clevis auto-generates CLI arguments:

python app.py --database-host localhost
python app.py --database-port 5432
python app.py --debug

Nested dataclasses become dashed arguments: database.host--database-host

Testing

# Run tests
make test

# Run with coverage
make test-cov

Library Integration

When 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"

Why cli=False?

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

API Reference

get_config(data_class, name="project", user=True, project=True, cli=True, args=None)

Load configuration from TOML files and CLI arguments.

Parameters:

  • data_class — The dataclass type to populate
  • name — Config file name (without .toml)
  • user — Load user-level config (~/.{name}.toml)
  • project — Load project-level config (./{name}.toml)
  • cli — Parse CLI arguments from sys.argv (default: True)
  • args — CLI arguments (defaults to sys.argv[1:] when cli=True)

Returns: Instance of the dataclass with merged configuration

Raises:

  • ConfigError — Missing required fields or wrong types
  • ImportError — No TOML parser available

Error Messages

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)

======================================================================

Acknowledgments

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

License

MIT

About

Configuration management for Python projects with dataclass-based schemas

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors