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)}]"