diff --git a/docs/providers/factory.rst b/docs/providers/factory.rst index 94c6c8f0..e9531503 100644 --- a/docs/providers/factory.rst +++ b/docs/providers/factory.rst @@ -123,35 +123,37 @@ provider with two peculiarities: :lines: 3- :emphasize-lines: 32 -Factory aggregate providers -~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Factory aggregate +~~~~~~~~~~~~~~~~~ -:py:class:`FactoryAggregate` provider is a special type of provider that -aggregates other :py:class:`Factory` providers. +:py:class:`FactoryAggregate` provider aggregates multiple factories. When you call the +``FactoryAggregate`` it delegates the call to one of the 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``. + +.. image:: images/factory_aggregate.png + :width: 100% + :align: center + +.. literalinclude:: ../../examples/providers/factory_aggregate.py + :language: python + :lines: 3- + :emphasize-lines: 31-35,43 + +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 +``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')``. .. note:: + You can not override the ``FactoryAggregate`` provider. - :py:class:`FactoryAggregate` is not overridable. Calling of - :py:meth:`FactoryAggregate.override` will result in raising of an - exception. - -Next prototype might be the best demonstration of -:py:class:`FactoryAggregate` features: - -.. literalinclude:: ../../examples/providers/factory_aggregate/prototype.py - :language: python - -Example below shows one of the :py:class:`FactoryAggregate` use cases, when -concrete implementation (game) must be selected based on dynamic input (CLI). - -Listing of ``games.py``: - -.. literalinclude:: ../../examples/providers/factory_aggregate/games.py - :language: python - -Listing of ``example.py``: - -.. literalinclude:: ../../examples/providers/factory_aggregate/example.py - :language: python +.. note:: + When you inject the ``FactoryAggregate`` provider it is passed "as is". .. disqus:: diff --git a/docs/providers/images/factory_aggregate.png b/docs/providers/images/factory_aggregate.png new file mode 100644 index 00000000..0b563372 Binary files /dev/null and b/docs/providers/images/factory_aggregate.png differ diff --git a/examples/providers/factory_aggregate.py b/examples/providers/factory_aggregate.py new file mode 100644 index 00000000..7facca65 --- /dev/null +++ b/examples/providers/factory_aggregate.py @@ -0,0 +1,55 @@ +"""`FactoryAggregate` provider example.""" + +import dataclasses +import sys + +from dependency_injector import providers + + +@dataclasses.dataclass +class Game: + player1: str + player2: str + + def play(self): + print( + f'{self.player1} and {self.player2} are ' + f'playing {self.__class__.__name__.lower()}' + ) + + +class Chess(Game): + ... + + +class Checkers(Game): + ... + + +class Ludo(Game): + ... + + +game_factory = providers.FactoryAggregate( + chess=providers.Factory(Chess), + checkers=providers.Factory(Checkers), + ludo=providers.Factory(Ludo), +) + + +if __name__ == '__main__': + game_type = sys.argv[1].lower() + player1 = sys.argv[2].capitalize() + player2 = sys.argv[3].capitalize() + + selected_game = game_factory(game_type, player1, player2) + selected_game.play() + + # $ python factory_aggregate.py chess John Jane + # John and Jane are playing chess + # + # $ python factory_aggregate.py checkers John Jane + # John and Jane are playing checkers + # + # $ python factory_aggregate.py ludo John Jane + # John and Jane are playing ludo diff --git a/examples/providers/factory_aggregate/example.py b/examples/providers/factory_aggregate/example.py deleted file mode 100644 index 906c8484..00000000 --- a/examples/providers/factory_aggregate/example.py +++ /dev/null @@ -1,31 +0,0 @@ -"""`FactoryAggregate` providers example.""" - -import sys - -import dependency_injector.providers as providers - -from games import Chess, Checkers, Ludo - - -game_factory = providers.FactoryAggregate( - chess=providers.Factory(Chess), - checkers=providers.Factory(Checkers), - ludo=providers.Factory(Ludo), -) - -if __name__ == '__main__': - game_type = sys.argv[1].lower() - player1 = sys.argv[2].capitalize() - player2 = sys.argv[3].capitalize() - - selected_game = game_factory(game_type, player1, player2) - selected_game.play() - - # $ python example.py chess John Jane - # John and Jane are playing chess - # - # $ python example.py checkers John Jane - # John and Jane are playing checkers - # - # $ python example.py ludo John Jane - # John and Jane are playing ludo diff --git a/examples/providers/factory_aggregate/games.py b/examples/providers/factory_aggregate/games.py deleted file mode 100644 index aa9e7a8a..00000000 --- a/examples/providers/factory_aggregate/games.py +++ /dev/null @@ -1,27 +0,0 @@ -"""Example games module.""" - - -class Game: - """Base game class.""" - - def __init__(self, player1, player2): - """Initialize instance.""" - self.player1 = player1 - self.player2 = player2 - - def play(self): - """Play game.""" - print('{0} and {1} are playing {2}'.format( - self.player1, self.player2, self.__class__.__name__.lower())) - - -class Chess(Game): - """Chess game.""" - - -class Checkers(Game): - """Checkers game.""" - - -class Ludo(Game): - """Ludo game.""" diff --git a/examples/providers/factory_aggregate/prototype.py b/examples/providers/factory_aggregate/prototype.py deleted file mode 100644 index 930a3159..00000000 --- a/examples/providers/factory_aggregate/prototype.py +++ /dev/null @@ -1,17 +0,0 @@ -"""FactoryAggregate provider prototype.""" - - -class FactoryAggregate: - """FactoryAggregate provider prototype.""" - - def __init__(self, **factories): - """Initialize instance.""" - self.factories = factories - - def __call__(self, factory_name, *args, **kwargs): - """Create object.""" - return self.factories[factory_name](*args, **kwargs) - - def __getattr__(self, factory_name): - """Return factory with specified name.""" - return self.factories[factory_name]