Merge branch 'release/4.19.0' into master

This commit is contained in:
Roman Mogylatov 2021-02-05 18:28:44 -05:00
commit ce6d3df72c
14 changed files with 2971 additions and 2681 deletions

View File

@ -7,6 +7,14 @@ that were made in every particular version.
From version 0.7.6 *Dependency Injector* framework strictly From version 0.7.6 *Dependency Injector* framework strictly
follows `Semantic versioning`_ follows `Semantic versioning`_
4.19.0
------
- Add ``singleton.full_reset()`` method to reset all underlying singleton providers.
- Fix ``container.reset_singleton()`` to reset all provider types, not only ``Singleton``.
- Improve ``container.traverse(types=[...])`` and ``provider.traverse(types=[...])`` typing stubs
to return ``types`` -typed iterator.
- Update docs on creating custom providers with a requirement to specify ``.related`` property.
4.18.0 4.18.0
------ ------
- Add ``container.reset_singleton()`` method to reset container singletons. - Add ``container.reset_singleton()`` method to reset container singletons.

View File

@ -20,8 +20,11 @@ To create a custom provider you need to follow these rules:
from the ``providers`` module. After the a new provider object is created use from the ``providers`` module. After the a new provider object is created use
``Provider._copy_overriding()`` method to copy all overriding providers. See the example ``Provider._copy_overriding()`` method to copy all overriding providers. See the example
below. below.
4. If the new provider has a ``__init__()`` method, it should call the parent 4. If new provider has a ``__init__()`` method, it should call the parent
``Provider.__init__()``. ``Provider.__init__()``.
5. If new provider stores any other providers, these providers should be listed in
``.related`` property. Property ``.related`` also should yield providers from parent
``.related`` property.
.. literalinclude:: ../../examples/providers/custom_factory.py .. literalinclude:: ../../examples/providers/custom_factory.py
:language: python :language: python

View File

@ -54,6 +54,14 @@ provider.
Resetting of the memorized object clears the reference to it. Further object's lifecycle is Resetting of the memorized object clears the reference to it. Further object's lifecycle is
managed by the garbage collector. managed by the garbage collector.
Method ``.reset()`` resets only current provider. To reset all dependent singleton providers
call ``.full_reset()`` method.
.. literalinclude:: ../../examples/providers/singleton_full_resetting.py
:language: python
:lines: 3-
:emphasize-lines: 25
Using singleton with multiple threads Using singleton with multiple threads
------------------------------------- -------------------------------------

View File

@ -25,6 +25,12 @@ class CustomFactory(providers.Provider):
return copied return copied
@property
def related(self):
"""Return related providers generator."""
yield from [self._factory]
yield from super().related
def _provide(self, args, kwargs): def _provide(self, args, kwargs):
return self._factory(*args, **kwargs) return self._factory(*args, **kwargs)

View File

@ -0,0 +1,31 @@
"""`Singleton` provider full resetting example."""
from dependency_injector import containers, providers
class Database:
...
class UserService:
def __init__(self, db: Database):
self.db = db
class Container(containers.DeclarativeContainer):
database = providers.Singleton(Database)
user_service = providers.Singleton(UserService, db=database)
if __name__ == '__main__':
container = Container()
user_service1 = container.user_service()
container.user_service.full_reset()
user_service2 = container.user_service()
assert user_service2 is not user_service1
assert user_service2.db is not user_service1.db

View File

@ -9,15 +9,15 @@ class UserService:
class Container(containers.DeclarativeContainer): class Container(containers.DeclarativeContainer):
user_service_provider = providers.Singleton(UserService) user_service = providers.Singleton(UserService)
if __name__ == '__main__': if __name__ == '__main__':
container = Container() container = Container()
user_service1 = container.user_service_provider() user_service1 = container.user_service()
container.user_service_provider.reset() container.user_service.reset()
user_service2 = container.user_service_provider() user_service2 = container.user_service()
assert user_service2 is not user_service1 assert user_service2 is not user_service1

View File

@ -1,6 +1,6 @@
"""Top-level package.""" """Top-level package."""
__version__ = '4.18.0' __version__ = '4.19.0'
"""Version number. """Version number.
:type: str :type: str

View File

@ -1620,7 +1620,6 @@ static const char __pyx_k_shutdown[] = "shutdown";
static const char __pyx_k_sub_memo[] = "sub_memo"; static const char __pyx_k_sub_memo[] = "sub_memo";
static const char __pyx_k_traverse[] = "traverse"; static const char __pyx_k_traverse[] = "traverse";
static const char __pyx_k_Container[] = "Container"; static const char __pyx_k_Container[] = "Container";
static const char __pyx_k_Singleton[] = "Singleton";
static const char __pyx_k_container[] = "container"; static const char __pyx_k_container[] = "container";
static const char __pyx_k_decorator[] = "_decorator"; static const char __pyx_k_decorator[] = "_decorator";
static const char __pyx_k_iteritems[] = "iteritems"; static const char __pyx_k_iteritems[] = "iteritems";
@ -1639,6 +1638,7 @@ static const char __pyx_k_isawaitable[] = "isawaitable";
static const char __pyx_k_IS_CONTAINER[] = "__IS_CONTAINER__"; static const char __pyx_k_IS_CONTAINER[] = "__IS_CONTAINER__";
static const char __pyx_k_dependencies[] = "dependencies"; static const char __pyx_k_dependencies[] = "dependencies";
static const char __pyx_k_version_info[] = "version_info"; static const char __pyx_k_version_info[] = "version_info";
static const char __pyx_k_BaseSingleton[] = "BaseSingleton";
static const char __pyx_k_add_metaclass[] = "add_metaclass"; static const char __pyx_k_add_metaclass[] = "add_metaclass";
static const char __pyx_k_all_providers[] = "all_providers"; static const char __pyx_k_all_providers[] = "all_providers";
static const char __pyx_k_asyncio_tasks[] = "asyncio.tasks"; static const char __pyx_k_asyncio_tasks[] = "asyncio.tasks";
@ -1724,6 +1724,7 @@ static const char __pyx_k_Declarative_inversion_of_control_2[] = "Declarative in
static PyObject *__pyx_kp_s_0_can_contain_only_1_instances; static PyObject *__pyx_kp_s_0_can_contain_only_1_instances;
static PyObject *__pyx_kp_s_Abstract_container; static PyObject *__pyx_kp_s_Abstract_container;
static PyObject *__pyx_n_s_AttributeError; static PyObject *__pyx_n_s_AttributeError;
static PyObject *__pyx_n_s_BaseSingleton;
static PyObject *__pyx_n_s_Container; static PyObject *__pyx_n_s_Container;
static PyObject *__pyx_kp_s_Container_0_could_not_be_overrid; static PyObject *__pyx_kp_s_Container_0_could_not_be_overrid;
static PyObject *__pyx_kp_s_Container_0_could_not_be_overrid_2; static PyObject *__pyx_kp_s_Container_0_could_not_be_overrid_2;
@ -1771,7 +1772,6 @@ static PyObject *__pyx_n_s_NotImplementedError;
static PyObject *__pyx_n_s_Object; static PyObject *__pyx_n_s_Object;
static PyObject *__pyx_n_s_Provider; static PyObject *__pyx_n_s_Provider;
static PyObject *__pyx_n_s_Resource; static PyObject *__pyx_n_s_Resource;
static PyObject *__pyx_n_s_Singleton;
static PyObject *__pyx_kp_s_Wiring_requires_Python_3_6_or_ab; static PyObject *__pyx_kp_s_Wiring_requires_Python_3_6_or_ab;
static PyObject *__pyx_n_s__11; static PyObject *__pyx_n_s__11;
static PyObject *__pyx_n_s_add_metaclass; static PyObject *__pyx_n_s_add_metaclass;
@ -6370,13 +6370,13 @@ static PyObject *__pyx_pf_19dependency_injector_10containers_16DynamicContainer_
* provider.apply_overridings() * provider.apply_overridings()
* *
* def reset_singletons(self): # <<<<<<<<<<<<<< * def reset_singletons(self): # <<<<<<<<<<<<<<
* """Reset all container singletons.""" * """Reset container singletons."""
* for provider in self.traverse(types=[providers.Singleton]): * for provider in self.traverse(types=[providers.BaseSingleton]):
*/ */
/* Python wrapper */ /* Python wrapper */
static PyObject *__pyx_pw_19dependency_injector_10containers_16DynamicContainer_34reset_singletons(PyObject *__pyx_self, PyObject *__pyx_v_self); /*proto*/ static PyObject *__pyx_pw_19dependency_injector_10containers_16DynamicContainer_34reset_singletons(PyObject *__pyx_self, PyObject *__pyx_v_self); /*proto*/
static char __pyx_doc_19dependency_injector_10containers_16DynamicContainer_33reset_singletons[] = "Reset all container singletons."; static char __pyx_doc_19dependency_injector_10containers_16DynamicContainer_33reset_singletons[] = "Reset container singletons.";
static PyMethodDef __pyx_mdef_19dependency_injector_10containers_16DynamicContainer_34reset_singletons = {"reset_singletons", (PyCFunction)__pyx_pw_19dependency_injector_10containers_16DynamicContainer_34reset_singletons, METH_O, __pyx_doc_19dependency_injector_10containers_16DynamicContainer_33reset_singletons}; static PyMethodDef __pyx_mdef_19dependency_injector_10containers_16DynamicContainer_34reset_singletons = {"reset_singletons", (PyCFunction)__pyx_pw_19dependency_injector_10containers_16DynamicContainer_34reset_singletons, METH_O, __pyx_doc_19dependency_injector_10containers_16DynamicContainer_33reset_singletons};
static PyObject *__pyx_pw_19dependency_injector_10containers_16DynamicContainer_34reset_singletons(PyObject *__pyx_self, PyObject *__pyx_v_self) { static PyObject *__pyx_pw_19dependency_injector_10containers_16DynamicContainer_34reset_singletons(PyObject *__pyx_self, PyObject *__pyx_v_self) {
PyObject *__pyx_r = 0; PyObject *__pyx_r = 0;
@ -6406,8 +6406,8 @@ static PyObject *__pyx_pf_19dependency_injector_10containers_16DynamicContainer_
/* "dependency_injector/containers.pyx":276 /* "dependency_injector/containers.pyx":276
* def reset_singletons(self): * def reset_singletons(self):
* """Reset all container singletons.""" * """Reset container singletons."""
* for provider in self.traverse(types=[providers.Singleton]): # <<<<<<<<<<<<<< * for provider in self.traverse(types=[providers.BaseSingleton]): # <<<<<<<<<<<<<<
* provider.reset() * provider.reset()
* *
*/ */
@ -6417,7 +6417,7 @@ static PyObject *__pyx_pf_19dependency_injector_10containers_16DynamicContainer_
__Pyx_GOTREF(__pyx_t_2); __Pyx_GOTREF(__pyx_t_2);
__Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_n_s_providers); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 276, __pyx_L1_error) __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_n_s_providers); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 276, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_3); __Pyx_GOTREF(__pyx_t_3);
__pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_Singleton); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 276, __pyx_L1_error) __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_BaseSingleton); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 276, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_4); __Pyx_GOTREF(__pyx_t_4);
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
__pyx_t_3 = PyList_New(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 276, __pyx_L1_error) __pyx_t_3 = PyList_New(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 276, __pyx_L1_error)
@ -6475,8 +6475,8 @@ static PyObject *__pyx_pf_19dependency_injector_10containers_16DynamicContainer_
__pyx_t_3 = 0; __pyx_t_3 = 0;
/* "dependency_injector/containers.pyx":277 /* "dependency_injector/containers.pyx":277
* """Reset all container singletons.""" * """Reset container singletons."""
* for provider in self.traverse(types=[providers.Singleton]): * for provider in self.traverse(types=[providers.BaseSingleton]):
* provider.reset() # <<<<<<<<<<<<<< * provider.reset() # <<<<<<<<<<<<<<
* *
* *
@ -6502,8 +6502,8 @@ static PyObject *__pyx_pf_19dependency_injector_10containers_16DynamicContainer_
/* "dependency_injector/containers.pyx":276 /* "dependency_injector/containers.pyx":276
* def reset_singletons(self): * def reset_singletons(self):
* """Reset all container singletons.""" * """Reset container singletons."""
* for provider in self.traverse(types=[providers.Singleton]): # <<<<<<<<<<<<<< * for provider in self.traverse(types=[providers.BaseSingleton]): # <<<<<<<<<<<<<<
* provider.reset() * provider.reset()
* *
*/ */
@ -6514,8 +6514,8 @@ static PyObject *__pyx_pf_19dependency_injector_10containers_16DynamicContainer_
* provider.apply_overridings() * provider.apply_overridings()
* *
* def reset_singletons(self): # <<<<<<<<<<<<<< * def reset_singletons(self): # <<<<<<<<<<<<<<
* """Reset all container singletons.""" * """Reset container singletons."""
* for provider in self.traverse(types=[providers.Singleton]): * for provider in self.traverse(types=[providers.BaseSingleton]):
*/ */
/* function exit code */ /* function exit code */
@ -12153,6 +12153,7 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = {
{&__pyx_kp_s_0_can_contain_only_1_instances, __pyx_k_0_can_contain_only_1_instances, sizeof(__pyx_k_0_can_contain_only_1_instances), 0, 0, 1, 0}, {&__pyx_kp_s_0_can_contain_only_1_instances, __pyx_k_0_can_contain_only_1_instances, sizeof(__pyx_k_0_can_contain_only_1_instances), 0, 0, 1, 0},
{&__pyx_kp_s_Abstract_container, __pyx_k_Abstract_container, sizeof(__pyx_k_Abstract_container), 0, 0, 1, 0}, {&__pyx_kp_s_Abstract_container, __pyx_k_Abstract_container, sizeof(__pyx_k_Abstract_container), 0, 0, 1, 0},
{&__pyx_n_s_AttributeError, __pyx_k_AttributeError, sizeof(__pyx_k_AttributeError), 0, 0, 1, 1}, {&__pyx_n_s_AttributeError, __pyx_k_AttributeError, sizeof(__pyx_k_AttributeError), 0, 0, 1, 1},
{&__pyx_n_s_BaseSingleton, __pyx_k_BaseSingleton, sizeof(__pyx_k_BaseSingleton), 0, 0, 1, 1},
{&__pyx_n_s_Container, __pyx_k_Container, sizeof(__pyx_k_Container), 0, 0, 1, 1}, {&__pyx_n_s_Container, __pyx_k_Container, sizeof(__pyx_k_Container), 0, 0, 1, 1},
{&__pyx_kp_s_Container_0_could_not_be_overrid, __pyx_k_Container_0_could_not_be_overrid, sizeof(__pyx_k_Container_0_could_not_be_overrid), 0, 0, 1, 0}, {&__pyx_kp_s_Container_0_could_not_be_overrid, __pyx_k_Container_0_could_not_be_overrid, sizeof(__pyx_k_Container_0_could_not_be_overrid), 0, 0, 1, 0},
{&__pyx_kp_s_Container_0_could_not_be_overrid_2, __pyx_k_Container_0_could_not_be_overrid_2, sizeof(__pyx_k_Container_0_could_not_be_overrid_2), 0, 0, 1, 0}, {&__pyx_kp_s_Container_0_could_not_be_overrid_2, __pyx_k_Container_0_could_not_be_overrid_2, sizeof(__pyx_k_Container_0_could_not_be_overrid_2), 0, 0, 1, 0},
@ -12200,7 +12201,6 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = {
{&__pyx_n_s_Object, __pyx_k_Object, sizeof(__pyx_k_Object), 0, 0, 1, 1}, {&__pyx_n_s_Object, __pyx_k_Object, sizeof(__pyx_k_Object), 0, 0, 1, 1},
{&__pyx_n_s_Provider, __pyx_k_Provider, sizeof(__pyx_k_Provider), 0, 0, 1, 1}, {&__pyx_n_s_Provider, __pyx_k_Provider, sizeof(__pyx_k_Provider), 0, 0, 1, 1},
{&__pyx_n_s_Resource, __pyx_k_Resource, sizeof(__pyx_k_Resource), 0, 0, 1, 1}, {&__pyx_n_s_Resource, __pyx_k_Resource, sizeof(__pyx_k_Resource), 0, 0, 1, 1},
{&__pyx_n_s_Singleton, __pyx_k_Singleton, sizeof(__pyx_k_Singleton), 0, 0, 1, 1},
{&__pyx_kp_s_Wiring_requires_Python_3_6_or_ab, __pyx_k_Wiring_requires_Python_3_6_or_ab, sizeof(__pyx_k_Wiring_requires_Python_3_6_or_ab), 0, 0, 1, 0}, {&__pyx_kp_s_Wiring_requires_Python_3_6_or_ab, __pyx_k_Wiring_requires_Python_3_6_or_ab, sizeof(__pyx_k_Wiring_requires_Python_3_6_or_ab), 0, 0, 1, 0},
{&__pyx_n_s__11, __pyx_k__11, sizeof(__pyx_k__11), 0, 0, 1, 1}, {&__pyx_n_s__11, __pyx_k__11, sizeof(__pyx_k__11), 0, 0, 1, 1},
{&__pyx_n_s_add_metaclass, __pyx_k_add_metaclass, sizeof(__pyx_k_add_metaclass), 0, 0, 1, 1}, {&__pyx_n_s_add_metaclass, __pyx_k_add_metaclass, sizeof(__pyx_k_add_metaclass), 0, 0, 1, 1},
@ -12648,8 +12648,8 @@ static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(void) {
* provider.apply_overridings() * provider.apply_overridings()
* *
* def reset_singletons(self): # <<<<<<<<<<<<<< * def reset_singletons(self): # <<<<<<<<<<<<<<
* """Reset all container singletons.""" * """Reset container singletons."""
* for provider in self.traverse(types=[providers.Singleton]): * for provider in self.traverse(types=[providers.BaseSingleton]):
*/ */
__pyx_tuple__52 = PyTuple_Pack(2, __pyx_n_s_self_2, __pyx_n_s_provider); if (unlikely(!__pyx_tuple__52)) __PYX_ERR(0, 274, __pyx_L1_error) __pyx_tuple__52 = PyTuple_Pack(2, __pyx_n_s_self_2, __pyx_n_s_provider); if (unlikely(!__pyx_tuple__52)) __PYX_ERR(0, 274, __pyx_L1_error)
__Pyx_GOTREF(__pyx_tuple__52); __Pyx_GOTREF(__pyx_tuple__52);
@ -13645,8 +13645,8 @@ if (!__Pyx_RefNanny) {
* provider.apply_overridings() * provider.apply_overridings()
* *
* def reset_singletons(self): # <<<<<<<<<<<<<< * def reset_singletons(self): # <<<<<<<<<<<<<<
* """Reset all container singletons.""" * """Reset container singletons."""
* for provider in self.traverse(types=[providers.Singleton]): * for provider in self.traverse(types=[providers.BaseSingleton]):
*/ */
__pyx_t_10 = __Pyx_CyFunction_New(&__pyx_mdef_19dependency_injector_10containers_16DynamicContainer_34reset_singletons, 0, __pyx_n_s_DynamicContainer_reset_singleton, NULL, __pyx_n_s_dependency_injector_containers, __pyx_d, ((PyObject *)__pyx_codeobj__53)); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 274, __pyx_L1_error) __pyx_t_10 = __Pyx_CyFunction_New(&__pyx_mdef_19dependency_injector_10containers_16DynamicContainer_34reset_singletons, 0, __pyx_n_s_DynamicContainer_reset_singleton, NULL, __pyx_n_s_dependency_injector_containers, __pyx_d, ((PyObject *)__pyx_codeobj__53)); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 274, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_10); __Pyx_GOTREF(__pyx_t_10);

View File

@ -21,6 +21,7 @@ from .providers import Provider
C_Base = TypeVar('C_Base', bound='Container') C_Base = TypeVar('C_Base', bound='Container')
C = TypeVar('C', bound='DeclarativeContainer') C = TypeVar('C', bound='DeclarativeContainer')
C_Overriding = TypeVar('C_Overriding', bound='DeclarativeContainer') C_Overriding = TypeVar('C_Overriding', bound='DeclarativeContainer')
TT = TypeVar('TT')
class Container: class Container:
@ -46,10 +47,10 @@ class Container:
def apply_container_providers_overridings(self) -> None: ... def apply_container_providers_overridings(self) -> None: ...
def reset_singletons(self) -> None: ... def reset_singletons(self) -> None: ...
@overload @overload
def traverse(self, types: Optional[Sequence[Type]] = None) -> Iterator[Provider]: ... def traverse(self, types: Optional[Sequence[TT]] = None) -> Iterator[TT]: ...
@classmethod @classmethod
@overload @overload
def traverse(cls, types: Optional[Sequence[Type]] = None) -> Iterator[Provider]: ... def traverse(cls, types: Optional[Sequence[TT]] = None) -> Iterator[TT]: ...
class DynamicContainer(Container): ... class DynamicContainer(Container): ...

View File

@ -272,8 +272,8 @@ class DynamicContainer(Container):
provider.apply_overridings() provider.apply_overridings()
def reset_singletons(self): def reset_singletons(self):
"""Reset all container singletons.""" """Reset container singletons."""
for provider in self.traverse(types=[providers.Singleton]): for provider in self.traverse(types=[providers.BaseSingleton]):
provider.reset() provider.reset()

File diff suppressed because it is too large Load Diff

View File

@ -36,6 +36,7 @@ from . import resources
Injection = Any Injection = Any
T = TypeVar('T') T = TypeVar('T')
TT = TypeVar('TT')
class OverridingContext: class OverridingContext:
@ -76,7 +77,7 @@ class Provider(Generic[T]):
def is_async_mode_undefined(self) -> bool: ... def is_async_mode_undefined(self) -> bool: ...
@property @property
def related(self) -> _Iterator[Provider]: ... def related(self) -> _Iterator[Provider]: ...
def traverse(self, types: Optional[_Iterable[Type]] = None) -> _Iterator[Provider]: ... def traverse(self, types: Optional[_Iterable[TT]] = None) -> _Iterator[TT]: ...
def _copy_overridings(self, copied: Provider, memo: Optional[_Dict[Any, Any]]) -> None: ... def _copy_overridings(self, copied: Provider, memo: Optional[_Dict[Any, Any]]) -> None: ...
@ -266,6 +267,7 @@ class BaseSingleton(Provider[T]):
def set_attributes(self, **kwargs: Injection) -> BaseSingleton[T]: ... def set_attributes(self, **kwargs: Injection) -> BaseSingleton[T]: ...
def clear_attributes(self) -> BaseSingleton[T]: ... def clear_attributes(self) -> BaseSingleton[T]: ...
def reset(self) -> None: ... def reset(self) -> None: ...
def full_reset(self) -> None: ...
class Singleton(BaseSingleton[T]): ... class Singleton(BaseSingleton[T]): ...

View File

@ -2468,6 +2468,15 @@ cdef class BaseSingleton(Provider):
""" """
raise NotImplementedError() raise NotImplementedError()
def full_reset(self):
"""Reset cached instance in current and all underlying singletons, if any.
:rtype: None
"""
self.reset()
for provider in self.traverse(types=[BaseSingleton]):
provider.reset()
@property @property
def related(self): def related(self):
"""Return related providers generator.""" """Return related providers generator."""

View File

@ -355,6 +355,37 @@ class _BaseSingletonTestCase(object):
self.assertIsNot(instance1, instance2) self.assertIsNot(instance1, instance2)
def test_reset_with_singleton(self):
dependent_singleton = providers.Singleton(object)
provider = self.singleton_cls(dict, dependency=dependent_singleton)
dependent_instance = dependent_singleton()
instance1 = provider()
self.assertIs(instance1['dependency'], dependent_instance)
provider.reset()
instance2 = provider()
self.assertIs(instance1['dependency'], dependent_instance)
self.assertIsNot(instance1, instance2)
def test_full_reset(self):
dependent_singleton = providers.Singleton(object)
provider = self.singleton_cls(dict, dependency=dependent_singleton)
dependent_instance1 = dependent_singleton()
instance1 = provider()
self.assertIs(instance1['dependency'], dependent_instance1)
provider.full_reset()
dependent_instance2 = dependent_singleton()
instance2 = provider()
self.assertIsNot(instance2['dependency'], dependent_instance1)
self.assertIsNot(dependent_instance1, dependent_instance2)
self.assertIsNot(instance1, instance2)
class SingletonTests(_BaseSingletonTestCase, unittest.TestCase): class SingletonTests(_BaseSingletonTestCase, unittest.TestCase):