ConfigSourceList#

pydantic model tollan.config.sources.ConfigSourceList[source]#

A list of configuration sources with conditional loading.

ConfigSourceList manages multiple ConfigSource instances, evaluates their enable_if conditions, and merges them in order.

Caching#

Per-source caching can be enabled with enable_cache(). This caches the loaded data for each source independently, which is useful for expensive loads (e.g., file I/O, remote APIs). Cache control can be granular: specify which sources to cache via names or orders.

Example

>>> sources = ConfigSourceList(data=[
...     {"format": "dict", "source": {"base": True}, "order": 0},
...     {
...         "format": "dict", "source": {"override": True},
...         "order": 1, "enable_if": "env == 'dev'"
...     }
... ])
>>> config = sources.load(context={"env": "dev"})
>>> config
{'base': True, 'override': True}

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

Show JSON schema
{
   "title": "ConfigSourceList",
   "description": "A list of configuration sources with conditional loading.\n\nConfigSourceList manages multiple ConfigSource instances, evaluates\ntheir enable_if conditions, and merges them in order.\n\nCaching\n-------\nPer-source caching can be enabled with enable_cache(). This caches\nthe loaded data for each source independently, which is useful for\nexpensive loads (e.g., file I/O, remote APIs). Cache control can be\ngranular: specify which sources to cache via names or orders.\n\nExample:\n    >>> sources = ConfigSourceList(data=[\n    ...     {\"format\": \"dict\", \"source\": {\"base\": True}, \"order\": 0},\n    ...     {\n    ...         \"format\": \"dict\", \"source\": {\"override\": True},\n    ...         \"order\": 1, \"enable_if\": \"env == 'dev'\"\n    ...     }\n    ... ])\n    >>> config = sources.load(context={\"env\": \"dev\"})\n    >>> config\n    {'base': True, 'override': True}",
   "type": "object",
   "properties": {
      "data": {
         "description": "List of configuration sources",
         "items": {
            "type": "object"
         },
         "title": "Data",
         "type": "array"
      },
      "name": {
         "anyOf": [
            {
               "type": "string"
            },
            {
               "type": "null"
            }
         ],
         "default": null,
         "description": "Optional name for this source list",
         "title": "Name"
      }
   },
   "required": [
      "data"
   ]
}

Config:
  • frozen: bool = True

Fields:
Validators:
  • _check_data_order_and_sort » data

  • _validate_arg » all fields

  • _validate_order_constraints » all fields

field data: Annotated[list[ConfigSource], WithJsonSchema({'type': 'array', 'items': {'type': 'object'}})] [Required]#

List of configuration sources

Constraints:
  • json_schema = {‘type’: ‘array’, ‘items’: {‘type’: ‘object’}}

Validated by:
  • _check_data_order_and_sort

  • _validate_arg

  • _validate_order_constraints

field name: str | None = None#

Optional name for this source list

Validated by:
  • _validate_arg

  • _validate_order_constraints

enable_cache(predicate: Callable[[ConfigSource], bool] | None = None, exclude: Callable[[ConfigSource], bool] | None = None) None[source]#

Enable per-source caching for sources matching predicate.

Caching is applied at the source level, not at the merged config level. This allows expensive sources (e.g., file I/O, remote APIs) to be cached while keeping mutable dict sources uncached.

Parameters:
  • predicate (Callable[[ConfigSource], bool] | None, optional) – Function to select sources to cache. If None, cache all sources (unless excluded), by default None

  • exclude (Callable[[ConfigSource], bool] | None, optional) – Function to select sources to exclude from caching. Applied after predicate, by default None

  • Example

    >>> from tollan.config.sources import ConfigSourceList
    >>> sources = ConfigSourceList(data=[
    ...     {"format": "dict", "source": {"a": 1}, "order": 0, "name": "base"},
    ...     {"format": "dict", "source": {"b": 2}, "order": 1, "name": "env"}
    ... ])
    
    >>> # Cache all except env
    >>> sources.enable_cache(
    ...     exclude=lambda s: s.name == "env"
    ... )
    
    >>> # Cache only YAML sources
    >>> sources.enable_cache(
    ...     lambda s: isinstance(s, YamlConfigSource)
    ... )
    
    >>> # Cache sources with specific orders
    >>> sources.enable_cache(lambda s: s.order > 5)
    
    >>> sources._cache_config.enabled
    True
    

get(predicate: Callable[[ConfigSource], bool], *, unique: Literal[True] = True) ConfigSource | None[source]#
get(predicate: Callable[[ConfigSource], bool], *, unique: Literal[False]) list[ConfigSource]

Get config source(s) using a predicate function.

Provides maximum flexibility for source selection via predicate function.

Parameters:
  • predicate (Callable[[ConfigSource], bool]) – Function taking ConfigSource and returning bool

  • unique (bool, optional) – If True (default), ensures only one match and returns single source. If False, returns list of all matching sources (empty if none), by default True

Returns:

  • If unique=True – ConfigSource if exactly one match found, None if no match.

  • If unique=False – list[ConfigSource] with all matches (empty if no matches).

Raises:

ValueError – If unique=True and multiple sources match the predicate.:

Examples

>>> from tollan.config.sources import ConfigSourceList
>>> sources = ConfigSourceList(data=[
...     {"format": "dict", "source": {"a": 1}, "order": 0, "name": "base"},
...     {"format": "dict", "source": {"b": 2}, "order": 1, "name": "env"},
...     {"format": "dict", "source": {"c": 3}, "order": 2, "name": "cli"},
... ])
>>> # Unique match (default)
>>> source = sources.get(lambda s: s.name == "base")
>>> source.order
0
>>> # Multiple matches with unique=False (non-base sources)
>>> sources_list = sources.get(
...     lambda s: s.name in {"env", "cli"}, unique=False
... )
>>> len(sources_list)
2
>>> [s.order for s in sources_list]
[1, 2]
>>> # All sources
>>> all_sources = sources.get(lambda s: True, unique=False)
>>> len(all_sources)
3
invalidate_cache(predicate: Callable[[ConfigSource], bool] | None = None) None[source]#

Invalidate cache for sources matching predicate or all sources.

Parameters:
  • predicate (Callable[[ConfigSource], bool] | None, optional) – Function to select sources to invalidate. If None, invalidate all cached sources, by default None

  • Example

    >>> from tollan.config.sources import ConfigSourceList
    >>> sources = ConfigSourceList(data=[
    ...     {"format": "dict", "source": {"a": 1}, "order": 0, "name": "base"},
    ...     {"format": "dict", "source": {"b": 2}, "order": 1, "name": "env"}
    ... ])
    >>> sources.enable_cache()
    >>> _ = sources.load()  # Populate cache
    
    >>> # Invalidate all
    >>> sources.invalidate_cache()
    
    >>> # Invalidate specific sources
    >>> sources.invalidate_cache(
    ...     lambda s: s.name == "env"
    ... )
    >>> sources.invalidate_cache(lambda s: s.order > 5)
    

load(context: dict[str, Any] | None = None) DictConfigT[source]#

Load and merge all enabled configuration sources.

Sources are evaluated for enable_if conditions, then loaded and merged in order (lower order first, higher order overrides).

If caching is enabled, individual sources may be cached based on the cache configuration.

Parameters:

context (dict[str, Any] | None, optional) – Context dictionary for evaluating enable_if conditions, by default None

Returns:

Merged configuration dictionary

Return type:

DictConfigT

model_post_init(context: Any, /) None#

This function is meant to behave like a BaseModel method to initialise private attributes.

It takes context as an argument since that’s what pydantic-core passes when calling it.

Parameters:
  • self – The BaseModel instance.

  • context – The context.