""" Abstract base class for feature extractors. Dependency Inversion Principle: Depend on abstractions for feature extraction. """ from abc import ABC, abstractmethod from typing import Dict, Any import geopandas as gpd class BaseFeatureExtractor(ABC): """ Abstract base class for watershed/basin feature extractors. Each extractor extracts specific category of features (topological, soil, etc.) """ def __init__(self, **kwargs): """ Initialize extractor. Args: **kwargs: Extractor-specific parameters """ self.params = kwargs @abstractmethod def extract(self, basin_gdf: gpd.GeoDataFrame) -> Dict[str, Any]: """ Extract features from basin geometry. Args: basin_gdf: GeoDataFrame with basin boundaries Returns: Dictionary of extracted features """ pass def get_feature_names(self) -> list: """ Get list of feature names this extractor produces. Returns: List of feature names """ return [] def validate_inputs(self, basin_gdf: gpd.GeoDataFrame) -> bool: """ Validate input geodataframe. Args: basin_gdf: GeoDataFrame to validate Returns: True if valid """ if basin_gdf is None or len(basin_gdf) == 0: return False if basin_gdf.geometry.is_empty.any(): return False return True