API Reference

iConfig Module

Main user interface for hierarchical configuration management.

This module provides the primary iConfig class that serves as the main entry point for users to interact with hierarchical configuration data. It includes a sophisticated singleton decorator and the core configuration access interface.

The module combines file-based configuration management with in-memory caching, environment variable expansion, and flexible access patterns. The singleton pattern ensures consistent configuration state across an application while allowing opt-out behavior when needed.

Key Features:
  • Conditional singleton pattern with configuration-based control

  • Hierarchical configuration access with path filtering

  • Environment variable expansion in configuration values

  • Lazy loading of configuration files for performance

  • Type-safe overloaded methods for better IDE support

Example

Basic usage of the iConfig interface:

from iconfig import iConfig

# Initialize configuration (singleton by default)
config = iConfig()

# Get configuration values
app_name = config.get('app_name')
db_port = config.get('port', path=['database'])

# Use with defaults and type hints
timeout = config.get('timeout', default=30)

# Callable interface
debug = config('debug', default=False)

# Set values (in-memory)
config.set('new_setting', value=True)
Classes:

iConfig: Main configuration interface with singleton support

Functions:

singleton_or_not: Decorator for conditional singleton behavior

KeyIndex Module

Internal indexing engine for fast hierarchical configuration lookups.

This module provides the KeyIndex class which serves as the core indexing engine for the iConfig system. It handles file discovery, builds searchable indexes of configuration keys, and provides fast lookups across multiple YAML files.

The KeyIndex class is designed for performance, building an in-memory index of all configuration keys with metadata about their locations, hierarchy levels, and file sources. This allows for O(1) key lookups without re-parsing configuration files.

Example

Using KeyIndex for configuration management:

from iconfig.keyindex import KeyIndex

# Initialize and build index
ki = KeyIndex()

# Get configuration values with filtering
result = ki.get('port', path=['database'])

# Add new configuration entry
ki.add('new_key', 'value', path=['section'], level=0)

# Save index to disk
ki.save()
Classes:

KeyIndex: Main indexing engine for hierarchical configuration management.

Note

This is an internal module. End users should typically use the iConfig class which provides a simpler interface wrapping KeyIndex functionality.

class iconfig.keyindex.KeyIndex(config_home=None, load_index=True, force_rebuild=False)[source]

Bases: object

Core indexing engine for hierarchical configuration management.

The KeyIndex class provides the internal engine that powers the iConfig system. It discovers configuration files, builds searchable indexes, and provides fast lookups with support for hierarchical filtering by path, level, and depth.

The class maintains three main data structures: - _index: Maps configuration keys to their metadata and locations - _files: Tracks discovered configuration files and their properties - _cfg: Runtime cache of loaded configuration file contents

Parameters:

load_index (bool, optional) – Whether to automatically load/build the index on initialization. Defaults to True.

_base

Base configuration directory path.

Type:

str

_fn

Index file name for persistence.

Type:

str

_index

Main key-to-metadata mapping.

Type:

dict

_files

File discovery and metadata cache.

Type:

dict

_cfg

Runtime configuration file content cache.

Type:

dict

Example

Basic KeyIndex operations:

# Initialize with automatic index building
ki = KeyIndex()

# Search for configuration keys
port_entries = ki.get('port')
db_port = ki.get('port', path=['database'])

# Get metadata about key locations
location = ki.whereis('app_name')

# Add new configuration entries
ki.add('timeout', 30, path=['api'], level=1)

# Persist changes
ki.save()

Note

The KeyIndex automatically discovers YAML files in the configuration directory and builds/maintains an index for fast lookups. The index is persisted to disk for quick startup times on subsequent runs.

__init__(config_home=None, load_index=True, force_rebuild=False)[source]

Initialize the KeyIndex with configuration directory and options.

Sets up the internal data structures and optionally loads or builds the configuration index from the specified directory.

Parameters:
  • config_home (str, optional) – Path to configuration directory. If not provided, uses INCONFIG_HOME environment variable or defaults to ‘config’.

  • load_index (bool, optional) – Whether to automatically load/build the index on initialization. Defaults to True.

get(key, path=None, level=-1, depth=-1, forcefirst=False, default=None)[source]

Retrieve a configuration value by its key.

Performs fast O(1) lookup of configuration values using the pre-built index. If the key exists in multiple files, returns the value from the file with the highest priority (lowest hierarchy level).

Parameters:
  • key (str) – The configuration key to look up.

  • path (list[str] | str | None) – Optional path filter to narrow search.

  • level (int) – Filter by hierarchy level (-1 for any level).

  • depth (int) – Filter by nesting depth (-1 for any depth).

  • forcefirst (bool) – Return first match instead of highest priority.

  • default (Any) – Default value if key not found.

Returns:

The configuration value associated with the key, or default if the key is not found.

Return type:

Any

Example

>>> index = KeyIndex()
>>> value = index.get('database.host')
>>> print(value)  # 'localhost'
whereis(key, path=None, level=-1, depth=-1)[source]

Find the file location and metadata for a configuration key.

Returns detailed information about where a configuration key is defined, including the hierarchy level and nesting path. This is useful for debugging configuration issues and understanding the configuration structure.

Parameters:
  • key (str) – The configuration key to locate.

  • path (list[str] | str | None) – Optional path filter to narrow search.

  • level (int) – Filter by hierarchy level (-1 for any level).

  • depth (int) – Filter by nesting depth (-1 for any depth).

Returns:

A list of dictionaries containing metadata about the key’s locations, each with:

  • ’level’: Hierarchy level (0 for root files)

  • ’path’: The full key path as a list

Returns None if the key is not found.

Return type:

list[dict] | None

Example

>>> index = KeyIndex()
>>> locations = index.whereis('database.host')
>>> print(locations)
# [{'level': 0, 'path': ['database', 'host']}]
add(key, level, depth, dict_ref, path)[source]

Add a configuration key entry to the index.

Adds metadata for a configuration key to the internal index, including its hierarchy level, nesting depth, source file, and path information. This method is typically called during index building.

Parameters:
  • key (str) – The configuration key to add.

  • level (int) – Hierarchy level (0 for root files, higher for subdirectories).

  • depth (int) – Nesting depth within the configuration structure.

  • dict_ref (str) – Reference to the source file containing this key.

  • path (str | list[str]) – The path to this key within the configuration.

Return type:

None

Example

>>> index = KeyIndex()
>>> index.add('host', 0, 1, 'config/db.yaml', ['database', 'host'])
has_entry(entry, list_of_entries)[source]
Return type:

bool

Labels Module

String constants and labels used throughout the iConfig system.

This module defines the Labels class that provides string constants used as dictionary keys and identifiers throughout the configuration system. Using a centralized Labels class ensures consistency and prevents typos in string literals across the codebase.

The Labels class provides string constants that can be used as dictionary keys and includes utility methods for introspection and iteration over the available labels.

Example

Using Labels for consistent key access:

from iconfig.labels import Labels

# Use labels as dictionary keys
entry = {
    Labels.FILE_PATH: '/path/to/config.yaml',
    Labels.LEVEL: 0,
    Labels.PATH: ['database']
}

# Access values using Labels
file_path = entry[Labels.FILE_PATH]
The module exports the :class:`Labels` class with all configuration constants.
class iconfig.labels.Labels[source]

Bases: object

String constants for configuration system keys and identifiers.

Provides string constants used as dictionary keys and identifiers throughout the iConfig system. The class includes both the constant definitions and utility methods for introspection and iteration.

The Labels class serves as a centralized location for all string constants used in the configuration system, preventing typos and ensuring consistency across the codebase.

INDEX

Key for index data in persistent storage (‘index’).

Type:

str

FILES

Key for file metadata in persistent storage (‘files’).

Type:

str

LEVEL

Key for hierarchy level information (‘level’).

Type:

str

DEPTH

Key for nesting depth information (‘depth’).

Type:

str

DICT_REF

Key for dictionary reference identifiers (‘dict_ref’).

Type:

str

PATH

Key for path context information (‘path’).

Type:

str

FILE_PATH

Key for file path information (‘file_path’).

Type:

str

MTIME

Key for modification time information (‘mtime’).

Type:

str

Example

Using Labels in configuration entries:

entry = {
    Labels.FILE_PATH: '/etc/myapp/config.yaml',
    Labels.LEVEL: 0,
    Labels.DEPTH: 2,
    Labels.PATH: ['database', 'connection'],
    Labels.DICT_REF: 'config_main'
}

# Access values using Labels
path = entry[Labels.FILE_PATH]
level = entry[Labels.LEVEL]

Note

This is a regular class (not an enum) that provides string constants and utility methods for working with those constants.

INDEX = 'index'
FILES = 'files'
LEVEL = 'level'
DEPTH = 'depth'
DICT_REF = 'dict_ref'
PATH = 'path'
FILE_PATH = 'file_path'
MTIME = 'mtime'
classmethod values()[source]

Return all label string values as a list.

Collects all string constants defined in the Labels class into a list, excluding methods and special attributes.

Returns:

List of all string constant values.

Return type:

list[str]

Example

>>> Labels.values()
['index', 'files', 'level', 'depth', 'dict_ref', 'path', 'file_path', 'mtime']
classmethod names()[source]

Return all label constant names as a list.

Collects all attribute names that correspond to string constants, excluding methods and special attributes.

Returns:

List of all constant attribute names.

Return type:

list[str]

Example

>>> Labels.names()
['INDEX', 'FILES', 'LEVEL', 'DEPTH', 'DICT_REF', 'PATH', 'FILE_PATH', 'MTIME']
classmethod items()[source]

Return (name, value) pairs for all label constants.

Provides a dictionary-like items() interface for the Labels class, returning tuples of (attribute_name, string_value) for all constants.

Returns:

List of (name, value) pairs for all constants.

Return type:

list[tuple[str, str]]

Example

>>> Labels.items()
[('INDEX', 'index'), ('FILES', 'files'), ('LEVEL', 'level'), ...]

Utils Module

Utility functions for configuration file discovery and key path processing.

This module provides essential utility functions used throughout the iConfig system for file system operations and key path manipulation. These functions support the core functionality of hierarchical configuration management.

The module includes functions for: - Discovering YAML configuration files in directory structures - Processing and normalizing key paths with dot notation support - File metadata collection for change detection

Example

Basic usage of utility functions:

from pathlib import Path
from iconfig.utils import discover_config_files, get_key_path

# Discover configuration files
config_dir = Path("config")
files = discover_config_files(config_dir)

# Process key paths
key, path = get_key_path("database.host", ["production"])
Functions:

discover_config_files: Recursively find YAML files with metadata get_key_path: Parse and normalize key paths with dot notation

iconfig.utils.discover_config_files(base_path, pattern='*.yaml')[source]

Recursively discover configuration files with metadata collection.

Scans the specified directory tree for files matching the given pattern and collects metadata including file paths, modification times, and hierarchy levels. This information is used for index building and change detection.

Parameters:
  • base_path (Path) – Root directory to search for configuration files.

  • pattern (str, optional) – Glob pattern for file matching. Defaults to “*.yaml”.

Returns:

Dictionary mapping relative file paths to metadata dictionaries containing:

  • file_path (str): Absolute path to the configuration file

  • mtime (float): File modification time as timestamp

  • level (int): Hierarchy level based on directory depth

Return type:

dict[str, dict[str, str|float]]

Example

Discovering configuration files:

config_dir = Path("config")
files = discover_config_files(config_dir)

# Result structure:
# {
#     "database.yaml": {
#         "file_path": "/path/to/config/database.yaml",
#         "mtime": 1699123456.789,
#         "level": 0
#     },
#     "api/settings.yaml": {
#         "file_path": "/path/to/config/api/settings.yaml",
#         "mtime": 1699123457.123,
#         "level": 1
#     }
# }

Note

The hierarchy level is calculated based on directory depth relative to the base path, with 0 representing files in the root directory.

iconfig.utils.get_key_path(key, path)[source]

Parse and normalize key paths with dot notation support.

Processes configuration keys that may contain dot notation (e.g., “database.host”) and combines them with existing path contexts to create normalized key and path components. This enables flexible key specification and hierarchical access.

Parameters:
  • key (str) – Configuration key, potentially with dot notation.

  • path (list) – Existing path context as a list of strings.

Returns:

A tuple containing:

  • key (str): The final key component (rightmost part after dots)

  • path (list[str]): Combined path context including dot notation parts

Return type:

Tuple[str, list[str]]

Example

Processing keys with dot notation:

# Simple key without dots
key, path = get_key_path("host", ["database"])
# Result: ("host", ["database"])

# Key with dot notation
key, path = get_key_path("database.host", [])
# Result: ("host", ["database"])

# Combining dot notation with existing path
key, path = get_key_path("connection.timeout", ["api"])
# Result: ("timeout", ["connection", "api"])

# String path converted to list
key, path = get_key_path("port", "database")
# Result: ("port", ["database"])

Note

When dot notation is present, the key is split and the rightmost component becomes the key while preceding components are prepended to the path context.

iconfig.utils.singleton_or_not(class_)[source]

Decorator that conditionally implements the singleton pattern.

Provides a sophisticated singleton implementation that can be controlled through configuration settings. The singleton behavior is determined by a configuration key ‘<class_name>.singleton’ - when True, the class behaves as a singleton; when False, new instances are created each time.

This allows applications to control singleton behavior through configuration without code changes, enabling different patterns for different environments (e.g., singleton in production, new instances in testing).

Parameters:

class – The class to decorate with conditional singleton behavior.

Returns:

A wrapper function that manages instance creation according to the singleton configuration setting.

Return type:

function

Example

Using the conditional singleton decorator:

@singleton_or_not
class MyConfig:
    def __init__(self):
        pass

# Behavior depends on 'myconfig.singleton' configuration:
# If True (default): same instance returned
# If False: new instance created each time
config1 = MyConfig()
config2 = MyConfig()  # Same or different based on config

Note

The decorator maintains an internal instances dictionary to track singleton objects. The singleton check is performed on each instantiation to allow dynamic behavior changes through configuration updates.