Skip to main content

A modern configuration manager for Python with layered overrides and CLI.

Project description

Confixer ๐Ÿ”ง

Python 3.11+ License: MIT

A modern configuration manager for Python that unifies multi-source configs (YAML, JSON, TOML, .env, environment variables, CLI args, runtime overrides) into a single validated, dot-accessible object.

โœจ Features

  • ๐Ÿ”„ Multi-format loading - YAML, JSON, TOML, .env files, and environment variables
  • ๐Ÿ“š Layered overrides - base config โ†’ env vars โ†’ CLI args โ†’ runtime with deep merge
  • ๐ŸŽฏ Dot-notation access - config.database.host instead of config["database"]["host"]
  • โœ… Schema validation - Pydantic models and dataclasses support
  • ๐Ÿ› ๏ธ CLI tool - Initialize, show, and validate configurations
  • ๐Ÿชข Environment nesting - DB__HOST=localhost becomes {"DB": {"HOST": "localhost"}}
  • ๐Ÿ”’ Type coercion - Automatic conversion of strings to bool/int/float/None

๐Ÿš€ Quick Start

Installation

pip install confixer

Basic Usage

from confixer import Loader, YamlSource, EnvSource

# Create loader with multiple sources (layered overrides)
loader = Loader([
    YamlSource("config.yaml"),      # Base configuration
    EnvSource(prefix="APP_")        # Environment overrides
])

# Load and merge all sources
config = loader.load()

# Access with dot notation
print(config.database.host)        # "localhost"
print(config.api.port)             # 8080

# Still works like a dictionary
print(config["database"]["host"])   # "localhost"

๐Ÿ“– Full Documentation

Configuration Sources

YAML Source

from confixer import YamlSource

source = YamlSource("config.yaml")
data = source.load()

JSON Source

from confixer import JsonSource

source = JsonSource("config.json")
data = source.load()

TOML Source

from confixer import TomlSource

source = TomlSource("config.toml")
data = source.load()

Environment Source

from confixer import EnvSource

# Load from environment variables
env_source = EnvSource()

# Load from .env file
env_source = EnvSource(path=".env")

# Filter by prefix (APP_DEBUG โ†’ DEBUG)
env_source = EnvSource(prefix="APP_")

# Nested environment variables
# DB__HOST=localhost โ†’ {"DB": {"HOST": "localhost"}}
# DB__PORT=5432 โ†’ {"DB": {"PORT": 5432}}

Layered Configuration

from confixer import Loader, YamlSource, EnvSource

# Sources are merged in order: base โ†’ overrides
loader = Loader([
    YamlSource("config.yaml"),          # Base config
    YamlSource("config.local.yaml"),    # Local overrides  
    EnvSource(path=".env"),             # Environment file
    EnvSource(prefix="APP_"),           # Environment variables
])

config = loader.load()

Environment Variable Nesting & Type Coercion

# Environment variables
export DB__HOST=localhost
export DB__PORT=5432
export DB__ENABLED=true
export DB__TIMEOUT=30.5
export DB__PASSWORD=secret123
from confixer import EnvSource

source = EnvSource()
config = source.load()

print(config.DB.HOST)      # "localhost" (string)
print(config.DB.PORT)      # 5432 (int)
print(config.DB.ENABLED)   # True (bool)
print(config.DB.TIMEOUT)   # 30.5 (float)
print(config.DB.PASSWORD)  # "secret123" (string)

Type Coercion Rules:

  • Booleans: true, yes, 1, on โ†’ True | false, no, 0, off โ†’ False
  • Numbers: 123 โ†’ 123 (int) | 123.45 โ†’ 123.45 (float)
  • None: null, none, nil โ†’ None
  • Strings: Everything else remains as string

Schema Validation

With Pydantic

from pydantic import BaseModel
from confixer import Loader, YamlSource, validate_with_schema

class DatabaseConfig(BaseModel):
    host: str = "localhost"
    port: int = 5432
    name: str
    user: str
    
class AppConfig(BaseModel):
    debug: bool = False
    database: DatabaseConfig

# Load and validate
loader = Loader([YamlSource("config.yaml")])
config_data = loader.load()

# Validate with schema
validated = validate_with_schema(dict(config_data), "myapp.models:AppConfig")
print(validated.database.host)

With Dataclasses

from dataclasses import dataclass
from confixer import validate_with_schema

@dataclass
class AppConfig:
    name: str
    debug: bool = False
    port: int = 8000

# Validate
config_data = {"name": "MyApp", "debug": True}
validated = validate_with_schema(config_data, "__main__:AppConfig")

๐Ÿ› ๏ธ CLI Tool

The confixer CLI provides commands to initialize, show, and validate configurations.

Initialize Configuration

# Create example YAML config
confixer init --format yaml --output config

# Create JSON config  
confixer init --format json --output settings

# Create TOML config
confixer init --format toml --output app

Show Merged Configuration

# Show merged config from YAML + environment
confixer show config.yaml

# With .env file
confixer show config.yaml --env .env

# With environment variable prefix
confixer show config.yaml --prefix APP_

# Show specific nested path
confixer show config.yaml --path database.host

# Runtime overrides
confixer show config.yaml --set database.port=5433 --set app.debug=true

# Output as YAML
confixer show config.yaml --format yaml

Validate Configuration

# Basic syntax validation
confixer validate config.yaml

# Schema validation
confixer validate config.yaml --schema myapp.config:AppConfig

๐Ÿ“ Example Files

config.yaml

app:
  name: "MyApp"
  version: "1.0.0"
  debug: false

database:
  host: "localhost"
  port: 5432
  name: "myapp"
  user: "admin"

api:
  host: "0.0.0.0"
  port: 8000
  workers: 4

.env

# Override database settings
DB__HOST=prod-db.example.com
DB__PORT=5432
DB__PASSWORD=secret123

# Override API settings
API__HOST=0.0.0.0
API__PORT=8080
API__DEBUG=true

# App settings
APP__ENVIRONMENT=production
APP__LOG_LEVEL=INFO

Usage Example

from confixer import Loader, YamlSource, EnvSource

# Load with environment overrides
loader = Loader([
    YamlSource("config.yaml"),      # Base: DB host = localhost
    EnvSource(path=".env")          # Override: DB host = prod-db.example.com
])

config = loader.load()

print(config.database.host)  # "prod-db.example.com" (from .env)
print(config.database.port)  # 5432 (from .env, coerced to int)
print(config.api.debug)      # True (from .env, coerced to bool)
print(config.app.name)       # "MyApp" (from YAML, not overridden)

๐Ÿ—๏ธ Architecture

confixer/
โ”œโ”€ merge.py         # deep_merge() for layered configs
โ”œโ”€ accessor.py      # DotConfig class (dot notation)  
โ”œโ”€ loader.py        # Main Loader class
โ”œโ”€ schema.py        # Validation (Pydantic/dataclasses)
โ”œโ”€ cli.py          # CLI commands (Typer)
โ””โ”€ sources/
   โ”œโ”€ base.py       # ConfigSource interface
   โ”œโ”€ yaml_source.py
   โ”œโ”€ json_source.py  
   โ”œโ”€ toml_source.py
   โ””โ”€ env_source.py  # Environment + .env + nesting

๐Ÿ”„ Configuration Flow

  1. Load - Each source loads its data into a dict
  2. Merge - Deep merge all sources in order (later overrides earlier)
  3. Wrap - Wrap result in DotConfig for dot-notation access
  4. Validate - Optional schema validation with Pydantic/dataclasses
  5. Access - Use config.key.subkey or config["key"]["subkey"]

๐Ÿค Contributing

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature/amazing-feature
  3. Make changes and add tests
  4. Run tests: pytest
  5. Run pre-commit: pre-commit run --all-files
  6. Commit changes: git commit -m 'Add amazing feature'
  7. Push to branch: git push origin feature/amazing-feature
  8. Open a Pull Request

๐Ÿ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.

๐Ÿ™ Acknowledgments


Confixer - Making configuration management simple, layered, and type-safe! ๐Ÿ”ง

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

confixer-0.1.0.tar.gz (16.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

confixer-0.1.0-py3-none-any.whl (13.3 kB view details)

Uploaded Python 3

File details

Details for the file confixer-0.1.0.tar.gz.

File metadata

  • Download URL: confixer-0.1.0.tar.gz
  • Upload date:
  • Size: 16.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.0

File hashes

Hashes for confixer-0.1.0.tar.gz
Algorithm Hash digest
SHA256 ccca7f262aaa18fb6945afa09adb445eec1c30a70357768bc821e4d6cd0e5f96
MD5 51d6165e75367e4391cd6c129063fd9c
BLAKE2b-256 ee94e64b05bd882335a17249a0edd56cc0e4b8c41a4ee90ce8a534d612555903

See more details on using hashes here.

File details

Details for the file confixer-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: confixer-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 13.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.0

File hashes

Hashes for confixer-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 a2ffb1849d01ee0df4eab65dec7ad460f7cb19740e1f5fd90199e88e3c920d02
MD5 38aaef87727b6afc53663fd464abdea9
BLAKE2b-256 c654a478b519b526eac7b6512d6df211250526006565fcce404c968d27aed80b

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page