New implementation of scopes #186
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
from cpl.application.abc import ApplicationABC
|
||||
from cpl.core.console.console import Console
|
||||
from cpl.dependency import ServiceProvider
|
||||
from cpl.dependency.scope import Scope
|
||||
from di.static_test import StaticTest
|
||||
from di.test_abc import TestABC
|
||||
from di.test_service import TestService
|
||||
@@ -17,26 +16,30 @@ class Application(ApplicationABC):
|
||||
ts: TestService = self._services.get_service(TestService)
|
||||
ts.run()
|
||||
|
||||
def configure(self): ...
|
||||
|
||||
def main(self):
|
||||
with self._services.create_scope() as scope:
|
||||
Console.write_line("Scope1")
|
||||
ts: TestService = scope.service_provider.get_service(TestService)
|
||||
ts: TestService = scope.get_service(TestService)
|
||||
ts.run()
|
||||
dit: DITesterService = scope.service_provider.get_service(DITesterService)
|
||||
dit: DITesterService = scope.get_service(DITesterService)
|
||||
dit.run()
|
||||
|
||||
if ts.name != dit.name:
|
||||
raise Exception("DI is broken!")
|
||||
|
||||
with self._services.create_scope() as scope:
|
||||
Console.write_line("Scope2")
|
||||
ts: TestService = scope.service_provider.get_service(TestService)
|
||||
ts: TestService = scope.get_service(TestService)
|
||||
ts.run()
|
||||
dit: DITesterService = scope.service_provider.get_service(DITesterService)
|
||||
dit: DITesterService = scope.get_service(DITesterService)
|
||||
dit.run()
|
||||
|
||||
if ts.name != dit.name:
|
||||
raise Exception("DI is broken!")
|
||||
|
||||
Console.write_line("Global")
|
||||
self._part_of_scoped()
|
||||
StaticTest.test()
|
||||
|
||||
self._services.get_service(Tester)
|
||||
Console.write_line(self._services.get_services(list[TestABC]))
|
||||
Console.write_line(self._services.get_services(TestABC))
|
||||
|
||||
@@ -6,6 +6,10 @@ class DITesterService:
|
||||
def __init__(self, ts: TestService):
|
||||
self._ts = ts
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
return self._ts.name
|
||||
|
||||
def run(self):
|
||||
Console.write_line("DIT: ")
|
||||
self._ts.run()
|
||||
|
||||
@@ -12,9 +12,11 @@ class Startup(StartupABC):
|
||||
def __init__(self):
|
||||
StartupABC.__init__(self)
|
||||
|
||||
def configure_configuration(self): ...
|
||||
@staticmethod
|
||||
def configure_configuration(): ...
|
||||
|
||||
def configure_services(self, services: ServiceCollection) -> ServiceProvider:
|
||||
@staticmethod
|
||||
def configure_services(services: ServiceCollection) -> ServiceProvider:
|
||||
services.add_scoped(TestService)
|
||||
services.add_scoped(DITesterService)
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ from di.test_abc import TestABC
|
||||
|
||||
class Test1Service(TestABC):
|
||||
def __init__(self):
|
||||
TestABC.__init__(self, String.random_string(string.ascii_lowercase, 8))
|
||||
TestABC.__init__(self, String.random(8))
|
||||
|
||||
def run(self):
|
||||
Console.write_line(f"Im {self._name}")
|
||||
|
||||
@@ -6,7 +6,7 @@ from di.test_abc import TestABC
|
||||
|
||||
class Test2Service(TestABC):
|
||||
def __init__(self):
|
||||
TestABC.__init__(self, String.random_string(string.ascii_lowercase, 8))
|
||||
TestABC.__init__(self, String.random(8))
|
||||
|
||||
def run(self):
|
||||
Console.write_line(f"Im {self._name}")
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import string
|
||||
|
||||
from cpl.core.console.console import Console
|
||||
from cpl.core.utils.string import String
|
||||
|
||||
@@ -8,5 +6,9 @@ class TestService:
|
||||
def __init__(self):
|
||||
self._name = String.random(8)
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
return self._name
|
||||
|
||||
def run(self):
|
||||
Console.write_line(f"Im {self._name}")
|
||||
|
||||
@@ -9,7 +9,8 @@ from cpl.core.environment import Environment
|
||||
from cpl.core.log import LoggerABC
|
||||
from cpl.core.pipes import IPAddressPipe
|
||||
from cpl.mail import EMail, EMailClientABC
|
||||
from cpl.query.extension.list import List
|
||||
from cpl.query import List
|
||||
from general.scoped_service import ScopedService
|
||||
from test_service import TestService
|
||||
from test_settings import TestSettings
|
||||
|
||||
@@ -38,7 +39,7 @@ class Application(ApplicationABC):
|
||||
def main(self):
|
||||
self._logger.debug(f"Host: {Environment.get_host_name()}")
|
||||
self._logger.debug(f"Environment: {Environment.get_environment()}")
|
||||
Console.write_line(List(int, range(0, 10)).select(lambda x: f"x={x}").to_list())
|
||||
Console.write_line(List(range(0, 10)).select(lambda x: f"x={x}").to_list())
|
||||
Console.spinner("Test", self._wait, 2, spinner_foreground_color="red")
|
||||
test: TestService = self._services.get_service(TestService)
|
||||
ip_pipe: IPAddressPipe = self._services.get_service(IPAddressPipe)
|
||||
@@ -48,10 +49,21 @@ class Application(ApplicationABC):
|
||||
Console.write_line(f"DI working: {test == test2 and ip_pipe != ip_pipe2}")
|
||||
Console.write_line(self._services.get_service(LoggerABC))
|
||||
|
||||
scope = self._services.create_scope()
|
||||
Console.write_line("scope", scope)
|
||||
with self._services.create_scope() as s:
|
||||
Console.write_line("with scope", s)
|
||||
root_scoped_service = self._services.get_service(ScopedService)
|
||||
with self._services.create_scope() as scope:
|
||||
s_srvc1 = scope.get_service(ScopedService)
|
||||
s_srvc2 = scope.get_service(ScopedService)
|
||||
|
||||
Console.write_line(root_scoped_service)
|
||||
Console.write_line(s_srvc1)
|
||||
Console.write_line(s_srvc2)
|
||||
if root_scoped_service == s_srvc1 or s_srvc1 != s_srvc2:
|
||||
raise Exception("Root scoped service should not be equal to scoped service")
|
||||
|
||||
root_scoped_service2 = self._services.get_service(ScopedService)
|
||||
Console.write_line(root_scoped_service2)
|
||||
if root_scoped_service != root_scoped_service2:
|
||||
raise Exception("Root scoped service should be equal to root scoped service 2")
|
||||
|
||||
test_settings = Configuration.get(TestSettings)
|
||||
Console.write_line(test_settings.value)
|
||||
|
||||
10
example/custom/general/src/general/scoped_service.py
Normal file
10
example/custom/general/src/general/scoped_service.py
Normal file
@@ -0,0 +1,10 @@
|
||||
from cpl.core.console import Console
|
||||
|
||||
|
||||
class ScopedService:
|
||||
def __init__(self):
|
||||
self.value = "I am a scoped service"
|
||||
Console.write_line(self.value, self)
|
||||
|
||||
def get_value(self):
|
||||
return self.value
|
||||
@@ -4,6 +4,7 @@ from cpl.core.configuration import Configuration
|
||||
from cpl.core.environment import Environment
|
||||
from cpl.core.pipes import IPAddressPipe
|
||||
from cpl.dependency import ServiceCollection
|
||||
from general.scoped_service import ScopedService
|
||||
from test_service import TestService
|
||||
|
||||
|
||||
@@ -21,3 +22,4 @@ class Startup(StartupABC):
|
||||
services.add_module(mail)
|
||||
services.add_transient(IPAddressPipe)
|
||||
services.add_singleton(TestService)
|
||||
services.add_scoped(ScopedService)
|
||||
|
||||
13
src/cpl-api/cpl/api/middleware/_scope_middleware.py
Normal file
13
src/cpl-api/cpl/api/middleware/_scope_middleware.py
Normal file
@@ -0,0 +1,13 @@
|
||||
from cpl.api.abc import ASGIMiddleware
|
||||
from cpl.dependency.service_provider import ServiceProvider
|
||||
|
||||
|
||||
class ScopeMiddleware(ASGIMiddleware):
|
||||
def __init__(self, app, provider: ServiceProvider):
|
||||
ASGIMiddleware.__init__(self, app)
|
||||
self._app = app
|
||||
self._provider = provider
|
||||
|
||||
async def __call__(self, scope, receive, send):
|
||||
with self._provider.create_scope():
|
||||
await self._app(scope, receive, send)
|
||||
@@ -114,12 +114,15 @@ class String:
|
||||
|
||||
characters = []
|
||||
if letters:
|
||||
characters.append(string.ascii_letters)
|
||||
characters.extend(string.ascii_letters)
|
||||
|
||||
if digits:
|
||||
characters.append(string.digits)
|
||||
characters.extend(string.digits)
|
||||
|
||||
if special_characters:
|
||||
characters.append(string.punctuation)
|
||||
characters.extend(string.punctuation)
|
||||
|
||||
return "".join(random.choice(characters) for _ in range(length)) if characters else ""
|
||||
x = "".join(random.choice(list(characters)) for _ in range(length)) if characters else ""
|
||||
if len(x) != length:
|
||||
raise Exception("No characters selected to generate random string")
|
||||
return x
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import copy
|
||||
import typing
|
||||
from contextlib import contextmanager
|
||||
from inspect import signature, Parameter, Signature
|
||||
from typing import Optional, Type
|
||||
|
||||
@@ -6,6 +8,7 @@ from cpl.core.configuration import Configuration
|
||||
from cpl.core.configuration.configuration_model_abc import ConfigurationModelABC
|
||||
from cpl.core.environment import Environment
|
||||
from cpl.core.typing import T, R, Source
|
||||
from cpl.dependency import use_provider
|
||||
from cpl.dependency.service_descriptor import ServiceDescriptor
|
||||
from cpl.dependency.service_lifetime import ServiceLifetimeEnum
|
||||
|
||||
@@ -132,6 +135,19 @@ class ServiceProvider:
|
||||
|
||||
return service_type(*params, *args, **kwargs)
|
||||
|
||||
@contextmanager
|
||||
def create_scope(self):
|
||||
scoped_descriptors = []
|
||||
for d in self._service_descriptors:
|
||||
if d.lifetime == ServiceLifetimeEnum.singleton:
|
||||
scoped_descriptors.append(d)
|
||||
else:
|
||||
scoped_descriptors.append(copy.deepcopy(d))
|
||||
|
||||
scoped_provider = ServiceProvider(scoped_descriptors)
|
||||
with use_provider(scoped_provider):
|
||||
yield scoped_provider
|
||||
|
||||
def get_service(self, service_type: T, *args, **kwargs) -> Optional[R]:
|
||||
result = self._find_service(service_type)
|
||||
|
||||
@@ -143,7 +159,7 @@ class ServiceProvider:
|
||||
|
||||
implementation = self._build_service(service_type, *args, **kwargs)
|
||||
if (
|
||||
result.lifetime == ServiceLifetimeEnum.singleton
|
||||
result.lifetime in (ServiceLifetimeEnum.singleton, ServiceLifetimeEnum.scoped)
|
||||
):
|
||||
result.implementation = implementation
|
||||
|
||||
|
||||
Reference in New Issue
Block a user