""" Abstract base class for data loaders. Dependency Inversion Principle: depend on abstractions, not concrete implementations. """ from abc import ABC, abstractmethod from pathlib import Path from typing import Any, Dict, Optional import pandas as pd class BaseDataLoader(ABC): """ Abstract base loader for all data sources. Concrete loaders must implement load() method. """ def __init__(self, data_path: Path, **kwargs): """ Initialize loader with data path. Args: data_path: Path to data file or directory **kwargs: Additional loader-specific parameters """ self.data_path = Path(data_path) self.kwargs = kwargs self._validate_path() def _validate_path(self) -> None: """Validate that data path exists.""" if not self.data_path.exists(): raise FileNotFoundError(f"Data path not found: {self.data_path}") @abstractmethod def load(self) -> pd.DataFrame: """ Load data and return as DataFrame. Must be implemented by concrete loaders. Returns: DataFrame with loaded data """ pass def get_metadata(self) -> Dict[str, Any]: """ Get metadata about the loaded data. Can be overridden by subclasses. Returns: Dictionary with metadata """ return { "source": self.__class__.__name__, "path": str(self.data_path) }