Source code for retrosys.core.dependency_injection.lazy

from typing import Generic, Type
from .project_types import T, ContainerProtocol


[docs] class Lazy(Generic[T]): """Wrapper for lazy dependency resolution. This class provides a way to delay the resolution of a dependency until it is actually needed. It acts as a proxy that resolves the dependency only when accessed, which can help break circular dependencies and improve performance when expensive dependencies might not always be used. Attributes: _container: The dependency injection container used to resolve the service. _service_type: The type of service to be lazily resolved. _context_key: Optional key for contextual binding. _instance: Cached instance of the resolved service (None until resolved). _resolved: Flag indicating whether the service has been resolved. Usage: # As a variable lazy_service = container.lazy_resolve(ServiceType) # Later, when needed service_instance = lazy_service() # For async resolution service_instance = await lazy_service.async_resolve() """
[docs] def __init__( self, container: ContainerProtocol, service_type: Type[T], context_key: str = "" ): """Initialize a new lazy dependency reference. Args: container: The container that will be used to resolve the service. service_type: The type of service to be lazily resolved. context_key: Optional key for contextual binding. Defaults to an empty string. """ self._container = container self._service_type = service_type self._context_key = context_key self._instance = None self._resolved = False
[docs] def __call__(self) -> T: """Resolve the dependency when the lazy object is called. This method allows the Lazy object to be used like a function. When called, it resolves the dependency if not already resolved, caches the instance, and returns it. Returns: T: The resolved service instance. Side Effects: Resolves the dependency and caches it on first call. """ if not self._resolved: self._instance = self._container.resolve( self._service_type, self._context_key ) self._resolved = True return self._instance
[docs] async def async_resolve(self) -> T: """Asynchronously resolve the dependency. This method is the asynchronous counterpart to __call__. It should be used when working with services that require async resolution. Returns: T: The resolved service instance. Side Effects: Asynchronously resolves the dependency and caches it on first call. """ if not self._resolved: self._instance = await self._container.resolve_async( self._service_type, self._context_key ) self._resolved = True return self._instance