Tomlev
TomlEv - Open-source Python framework to easy manage environment variables
Install / Use
/learn @thesimj/TomlevREADME
Motivation
TomlEv is a lightweight Python framework designed to simplify environment variable management using TOML configuration files with type-safe configuration models. It allows you to:
- Type-safe configuration: Define configuration schemas using Python classes with type hints
- Automatic type conversion: Convert environment variables to appropriate types (bool, int, float, str, lists, dicts, sets, tuples)
- Nested configuration: Support for complex nested configuration structures
- Environment variable substitution: Reference environment variables in TOML files with
${VAR|-default}syntax - Validation: Automatic validation of configuration structure and types
- High performance: 50-60% faster than previous versions with optimized parsing and type conversion
- Memory efficient: 40-50% less memory usage with automatic
__slots__generation - Async support: Non-blocking configuration loading for async applications
- AI coding agent ready: Full type checking support makes configurations perfectly compatible with AI coding agents and IDEs
- IDE support: Complete IDE autocompletion and static type analysis support
Install
# pip
pip install tomlev
# With async support
pip install 'tomlev[async]'
# uv
uv add tomlev
# With async support
uv add tomlev --optional async
# poetry
poetry add tomlev
# With async support
poetry add 'tomlev[async]'
Note: The [async] extra installs aiofiles for non-blocking file I/O operations. Use this when building async
applications with FastAPI, aiohttp, or other async frameworks.
Basic usage
1. Create a TOML configuration file
Create a TOML configuration file (env.toml by default):
# env.toml
app_name = "My Application"
debug = "${DEBUG|-false}"
environment = "${ENV|-development}"
[database]
host = "${DB_HOST|-localhost}"
port = "${DB_PORT|-5432}"
user = "${DB_USER}"
password = "${DB_PASSWORD}"
name = "${DB_NAME|-app_db}"
[redis]
host = "${REDIS_HOST|-127.0.0.1}"
port = "${REDIS_PORT|-6379}"
Optionally include fragments inside a table using __include (paths are resolved relative to the TOML file):
# main.toml
[features]
__include = ["features.toml"]
# features.toml (merged under [features])
enabled = true
name = "awesome"
2. Define Configuration Models
Create configuration model classes that inherit from BaseConfigModel:
from tomlev import BaseConfigModel, TomlEv
class DatabaseConfig(BaseConfigModel):
host: str
port: int
user: str
password: str
name: str
class RedisConfig(BaseConfigModel):
host: str
port: int
class FeaturesConfig(BaseConfigModel):
# Matches the content merged under [features] via __include
enabled: bool
name: str
class AppConfig(BaseConfigModel):
app_name: str
debug: bool
environment: str
database: DatabaseConfig
redis: RedisConfig
features: FeaturesConfig
Tip: See the File Includes section for more details on __include usage and merge rules.
3. Use TomlEv in your Python code
Recommended: Simple convenience function
from tomlev import tomlev
# Simple one-liner - load and validate configuration
# Uses defaults: "env.toml" and ".env"
config: AppConfig = tomlev(AppConfig)
# Or explicitly specify files
config: AppConfig = tomlev(AppConfig, "env.toml", ".env")
# You can also set defaults via environment variables
# export TOMLEV_TOML_FILE="config/production.toml"
# export TOMLEV_ENV_FILE="config/.env.production"
# Then just use:
config: AppConfig = tomlev(AppConfig) # Uses env var defaults
# Access configuration with type safety
print(f"App: {config.app_name}")
print(f"Environment: {config.environment}")
print(f"Debug mode: {config.debug}") # Automatically converted to bool
# Access nested configuration
db_host = config.database.host
db_port = config.database.port # Automatically converted to int
# All properties are type-safe and validated
redis_host = config.redis.host
redis_port = config.redis.port # Automatically converted to int
Alternative: Class-based approach (when you need advanced features)
Use the TomlEv class when you need access to .environ, .strict, or .raw properties:
from tomlev import TomlEv
# Create instance to access additional properties
loader = TomlEv(AppConfig, "env.toml", ".env")
# Access environment variables used
env_vars = loader.environ
# Check strict mode setting
is_strict = loader.strict
# Get raw parsed TOML dict
raw_config = loader.raw
# Get validated config
config: AppConfig = loader.validate()
Async Support
TomlEv provides async I/O support for non-blocking configuration loading, perfect for async applications like FastAPI, aiohttp, or any async-based framework.
Installation:
pip install 'tomlev[async]'
# or with uv
uv add tomlev --optional async
Usage:
# Save as async_app.py, then run with: python async_app.py (or: uv run python async_app.py)
import asyncio
from tomlev import tomlev_async, BaseConfigModel
class AppConfig(BaseConfigModel):
host: str
port: int
debug: bool
async def main():
# Non-blocking configuration loading
config = await tomlev_async(AppConfig, "env.toml", ".env")
print(f"Server: {config.host}:{config.port}")
asyncio.run(main())
Advanced async usage with TomlEvAsync:
from tomlev import TomlEvAsync
async def main():
# Create loader instance for access to additional properties
loader = await TomlEvAsync.create(AppConfig, "env.toml", ".env")
# Access environment variables
env_vars = loader.environ
# Get validated config
config = loader.validate()
Benefits:
- Non-blocking file I/O
- Perfect for async web frameworks (FastAPI, aiohttp, Starlette)
- Same API as synchronous version
- Optional dependency - only install when needed
Immutable Configurations
Create frozen (immutable) configurations that cannot be modified after initialization:
from tomlev import BaseConfigModel, tomlev
class AppConfig(BaseConfigModel, frozen=True):
host: str
port: int
config = tomlev(AppConfig, "env.toml")
# This will raise AttributeError
try:
config.port = 9000
except AttributeError as e:
print(e) # Cannot modify frozen configuration model: AppConfig
Benefits:
- Thread-safe after initialization
- Prevents accidental modifications
- Clear intent in code
- No performance penalty
Configuration Models
TomlEv uses BaseConfigModel to provide type-safe configuration handling. Here are the supported types:
Supported Types
- Basic types:
str,int,float,bool - Collections:
list[T],dict[str, T],set[T],tuple[T, ...]where T is any supported type - Complex collections:
list[dict[str, Any]]for lists of dictionaries - Nested models: Other
BaseConfigModelsubclasses - Generic types:
typing.Anyfor flexible values
Advanced Example
from typing import Any
from tomlev import BaseConfigModel, tomlev, TomlEv
class QueryConfig(BaseConfigModel):
get_version: str
get_users: str
class DatabaseConfig(BaseConfigModel):
host: str
port: int
user: str
password: str
name: str
uri: str
queries: dict[str, str] # Dictionary of queries
class RedisConfig(BaseConfigModel):
host: str
port: int
keys: list[str] # List of strings
nums: list[int] # List of integers
atts: list[dict[str, Any]] # List of dictionaries
tags: set[str] # Set of unique strings
coordinates: tuple[float, float, float] # Tuple with fixed types
weight: int
mass: float
class AppConfig(BaseConfigModel):
debug: bool
environment: str
temp: float
database: DatabaseConfig
redis: RedisConfig
# Simple usage with convenience function (recommended)
config: AppConfig = tomlev(AppConfig)
# Or explicitly specify files
config: AppConfig = tomlev(AppConfig, "env.toml", ".env")
# Alternative: Class-based approach if you need .environ, .strict, or .raw
config: AppConfig = TomlEv(AppConfig).validate()
CLI Usage
TomlEv also provides a small CLI to validate TOML configuration files with environment substitution, without writing Python code.
Validate using defaults (env.toml and .env in the current directory):
tomlev validate
# or with uv
uv run tomlev validate
Validate explicit files:
tomlev validate --toml path/to/app.toml --env-file path/to/.env
# or with uv
uv run tomlev validate --toml path/to/app.toml --env-file path/to/.env
Setting Default File Paths via Environment Variables
You can set default file paths using environment variables, which is useful for CI/CD pipelines or containerized environments:
# Set default file paths
export TOMLEV_TOML_FILE="config/production.toml"
Related Skills
node-connect
348.0kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
claude-opus-4-5-migration
108.8kMigrate prompts and code from Claude Sonnet 4.0, Sonnet 4.5, or Opus 4.1 to Opus 4.5
frontend-design
108.8kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
model-usage
348.0kUse CodexBar CLI local cost usage to summarize per-model usage for Codex or Claude, including the current (most recent) model or a full model breakdown. Trigger when asked for model-level usage/cost data from codexbar, or when you need a scriptable per-model summary from codexbar cost JSON.
