SkillAgentSearch skills...

Tomlev

TomlEv - Open-source Python framework to easy manage environment variables

Install / Use

/learn @thesimj/Tomlev

README

<h2> <p style="text-align: center;"> TomlEv - Open-source Python framework to manage environment variables </p> </h2>

Latest Version Tomlev CI/CD Pipeline Coverage Status Versions Code Style: Ruff License Downloads

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 BaseConfigModel subclasses
  • Generic types: typing.Any for 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

View on GitHub
GitHub Stars4
CategoryDevelopment
Updated23d ago
Forks0

Languages

Python

Security Score

90/100

Audited on Mar 12, 2026

No findings