Source code for src.configurator

"""This module contains the implementation of the Configurator class,
    which manages the configuration setup for an analysis pipeline.

    It handles command-line argument parsing, logging configuration,
    output directory validation/creation, and loading configuration
    parameters from a configuration file.

    The Configurator class is designed as a singleton to ensure
    a single point of configuration management throughout the application.

    It utilizes other components such as PathValidator,
    LoggingConfigurator, and ConfigLoader to perform its tasks.

    Usage:
        Instantiate the Configurator class to initialize configuration,
        logging, and output directories.
"""

# region Imports
import os
import sys
import argparse
import logging

from os import PathLike
from typing import AnyStr, Optional

from src.core.base import SingletonMeta

from src.core.configurator.path_validator import PathValidator
from src.core.configurator.argument_parser import ArgumentParser
from src.core.configurator.config_loader import ConfigLoader
from src.core.configurator.logging_configurator import LoggingConfigurator
# endregion


[docs] class Configurator(metaclass=SingletonMeta): """Singleton class responsible for managing configuration, logging, and output directory setup for the analysis pipeline. This class handles parsing command-line arguments, setting up logging, validating and creating the output directory, and loading configuration parameters from a configuration file. Attributes: args (argparse.Namespace): Parsed command-line arguments. log_path (str): Absolute path to the log file. logger (logging.Logger): Logger instance for logging messages. output_dir (str): Path to the output directory where results will be stored. config (dict): Dictionary containing configuration parameters. Methods: _parse_args(): Parses command-line arguments. _setup_logger(log_filename): Sets up the logging configuration. _setup_output_directory(output_dir): Validates or creates the output directory. _load_configuration(config_path): Loads configuration parameters. parse_configuration(base_config_filepath, target_section): Loads specific configuration sections. """ def __init__( self, args: argparse.Namespace = None, config_path: PathLike[AnyStr] = None, log_path: PathLike[AnyStr] = None, output_dir: PathLike[AnyStr] = None ): """Initializes the Configurator, setting up logging, \ output directory, and configuration. Args: args (argparse.Namespace, optional): Parsed command-line arguments. If None, parsed internally. config_path (PathLike[AnyStr], optional): Path to configuration file. Defaults to None. log_path (PathLike[AnyStr], optional): Path to log file. Defaults to None. output_dir (PathLike[AnyStr], optional): Path to output directory. Defaults to None. """ self.args = args or self._parse_args() self.log_path, self.logger = self._setup_logger( log_filename=log_path or self.args.logFilename, args=self.args) self.output_dir = self._setup_output_directory(self.args.outputDir) self.config = self.parse_configuration( base_config_filepath=self.args.configFilepath, target_section='Pathes' )
[docs] @staticmethod def _parse_args() -> argparse.Namespace: """Parses command-line arguments using argparse. Returns: argparse.Namespace: Parsed arguments object containing command-line parameters. """ parser = ArgumentParser() return parser.parse()
[docs] @staticmethod def _setup_logger( log_filename: PathLike[AnyStr], args: argparse.Namespace = None ) -> tuple[PathLike[AnyStr], logging.Logger]: """Sets up the logging system with the specified log file. Args: log_filename (PathLike[AnyStr]): Path to the log file. Returns: tuple: A tuple containing the absolute path to the log file and the configured Logger object. """ logger = LoggingConfigurator(path_validator=PathValidator(), args=args) return ( os.path.abspath(log_filename), logger.set_logger(silent=False) )
[docs] def _setup_output_directory( self, output_dir: PathLike[AnyStr] ) -> PathLike[AnyStr]: """Validates the output directory path, creates it if it doesn't exist, and handles existing directory conflicts based on user input. Args: output_dir (PathLike[AnyStr]): Path to the desired output directory. Returns: PathLike[AnyStr]: Absolute path to the validated or created output directory. """ output_dir = os.path.abspath(os.path.normpath(output_dir)) if os.path.exists(output_dir): # Create output directory if not os.path.isdir(output_dir): os.mkdir(output_dir) else: msg = f"Directory '{output_dir}' already exists" self.logger.warning(msg) match input( f"Do you want to use existing directory '{output_dir}'" f" as the current output directory [y/n]: " ).lower(): case 'n': sys.exit(os.EX_OK) case _: pass else: os.mkdir(output_dir) self.logger.info("Use '%s' directory as output", output_dir) return output_dir
[docs] def parse_configuration( self, base_config_filepath: Optional[PathLike[AnyStr]], target_section: AnyStr = 'Pathes' ) -> dict: """Loads a specific section of the configuration from a base configuration file. Args: base_config_filepath (PathLike[AnyStr], optional): Path to the base configuration file. Defaults to 'src/conf/config.ini' relative to current directory. target_section (str, optional): The section within the configuration file to load. Defaults to 'Pathes'. Returns: dict: Dictionary of configuration parameters from the specified section. """ if base_config_filepath is None: base_config_filepath = self.args.configFilepath return ConfigLoader(logger=self.logger).load( base_config_filepath, target_section)