Source code for confii.loaders.loader

from abc import ABC, abstractmethod
from typing import Any, Dict, Optional

from confii.exceptions import ConfigFormatError, ConfigLoadError


[docs] class Loader(ABC): """Abstract base class for configuration loaders. All configuration loaders must inherit from this class and implement the `load()` method. This provides a consistent interface for loading configuration from various sources (files, remote URLs, environment, etc.). Attributes: source: The source identifier (file path, URL, prefix, etc.) config: The loaded configuration dictionary (may be empty if not loaded yet) """
[docs] def __init__(self, source: str) -> None: """Initialize the loader with a source. Args: source: The source identifier (file path, URL, prefix, etc.) """ self.source: str = source self.config: Dict[str, Any] = {}
[docs] @abstractmethod def load(self) -> Optional[Dict[str, Any]]: """Load configuration from the source. This method must be implemented by subclasses to load configuration from their specific source type. Returns: Dictionary containing the loaded configuration, or None if the source doesn't exist or couldn't be loaded (depending on loader behavior). Raises: ConfigLoadError: If loading fails due to an error (not just missing source) ConfigFormatError: If the configuration format is invalid """ raise NotImplementedError("Load method must be implemented by subclasses")
def _read_file(self, source: str) -> str: """Read file contents from a file path. Args: source: Path to the file to read Returns: File contents as a string Raises: ConfigLoadError: If the file cannot be read """ try: with open(source, encoding="utf-8") as file: return file.read() except FileNotFoundError as e: raise ConfigLoadError( f"Configuration file not found: {source}", source=source, loader_type=self.__class__.__name__, original_error=e, ) from e except PermissionError as e: raise ConfigLoadError( f"Permission denied reading configuration file: {source}", source=source, loader_type=self.__class__.__name__, original_error=e, ) from e except Exception as e: raise ConfigLoadError( f"Error reading configuration file: {source}", source=source, loader_type=self.__class__.__name__, original_error=e, ) from e def _handle_error(self, error: Exception) -> None: """Handle errors during configuration loading. Args: error: The exception that occurred during loading Raises: ConfigFormatError: For format-related errors ConfigLoadError: For other loading errors """ # Try to extract format-specific information from the error if hasattr(error, "lineno") and hasattr(error, "colno"): raise ConfigFormatError( f"Configuration format error in {self.source}", source=self.source, line_number=getattr(error, "lineno", None), column_number=getattr(error, "colno", None), original_error=error, ) from error raise ConfigLoadError( f"Error loading configuration from {self.source}", source=self.source, loader_type=self.__class__.__name__, original_error=error, ) from error