Configuration Enhanced & Easy ☕️ - A Hydra-like configuration parser helper package
Project description
Language: 한국어 | English
Hydra-style Configuration Management + Pydantic Type Safety + Typer-style Auto Help Generation
☕️ Overview
confee is a package that makes configuration management in Python applications simple, type-safe, and intuitive. It combines the best of Hydra and Pydantic, allowing you to manage configuration files, environment variables, and CLI arguments seamlessly.
✨ Key Features
- 🎯 Type-Safe Configuration — Automatic type validation & IDE autocomplete with Pydantic V2
- 📋 Multi-Format Support — Automatic detection and parsing of YAML, JSON, and TOML
- 🔄 Flexible Override System — Override values via CLI arguments and environment variables
- 🏗️ Configuration Inheritance — Merge and combine parent-child configurations
- 📁 File Reference — Load file contents with
@file:&@config:prefixes - 🔐 Secret Masking — Mark sensitive fields with
SecretField()for automatic masking - 🧊 Config Freezing — Freeze configurations for runtime immutability
- 📐 JSON Schema Export — Generate JSON Schema from configuration classes
- ⚡ Async Loading — Non-blocking config loading with file watching support
- 🔌 Plugin System — Extend with custom format loaders and data sources
- 📦 Zero Configuration — Ready to use with sensible defaults
- ⚙️ Parse Order Control — Freely adjust priority of file/env/cli sources
- 💬 Auto Help Generation — Display all options and defaults with
--helpflag - 🪆 Nested Field Access — Override nested fields with dot notation (database.host=localhost)
- 🧾 Verbosity Control — Adjust output verbosity with
--quiet/--verbose/--no-colorflags
📦 Installation
pip install confee
# With optional features
pip install confee[remote] # For async remote config loading
🚀 Quick Start
Basic Usage
from confee import ConfigBase
class AppConfig(ConfigBase):
name: str
debug: bool = False
workers: int = 4
# Parse from all sources (file, environment, CLI)
config = AppConfig.load(config_file="config.yaml")
print(config.name) # Type-safe access
print(config.debug) # Full IDE support
print(config.workers) # Auto-completion enabled
YAML Configuration File
name: production-app
debug: false
workers: 8
Command Line Override
python app.py name=my-app debug=true workers=16
Environment Variables
export CONFEE_NAME=my-app
export CONFEE_DEBUG=true
export CONFEE_WORKERS=16
python app.py
Help Display
python app.py --help
Detailed Validation Error Messages
By default, validation errors are displayed concisely, but using the --verbose flag shows detailed error information for each field:
# Concise error message (default)
python app.py name=123
# Output:
# Config error: field 'name' - Input should be a valid string
# Display detailed error messages in verbose mode
python app.py name=123 --verbose
# Output:
# ❌ Configuration Validation Error
#
# Found 1 validation error(s):
#
# [1] Field: name
# Error: Input should be a valid string
# Type: string_type
# Got: 123
#
# 💡 How to fix:
# 1. Add the required field to your configuration file
# 2. Or pass the value via CLI: python main.py name=myapp
# 3. Or set an environment variable: export CONFEE_NAME=myapp
# 4. Check field types match your configuration class
Or set via environment variable:
export CONFEE_VERBOSITY=verbose
python app.py name=123
🎯 Advanced Features
Nested Configuration
from confee import ConfigBase
class DatabaseConfig(ConfigBase):
host: str = "localhost"
port: int = 5432
class AppConfig(ConfigBase):
name: str
database: DatabaseConfig
# Override nested fields from CLI
# python app.py database.host=prod.db database.port=3306
config = AppConfig.load()
print(config.database.host) # "prod.db"
File References
# config.yaml
name: my-app
api_key: "@file:secrets/api_key.txt"
database_config: "@config:configs/database.yaml"
Custom Environment Prefix
# Use custom prefix instead of CONFEE_
# MYAPP_DEBUG=true instead of CONFEE_DEBUG=true
config = AppConfig.load(env_prefix="MYAPP_")
Custom Source Order
# Control which sources override others
config = AppConfig.load(
config_file="config.yaml",
source_order=["cli", "env", "file"] # CLI highest priority
)
Strict/Non-Strict Modes
# Strict mode (default): Forbid unknown fields
class Config(ConfigBase):
name: str
# Non-strict mode: Ignore unknown fields
config = Config.load(strict=False)
🆕 New in v0.3.0
TOML Support
# Load from TOML file
config = AppConfig.load(config_file="config.toml")
# Load from pyproject.toml
from confee import ConfigLoader
data = ConfigLoader.load_pyproject("pyproject.toml", tool_name="myapp")
# config.toml
name = "my-app"
debug = false
workers = 8
[database]
host = "localhost"
port = 5432
Secret Field Masking
from confee import ConfigBase, SecretField
class AppConfig(ConfigBase):
name: str
api_key: str = SecretField(default="")
database_password: str = SecretField()
config = AppConfig(name="app", api_key="secret123", database_password="pwd")
# Safe output masks secrets
print(config.to_safe_dict())
# {'name': 'app', 'api_key': '***MASKED***', 'database_password': '***MASKED***'}
config.print(safe=True) # Pretty print with masked secrets
Config Freezing
config = AppConfig.load(config_file="config.yaml")
# Freeze to prevent modifications
config.freeze()
config.name = "new" # Raises AttributeError
# Check frozen state
if config.is_frozen():
config = config.copy_unfrozen() # Create mutable copy
config.name = "new"
JSON Schema Export
from confee import SchemaGenerator
# Generate JSON Schema
schema = AppConfig.to_json_schema()
AppConfig.save_schema("config.schema.json")
# Validate data against schema
from confee import SchemaValidator
validator = SchemaValidator(AppConfig)
is_valid = validator.validate({"name": "app", "workers": 4})
Async Config Loading
from confee import AsyncConfigLoader
async def main():
# Load local file (static method - no instantiation needed)
config = await AsyncConfigLoader.load_as("config.yaml", AppConfig)
# Load from URL (requires aiohttp) - returns dict
data = await AsyncConfigLoader.load_remote("https://example.com/config.yaml")
# Watch for file changes
async def on_change(old_config, new_config):
print("Config changed:", new_config)
watcher = await AsyncConfigLoader.watch("config.yaml", on_change)
# ... application runs ...
await watcher.stop()
Plugin System
from confee import PluginRegistry
# Register custom loader
@PluginRegistry.loader(".ini")
def load_ini(path: str) -> dict:
import configparser
parser = configparser.ConfigParser()
parser.read(path)
return {s: dict(parser[s]) for s in parser.sections()}
# Now .ini files are automatically supported
config = AppConfig.load(config_file="config.ini")
Config Diff & Merge
config1 = AppConfig(name="app1", workers=4)
config2 = AppConfig(name="app2", workers=8)
# Compare configurations
diff = config1.diff(config2)
# {'name': ('app1', 'app2'), 'workers': (4, 8)}
# Merge configurations
merged = config1.merge(config2) # config2 values take precedence
📚 Documentation
🎯 Use Cases
Environment-specific Configuration
# dev.yaml
debug: true
workers: 2
# prod.yaml
debug: false
workers: 32
# Load appropriate config
import os
env = os.getenv("APP_ENV", "dev")
config = AppConfig.load(config_file=f"{env}.yaml")
Kubernetes Environment Variables
# pod.yaml
containers:
- env:
- name: CONFEE_DEBUG
value: "false"
- name: CONFEE_WORKERS
value: "16"
Configuration Validation
from pydantic import Field
class AppConfig(ConfigBase):
workers: int = Field(ge=1, le=128) # Validate range
timeout: float = Field(gt=0) # Must be positive
🔄 Integration Examples
With FastAPI
from fastapi import FastAPI
from confee import ConfigBase
class AppConfig(ConfigBase):
title: str = "My API"
debug: bool = False
# Load config from file and environment only (no CLI)
config = AppConfig.load(
config_file="config.yaml",
source_order=["env", "file"]
)
app = FastAPI(title=config.title, debug=config.debug)
With Click
import click
from confee import ConfigBase
class AppConfig(ConfigBase):
name: str
# Load config from file and environment only (no CLI)
config = AppConfig.load(
config_file="config.yaml",
source_order=["env", "file"]
)
@click.command()
def main():
click.echo(f"Hello {config.name}")
✅ Testing Your Configuration
def test_config_loading():
config = AppConfig.load(
config_file="tests/fixtures/config.yaml",
cli_args=["debug=true"],
strict=True
)
assert config.debug is True
🤝 Contributing
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch
- Write tests for your changes
- Submit a pull request
📜 License
MIT License © 2025
See LICENSE for details.
💬 Support
For issues and questions:
- GitHub Issues: https://github.com/bestend/confee/issues
- GitHub Discussions: https://github.com/bestend/confee/discussions
Enjoy ☕️ configuration management!
Language: 한국어 | English
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file confee-0.3.0.tar.gz.
File metadata
- Download URL: confee-0.3.0.tar.gz
- Upload date:
- Size: 788.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
29ef37ab267c13814d80dfa5c9d059225c26c5419b3d1de3b465b982f92ac6bf
|
|
| MD5 |
80c05c97e7f24a1066a59db08f649a3b
|
|
| BLAKE2b-256 |
a0d6818d5297339c84929c18d9a86ef79c3a0e2f33d284475088c475e69d7892
|
File details
Details for the file confee-0.3.0-py3-none-any.whl.
File metadata
- Download URL: confee-0.3.0-py3-none-any.whl
- Upload date:
- Size: 37.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
aea394b7452df2e69ca5551f84d8713b287f84028899e63d9431cf3f2b0b5de1
|
|
| MD5 |
b6c09bbe49e167b752290355d1bf7c7a
|
|
| BLAKE2b-256 |
a4f3d4c5624a8c391980c73d29443c71fc9ec7211652f519dfb2a9feb47d9a8f
|