Skip to content

Settings that fail fast

Configuration objects should stop a misconfigured application at startup, before any request runs, and still be swappable in tests.

myapp/settings.py
from typing import Annotated

from pydantic_settings import BaseSettings

from wireme import wired


class Settings(BaseSettings):
    database_url: str
    request_timeout: float = 5.0


settings = Settings()  # (1)!


def get_settings() -> Settings:
    return settings


type SettingsDep = Annotated[Settings, wired(get_settings)]
  1. Constructing at module scope validates the environment at import time: a missing DATABASE_URL fails the deployment, not the first request.

Every consumer declares the alias and receives the same instance:

@wire
def make_report(*, config: SettingsDep = Wired()) -> str:
    return f"report against {config.database_url}"

Tests override the named factory, so the whole graph sees test settings:

def get_test_settings() -> Settings:
    return Settings(database_url="sqlite://:memory:")


with override_dependency(get_settings, get_test_settings):
    make_report()

Not use_cache, not a lambda

use_cache=True caches once per wired call, not process-wide, and wired(lambda: settings) creates a distinct factory per call site that overrides cannot target. The named factory over a module instance is the whole recipe.

When eager construction is wrong (optional integrations, expensive clients), swap the module instance for a cached factory:

import functools


@functools.cache
def get_settings() -> Settings:
    return Settings()