Source code for src.core.configurator.config_loader

"""This module provides functionality to load
    configuration settings from a file.

    It defines:
        - `IConfigLoader`:
            An interface (via Protocol) that specifies a `load()`
            method for loading configuration data.
        - `ConfigLoader`:
            Implements `IConfigLoader` and `LoggerMixin` to load
            configuration from an INI file.

    Main features:
        - Loads configuration from a specified file path,
        defaulting to 'src/conf/config.ini'.
        - Reads a specific section (default 'Pathes')
        from the configuration file.
        - Returns a dictionary containing configuration key-value pairs.
        - Raises `FileNotFoundError` if the configuration file does not exist.
        - Raises `ConfigurationError` if the section is missing or invalid.

    Usage:
        Instantiate `ConfigLoader`, optionally passing a logger,
        and call `load()` with the desired file path and section.
"""

# region Imports
import os
import logging
import configparser

from os import PathLike
from typing import Protocol, Optional, AnyStr

from src.core.base import LoggerMixin
from src.core.configurator.configuration_error import ConfigurationError
# endregion


[docs] class IConfigLoader(Protocol): """Interface for configuration loader classes. Defines a load() method to load configuration data. """
[docs] def load(self) -> dict: """Loads configuration from a file. Returns: A dictionary containing the loaded configuration. Returns an empty dictionary if the file doesn't exist or is invalid. Raises: FileNotFoundError: if loading fails. """ raise NotImplementedError
[docs] class ConfigLoader(LoggerMixin, IConfigLoader): """Loads configuration data from an INI file, with logging support.""" def __init__(self, logger: Optional[logging.Logger] = None): super().__init__(logger)
[docs] def load( self, base_config_filepath: Optional[PathLike[AnyStr]] = os.path.abspath( os.path.join('src', 'conf', 'config.ini') ), target_section: AnyStr = 'Pathes', ) -> dict: """Loads configuration from the specified INI file and section. Args: base_config_filepath (PathLike): Path to the configuration file. target_section (str): Section in the configuration file to load. Returns: dict: Dictionary with configuration entries from the section. Raises: FileNotFoundError: if the configuration file does not exist. ConfigurationError: if the section is missing or cannot be parsed. """ if ( os.path.exists(base_config_filepath) and os.path.isfile(base_config_filepath) ): conf = configparser.ConfigParser( inline_comment_prefixes=[';', '#'], comment_prefixes=[';', '#']) conf.read(os.path.join(base_config_filepath)) config_dict = {'target_section': target_section} if target_section in conf: for path_value in conf[target_section]: config_dict[path_value] = conf[target_section][path_value] else: raise ConfigurationError( "Can't parse configuration file " f"under path '{base_config_filepath}'. " "See the project config documentation" ) return config_dict else: file_not_found_msg = \ f"Can't find config file under path '{base_config_filepath}'", self.logger.critical(file_not_found_msg) raise FileNotFoundError(file_not_found_msg)