Reserved placeholder for pyw-config (configuration utilities for pythonWoods suite)
Project description
pyw-config ⚙️
Configuration management utilities for the pythonWoods ecosystem.
Overview
pyw-config fornisce un sistema di gestione configurazioni type-safe e flessibile, con supporto per multipli backend (file, environment variables, remote sources) e validazione automatica tramite Pydantic.
Philosophy
- Type-safe configs – Pydantic models per zero errori di configurazione
- Multiple sources – YAML, JSON, TOML, .env, environment variables
- Hierarchical merging – override intelligente di configurazioni
- Environment-aware – profili per dev/staging/prod
- Validation-first – errori chiari e actionable per configurazioni invalide
Installation
pip install pyw-config
Per backend aggiuntivi:
pip install pyw-config[yaml] # + PyYAML per file YAML
pip install pyw-config[toml] # + tomli/tomllib per TOML
pip install pyw-config[vault] # + hvac per HashiCorp Vault
pip install pyw-config[remote] # + requests per config remote
pip install pyw-config[full] # tutti i backend
Quick Start
Basic Configuration
from pyw.config import BaseConfig, Field
from pyw.config.sources import from_file, from_env
class DatabaseConfig(BaseConfig):
host: str = Field(default="localhost")
port: int = Field(default=5432, ge=1, le=65535)
username: str
password: str = Field(..., min_length=8)
database: str
ssl_enabled: bool = Field(default=True)
class AppConfig(BaseConfig):
debug: bool = Field(default=False)
secret_key: str = Field(..., min_length=32)
db: DatabaseConfig
api_timeout: float = Field(default=30.0, gt=0)
# Carica da file + environment
config = AppConfig.from_sources(
from_file("config.yaml"),
from_env(prefix="MYAPP_")
)
print(f"Connecting to {config.db.host}:{config.db.port}")
Configuration Files
config.yaml:
debug: false
secret_key: "your-super-secret-key-here-min-32-chars"
db:
host: "prod-db.example.com"
username: "myapp"
database: "production"
ssl_enabled: true
api_timeout: 60.0
Environment Variables:
export MYAPP_DEBUG=true
export MYAPP_DB_PASSWORD=secure_password_123
export MYAPP_DB_PORT=5433
Features
🔄 Multiple Configuration Sources
from pyw.config.sources import (
from_file, from_env, from_dict,
from_vault, from_url
)
config = AppConfig.from_sources(
# 1. File di base
from_file("config.yaml"),
# 2. Override per environment
from_file(f"config.{env}.yaml", optional=True),
# 3. Secrets da Vault
from_vault("secret/myapp", optional=True),
# 4. Environment variables (priorità massima)
from_env(prefix="MYAPP_"),
# 5. Config remota
from_url("https://config.myapp.com/api/config", optional=True)
)
🌍 Environment Profiles
from pyw.config import ConfigProfile
class AppConfig(BaseConfig):
class Meta:
profiles = {
"development": {
"debug": True,
"db.host": "localhost",
"api_timeout": 5.0
},
"production": {
"debug": False,
"db.ssl_enabled": True,
"api_timeout": 30.0
}
}
# Carica profilo automaticamente da ENV
config = AppConfig.load_profile() # Legge ENVIRONMENT=production
# Oppure esplicitamente
config = AppConfig.load_profile("development")
🔒 Secrets Management
from pyw.config import SecretStr, SecretBytes
from pyw.config.secrets import from_keyring, from_1password
class Config(BaseConfig):
# Secrets non loggati/serializzati
api_key: SecretStr
private_key: SecretBytes
# Caricamento da secret manager
class Meta:
secret_sources = [
from_keyring("myapp"),
from_1password("myapp-vault")
]
# I secrets sono automaticamente mascherati
print(config.api_key) # → SecretStr('**********')
print(config.api_key.get_secret_value()) # → valore reale
🔄 Dynamic Configuration
from pyw.config import WatchableConfig
import asyncio
class AppConfig(WatchableConfig):
feature_flags: dict[str, bool] = Field(default_factory=dict)
rate_limit: int = 100
# Reload automatico su cambio file
config = AppConfig.from_file("config.yaml", watch=True)
@config.on_change
async def config_changed(old_config, new_config):
if old_config.rate_limit != new_config.rate_limit:
await update_rate_limiter(new_config.rate_limit)
# Avvia watching
await config.start_watching()
📊 Configuration Validation
from pyw.config import validator, root_validator
from typing import Optional
class DatabaseConfig(BaseConfig):
host: str
port: int = Field(ge=1, le=65535)
replica_hosts: Optional[list[str]] = None
@validator('host')
def validate_host(cls, v):
if not v or v == 'localhost':
return v
# Valida formato hostname/IP
import socket
try:
socket.gethostbyname(v)
return v
except socket.gaierror:
raise ValueError(f"Invalid hostname: {v}")
@root_validator
def validate_replicas(cls, values):
if values.get('replica_hosts'):
main_host = values.get('host')
if main_host in values['replica_hosts']:
raise ValueError("Main host cannot be in replica list")
return values
🧪 Testing Support
from pyw.config.testing import temporary_config, mock_env
class TestApp:
def test_with_temp_config(self):
with temporary_config(AppConfig, {"debug": True}):
config = AppConfig.load()
assert config.debug is True
def test_with_mock_env(self):
with mock_env(MYAPP_DEBUG="false"):
config = AppConfig.from_env(prefix="MYAPP_")
assert config.debug is False
Advanced Usage
Custom Configuration Sources
from pyw.config.sources import ConfigSource
import redis
class RedisConfigSource(ConfigSource):
def __init__(self, redis_client, key_prefix="config:"):
self.redis = redis_client
self.prefix = key_prefix
def load(self) -> dict:
keys = self.redis.keys(f"{self.prefix}*")
config = {}
for key in keys:
config_key = key.decode().replace(self.prefix, "")
config[config_key] = self.redis.get(key).decode()
return config
# Utilizzo
redis_client = redis.Redis()
config = AppConfig.from_sources(
RedisConfigSource(redis_client),
from_env(prefix="MYAPP_")
)
Configuration Schemas
from pyw.config import ConfigSchema, generate_schema
# Genera JSON Schema
schema = generate_schema(AppConfig)
print(schema)
# Genera esempio di configurazione
example = AppConfig.generate_example()
with open("config.example.yaml", "w") as f:
yaml.dump(example, f)
# Validazione esterna
from pyw.config.validation import validate_file
errors = validate_file("config.yaml", AppConfig)
if errors:
for error in errors:
print(f"❌ {error.location}: {error.message}")
Configuration Migrations
from pyw.config.migrations import ConfigMigration
class Migration001(ConfigMigration):
"""Rename db_host to database.host"""
version = "0.0.1"
def migrate(self, config: dict) -> dict:
if "db_host" in config:
config.setdefault("database", {})
config["database"]["host"] = config.pop("db_host")
return config
# Auto-apply migrations
config = AppConfig.from_file("old-config.yaml",
migrations=[Migration001()])
Integration Examples
FastAPI Integration
from fastapi import FastAPI, Depends
from pyw.config import inject_config
app = FastAPI()
@app.get("/status")
def get_status(config: AppConfig = Depends(inject_config(AppConfig))):
return {
"debug": config.debug,
"database_host": config.db.host
}
Django Integration
# settings.py
from pyw.config import django_settings
class DjangoConfig(BaseConfig):
SECRET_KEY: str
DEBUG: bool = False
DATABASES: dict
ALLOWED_HOSTS: list[str] = Field(default_factory=list)
# Auto-populate Django settings
config = DjangoConfig.from_sources(
from_file("django.yaml"),
from_env(prefix="DJANGO_")
)
globals().update(django_settings(config))
CLI Integration
# Valida configurazione
pyw-config validate config.yaml --schema=myapp.config:AppConfig
# Genera esempio
pyw-config generate-example myapp.config:AppConfig > config.example.yaml
# Merge configurazioni
pyw-config merge base.yaml override.yaml > final.yaml
# Mostra configurazione risolta (con secrets mascherati)
pyw-config show --env=production
Roadmap
- 🔐 Enhanced secrets: Integrazione con AWS Secrets Manager, Azure Key Vault
- 🌐 Remote configs: Etcd, Consul, Kubernetes ConfigMaps
- 📝 Configuration UI: Web interface per editing configurazioni
- 🔄 Hot reload: Reload automatico in runtime senza restart
- 📊 Config analytics: Metriche di utilizzo e drift detection
- 🧩 Plugin system: Custom validators e sources
Contributing
- Fork il repo:
git clone https://github.com/pythonWoods/pyw-config.git - Crea virtual-env:
poetry install && poetry shell - Lancia tests:
pytest - Lancia linter:
ruff check . && mypy - Apri la PR: CI esegue tutti i check
Felice configurazione nella foresta di pythonWoods! 🌲⚙️
Links utili
Documentazione dev (work-in-progress) → https://pythonwoods.dev/docs/pyw-config/latest/
Issue tracker → https://github.com/pythonWoods/pyw-config/issues
Changelog → https://github.com/pythonWoods/pyw-config/releases
© pythonWoods — MIT License
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 pyw_config-0.0.0.post2.tar.gz.
File metadata
- Download URL: pyw_config-0.0.0.post2.tar.gz
- Upload date:
- Size: 4.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.12.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
52b6851709968b02e20ce7827b988cbd366de24820c59ccbddda09694adb5180
|
|
| MD5 |
3a2048a0e58ba8180d6e04d5bbb943cd
|
|
| BLAKE2b-256 |
14e9a877b43b7333ec8de61993ca6543e29709ca30b682c4cd19ac1c2f1029a5
|
File details
Details for the file pyw_config-0.0.0.post2-py3-none-any.whl.
File metadata
- Download URL: pyw_config-0.0.0.post2-py3-none-any.whl
- Upload date:
- Size: 5.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.12.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
05c5d6f877d53b2692d61fd07810c95e8383a46eedf8d8e1404a3a9a8279824d
|
|
| MD5 |
bb72738efbd0a64e0db0372a2760996c
|
|
| BLAKE2b-256 |
e1780e9e1c9ad0479567bc5c6db88c1aa23a427197eb27bba5a96f43a78d7cb6
|