Source code for mafw.processor.meta

#  Copyright 2025–2026 European Union
#  Author: Bulgheroni Antonio (antonio.bulgheroni@ec.europa.eu)
#  SPDX-License-Identifier: EUPL-1.2
"""
Metaclass for the Processor framework.

This module defines :class:`~mafw.processor.ProcessorMeta`, the metaclass responsible for
finalising every :class:`~mafw.processor.Processor` subclass at creation time.
Its duties include:

- Ensuring parameter definitions are properly inherited and registered.
- Validating any declared filter schema against the allowed model constraints.
- Installing the super-call wrappers that guard method execution at runtime.
- Invoking :meth:`~mafw.processor.Processor.__post_init__` after each instance
  is constructed.

.. versionadded:: 2.3
    Extracted from the monolithic ``processor.py`` module for improved
    maintainability and focused testing.
"""

from __future__ import annotations

from typing import TYPE_CHECKING, Any, cast

from mafw.processor.parameters import _ensure_parameter_definitions, _validate_filter_schema

if TYPE_CHECKING:
    from mafw.processor.base import Processor


[docs] class ProcessorMeta(type): """Metaclass that finalizes Processor subclasses before instantiation.""" def __init__(cls, name: str, bases: tuple[type, ...], namespace: dict[str, Any]) -> None: """ Set up new Processor subclasses. This method first checks the class for well-formed parameter definitions and filter metadata, then runs the super-call wrapping machinery described below. The wrappers are installed at class-creation time so that any later instance will be guarded before it even starts executing. """ super().__init__(name, bases, namespace) # Validate and register parameter descriptors declared on the new class. _ensure_parameter_definitions(cast(type['Processor'], cls)) _validate_filter_schema(cast(type['Processor'], cls)) # If the metaclass detected a deferred error during descriptor registration # (e.g. duplicate parameter names), raise it now. error = getattr(cls, '_parameter_definition_error', None) if error is not None: delattr(cls, '_parameter_definition_error') raise error # For concrete Processor subclasses (not Processor itself), install wrappers # that verify super() was called in overridden lifecycle methods. if any(base.__name__ == 'Processor' for base in cls.__mro__[1:]): apply_wrappers = getattr(cls, '_apply_super_call_wrappers', None) if apply_wrappers is not None: apply_wrappers() def __call__(cls, *args: Any, **kwargs: Any) -> ProcessorMeta: """ Create a new Processor instance and run post-initialisation. After the standard ``type.__call__`` produces the instance, this override invokes ``__post_init__`` — giving subclasses a hook that runs after ``__init__`` completes but before the caller receives the object. """ obj = type.__call__(cls, *args, **kwargs) obj.__post_init__() return cast(ProcessorMeta, obj)