mirror of
https://github.com/ets-labs/python-dependency-injector.git
synced 2024-11-22 09:36:48 +03:00
Add .providers attribute and .set_providers() method to FactoryAggregate provider
This commit is contained in:
parent
541131e338
commit
7238482402
|
@ -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`_
|
||||||
|
|
||||||
|
Development version
|
||||||
|
-------------------
|
||||||
|
- Add ``.providers`` attribute to the ``FactoryAggregate`` provider. It is an alias for
|
||||||
|
``FactoryAggregate.factories`` attribute.
|
||||||
|
- Add ``.set_providers()`` method to the ``FactoryAggregate`` provider. It is an alias for
|
||||||
|
``FactoryAggregate.set_factories()`` method.
|
||||||
|
- Refactor ``FactoryAggregate`` provider internals.
|
||||||
|
|
||||||
4.37.0
|
4.37.0
|
||||||
------
|
------
|
||||||
- Add support of Python 3.10.
|
- Add support of Python 3.10.
|
||||||
|
|
|
@ -163,9 +163,9 @@ The aggregated factories are associated with the string keys. When you call the
|
||||||
:lines: 3-
|
:lines: 3-
|
||||||
:emphasize-lines: 33-37,47
|
:emphasize-lines: 33-37,47
|
||||||
|
|
||||||
You can get a dictionary of the aggregated factories using the ``.factories`` attribute.
|
You can get a dictionary of the aggregated providers using ``.providers`` attribute.
|
||||||
To get a game factories dictionary from the previous example you can use
|
To get a game provider dictionary from the previous example you can use
|
||||||
``game_factory.factories`` attribute.
|
``game_factory.providers`` attribute.
|
||||||
|
|
||||||
You can also access an aggregated factory as an attribute. To create the ``Chess`` object from the
|
You can also access an aggregated factory as an attribute. To create the ``Chess`` object from the
|
||||||
previous example you can do ``chess = game_factory.chess("John", "Jane")``.
|
previous example you can do ``chess = game_factory.chess("John", "Jane")``.
|
||||||
|
@ -176,7 +176,7 @@ previous example you can do ``chess = game_factory.chess("John", "Jane")``.
|
||||||
.. note::
|
.. note::
|
||||||
When you inject the ``FactoryAggregate`` provider it is passed "as is".
|
When you inject the ``FactoryAggregate`` provider it is passed "as is".
|
||||||
|
|
||||||
To use non-string keys or keys with ``.`` and ``-`` you can provide a dictionary as a positional argument:
|
To use non-string keys or string keys with ``.`` and ``-``, you can provide a dictionary as a positional argument:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
|
|
|
@ -1209,12 +1209,12 @@ struct __pyx_obj_19dependency_injector_9providers_FactoryDelegate {
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* cdef class FactoryAggregate(Provider): # <<<<<<<<<<<<<<
|
* cdef class FactoryAggregate(Provider): # <<<<<<<<<<<<<<
|
||||||
* cdef dict __factories
|
* cdef dict __providers
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
struct __pyx_obj_19dependency_injector_9providers_FactoryAggregate {
|
struct __pyx_obj_19dependency_injector_9providers_FactoryAggregate {
|
||||||
struct __pyx_obj_19dependency_injector_9providers_Provider __pyx_base;
|
struct __pyx_obj_19dependency_injector_9providers_Provider __pyx_base;
|
||||||
PyObject *__pyx___factories;
|
PyObject *__pyx___providers;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -2077,13 +2077,13 @@ static struct __pyx_vtabstruct_19dependency_injector_9providers_FactoryDelegate
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* cdef class FactoryAggregate(Provider): # <<<<<<<<<<<<<<
|
* cdef class FactoryAggregate(Provider): # <<<<<<<<<<<<<<
|
||||||
* cdef dict __factories
|
* cdef dict __providers
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct __pyx_vtabstruct_19dependency_injector_9providers_FactoryAggregate {
|
struct __pyx_vtabstruct_19dependency_injector_9providers_FactoryAggregate {
|
||||||
struct __pyx_vtabstruct_19dependency_injector_9providers_Provider __pyx_base;
|
struct __pyx_vtabstruct_19dependency_injector_9providers_Provider __pyx_base;
|
||||||
struct __pyx_obj_19dependency_injector_9providers_Factory *(*__pyx___get_factory)(struct __pyx_obj_19dependency_injector_9providers_FactoryAggregate *, PyObject *);
|
struct __pyx_obj_19dependency_injector_9providers_Provider *(*__pyx___get_provider)(struct __pyx_obj_19dependency_injector_9providers_FactoryAggregate *, PyObject *);
|
||||||
};
|
};
|
||||||
static struct __pyx_vtabstruct_19dependency_injector_9providers_FactoryAggregate *__pyx_vtabptr_19dependency_injector_9providers_FactoryAggregate;
|
static struct __pyx_vtabstruct_19dependency_injector_9providers_FactoryAggregate *__pyx_vtabptr_19dependency_injector_9providers_FactoryAggregate;
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -143,9 +143,9 @@ cdef class FactoryDelegate(Delegate):
|
||||||
|
|
||||||
|
|
||||||
cdef class FactoryAggregate(Provider):
|
cdef class FactoryAggregate(Provider):
|
||||||
cdef dict __factories
|
cdef dict __providers
|
||||||
|
|
||||||
cdef Factory __get_factory(self, object factory_name)
|
cdef Provider __get_provider(self, object provider_name)
|
||||||
|
|
||||||
|
|
||||||
# Singleton providers
|
# Singleton providers
|
||||||
|
|
|
@ -303,18 +303,22 @@ class FactoryDelegate(Delegate):
|
||||||
|
|
||||||
|
|
||||||
class FactoryAggregate(Provider[T]):
|
class FactoryAggregate(Provider[T]):
|
||||||
def __init__(self, dict_: Optional[_Dict[Any, Factory[T]]] = None, **factories: Factory[T]): ...
|
def __init__(self, provider_dict: Optional[_Dict[Any, Provider[T]]] = None, **provider_kwargs: Provider[T]): ...
|
||||||
def __getattr__(self, factory_name: Any) -> Factory[T]: ...
|
def __getattr__(self, provider_name: Any) -> Provider[T]: ...
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
def __call__(self, factory_name: Any, *args: Injection, **kwargs: Injection) -> T: ...
|
def __call__(self, provider_name: Optional[Any] = None, *args: Injection, **kwargs: Injection) -> T: ...
|
||||||
@overload
|
@overload
|
||||||
def __call__(self, factory_name: Any, *args: Injection, **kwargs: Injection) -> Awaitable[T]: ...
|
def __call__(self, provider_name: Optional[Any] = None, *args: Injection, **kwargs: Injection) -> Awaitable[T]: ...
|
||||||
def async_(self, factory_name: Any, *args: Injection, **kwargs: Injection) -> Awaitable[T]: ...
|
def async_(self, provider_name: Optional[Any] = None, *args: Injection, **kwargs: Injection) -> Awaitable[T]: ...
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def factories(self) -> _Dict[Any, Factory[T]]: ...
|
def providers(self) -> _Dict[Any, Provider[T]]: ...
|
||||||
def set_factories(self, dict_: Optional[_Dict[Any, Factory[T]]] = None, **factories: Factory[T]) -> FactoryAggregate[T]: ...
|
def set_providers(self, provider_dict: Optional[_Dict[Any, Provider[T]]] = None, **provider_kwargs: Provider[T]) -> FactoryAggregate[T]: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def factories(self) -> _Dict[Any, Provider[T]]: ...
|
||||||
|
def set_factories(self, provider_dict: Optional[_Dict[Any, Provider[T]]] = None, **provider_kwargs: Provider[T]) -> FactoryAggregate[T]: ...
|
||||||
|
|
||||||
|
|
||||||
class BaseSingleton(Provider[T]):
|
class BaseSingleton(Provider[T]):
|
||||||
|
|
|
@ -2558,17 +2558,17 @@ cdef class FactoryAggregate(Provider):
|
||||||
:py:class:`FactoryAggregate` is a delegated provider, meaning that it is
|
:py:class:`FactoryAggregate` is a delegated provider, meaning that it is
|
||||||
injected "as is".
|
injected "as is".
|
||||||
|
|
||||||
All aggregated factories could be retrieved as a read-only
|
All aggregated providers can be retrieved as a read-only
|
||||||
dictionary :py:attr:`FactoryAggregate.factories` or just as an attribute of
|
dictionary :py:attr:`FactoryAggregate.providers` or as an attribute of
|
||||||
:py:class:`FactoryAggregate`.
|
:py:class:`FactoryAggregate`.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__IS_DELEGATED__ = True
|
__IS_DELEGATED__ = True
|
||||||
|
|
||||||
def __init__(self, factories_dict_=None, **factories_kwargs):
|
def __init__(self, provider_dict=None, **provider_kwargs):
|
||||||
"""Initialize provider."""
|
"""Initialize provider."""
|
||||||
self.__factories = {}
|
self.__providers = {}
|
||||||
self.set_factories(factories_dict_, **factories_kwargs)
|
self.set_providers(provider_dict, **provider_kwargs)
|
||||||
super(FactoryAggregate, self).__init__()
|
super(FactoryAggregate, self).__init__()
|
||||||
|
|
||||||
def __deepcopy__(self, memo):
|
def __deepcopy__(self, memo):
|
||||||
|
@ -2578,48 +2578,69 @@ cdef class FactoryAggregate(Provider):
|
||||||
return copied
|
return copied
|
||||||
|
|
||||||
copied = _memorized_duplicate(self, memo)
|
copied = _memorized_duplicate(self, memo)
|
||||||
copied.set_factories(deepcopy(self.factories, memo))
|
copied.set_providers(deepcopy(self.providers, memo))
|
||||||
|
|
||||||
self._copy_overridings(copied, memo)
|
self._copy_overridings(copied, memo)
|
||||||
|
|
||||||
return copied
|
return copied
|
||||||
|
|
||||||
def __getattr__(self, factory_name):
|
def __getattr__(self, factory_name):
|
||||||
"""Return aggregated factory."""
|
"""Return aggregated provider."""
|
||||||
return self.__get_factory(factory_name)
|
return self.__get_provider(factory_name)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
"""Return string representation of provider.
|
"""Return string representation of provider.
|
||||||
|
|
||||||
:rtype: str
|
:rtype: str
|
||||||
"""
|
"""
|
||||||
return represent_provider(provider=self, provides=self.factories)
|
return represent_provider(provider=self, provides=self.providers)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def factories(self):
|
def providers(self):
|
||||||
"""Return dictionary of factories, read-only."""
|
"""Return dictionary of providers, read-only.
|
||||||
return self.__factories
|
|
||||||
|
|
||||||
def set_factories(self, factories_dict_=None, **factories_kwargs):
|
Alias for ``.factories`` attribute.
|
||||||
"""Set factories."""
|
"""
|
||||||
factories = {}
|
return dict(self.__providers)
|
||||||
factories.update(factories_kwargs)
|
|
||||||
if factories_dict_:
|
|
||||||
factories.update(factories_dict_)
|
|
||||||
|
|
||||||
for factory in factories.values():
|
def set_providers(self, provider_dict=None, **provider_kwargs):
|
||||||
if isinstance(factory, Factory) is False:
|
"""Set providers.
|
||||||
|
|
||||||
|
Alias for ``.set_factories()`` method.
|
||||||
|
"""
|
||||||
|
providers = {}
|
||||||
|
providers.update(provider_kwargs)
|
||||||
|
if provider_dict:
|
||||||
|
providers.update(provider_dict)
|
||||||
|
|
||||||
|
for provider in providers.values():
|
||||||
|
if not is_provider(provider):
|
||||||
raise Error(
|
raise Error(
|
||||||
'{0} can aggregate only instances of {1}, given - {2}'.format(
|
'{0} can aggregate only instances of {1}, given - {2}'.format(
|
||||||
self.__class__,
|
self.__class__,
|
||||||
Factory,
|
Provider,
|
||||||
factory,
|
provider,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
self.__factories = factories
|
self.__providers = providers
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
@property
|
||||||
|
def factories(self):
|
||||||
|
"""Return dictionary of factories, read-only.
|
||||||
|
|
||||||
|
Alias for ``.providers()`` attribute.
|
||||||
|
"""
|
||||||
|
return self.providers
|
||||||
|
|
||||||
|
def set_factories(self, factory_dict=None, **factory_kwargs):
|
||||||
|
"""Set factories.
|
||||||
|
|
||||||
|
Alias for ``.set_providers()`` method.
|
||||||
|
"""
|
||||||
|
return self.set_providers(factory_dict, **factory_kwargs)
|
||||||
|
|
||||||
def override(self, _):
|
def override(self, _):
|
||||||
"""Override provider with another provider.
|
"""Override provider with another provider.
|
||||||
|
|
||||||
|
@ -2633,26 +2654,26 @@ cdef class FactoryAggregate(Provider):
|
||||||
@property
|
@property
|
||||||
def related(self):
|
def related(self):
|
||||||
"""Return related providers generator."""
|
"""Return related providers generator."""
|
||||||
yield from self.__factories.values()
|
yield from self.__providers.values()
|
||||||
yield from super().related
|
yield from super().related
|
||||||
|
|
||||||
cpdef object _provide(self, tuple args, dict kwargs):
|
cpdef object _provide(self, tuple args, dict kwargs):
|
||||||
try:
|
try:
|
||||||
factory_name = args[0]
|
provider_name = args[0]
|
||||||
except IndexError:
|
except IndexError:
|
||||||
try:
|
try:
|
||||||
factory_name = kwargs.pop('factory_name')
|
provider_name = kwargs.pop("factory_name")
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise TypeError('Factory missing 1 required positional argument: \'factory_name\'')
|
raise TypeError("Missing 1st required positional argument: \"provider_name\"")
|
||||||
else:
|
else:
|
||||||
args = args[1:]
|
args = args[1:]
|
||||||
|
|
||||||
return self.__get_factory(factory_name)(*args, **kwargs)
|
return self.__get_provider(provider_name)(*args, **kwargs)
|
||||||
|
|
||||||
cdef Factory __get_factory(self, object factory_key):
|
cdef Provider __get_provider(self, object provider_name):
|
||||||
if factory_key not in self.__factories:
|
if provider_name not in self.__providers:
|
||||||
raise NoSuchProviderError('{0} does not contain factory with name {1}'.format(self, factory_key))
|
raise NoSuchProviderError("{0} does not contain provider with name {1}".format(self, provider_name))
|
||||||
return <Factory> self.__factories[factory_key]
|
return <Provider> self.__providers[provider_name]
|
||||||
|
|
||||||
|
|
||||||
cdef class BaseSingleton(Provider):
|
cdef class BaseSingleton(Provider):
|
||||||
|
|
|
@ -78,6 +78,52 @@ def test_init_with_not_a_factory():
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@mark.parametrize("factory_type", ["empty"])
|
||||||
|
def test_init_optional_providers(factory_aggregate, factory_a, factory_b):
|
||||||
|
factory_aggregate.set_providers(
|
||||||
|
example_a=factory_a,
|
||||||
|
example_b=factory_b,
|
||||||
|
)
|
||||||
|
assert factory_aggregate.providers == {
|
||||||
|
"example_a": factory_a,
|
||||||
|
"example_b": factory_b,
|
||||||
|
}
|
||||||
|
assert isinstance(factory_aggregate("example_a"), ExampleA)
|
||||||
|
assert isinstance(factory_aggregate("example_b"), ExampleB)
|
||||||
|
|
||||||
|
|
||||||
|
@mark.parametrize("factory_type", ["non-string-keys"])
|
||||||
|
def test_set_factories_with_non_string_keys(factory_aggregate, factory_a, factory_b):
|
||||||
|
factory_aggregate.set_providers({
|
||||||
|
ExampleA: factory_a,
|
||||||
|
ExampleB: factory_b,
|
||||||
|
})
|
||||||
|
|
||||||
|
object_a = factory_aggregate(ExampleA, 1, 2, init_arg3=3, init_arg4=4)
|
||||||
|
object_b = factory_aggregate(ExampleB, 11, 22, init_arg3=33, init_arg4=44)
|
||||||
|
|
||||||
|
assert isinstance(object_a, ExampleA)
|
||||||
|
assert object_a.init_arg1 == 1
|
||||||
|
assert object_a.init_arg2 == 2
|
||||||
|
assert object_a.init_arg3 == 3
|
||||||
|
assert object_a.init_arg4 == 4
|
||||||
|
|
||||||
|
assert isinstance(object_b, ExampleB)
|
||||||
|
assert object_b.init_arg1 == 11
|
||||||
|
assert object_b.init_arg2 == 22
|
||||||
|
assert object_b.init_arg3 == 33
|
||||||
|
assert object_b.init_arg4 == 44
|
||||||
|
|
||||||
|
assert factory_aggregate.providers == {
|
||||||
|
ExampleA: factory_a,
|
||||||
|
ExampleB: factory_b,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def test_set_providers_returns_self(factory_aggregate, factory_a):
|
||||||
|
assert factory_aggregate.set_providers(example_a=factory_a) is factory_aggregate
|
||||||
|
|
||||||
|
|
||||||
@mark.parametrize("factory_type", ["empty"])
|
@mark.parametrize("factory_type", ["empty"])
|
||||||
def test_init_optional_factories(factory_aggregate, factory_a, factory_b):
|
def test_init_optional_factories(factory_aggregate, factory_a, factory_b):
|
||||||
factory_aggregate.set_factories(
|
factory_aggregate.set_factories(
|
||||||
|
|
Loading…
Reference in New Issue
Block a user