mirror of
https://github.com/ets-labs/python-dependency-injector.git
synced 2024-11-25 02:53:56 +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
|
||||
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
|
||||
------
|
||||
- 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-
|
||||
:emphasize-lines: 33-37,47
|
||||
|
||||
You can get a dictionary of the aggregated factories using the ``.factories`` attribute.
|
||||
To get a game factories dictionary from the previous example you can use
|
||||
``game_factory.factories`` attribute.
|
||||
You can get a dictionary of the aggregated providers using ``.providers`` attribute.
|
||||
To get a game provider dictionary from the previous example you can use
|
||||
``game_factory.providers`` attribute.
|
||||
|
||||
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")``.
|
||||
|
@ -176,7 +176,7 @@ previous example you can do ``chess = game_factory.chess("John", "Jane")``.
|
|||
.. note::
|
||||
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
|
||||
|
||||
|
|
|
@ -1209,12 +1209,12 @@ struct __pyx_obj_19dependency_injector_9providers_FactoryDelegate {
|
|||
*
|
||||
*
|
||||
* cdef class FactoryAggregate(Provider): # <<<<<<<<<<<<<<
|
||||
* cdef dict __factories
|
||||
* cdef dict __providers
|
||||
*
|
||||
*/
|
||||
struct __pyx_obj_19dependency_injector_9providers_FactoryAggregate {
|
||||
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 dict __factories
|
||||
* cdef dict __providers
|
||||
*
|
||||
*/
|
||||
|
||||
struct __pyx_vtabstruct_19dependency_injector_9providers_FactoryAggregate {
|
||||
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;
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -143,9 +143,9 @@ cdef class FactoryDelegate(Delegate):
|
|||
|
||||
|
||||
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
|
||||
|
|
|
@ -303,18 +303,22 @@ class FactoryDelegate(Delegate):
|
|||
|
||||
|
||||
class FactoryAggregate(Provider[T]):
|
||||
def __init__(self, dict_: Optional[_Dict[Any, Factory[T]]] = None, **factories: Factory[T]): ...
|
||||
def __getattr__(self, factory_name: Any) -> Factory[T]: ...
|
||||
def __init__(self, provider_dict: Optional[_Dict[Any, Provider[T]]] = None, **provider_kwargs: Provider[T]): ...
|
||||
def __getattr__(self, provider_name: Any) -> Provider[T]: ...
|
||||
|
||||
@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
|
||||
def __call__(self, factory_name: Any, *args: Injection, **kwargs: Injection) -> Awaitable[T]: ...
|
||||
def async_(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, provider_name: Optional[Any] = None, *args: Injection, **kwargs: Injection) -> Awaitable[T]: ...
|
||||
|
||||
@property
|
||||
def factories(self) -> _Dict[Any, Factory[T]]: ...
|
||||
def set_factories(self, dict_: Optional[_Dict[Any, Factory[T]]] = None, **factories: Factory[T]) -> FactoryAggregate[T]: ...
|
||||
def providers(self) -> _Dict[Any, Provider[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]):
|
||||
|
|
|
@ -2558,17 +2558,17 @@ cdef class FactoryAggregate(Provider):
|
|||
:py:class:`FactoryAggregate` is a delegated provider, meaning that it is
|
||||
injected "as is".
|
||||
|
||||
All aggregated factories could be retrieved as a read-only
|
||||
dictionary :py:attr:`FactoryAggregate.factories` or just as an attribute of
|
||||
All aggregated providers can be retrieved as a read-only
|
||||
dictionary :py:attr:`FactoryAggregate.providers` or as an attribute of
|
||||
:py:class:`FactoryAggregate`.
|
||||
"""
|
||||
|
||||
__IS_DELEGATED__ = True
|
||||
|
||||
def __init__(self, factories_dict_=None, **factories_kwargs):
|
||||
def __init__(self, provider_dict=None, **provider_kwargs):
|
||||
"""Initialize provider."""
|
||||
self.__factories = {}
|
||||
self.set_factories(factories_dict_, **factories_kwargs)
|
||||
self.__providers = {}
|
||||
self.set_providers(provider_dict, **provider_kwargs)
|
||||
super(FactoryAggregate, self).__init__()
|
||||
|
||||
def __deepcopy__(self, memo):
|
||||
|
@ -2578,48 +2578,69 @@ cdef class FactoryAggregate(Provider):
|
|||
return copied
|
||||
|
||||
copied = _memorized_duplicate(self, memo)
|
||||
copied.set_factories(deepcopy(self.factories, memo))
|
||||
copied.set_providers(deepcopy(self.providers, memo))
|
||||
|
||||
self._copy_overridings(copied, memo)
|
||||
|
||||
return copied
|
||||
|
||||
def __getattr__(self, factory_name):
|
||||
"""Return aggregated factory."""
|
||||
return self.__get_factory(factory_name)
|
||||
"""Return aggregated provider."""
|
||||
return self.__get_provider(factory_name)
|
||||
|
||||
def __str__(self):
|
||||
"""Return string representation of provider.
|
||||
|
||||
:rtype: str
|
||||
"""
|
||||
return represent_provider(provider=self, provides=self.factories)
|
||||
return represent_provider(provider=self, provides=self.providers)
|
||||
|
||||
@property
|
||||
def factories(self):
|
||||
"""Return dictionary of factories, read-only."""
|
||||
return self.__factories
|
||||
def providers(self):
|
||||
"""Return dictionary of providers, read-only.
|
||||
|
||||
def set_factories(self, factories_dict_=None, **factories_kwargs):
|
||||
"""Set factories."""
|
||||
factories = {}
|
||||
factories.update(factories_kwargs)
|
||||
if factories_dict_:
|
||||
factories.update(factories_dict_)
|
||||
Alias for ``.factories`` attribute.
|
||||
"""
|
||||
return dict(self.__providers)
|
||||
|
||||
for factory in factories.values():
|
||||
if isinstance(factory, Factory) is False:
|
||||
def set_providers(self, provider_dict=None, **provider_kwargs):
|
||||
"""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(
|
||||
'{0} can aggregate only instances of {1}, given - {2}'.format(
|
||||
self.__class__,
|
||||
Factory,
|
||||
factory,
|
||||
Provider,
|
||||
provider,
|
||||
),
|
||||
)
|
||||
|
||||
self.__factories = factories
|
||||
self.__providers = providers
|
||||
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, _):
|
||||
"""Override provider with another provider.
|
||||
|
||||
|
@ -2633,26 +2654,26 @@ cdef class FactoryAggregate(Provider):
|
|||
@property
|
||||
def related(self):
|
||||
"""Return related providers generator."""
|
||||
yield from self.__factories.values()
|
||||
yield from self.__providers.values()
|
||||
yield from super().related
|
||||
|
||||
cpdef object _provide(self, tuple args, dict kwargs):
|
||||
try:
|
||||
factory_name = args[0]
|
||||
provider_name = args[0]
|
||||
except IndexError:
|
||||
try:
|
||||
factory_name = kwargs.pop('factory_name')
|
||||
provider_name = kwargs.pop("factory_name")
|
||||
except KeyError:
|
||||
raise TypeError('Factory missing 1 required positional argument: \'factory_name\'')
|
||||
raise TypeError("Missing 1st required positional argument: \"provider_name\"")
|
||||
else:
|
||||
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):
|
||||
if factory_key not in self.__factories:
|
||||
raise NoSuchProviderError('{0} does not contain factory with name {1}'.format(self, factory_key))
|
||||
return <Factory> self.__factories[factory_key]
|
||||
cdef Provider __get_provider(self, object provider_name):
|
||||
if provider_name not in self.__providers:
|
||||
raise NoSuchProviderError("{0} does not contain provider with name {1}".format(self, provider_name))
|
||||
return <Provider> self.__providers[provider_name]
|
||||
|
||||
|
||||
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"])
|
||||
def test_init_optional_factories(factory_aggregate, factory_a, factory_b):
|
||||
factory_aggregate.set_factories(
|
||||
|
|
Loading…
Reference in New Issue
Block a user