Skip to content
Permalink
Branch: master
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
188 lines (134 sloc) 6.12 KB

Factory providers

.. currentmodule:: dependency_injector.providers

:py:class:`Factory` provider creates new instance of specified class on every call.

Nothing could be better than brief example:

/images/providers/factory.png

.. literalinclude:: ../../examples/providers/factory.py
   :language: python
   :linenos:

Factory providers and __init__ injections

:py:class:`Factory` takes a various number of positional and keyword arguments that are used as __init__() injections. Every time, when :py:class:`Factory` creates new one instance, positional and keyword argument injections would be passed as instance arguments.

Injections are done according to the next rules:

  • All providers (instances of :py:class:`Provider`) are called every time when injection needs to be done.
  • Providers could be injected "as is" (delegated), if it is defined obviously. Check out :ref:`factory_providers_delegation`.
  • All other injectable values are provided "as is".
  • Positional context arguments will be appended after :py:class:`Factory` positional injections.
  • Keyword context arguments have priority on :py:class:`Factory` keyword injections and will be merged over them.

For example, if injectable value of injection is a :py:class:`Factory`, it will provide new one instance (as a result of its call) every time, when injection needs to be done.

Example below is a little bit more complicated. It shows how to create :py:class:`Factory` of particular class with __init__() injections which injectable values are also provided by another factories:

/images/providers/factory_init_injections.png

.. literalinclude:: ../../examples/providers/factory_init_injections.py
   :language: python
   :linenos:

Factory providers delegation

:py:class:`Factory` provider could be delegated to any other provider via any kind of injection.

As it was mentioned earlier, if :py:class:`Factory` is injectable value, it will be called every time when injection needs to be done. But sometimes there is a need to inject :py:class:`Factory` provider itself (not a result of its call) as a dependency. Such injections are called - delegated provider injections.

Saying in other words, delegation of factories - is a way to inject factories themselves, instead of results of their calls.

:py:class:`Factory` delegation is performed by wrapping delegated :py:class:`Factory` into special provider type - :py:class:`Delegate`, that just returns wrapped :py:class:`Factory`.

Actually, there are three ways for creating factory delegates:

  • DelegatedFactory(...) - use special type of factory - :py:class:`DelegatedFactory`. Such factories are always injected as delegates ("as is").
  • Delegate(Factory(...)) - obviously wrapping factory into :py:class:`Delegate` provider.
  • Factory(...).delegate() - calling factory :py:meth:`Factory.delegate` method, that returns delegate wrapper for current factory.
  • Factory(...).provider - getting factory :py:attr:`Factory.provider` attribute, that returns delegate wrapper for current factory (alias of Factory(...).delegate() method).

Example:

/images/providers/factory_delegation.png

.. literalinclude:: ../../examples/providers/factory_delegation.py
   :language: python
   :linenos:

Factory providers specialization

:py:class:`Factory` provider could be specialized for any kind of needs via creating its subclasses.

One of such specialization features is a limitation to :py:class:`Factory` provided type:

.. literalinclude:: ../../examples/providers/factory_provided_type.py
   :language: python
   :linenos:

Abstract factory providers

:py:class:`AbstractFactory` provider is a :py:class:`Factory` provider that must be explicitly overridden before calling.

Note

Overriding of :py:class:`AbstractFactory` provider is possible only by another :py:class:`Factory` provider.

:py:class:`AbstractFactory` provider is useful when it is needed to specify explicitly that it only provides abstraction, but not an implementation. Client code must override such factories with factories that provide particular implementations. Otherwise, :py:class:`AbstractFactory` will raise an error on attempt of calling it. At the same time, :py:class:`AbstractFactory` is regular provider that could be injected into other providers (or used for any other kind of bindings) without being overridden. After :py:class:`AbstractFactory` provider has been overridden, its behaviour is identical to regular :py:class:`Factory` provider.

Example:

/images/providers/abstract_factory.png

Listing of cache.py:

.. literalinclude:: ../../examples/providers/abstract_factory/cache.py
   :language: python
   :linenos:

Listing of example.py:

.. literalinclude:: ../../examples/providers/abstract_factory/example.py
   :language: python
   :linenos:

Factory aggregate providers

:py:class:`FactoryAggregate` provider is a special type of provider that aggregates other :py:class:`Factory` providers.

Note

:py:class:`FactoryAggregate` is not overridable. Calling of :py:meth:`FactoryAggregate.override` will result in raising of an expection.

Next prototype might be the best demonstration of :py:class:`FactoryAggregate` features:

.. literalinclude:: ../../examples/providers/factory_aggregate/prototype.py
   :language: python
   :linenos:

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

Listing of example.py:

.. literalinclude:: ../../examples/providers/factory_aggregate/example.py
   :language: python
   :linenos:

.. disqus::
You can’t perform that action at this time.