""" Pluggable Result Extractor System Base classes and implementations for extracting metrics from FEA results. """ from abc import ABC, abstractmethod from typing import Dict, Any, Optional from pathlib import Path class ResultExtractor(ABC): """Base class for all result extractors.""" @abstractmethod def extract(self, result_files: Dict[str, Path], config: Dict[str, Any]) -> Dict[str, float]: """ Extract metrics from FEA results. Args: result_files: Dictionary mapping file types to paths (e.g., {'op2': Path(...), 'f06': Path(...)}) config: Extractor-specific configuration parameters Returns: Dictionary mapping metric names to values """ pass @property @abstractmethod def required_files(self) -> list[str]: """List of required file types (e.g., ['op2'], ['f06'], etc.).""" pass @property def name(self) -> str: """Extractor name for registration.""" return self.__class__.__name__.replace("Extractor", "").lower() # Registry of available extractors _EXTRACTOR_REGISTRY: Dict[str, type[ResultExtractor]] = {} def register_extractor(extractor_class: type[ResultExtractor]) -> type[ResultExtractor]: """Decorator to register an extractor.""" _EXTRACTOR_REGISTRY[extractor_class().name] = extractor_class return extractor_class def get_extractor(name: str) -> Optional[type[ResultExtractor]]: """Get extractor class by name.""" return _EXTRACTOR_REGISTRY.get(name) def list_extractors() -> list[str]: """List all registered extractor names.""" return list(_EXTRACTOR_REGISTRY.keys()) __all__ = [ "ResultExtractor", "register_extractor", "get_extractor", "list_extractors", ]