Source code for edri.dataclass.injection

from collections.abc import Callable
from copy import copy
from inspect import signature
from typing import Any

__all__ = ["Injection"]


[docs] class Injection: """ A class that facilitates the injection of dependencies into one or more classes. It manages the initialization of multiple classes by providing their necessary parameters. This class iterates over provided classes and dynamically creates callables that can instantiate each class with filtered parameters based on the provided arguments. Args: classes (tuple[Callable]): Validator classes or functions to call. parameters (dict[str, Any]): A dictionary of parameter names and values that will be passed to the constructors of the classes. Only parameters matching the constructor's signature will be passed to the class. Use ``| None`` to mark an injection as nullable — when the value is ``None``, conversion returns ``None`` instead of running validation:: inject(StringValidator, minimum_length=2) | None Methods: __or__: Supports ``inject(...) | None`` syntax. Returns a copy of the Injection with ``_nullable=True``. __repr__: Returns a string representation of the Injection instance, showing the classes and the parameters that will be passed to their constructors. """ def __init__( self, classes: tuple[Callable[..., Any], ...], parameters: dict[str, Any], _nullable: bool = False, ) -> None: super().__init__() self.classes = classes # Store the classes self.parameters = parameters # Store the parameters self._nullable = _nullable def __or__(self, other: Any) -> Any: if other is None: result = copy(self) result._nullable = True return result return NotImplemented def __repr__(self) -> str: # Representation of the class, including class names and their filtered parameters param_info = [] for cls in self.classes: # Get the signature of the __init__ method of the class sig = signature(cls) # Extract parameter names from the signature param_names: list[str] = [param.name for param in sig.parameters.values() if param.name != 'self'] # Filter the parameters dictionary to include only the ones needed for the class filtered_params: dict[str, Any] = {k: v for k, v in self.parameters.items() if k in param_names} name = getattr(cls, "__name__", type(cls).__name__) param_info.append(f"{name}({', '.join([f'{k}={v}' for k, v in filtered_params.items()])})") # Return a string with the class names and their parameters return f"Injection[{', '.join(param_info)}]"