loom.core.config

Configuration loading utilities for Loom applications.

Provides an omegaConf-backed loader that supports multiple YAML files and typed section extraction. The framework imposes no shape on the config object — the user owns the structure.

Example:

from loom.core.config import load_config, section

cfg = load_config("config/base.yaml", "config/local.yaml")
db = section(cfg, "database", DatabaseConfig)
exception loom.core.config.ConfigError[source]

Bases: Exception

Raised when configuration loading or validation fails.

Parameters:

message – Human-readable description of the failure.

Example:

raise ConfigError("Missing required field: db_url")
class loom.core.config.ConfigResolver(*args, **kwargs)[source]

Bases: Protocol

Protocol for pluggable config value resolvers.

Implementors provide a name (used as the OmegaConf placeholder prefix) and a resolve callable that fetches the actual value at parse time.

Example:

class SsmResolver:
    name = "ssm"

    def __init__(self, region: str) -> None:
        self._region = region

    def resolve(self, key: str) -> str:
        import boto3
        client = boto3.client("ssm", region_name=self._region)
        return client.get_parameter(Name=key, WithDecryption=True)[
            "Parameter"
        ]["Value"]

cfg = load_config("s3://bucket/prod.yaml", resolvers=[SsmResolver("eu-west-1")])
property name: str

OmegaConf resolver prefix.

Used as the placeholder prefix in YAML: ${<name>:key}. Must be unique across all registered resolvers.

Returns:

Resolver name string (e.g. "ssm", "keyvault").

resolve(key)[source]

Resolve key to its string value.

Called by OmegaConf when materialising ${<name>:key} placeholders. Runs at config parse time (job startup), so the returned value reflects the current state of the backing store.

Parameters:

key (str) – Key portion of the placeholder after the prefix separator (e.g. "/prod/token" for ${ssm:/prod/token}).

Returns:

Resolved string value.

Return type:

str

loom.core.config.load_config(*config_files, resolvers=())[source]

Load and merge one or more YAML config files into a DictConfig.

Accepts local filesystem paths and cloud storage URIs (s3://, gs://, abfss://, r2:// …). Cloud files are fetched via fsspec at call time.

Files are merged left-to-right: values in later files override those in earlier ones. ${oc.env:VAR} interpolations are resolved by OmegaConf. Custom resolvers are registered before parsing so their ${name:key} placeholders resolve during the same pass.

Local files may declare a top-level includes list to pull in additional files before their own values. Included paths are relative to the declaring file. Circular includes raise ConfigError. The includes directive is not supported for cloud URIs.

The framework does not impose any shape on the resulting config — the user owns the structure entirely. Use section() to extract typed sub-objects where desired.

Parameters:
  • *config_files (str) – One or more local paths or cloud URIs.

  • resolvers (Sequence[ConfigResolver]) – Optional sequence of ConfigResolver instances. Each resolver registers a ${name:key} placeholder resolved at parse time (e.g. from AWS SSM or Azure Key Vault).

Returns:

Merged omegaconf.DictConfig with interpolation support.

Raises:

ConfigError – If no files are provided, a file is not found, parsing fails, a circular include is detected, omegaconf is not installed, or a cloud URI fetch fails.

Return type:

DictConfig

Example — single local file with inline includes:

cfg = load_config("config.yaml")

Example — explicit multi-file composition:

cfg = load_config("config/base.yaml", "config/production.yaml")
db_url = cfg.database.url

Example — cloud URI:

cfg = load_config("s3://my-bucket/config/prod.yaml")

Example — with custom resolver:

cfg = load_config("config/prod.yaml", resolvers=[SsmResolver("eu-west-1")])
loom.core.config.section(cfg, key, target_type)[source]

Extract and validate a config section as a typed object.

Navigates cfg by key (dot-notation supported, e.g. "database.primary"), resolves omegaConf interpolations, and converts the result to target_type via msgspec.convert.

Works with any type supported by msgspec.convert: msgspec.Struct subclasses, dataclasses, TypedDict, plain dicts, etc.

Parameters:
  • cfg (DictConfig) – Root omegaconf.DictConfig returned by load_config().

  • key (str) – Dot-separated path to the desired section (e.g. "database" or "services.cache").

  • target_type (type[T]) – Type to convert the section into.

Returns:

Validated instance of target_type.

Raises:

ConfigError – If the key is absent, the section cannot be resolved, or msgspec validation fails.

Return type:

T

Example:

class DatabaseConfig(msgspec.Struct, kw_only=True):
    url: str
    pool_size: int = 5

db = section(cfg, "database", DatabaseConfig)