Added logic to handle scoped services

This commit is contained in:
2021-11-14 11:56:42 +01:00
parent 7749d5a789
commit 98e343a108
18 changed files with 273 additions and 4 deletions

View File

@@ -0,0 +1,18 @@
from cpl_core.console.console import Console
from cpl_core.dependency_injection.scope_abc import ScopeABC
from cpl_core.dependency_injection.service_provider_abc import ServiceProviderABC
class Scope(ScopeABC):
def __init__(self, service_provider: ServiceProviderABC):
self._service_provider = service_provider
self._service_provider.set_scope(self)
@property
def service_provider(self) -> ServiceProviderABC:
return self._service_provider
def dispose(self):
self._service_provider = None

View File

@@ -0,0 +1,24 @@
from abc import ABC, abstractmethod
class ScopeABC(ABC):
r"""ABC for the class :class:`cpl_core.dependency_injection.scope.Scope`"""
def __init__(self):
pass
@property
@abstractmethod
def service_provider(self):
r"""Returns to service provider of scope
Returns
-------
Object of type :class:`cpl_core.dependency_injection.service_provider_abc.ServiceProviderABC`
"""
pass
@abstractmethod
def dispose():
r"""Sets service_provider to None
"""
pass

View File

@@ -0,0 +1,19 @@
from cpl_core.dependency_injection.scope import Scope
from cpl_core.dependency_injection.scope_abc import ScopeABC
from cpl_core.dependency_injection.service_provider_abc import ServiceProviderABC
class ScopeBuilder:
r"""Class to build :class:`cpl_core.dependency_injection.scope.Scope`"""
def __init__(self, service_provider: ServiceProviderABC) -> None:
self._service_provider = service_provider
def build(self) -> ScopeABC:
r"""Returns scope
Returns
-------
Object of type :class:`cpl_core.dependency_injection.scope.Scope`
"""
return Scope(self._service_provider)

View File

@@ -4,5 +4,5 @@ from enum import Enum
class ServiceLifetimeEnum(Enum):
singleton = 0
scoped = 1 # not supported yet
scoped = 1
transient = 2

View File

@@ -1,10 +1,13 @@
from collections import Callable
import copy
from inspect import signature, Parameter
from typing import Optional
from cpl_core.configuration.configuration_abc import ConfigurationABC
from cpl_core.configuration.configuration_model_abc import ConfigurationModelABC
from cpl_core.database.context.database_context_abc import DatabaseContextABC
from cpl_core.dependency_injection.scope_abc import ScopeABC
from cpl_core.dependency_injection.scope_builder import ScopeBuilder
from cpl_core.dependency_injection.service_provider_abc import ServiceProviderABC
from cpl_core.dependency_injection.service_descriptor import ServiceDescriptor
from cpl_core.dependency_injection.service_lifetime_enum import ServiceLifetimeEnum
@@ -30,6 +33,7 @@ class ServiceProvider(ServiceProviderABC):
self._service_descriptors: list[ServiceDescriptor] = service_descriptors
self._configuration: ConfigurationABC = config
self._database_context = db_context
self._scope: Optional[ScopeABC] = None
def _find_service(self, service_type: type) -> ServiceDescriptor:
for descriptor in self._service_descriptors:
@@ -84,8 +88,15 @@ class ServiceProvider(ServiceProviderABC):
params.append(self._get_service(parameter))
return service_type(*params)
def set_scope(self, scope: ScopeABC):
self._scope = scope
def create_scope(self) -> ScopeABC:
sb = ScopeBuilder(ServiceProvider(copy.deepcopy(self._service_descriptors), self._configuration, self._database_context))
return sb.build()
def get_service(self, service_type: type) -> Optional[Callable]:
def get_service(self, service_type: type) -> Optional[Callable[object]]:
result = self._find_service(service_type)
if result is None:
@@ -95,7 +106,7 @@ class ServiceProvider(ServiceProviderABC):
return result.implementation
implementation = self.build_service(service_type)
if result.lifetime == ServiceLifetimeEnum.singleton:
if result.lifetime == ServiceLifetimeEnum.singleton or result.lifetime == ServiceLifetimeEnum.scoped and self._scope is not None:
result.implementation = implementation
return implementation

View File

@@ -2,6 +2,8 @@ from abc import abstractmethod, ABC
from collections import Callable
from typing import Type, Optional
from cpl_core.dependency_injection.scope_abc import ScopeABC
class ServiceProviderABC(ABC):
r"""ABC for the class :class:`cpl_core.dependency_injection.service_provider.ServiceProvider`"""
@@ -24,9 +26,30 @@ class ServiceProviderABC(ABC):
Object of the given type
"""
pass
@abstractmethod
def set_scope(self, scope: ScopeABC):
r"""Sets the scope of service provider
Parameter
---------
scope :class:`cpl_core.dependency_injection.scope.Scope`
Service scope
"""
pass
@abstractmethod
def create_scope(self) -> ScopeABC:
r"""Creates a service scope
Returns
-------
Object of type :class:`cpl_core.dependency_injection.scope.Scope`
"""
pass
@abstractmethod
def get_service(self, instance_type: Type) -> Optional[Callable]:
def get_service(self, instance_type: Type) -> Optional[Callable[object]]:
r"""Returns instance of given type
Parameter