Component Processor Metaprogramming

Overview

Traditional component processing systems hardcode assumptions about component names and processing patterns. The DynamicInterfaceMeta system eliminates these assumptions by generating abstract method interfaces dynamically from component enums.

# Generate processing interface for any component enum
ProcessorInterface = DynamicInterfaceMeta(
    "CustomProcessor",
    (ComponentProcessorInterface,),
    {},
    component_enum=MyComponents,
    method_patterns=['process', 'validate', 'summarize']
)

# Interface automatically gets abstract methods:
# - process_well(), process_site(), process_channel()
# - validate_well(), validate_site(), validate_channel()
# - summarize_well(), summarize_site(), summarize_channel()

This enables the same processing framework to work with any component structure without manual interface definitions.

Dynamic Interface Generation

The metaclass generates abstract methods for each component × pattern combination.

class DynamicInterfaceMeta(type):
    """Metaclass that generates component processing interfaces."""

    def __new__(mcs, name, bases, namespace, component_enum=None, method_patterns=None, **kwargs):
        """Create interface class with generated abstract methods."""
        if component_enum and method_patterns:
            # Generate abstract methods for each component × pattern combination
            for component in component_enum:
                for pattern in method_patterns:
                    method_name = f"{pattern}_{component.value}"
                    # Create abstract method dynamically
                    def create_abstract_method(method_name=method_name):
                        @abstractmethod
                        def abstract_method(self, context, **kwargs):
                            raise NotImplementedError(f"Method {method_name} must be implemented")
                        abstract_method.__name__ = method_name
                        return abstract_method
                    namespace[method_name] = create_abstract_method()

        return super().__new__(mcs, name, bases, namespace)

This creates abstract methods that must be implemented by concrete processor classes.

Concrete Implementation

Concrete processors inherit from the generated interface and implement the abstract methods.

# Generate interface for specific component enum
MyProcessorInterface = DynamicInterfaceMeta(
    "MyProcessorInterface",
    (ComponentProcessorInterface,),
    {},
    component_enum=MyComponents,
    method_patterns=['process', 'validate']
)

# Implement concrete processor
class MyProcessor(MyProcessorInterface):
    def process_well(self, context, **kwargs):
        # Process well data
        pass

    def process_site(self, context, **kwargs):
        # Process site data
        pass

    def validate_well(self, context, **kwargs):
        # Validate well configuration
        pass

The metaclass ensures all required methods are implemented at class creation time.

Factory Pattern

The InterfaceGenerator provides cached interface creation for performance.

class InterfaceGenerator:
    def __init__(self):
        self._interface_cache: Dict[str, Type] = {}

    def create_interface(self, component_enum: Type[T],
                        method_patterns: Optional[list] = None) -> Type:
        """Create component-specific interface class."""
        cache_key = f"{component_enum.__name__}_{id(component_enum)}"
        if cache_key in self._interface_cache:
            return self._interface_cache[cache_key]

        interface_class = DynamicInterfaceMeta(
            f"{component_enum.__name__}ProcessorInterface",
            (ComponentProcessorInterface,),
            {},
            component_enum=component_enum,
            method_patterns=method_patterns or ['process', 'validate']
        )

        self._interface_cache[cache_key] = interface_class
        return interface_class

This enables efficient creation of component-specific processing interfaces.

Usage Example

# Create interface for custom components
class AnalysisComponents(Enum):
    SAMPLE = "sample"
    CONDITION = "condition"
    REPLICATE = "replicate"

generator = InterfaceGenerator()
AnalysisInterface = generator.create_interface(
    AnalysisComponents,
    method_patterns=['analyze', 'validate', 'export']
)

# Implement concrete processor
class SampleAnalyzer(AnalysisInterface):
    def analyze_sample(self, context, **kwargs):
        # Process sample data
        pass

    def validate_condition(self, context, **kwargs):
        # Validate condition setup
        pass

    # Must implement all generated abstract methods

Common Gotchas:

  • All generated abstract methods must be implemented - missing methods cause initialization errors

  • Method patterns are fixed at interface creation time - can’t be changed later

  • Interface classes are cached by enum object ID - enum changes require new interfaces