Compare commits

..

No commits in common. "7af83b49a5c46c8a203b21b4760caf4b732f2440" and "a507ed9f466304648833f80a4426957c0f624707" have entirely different histories.

11 changed files with 45 additions and 146 deletions

View File

@ -1,16 +1,17 @@
import copy
import typing
import functools
from inspect import signature, Parameter, Signature
from typing import Optional
from typing import Optional, Callable
from cpl_core.configuration.configuration_abc import ConfigurationABC
from cpl_core.configuration.configuration_model_abc import ConfigurationModelABC
from cpl_core.console import Console
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
from cpl_core.dependency_injection.service_provider_abc import ServiceProviderABC
from cpl_core.environment.application_environment_abc import ApplicationEnvironmentABC
from cpl_core.type import T
@ -43,7 +44,7 @@ class ServiceProvider(ServiceProviderABC):
return None
def _get_service(self, parameter: Parameter) -> Optional[object]:
def _get_service(self, parameter: Parameter) -> object:
for descriptor in self._service_descriptors:
if descriptor.service_type == parameter.annotation or issubclass(descriptor.service_type, parameter.annotation):
if descriptor.implementation is not None:
@ -57,32 +58,12 @@ class ServiceProvider(ServiceProviderABC):
# raise Exception(f'Service {parameter.annotation} not found')
def _get_services(self, t: type) -> list[Optional[object]]:
implementations = []
for descriptor in self._service_descriptors:
if descriptor.service_type == t or issubclass(descriptor.service_type, t):
if descriptor.implementation is not None:
implementations.append(descriptor.implementation)
continue
implementation = self.build_service(descriptor.service_type)
if descriptor.lifetime == ServiceLifetimeEnum.singleton:
descriptor.implementation = implementation
implementations.append(implementation)
return implementations
def build_by_signature(self, sig: Signature) -> list[T]:
params = []
for param in sig.parameters.items():
parameter = param[1]
if parameter.name != 'self' and parameter.annotation != Parameter.empty:
if typing.get_origin(parameter.annotation) == list:
params.append(self._get_services(typing.get_args(parameter.annotation)[0]))
elif issubclass(parameter.annotation, ServiceProviderABC):
if issubclass(parameter.annotation, ServiceProviderABC):
params.append(self)
elif issubclass(parameter.annotation, ApplicationEnvironmentABC):
@ -102,7 +83,7 @@ class ServiceProvider(ServiceProviderABC):
return params
def build_service(self, service_type: type) -> object:
def build_service(self, service_type: T) -> object:
for descriptor in self._service_descriptors:
if descriptor.service_type == service_type or issubclass(descriptor.service_type, service_type):
if descriptor.implementation is not None:
@ -139,12 +120,17 @@ class ServiceProvider(ServiceProviderABC):
return implementation
def get_services(self, service_type: T) -> list[Optional[T]]:
implementations = []
@classmethod
def inject(cls, f=None):
if f is None:
return functools.partial(cls.inject)
if typing.get_origin(service_type) != list:
raise Exception(f'Invalid type {service_type}! Expected list of type')
@functools.wraps(f)
def inner(*args, **kwargs):
if cls._provider is None:
raise Exception(f'{cls.__name__} not build!')
implementations.extend(self._get_services(typing.get_args(service_type)[0]))
injection = cls._provider.build_by_signature(signature(f))
return f(*injection, *args, **kwargs)
return implementations
return inner

View File

@ -1,8 +1,8 @@
import functools
from abc import abstractmethod, ABC
from inspect import Signature, signature
from inspect import Signature
from typing import Type, Optional
from cpl_core.dependency_injection.scope_abc import ScopeABC
from cpl_core.type import T
@ -23,12 +23,12 @@ class ServiceProviderABC(ABC):
def build_by_signature(self, sig: Signature) -> list[T]: pass
@abstractmethod
def build_service(self, service_type: type) -> object:
def build_service(self, service_type: T) -> object:
r"""Creates instance of given type
Parameter
---------
instance_type: :class:`type`
instance_type: :class:`Type`
The type of the searched instance
Returns
@ -36,25 +36,25 @@ class ServiceProviderABC(ABC):
Object of the given type
"""
pass
@abstractmethod
def set_scope(self, scope: ScopeABC):
r"""Sets the scope of service provider
Parameter
---------
Object of type :class:`cpl_core.dependency_injection.scope_abc.ScopeABC`
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_abc.ScopeABC`
Object of type :class:`cpl_core.dependency_injection.scope.Scope`
"""
pass
@ -64,51 +64,16 @@ class ServiceProviderABC(ABC):
Parameter
---------
instance_type: :class:`cpl_core.type.T`
instance_type: :class:`Type`
The type of the searched instance
Returns
-------
Object of type Optional[:class:`cpl_core.type.T`]
Object of type Optional[Callable[:class:`object`]]
"""
pass
@abstractmethod
def get_services(self, service_type: T) -> list[Optional[T]]:
r"""Returns instance of given type
Parameter
---------
instance_type: :class:`cpl_core.type.T`
The type of the searched instance
Returns
-------
Object of type list[Optional[:class:`cpl_core.type.T`]
"""
pass
@classmethod
def inject(cls, f=None):
r"""Decorator to allow injection into static and class methods
Parameter
---------
f: Callable
Returns
-------
function
"""
if f is None:
return functools.partial(cls.inject)
@functools.wraps(f)
def inner(*args, **kwargs):
if cls._provider is None:
raise Exception(f'{cls.__name__} not build!')
injection = cls._provider.build_by_signature(signature(f))
return f(*injection, *args, **kwargs)
return inner
# @classmethod
# @abstractmethod
# def inject(cls):
# pass

View File

@ -4,10 +4,8 @@ from cpl_core.console.console import Console
from cpl_core.dependency_injection import ServiceProviderABC
from cpl_core.dependency_injection.scope import Scope
from di.static_test import StaticTest
from di.test_abc import TestABC
from di.test_service import TestService
from di.test_service_service import TestService
from di.di_tester_service import DITesterService
from di.tester import Tester
class Application(ApplicationABC):
@ -30,6 +28,10 @@ class Application(ApplicationABC):
dit: DITesterService = scope.service_provider.get_service(DITesterService)
dit.run()
# Console.write_line('Disposed:')
# ts1: TestService = scope1.service_provider.get_service(TestService)
# ts1.run()
with self._services.create_scope() as scope:
Console.write_line('Scope2')
ts: TestService = scope.service_provider.get_service(TestService)
@ -40,6 +42,5 @@ class Application(ApplicationABC):
Console.write_line('Global')
self._part_of_scoped()
StaticTest.test()
self._services.get_service(Tester)
Console.write_line(self._services.get_services(list[TestABC]))
with self._services.create_scope() as scope:
StaticTest.test()

View File

@ -1,5 +1,5 @@
from cpl_core.console.console import Console
from di.test_service import TestService
from di.test_service_service import TestService
class DITesterService:

View File

@ -2,12 +2,8 @@ from cpl_core.application import StartupABC
from cpl_core.configuration import ConfigurationABC
from cpl_core.dependency_injection import ServiceProviderABC, ServiceCollectionABC
from cpl_core.environment import ApplicationEnvironment
from di.test1_service import Test1Service
from di.test2_service import Test2Service
from di.test_abc import TestABC
from di.test_service import TestService
from di.test_service_service import TestService
from di.di_tester_service import DITesterService
from di.tester import Tester
class Startup(StartupABC):
@ -21,9 +17,5 @@ class Startup(StartupABC):
def configure_services(self, services: ServiceCollectionABC, environment: ApplicationEnvironment) -> ServiceProviderABC:
services.add_scoped(TestService)
services.add_scoped(DITesterService)
services.add_singleton(TestABC, Test1Service)
services.add_singleton(TestABC, Test2Service)
services.add_singleton(Tester)
return services.build_service_provider()

View File

@ -1,6 +1,6 @@
from cpl_core.configuration import ConfigurationABC
from cpl_core.dependency_injection import ServiceProvider, ServiceProviderABC
from di.test_service import TestService
from di.test_service_service import TestService
class StaticTest:

View File

@ -1,13 +0,0 @@
import string
from cpl_core.console.console import Console
from cpl_core.utils.string import String
from di.test_abc import TestABC
class Test1Service(TestABC):
def __init__(self):
TestABC.__init__(self, String.random_string(string.ascii_lowercase, 8))
def run(self):
Console.write_line(f'Im {self._name}')

View File

@ -1,13 +0,0 @@
import string
from cpl_core.console.console import Console
from cpl_core.utils.string import String
from di.test_abc import TestABC
class Test2Service(TestABC):
def __init__(self):
TestABC.__init__(self, String.random_string(string.ascii_lowercase, 8))
def run(self):
Console.write_line(f'Im {self._name}')

View File

@ -1,10 +0,0 @@
from abc import ABC
class TestABC(ABC):
def __init__(self, name: str):
self._name = name
def __repr__(self):
return f'<{type(self).__name__} {self._name}>'

View File

@ -1,5 +1,4 @@
import string
from cpl_core.console.console import Console
from cpl_core.utils.string import String
@ -8,6 +7,7 @@ class TestService:
def __init__(self):
self._name = String.random_string(string.ascii_lowercase, 8)
def run(self):
Console.write_line(f'Im {self._name}')
Console.write_line(f'Im {self._name}')

View File

@ -1,9 +0,0 @@
from cpl_core.console.console import Console
from di.test_abc import TestABC
class Tester:
def __init__(self, t1: TestABC, t2: TestABC, t3: list[TestABC]):
Console.write_line('Tester:')
Console.write_line(t1, t2, t3)