Implement lazy initialization and improve copying for FactoryAggregate provider

This commit is contained in:
Roman Mogylatov 2021-03-08 18:12:22 -05:00
parent a80e027c51
commit ee44c8f838
4 changed files with 473 additions and 342 deletions

File diff suppressed because it is too large Load Diff

View File

@ -270,6 +270,7 @@ class FactoryAggregate(Provider):
@property @property
def factories(self) -> _Dict[str, Factory]: ... def factories(self) -> _Dict[str, Factory]: ...
def set_factories(self, **factories: Factory) -> FactoryAggregate: ...
class BaseSingleton(Provider[T]): class BaseSingleton(Provider[T]):

View File

@ -2377,29 +2377,19 @@ cdef class FactoryAggregate(Provider):
__IS_DELEGATED__ = True __IS_DELEGATED__ = True
def __init__(self, **factories): def __init__(self, **factories):
"""Initializer. """Initialize provider."""
self.__factories = {}
:param factories: Dictionary of aggregate factories. self.set_factories(**factories)
:type factories: dict[str, :py:class:`Factory`]
"""
for factory in factories.values():
if isinstance(factory, Factory) is False:
raise Error(
'{0} can aggregate only instances of {1}, given - {2}'
.format(self.__class__, Factory, factory))
self.__factories = factories
super(FactoryAggregate, self).__init__() super(FactoryAggregate, self).__init__()
def __deepcopy__(self, memo): def __deepcopy__(self, memo):
"""Create and return full copy of provider.""" """Create and return full copy of provider."""
cdef FactoryAggregate copied
copied = memo.get(id(self)) copied = memo.get(id(self))
if copied is not None: if copied is not None:
return copied return copied
copied = self.__class__() copied = _memorized_duplicate(self, memo)
copied.__factories = deepcopy(self.__factories, memo) copied.set_factories(**deepcopy(self.factories, memo))
self._copy_overridings(copied, memo) self._copy_overridings(copied, memo)
@ -2421,6 +2411,16 @@ cdef class FactoryAggregate(Provider):
"""Return dictionary of factories, read-only.""" """Return dictionary of factories, read-only."""
return self.__factories return self.__factories
def set_factories(self, **factories):
"""Set factories."""
for factory in factories.values():
if isinstance(factory, Factory) is False:
raise Error(
'{0} can aggregate only instances of {1}, given - {2}'
.format(self.__class__, Factory, factory))
self.__factories = factories
return self
def override(self, _): def override(self, _):
"""Override provider with another provider. """Override provider with another provider.

View File

@ -512,6 +512,26 @@ class FactoryAggregateTests(unittest.TestCase):
example_a=providers.Factory(self.ExampleA), example_a=providers.Factory(self.ExampleA),
example_b=object()) example_b=object())
def test_init_optional_factories(self):
provider = providers.FactoryAggregate()
provider.set_factories(
example_a=self.example_a_factory,
example_b=self.example_b_factory,
)
self.assertEqual(
provider.factories,
{
'example_a': self.example_a_factory,
'example_b': self.example_b_factory,
},
)
self.assertIsInstance(provider('example_a'), self.ExampleA)
self.assertIsInstance(provider('example_b'), self.ExampleB)
def test_set_provides_returns_self(self):
provider = providers.FactoryAggregate()
self.assertIs(provider.set_factories(example_a=self.example_a_factory), provider)
def test_call(self): def test_call(self):
object_a = self.factory_aggregate('example_a', object_a = self.factory_aggregate('example_a',
1, 2, init_arg3=3, init_arg4=4) 1, 2, init_arg3=3, init_arg4=4)