diff --git a/docs/providers/aggregate.rst b/docs/providers/aggregate.rst new file mode 100644 index 00000000..b09c74a8 --- /dev/null +++ b/docs/providers/aggregate.rst @@ -0,0 +1,71 @@ +.. _aggregate-provider: + +Aggregate provider +================== + +.. meta:: + :keywords: Python,DI,Dependency injection,IoC,Inversion of Control,Configuration,Injection, + Aggregate,Polymorphism,Environment Variable,Flexibility + :description: Aggregate provider aggregates other providers. + This page demonstrates how to implement the polymorphism and increase the + flexibility of your application using the Aggregate provider. + +:py:class:`Aggregate` provider aggregates other providers. + +.. currentmodule:: dependency_injector.providers + +.. literalinclude:: ../../examples/providers/aggregate.py + :language: python + :lines: 3- + :emphasize-lines: 24-27 + +Each provider in the ``Aggregate`` is associated with a key. You can call aggregated providers by providing +their key as a first argument. All positional and keyword arguments after the key will be forwarded to +the called provider: + +.. code-block:: python + + yaml_reader = container.config_readers("yaml", "./config.yml", foo=...) + +You can also retrieve an aggregated provider by providing its key as an attribute name: + +.. code-block:: python + + yaml_reader = container.config_readers.yaml("./config.yml", foo=...) + +To retrieve a dictionary of aggregated providers with their associated keys, use ``.providers`` attribute: + +.. code-block:: python + + container.config_readers.providers == { + "yaml": , + "json": , + } + +.. note:: + You can not override the ``Aggregate`` provider. + +.. note:: + When you inject the ``Aggregate`` provider it is passed "as is". + +To use non-string keys or string keys with ``.`` and ``-``, provide a dictionary as a positional argument: + +.. code-block:: python + + aggregate = providers.Aggregate({ + SomeClass: providers.Factory(...), + "key.with.periods": providers.Factory(...), + "key-with-dashes": providers.Factory(...), + }) + +``Aggregate`` provider is a successor of :ref:`factory-aggregate-provider` provider. ``Aggregate`` provider doesn't have +a restriction on the provider type, while ``FactoryAggregate`` can aggregate only ``Factory`` providers. + +``Aggregate`` provider is different from the :ref:`selector-provider`. ``Aggregate`` provider doesn't select which provider +to inject and doesn't have a selector. It is always injected "as is". The rest of the interface of both providers is similar. + + + + + +.. disqus:: diff --git a/docs/providers/factory.rst b/docs/providers/factory.rst index 611e49d3..c16341de 100644 --- a/docs/providers/factory.rst +++ b/docs/providers/factory.rst @@ -145,6 +145,8 @@ provider with two peculiarities: :lines: 3- :emphasize-lines: 34 +.. _factory-aggregate-provider: + Factory aggregate ----------------- diff --git a/docs/providers/index.rst b/docs/providers/index.rst index 86965026..3edbf127 100644 --- a/docs/providers/index.rst +++ b/docs/providers/index.rst @@ -46,6 +46,7 @@ Providers module API docs - :py:mod:`dependency_injector.providers` dict configuration resource + aggregate selector dependency overriding diff --git a/examples/providers/aggregate.py b/examples/providers/aggregate.py new file mode 100644 index 00000000..9f4b07d1 --- /dev/null +++ b/examples/providers/aggregate.py @@ -0,0 +1,39 @@ +"""`Aggregate` provider example.""" + +from dependency_injector import containers, providers + + +class ConfigReader: + + def __init__(self, path): + self._path = path + + def read(self): + print(f"Parsing {self._path} with {self.__class__.__name__}") + ... + + +class YamlReader(ConfigReader): + ... + + +class JsonReader(ConfigReader): + ... + + +class Container(containers.DeclarativeContainer): + + config_readers = providers.Aggregate( + yaml=providers.Factory(YamlReader), + json=providers.Factory(JsonReader), + ) + + +if __name__ == "__main__": + container = Container() + + yaml_reader = container.config_readers("yaml", "./config.yml") + yaml_reader.read() # Parsing ./config.yml with YamlReader + + json_reader = container.config_readers("json", "./config.json") + json_reader.read() # Parsing ./config.json with JsonReader