Module

config

Configuration system with deep merge, environment overlays, and origin tracking.

Classes

ConfigSpec 5
Declarative configuration schema. Describes where config comes from and how it merges:: cli.c…

Declarative configuration schema.

Describes where config comes from and how it merges::

cli.config_spec = ConfigSpec(
    sources=("bengal.toml", "config/*.yaml"),
    env_prefix="BENGAL_",
    profiles={"writer": {"build.drafts": True}},
    overlays={"production": "config/production.yaml"},
)

Attributes

Name Type Description
sources tuple[str, ...]
env_prefix str
defaults dict[str, Any]
profiles dict[str, dict[str, Any]]
overlays dict[str, str]
Config 12
Immutable, merged configuration with origin tracking. Usage:: config = Config.load(spec, root…

Immutable, merged configuration with origin tracking.

Usage::

config = Config.load(spec, root=Path("."), profile="dev", overlay="production")
url = config.get("site.url", "http://localhost")
print(config.origin_of("site.url"))  # "file:config/site.yaml"

Methods

load 4 Config
Load, merge, and freeze config from all sources. Merge precedence (lowest to h…
classmethod
def load(cls, spec: ConfigSpec, *, root: Path | None = None, profile: str = '', overlay: str = '') -> Config

Load, merge, and freeze config from all sources.

Merge precedence (lowest to highest):

  1. spec.defaults
  2. File sources (in order)
  3. Environment variables
  4. Profile overrides
  5. Overlay file
Parameters
Name Type Description
spec
root Default:None
profile Default:''
overlay Default:''
Returns
Config
from_dict 2 Config
Create a Config from a plain dictionary.
classmethod
def from_dict(cls, data: dict[str, Any], origin: str = 'dict') -> Config
Parameters
Name Type Description
data
origin Default:'dict'
Returns
Config
get 2 Any
Dot-notation access: ``config.get("site.url")``.
def get(self, key: str, default: Any = None) -> Any
Parameters
Name Type Description
key
default Default:None
Returns
Any
origin_of 1 str
Return the source that contributed a key's value.
def origin_of(self, key: str) -> str
Parameters
Name Type Description
key
Returns
str
as_dict 0 dict[str, Any]
Return a deep copy of the merged config.
def as_dict(self) -> dict[str, Any]
Returns
dict[str, Any]
to_state 0 dict[str, Any]
Convert to a Store-compatible state dict.
def to_state(self) -> dict[str, Any]
Returns
dict[str, Any]
validate 1 list[str]
Validate config values against the spec's defaults for type consistency. Retur…
def validate(self, spec: ConfigSpec) -> list[str]

Validate config values against the spec's defaults for type consistency.

Returns a list of error messages. An empty list means validation passed. Type expectations are inferred from the default values inspec.defaults.

Parameters
Name Type Description
spec
Returns
list[str]
init 3 Path
Generate a starter config file from a ConfigSpec. Writes spec.defaults to the …
staticmethod
def init(spec: ConfigSpec, *, root: Path | None = None, fmt: str = 'toml') -> Path

Generate a starter config file from a ConfigSpec.

Writes spec.defaults to the first source pattern's filename. Returns the path of the created file.

Parameters
Name Type Description
spec
root Default:None
fmt Default:'toml'
Returns
Path
Internal Methods 4
__init__ 2
def __init__(self, data: dict[str, Any], origins: dict[str, str]) -> None
Parameters
Name Type Description
data
origins
_validate_types 4
Recursively check that actual values match the types of defaults.
staticmethod
def _validate_types(defaults: dict[str, Any], actual: dict[str, Any], errors: list[str], prefix: str) -> None
Parameters
Name Type Description
defaults
actual
errors
prefix
__contains__ 1 bool
def __contains__(self, key: str) -> bool
Parameters
Name Type Description
key
Returns
bool
__repr__ 0 str
def __repr__(self) -> str
Returns
str

Functions

_load_file 1 dict[str, Any]
Load a TOML or YAML file.
def _load_file(filepath: str) -> dict[str, Any]
Parameters
Name Type Description
filepath str
Returns
dict[str, Any]
_load_env_vars 1 dict[str, Any]
Load environment variables with a given prefix into nested dict. BENGAL_SITE_U…
def _load_env_vars(prefix: str) -> dict[str, Any]

Load environment variables with a given prefix into nested dict.

BENGAL_SITE_URL -> {"site": {"url": "value"}}

Parameters
Name Type Description
prefix str
Returns
dict[str, Any]
_deep_merge 5 None
Deep merge source into target, tracking origins for leaf values.
def _deep_merge(target: dict[str, Any], source: dict[str, Any], origins: dict[str, str], origin: str, prefix: str = '') -> None
Parameters
Name Type Description
target dict[str, Any]
source dict[str, Any]
origins dict[str, str]
origin str
prefix str Default:''
_track_origins 4 None
Recursively track origins for all keys in a dict.
def _track_origins(data: dict[str, Any], origins: dict[str, str], origin: str, prefix: str) -> None
Parameters
Name Type Description
data dict[str, Any]
origins dict[str, str]
origin str
prefix str
_expand_dotted 1 dict[str, Any]
Expand dotted keys into nested dicts. {"build.output": "_site"} -> {"build": {…
def _expand_dotted(flat: dict[str, Any]) -> dict[str, Any]

Expand dotted keys into nested dicts.

{"build.output": "_site"} -> {"build": {"output": "_site"}}

Parameters
Name Type Description
flat dict[str, Any]
Returns
dict[str, Any]
_write_toml 2 None
Write a dict as TOML (stdlib-only, simple values).
def _write_toml(filepath: Path, data: dict[str, Any]) -> None
Parameters
Name Type Description
filepath Path
data dict[str, Any]
_write_toml_section 3 None
Recursively write TOML sections.
def _write_toml_section(data: dict[str, Any], lines: list[str], prefix: str) -> None
Parameters
Name Type Description
data dict[str, Any]
lines list[str]
prefix str
_toml_value 1 str
Format a Python value as TOML.
def _toml_value(value: Any) -> str
Parameters
Name Type Description
value Any
Returns
str
_write_yaml 2 None
Write a dict as YAML.
def _write_yaml(filepath: Path, data: dict[str, Any]) -> None
Parameters
Name Type Description
filepath Path
data dict[str, Any]
_write_yaml_simple 3 None
Simple YAML writer for basic types.
def _write_yaml_simple(data: dict[str, Any], lines: list[str], indent: int) -> None
Parameters
Name Type Description
data dict[str, Any]
lines list[str]
indent int