Pydantic Configuration Management
Code Properties
- Language: Python
- Packages:
pydantic,pydantic-settings
Overview
Environment-aware configuration management using Pydantic Settings with support for .env files, secrets, and environment-specific overrides.
Code
import os
import sys
import site
from typing import Union, Type, Tuple
from pydantic import Field, computed_field
from pydantic_settings import (BaseSettings, SettingsConfigDict,
PydanticBaseSettingsSource)
USER_BASE = site.getuserbase()
SECRETS_DIR = ('/run/secrets'
if os.path.exists('/.dockerenv')
else f'{site.USER_BASE}/secrets')
ENVIRONMENT = os.getenv('ENVIRONMENT', 'dev')
class Common(BaseSettings):
"""Common configuration shared between all environments."""
model_config = SettingsConfigDict(
extra='ignore',
secrets_dir=SECRETS_DIR,
env_file_encoding='utf-8',
env_file=f'{USER_BASE}/.env'
)
# constant parameters
api_timeout: tuple = (9.05, 60)
# environment-dependent parameters
env: str = ENVIRONMENT
# secrets
api_key: str = Field("", alias='api_key')
@computed_field
@property
def headers(self) -> dict:
"""Return API headers with API key."""
return {
'Content-Type': 'application/json',
'X-API-Key': self.api_key
}
class Dev(Common):
"""Development environment configuration."""
model_config = SettingsConfigDict(env_file=f'{USER_BASE}/dev.env')
api_root: str = 'http://localhost'
debug: bool = True
class Prod(Common):
"""Production environment configuration."""
model_config = SettingsConfigDict(env_file=f'{USER_BASE}/prod.env')
api_root: str = 'https://api.example.com'
debug: bool = False
_setup = dict(dev=Dev, prod=Prod)
# instantiate environment configuration
config: Union[Dev, Prod] = _setup[ENVIRONMENT]()Usage
from configurator import config
# access configuration
print(config.api_root)
print(config.headers)
print(config.env)Appendix
Note created on 2024-04-15 and last modified on 2024-12-31.
See Also
Backlinks
(c) No Clocks, LLC | 2024