deployment.loader#

Configuration Parameter Loading and Management System.

This module provides a sophisticated parameter loading system that supports YAML configuration files with import directives, hierarchical parameter access, and environment variable expansion. The system is designed for flexible deployment configurations where complex service arrangements need robust parameter management.

The module implements a type-safe parameter access pattern through the Params class, which provides dot-notation access to nested configuration data while maintaining validation and error handling. Invalid parameter access returns InvalidParam objects rather than raising exceptions, enabling graceful degradation in configuration scenarios.

Key Features:
  • Recursive YAML file imports with circular dependency detection

  • Environment variable expansion in string values

  • Type-safe parameter access with validation

  • Graceful error handling for missing configuration keys

  • Deep dictionary merging for configuration composition

Examples

Basic parameter loading:

>>> params = load_params('config.yml')
>>> database_host = params.database.host
>>> timeout = params.services.timeout

Configuration with imports:

# base_config.yml
database:
  host: localhost
  port: 5432

# app_config.yml
import: base_config.yml
database:
  name: myapp  # Merged with base config
services:
  timeout: 30

>>> params = load_params('app_config.yml')
>>> print(params.database.host)  # 'localhost' from base
>>> print(params.database.name)  # 'myapp' from app config

Environment variable expansion:

# config.yml
project_root: ${PROJECT_ROOT}
data_dir: ${PROJECT_ROOT}/data

>>> os.environ['PROJECT_ROOT'] = '/home/user/project'
>>> params = load_params('config.yml')
>>> print(params.data_dir)  # '/home/user/project/data'

See also

Params : Main parameter container with hierarchical access InvalidParam : Error handling for missing configuration keys _load_yaml() : Core YAML loading with import processing deployment.container_manager : Uses this system for service configuration

loader.load_params(file_path)[source]#

Load configuration parameters from YAML file into a Params object.

This is the main entry point for the configuration loading system. It loads a YAML configuration file (processing any import directives) and wraps the resulting data in a Params object that provides type-safe, hierarchical access to configuration values.

The function handles the complete configuration loading pipeline including import processing, environment variable expansion, and parameter object creation. The resulting Params object provides dot-notation access to nested configuration data with built-in validation and error handling.

Parameters:

file_path (str) – Path to the YAML configuration file to load

Raises:
  • FileNotFoundError – If the configuration file cannot be found

  • yaml.YAMLError – If YAML parsing fails

  • ValueError – If circular imports are detected

Returns:

Parameter container with hierarchical access to configuration data

Return type:

Params

Examples

Basic configuration loading:

# config.yml
database:
  host: localhost
  port: 5432
services:
  timeout: 30
  retry_count: 3

>>> params = load_params('config.yml')
>>> db_host = params.database.host  # 'localhost'
>>> timeout = params.services.timeout  # 30
>>> invalid = params.nonexistent.key  # InvalidParam, not exception

Environment variable expansion:

# config.yml
project_root: ${PROJECT_ROOT}
data_directory: ${PROJECT_ROOT}/data

>>> import os
>>> os.environ['PROJECT_ROOT'] = '/home/user/project'
>>> params = load_params('config.yml')
>>> print(params.data_directory)  # '/home/user/project/data'

See also

_load_yaml() : Core YAML loading implementation Params : Return type providing parameter access InvalidParam : Error handling for missing configuration keys deployment.container_manager : Primary consumer of this functionality

class loader.AbstractParam(name, parent=None)[source]#

Bases: object

__init__(name, parent=None)[source]#
get_path()[source]#
copy()[source]#
is_valid()[source]#
class loader.InvalidParam(name, parent=None)[source]#

Bases: AbstractParam

Parameter object representing missing or invalid configuration data.

This class provides graceful error handling for configuration access patterns where requested parameters don’t exist. Instead of raising exceptions immediately, the system returns InvalidParam objects that maintain the access chain and provide meaningful error messages when finally used.

InvalidParam objects support continued dot-notation access, allowing code to chain parameter lookups naturally even when intermediate parameters are missing. The error is only raised when the parameter is actually used (e.g., in a boolean context or when converted to a string).

This approach enables defensive programming patterns where configuration access can be attempted optimistically, with errors handled at the point of actual use.

Parameters:
  • name (str) – Name of the missing parameter

  • parent (AbstractParam, optional) – Parent parameter object in the access chain

Examples

Graceful error handling:

>>> params = load_params('config.yml')  # Missing 'database.timeout'
>>> timeout = params.database.timeout  # Returns InvalidParam, no exception
>>> if timeout:  # Now evaluates to False
...     print(f"Timeout: {timeout}")
... else:
...     print("Using default timeout")

Error chain preservation:

>>> missing = params.nonexistent.deeply.nested.value
>>> print(missing)  # Shows path to first missing parameter
<InvalidParam: 'root.nonexistent'>

See also

Params : Valid parameter container that returns InvalidParam for missing keys AbstractParam.get_path() : Path construction used in error messages

__init__(name, parent=None)[source]#
is_valid()[source]#

Check if this parameter is valid.

Returns:

Always False for InvalidParam objects

Return type:

bool

__getattr__(key)[source]#

Support continued dot-notation access on invalid parameters.

Allows chaining of parameter access even when intermediate parameters are missing, maintaining the error state through the access chain.

Parameters:

key (str) – Attribute name being accessed

Returns:

New InvalidParam representing the continued invalid access

Return type:

InvalidParam

Examples

Continued access on missing parameters:

>>> invalid = params.missing.parameter
>>> still_invalid = invalid.more.nested.access
>>> print(still_invalid.is_valid())  # False
__getitem__(key)[source]#

Raise error when bracket notation is used on invalid parameters.

Parameters:

key (str or int) – Key being accessed

Raises:

TypeError – Always raises with error message showing the invalid path

Note

Unlike dot notation (__getattr__), bracket notation immediately raises an error to provide clear feedback about the invalid parameter access.

__bool__()[source]#

Evaluate InvalidParam objects as False in boolean contexts.

Returns:

Always False

Return type:

bool

Examples

Boolean evaluation for error handling:

>>> param = params.possibly.missing.value
>>> if param:
...     process_value(param)
... else:
...     use_default_value()
__repr__()[source]#

Provide clear error message showing the invalid parameter path.

Traces back through the InvalidParam chain to find the first missing parameter and displays its full path for debugging.

Returns:

String representation showing the invalid parameter path

Return type:

str

Examples

Error message generation:

>>> missing = params.database.missing.timeout
>>> print(missing)
<InvalidParam: 'root.database.missing'>
class loader.Params(data, name, parent=None)[source]#

Bases: AbstractParam

Primary parameter container providing hierarchical access to configuration data.

This class wraps configuration data (dictionaries, lists, or scalar values) and provides type-safe, hierarchical access through dot notation and bracket notation. The class handles environment variable expansion, supports deep copying, and provides graceful error handling through InvalidParam objects.

Params objects automatically detect the data type (dict, list, or scalar) and provide appropriate access methods. Nested structures are recursively wrapped in Params objects, creating a complete hierarchy that maintains parent-child relationships for path tracking and error reporting.

Environment variable expansion is performed on string values using os.expandvars, allowing configuration files to reference environment variables with ${VAR} syntax.

Parameters:
  • data (dict or list or Any) – Configuration data to wrap (dict, list, or scalar value)

  • name (str) – Name of this parameter within its parent container

  • parent (AbstractParam, optional) – Parent parameter object, None for root parameters

Examples

Dictionary access patterns:

>>> config_data = {'database': {'host': 'localhost', 'port': 5432}}
>>> params = Params(config_data, 'root')
>>> host = params.database.host  # 'localhost'
>>> port = params.database['port']  # 5432
>>> missing = params.cache.timeout  # InvalidParam, not exception

List access patterns:

>>> config_data = {'servers': ['web1', 'web2', 'api1']}
>>> params = Params(config_data, 'root')
>>> first_server = params.servers[0]  # 'web1'
>>> server_count = len(params.servers)  # 3

Environment variable expansion:

>>> config_data = {'path': '${HOME}/data', 'url': '${API_HOST}:${API_PORT}'}
>>> params = Params(config_data, 'root')
>>> # Environment variables are expanded when values are accessed
>>> data_path = params.path  # '/home/user/data' (if HOME is set)

See also

InvalidParam : Error handling for missing configuration keys AbstractParam : Base class defining the parameter interface load_params() : Main entry point for creating Params from YAML files

__init__(data, name, parent=None)[source]#
is_valid()[source]#
keys()[source]#
values()[source]#
items()[source]#
get(key, default=None)[source]#
__deepcopy__(memo)[source]#

Copies the data into its native format, without Param objects.