Skip to content

FactoryAggregate - non string keys #496

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Aug 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/main/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ follows `Semantic versioning`_

Development version
-------------------
- Add support of non-string keys for ``FactoryAggregate`` provider.
- Improve ``FactoryAggregate`` typing stub.
- Improve resource subclasses typing and make shutdown definition optional
`PR #492 <https://github.com/ets-labs/python-dependency-injector/pull/492>`_.
Thanks to `@EdwardBlair <https://github.com/EdwardBlair>`_ for suggesting the improvement.
Expand Down
34 changes: 25 additions & 9 deletions docs/providers/factory.rst
Original file line number Diff line number Diff line change
Expand Up @@ -148,13 +148,11 @@ provider with two peculiarities:
Factory aggregate
-----------------

:py:class:`FactoryAggregate` provider aggregates multiple factories. When you call the
``FactoryAggregate`` it delegates the call to one of the factories.
:py:class:`FactoryAggregate` provider aggregates multiple factories.

The aggregated factories are associated with the string names. When you call the
``FactoryAggregate`` you have to provide one of the these names as a first argument.
``FactoryAggregate`` looks for the factory with a matching name and delegates it the work. The
rest of the arguments are passed to the delegated ``Factory``.
The aggregated factories are associated with the string keys. When you call the
``FactoryAggregate`` you have to provide one of the these keys as a first argument.
``FactoryAggregate`` looks for the factory with a matching key and calls it with the rest of the arguments.

.. image:: images/factory_aggregate.png
:width: 100%
Expand All @@ -165,17 +163,35 @@ rest of the arguments are passed to the delegated ``Factory``.
:lines: 3-
:emphasize-lines: 33-37,47

You can get a dictionary of the aggregated factories using the ``.factories`` attribute of the
``FactoryAggregate``. To get a game factories dictionary from the previous example you can use
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 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")``.

.. note::
You can not override the ``FactoryAggregate`` provider.

.. 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:

.. code-block:: python

providers.FactoryAggregate({
SomeClass: providers.Factory(...),
"key.with.periods": providers.Factory(...),
"key-with-dashes": providers.Factory(...),
})

Example:

.. literalinclude:: ../../examples/providers/factory_aggregate_non_string_keys.py
:language: python
:lines: 3-
:emphasize-lines: 30-33,39-40


.. disqus::
45 changes: 45 additions & 0 deletions examples/providers/factory_aggregate_non_string_keys.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
"""`FactoryAggregate` provider with non-string keys example."""

from dependency_injector import containers, providers


class Command:
...


class CommandA(Command):
...


class CommandB(Command):
...


class Handler:
...


class HandlerA(Handler):
...


class HandlerB(Handler):
...


class Container(containers.DeclarativeContainer):

handler_factory = providers.FactoryAggregate({
CommandA: providers.Factory(HandlerA),
CommandB: providers.Factory(HandlerB),
})


if __name__ == "__main__":
container = Container()

handler_a = container.handler_factory(CommandA)
handler_b = container.handler_factory(CommandB)

assert isinstance(handler_a, HandlerA)
assert isinstance(handler_b, HandlerB)
Loading