Skip to content

Commit 14d8ed9

Browse files
authored
FactoryAggregate - non string keys (#496)
* Improve FactoryAggregate typing stub * Add implementation, typing stubs, and tests * Update changelog * Fix deepcopying * Add example * Update docs * Fix errors formatting for pypy3
1 parent 6af8181 commit 14d8ed9

File tree

9 files changed

+4105
-3804
lines changed

9 files changed

+4105
-3804
lines changed

docs/main/changelog.rst

+2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ follows `Semantic versioning`_
99

1010
Development version
1111
-------------------
12+
- Add support of non-string keys for ``FactoryAggregate`` provider.
13+
- Improve ``FactoryAggregate`` typing stub.
1214
- Improve resource subclasses typing and make shutdown definition optional
1315
`PR #492 <https://github.com/ets-labs/python-dependency-injector/pull/492>`_.
1416
Thanks to `@EdwardBlair <https://github.com/EdwardBlair>`_ for suggesting the improvement.

docs/providers/factory.rst

+25-9
Original file line numberDiff line numberDiff line change
@@ -148,13 +148,11 @@ provider with two peculiarities:
148148
Factory aggregate
149149
-----------------
150150

151-
:py:class:`FactoryAggregate` provider aggregates multiple factories. When you call the
152-
``FactoryAggregate`` it delegates the call to one of the factories.
151+
:py:class:`FactoryAggregate` provider aggregates multiple factories.
153152

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

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

168-
You can get a dictionary of the aggregated factories using the ``.factories`` attribute of the
169-
``FactoryAggregate``. To get a game factories dictionary from the previous example you can use
166+
You can get a dictionary of the aggregated factories using the ``.factories`` attribute.
167+
To get a game factories dictionary from the previous example you can use
170168
``game_factory.factories`` attribute.
171169

172170
You can also access an aggregated factory as an attribute. To create the ``Chess`` object from the
173-
previous example you can do ``chess = game_factory.chess('John', 'Jane')``.
171+
previous example you can do ``chess = game_factory.chess("John", "Jane")``.
174172

175173
.. note::
176174
You can not override the ``FactoryAggregate`` provider.
177175

178176
.. note::
179177
When you inject the ``FactoryAggregate`` provider it is passed "as is".
180178

179+
To use non-string keys or keys with ``.`` and ``-`` you can provide a dictionary as a positional argument:
180+
181+
.. code-block:: python
182+
183+
providers.FactoryAggregate({
184+
SomeClass: providers.Factory(...),
185+
"key.with.periods": providers.Factory(...),
186+
"key-with-dashes": providers.Factory(...),
187+
})
188+
189+
Example:
190+
191+
.. literalinclude:: ../../examples/providers/factory_aggregate_non_string_keys.py
192+
:language: python
193+
:lines: 3-
194+
:emphasize-lines: 30-33,39-40
195+
196+
181197
.. disqus::
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
"""`FactoryAggregate` provider with non-string keys example."""
2+
3+
from dependency_injector import containers, providers
4+
5+
6+
class Command:
7+
...
8+
9+
10+
class CommandA(Command):
11+
...
12+
13+
14+
class CommandB(Command):
15+
...
16+
17+
18+
class Handler:
19+
...
20+
21+
22+
class HandlerA(Handler):
23+
...
24+
25+
26+
class HandlerB(Handler):
27+
...
28+
29+
30+
class Container(containers.DeclarativeContainer):
31+
32+
handler_factory = providers.FactoryAggregate({
33+
CommandA: providers.Factory(HandlerA),
34+
CommandB: providers.Factory(HandlerB),
35+
})
36+
37+
38+
if __name__ == "__main__":
39+
container = Container()
40+
41+
handler_a = container.handler_factory(CommandA)
42+
handler_b = container.handler_factory(CommandB)
43+
44+
assert isinstance(handler_a, HandlerA)
45+
assert isinstance(handler_b, HandlerB)

0 commit comments

Comments
 (0)