mirror of
https://github.com/ets-labs/python-dependency-injector.git
synced 2024-12-01 14:04:01 +03:00
Add singleton implementation + tests for all singleton types
This commit is contained in:
parent
f07f3e4943
commit
6020c6caf4
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -141,6 +141,7 @@ cdef class FactoryAggregate(Provider):
|
|||
# Singleton providers
|
||||
cdef class BaseSingleton(Provider):
|
||||
cdef Factory __instantiator
|
||||
cdef bint __async
|
||||
|
||||
|
||||
cdef class Singleton(BaseSingleton):
|
||||
|
|
|
@ -1941,6 +1941,7 @@ cdef class BaseSingleton(Provider):
|
|||
self.__class__, self.__class__.provided_type))
|
||||
|
||||
self.__instantiator = Factory(provides, *args, **kwargs)
|
||||
self.__async = False
|
||||
|
||||
super(BaseSingleton, self).__init__()
|
||||
|
||||
|
@ -2128,10 +2129,30 @@ cdef class Singleton(BaseSingleton):
|
|||
cpdef object _provide(self, tuple args, dict kwargs):
|
||||
"""Return single instance."""
|
||||
if self.__storage is None:
|
||||
self.__storage = __factory_call(self.__instantiator,
|
||||
args, kwargs)
|
||||
instance = __factory_call(self.__instantiator, args, kwargs)
|
||||
|
||||
if __isawaitable(instance):
|
||||
future_result = asyncio.Future()
|
||||
instance = asyncio.ensure_future(instance)
|
||||
instance.add_done_callback(functools.partial(self._async_init_instance, future_result))
|
||||
self.__storage = future_result
|
||||
return future_result
|
||||
|
||||
self.__storage = instance
|
||||
|
||||
if self.__async:
|
||||
result = asyncio.Future()
|
||||
result.set_result(self.__storage)
|
||||
return result
|
||||
|
||||
return self.__storage
|
||||
|
||||
def _async_init_instance(self, future_result, result):
|
||||
instance = result.result()
|
||||
self.__storage = instance
|
||||
self.__async = True
|
||||
future_result.set_result(instance)
|
||||
|
||||
|
||||
cdef class DelegatedSingleton(Singleton):
|
||||
"""Delegated singleton is injected "as is".
|
||||
|
@ -3488,8 +3509,20 @@ def merge_dicts(dict1, dict2):
|
|||
return result
|
||||
|
||||
|
||||
def isawaitable(obj):
|
||||
"""Check if object is a coroutine function.
|
||||
|
||||
Return False for any object in Python 3.4 or below.
|
||||
"""
|
||||
try:
|
||||
return inspect.isawaitable(obj)
|
||||
except AttributeError:
|
||||
return False
|
||||
|
||||
|
||||
def iscoroutinefunction(obj):
|
||||
"""Check if object is a coroutine function.
|
||||
|
||||
Return False for any object in Python 3.4 or below.
|
||||
"""
|
||||
try:
|
||||
|
@ -3500,6 +3533,7 @@ def iscoroutinefunction(obj):
|
|||
|
||||
def isasyncgenfunction(obj):
|
||||
"""Check if object is an asynchronous generator function.
|
||||
|
||||
Return False for any object in Python 3.4 or below.
|
||||
"""
|
||||
try:
|
||||
|
|
|
@ -218,3 +218,154 @@ class FactoryTests(AsyncTestCase):
|
|||
self.assertIs(service2.client.resource2, RESOURCE2)
|
||||
|
||||
self.assertIsNot(service1.client, service2.client)
|
||||
|
||||
|
||||
class SingletonTests(AsyncTestCase):
|
||||
|
||||
def test_injections(self):
|
||||
class ContainerWithSingletons(containers.DeclarativeContainer):
|
||||
resource1 = providers.Resource(init_resource, providers.Object(RESOURCE1))
|
||||
resource2 = providers.Resource(init_resource, providers.Object(RESOURCE2))
|
||||
|
||||
client = providers.Singleton(
|
||||
Client,
|
||||
resource1=resource1,
|
||||
resource2=resource2,
|
||||
)
|
||||
|
||||
service = providers.Singleton(
|
||||
Service,
|
||||
client=client,
|
||||
)
|
||||
|
||||
container = ContainerWithSingletons()
|
||||
|
||||
client1 = self._run(container.client())
|
||||
client2 = self._run(container.client())
|
||||
|
||||
self.assertIsInstance(client1, Client)
|
||||
self.assertIs(client1.resource1, RESOURCE1)
|
||||
self.assertIs(client1.resource2, RESOURCE2)
|
||||
|
||||
self.assertIsInstance(client2, Client)
|
||||
self.assertIs(client2.resource1, RESOURCE1)
|
||||
self.assertIs(client2.resource2, RESOURCE2)
|
||||
|
||||
service1 = self._run(container.service())
|
||||
service2 = self._run(container.service())
|
||||
|
||||
self.assertIsInstance(service1, Service)
|
||||
self.assertIsInstance(service1.client, Client)
|
||||
self.assertIs(service1.client.resource1, RESOURCE1)
|
||||
self.assertIs(service1.client.resource2, RESOURCE2)
|
||||
|
||||
self.assertIsInstance(service2, Service)
|
||||
self.assertIsInstance(service2.client, Client)
|
||||
self.assertIs(service2.client.resource1, RESOURCE1)
|
||||
self.assertIs(service2.client.resource2, RESOURCE2)
|
||||
|
||||
self.assertIs(service1, service2)
|
||||
self.assertIs(service1.client, service2.client)
|
||||
self.assertIs(service1.client, client1)
|
||||
|
||||
self.assertIs(service2.client, client2)
|
||||
self.assertIs(client1, client2)
|
||||
|
||||
def test_async_mode(self):
|
||||
instance = object()
|
||||
|
||||
async def create_instance():
|
||||
return instance
|
||||
|
||||
provider = providers.Singleton(create_instance)
|
||||
|
||||
instance1 = self._run(provider())
|
||||
instance2 = self._run(provider())
|
||||
|
||||
self.assertIs(instance1, instance2)
|
||||
self.assertIs(instance, instance)
|
||||
|
||||
|
||||
class DelegatedSingletonTests(AsyncTestCase):
|
||||
|
||||
def test_async_mode(self):
|
||||
instance = object()
|
||||
|
||||
async def create_instance():
|
||||
return instance
|
||||
|
||||
provider = providers.DelegatedSingleton(create_instance)
|
||||
|
||||
instance1 = self._run(provider())
|
||||
instance2 = self._run(provider())
|
||||
|
||||
self.assertIs(instance1, instance2)
|
||||
self.assertIs(instance, instance)
|
||||
|
||||
|
||||
class ThreadSafeSingletonTests(AsyncTestCase):
|
||||
|
||||
def test_async_mode(self):
|
||||
instance = object()
|
||||
|
||||
async def create_instance():
|
||||
return instance
|
||||
|
||||
provider = providers.ThreadSafeSingleton(create_instance)
|
||||
|
||||
instance1 = self._run(provider())
|
||||
instance2 = self._run(provider())
|
||||
|
||||
self.assertIs(instance1, instance2)
|
||||
self.assertIs(instance, instance)
|
||||
|
||||
|
||||
class DelegatedThreadSafeSingletonTests(AsyncTestCase):
|
||||
|
||||
def test_async_mode(self):
|
||||
instance = object()
|
||||
|
||||
async def create_instance():
|
||||
return instance
|
||||
|
||||
provider = providers.DelegatedThreadSafeSingleton(create_instance)
|
||||
|
||||
instance1 = self._run(provider())
|
||||
instance2 = self._run(provider())
|
||||
|
||||
self.assertIs(instance1, instance2)
|
||||
self.assertIs(instance, instance)
|
||||
|
||||
|
||||
class ThreadLocalSingletonTests(AsyncTestCase):
|
||||
|
||||
def test_async_mode(self):
|
||||
instance = object()
|
||||
|
||||
async def create_instance():
|
||||
return instance
|
||||
|
||||
provider = providers.ThreadLocalSingleton(create_instance)
|
||||
|
||||
instance1 = self._run(provider())
|
||||
instance2 = self._run(provider())
|
||||
|
||||
self.assertIs(instance1, instance2)
|
||||
self.assertIs(instance, instance)
|
||||
|
||||
|
||||
class DelegatedThreadLocalSingletonTests(AsyncTestCase):
|
||||
|
||||
def test_async_mode(self):
|
||||
instance = object()
|
||||
|
||||
async def create_instance():
|
||||
return instance
|
||||
|
||||
provider = providers.DelegatedThreadLocalSingleton(create_instance)
|
||||
|
||||
instance1 = self._run(provider())
|
||||
instance2 = self._run(provider())
|
||||
|
||||
self.assertIs(instance1, instance2)
|
||||
self.assertIs(instance, instance)
|
||||
|
|
Loading…
Reference in New Issue
Block a user