python-dependency-injector/docs/providers/factory.rst

188 lines
7.2 KiB
ReStructuredText
Raw Normal View History

2015-06-10 09:53:15 +03:00
Factory providers
-----------------
2015-11-30 00:30:48 +03:00
.. currentmodule:: dependency_injector.providers
:py:class:`Factory` provider creates new instance of specified class on every
call.
2015-06-10 09:53:15 +03:00
Nothing could be better than brief example:
.. image:: /images/providers/factory.png
2015-07-28 01:30:05 +03:00
:width: 80%
:align: center
2015-06-23 16:21:37 +03:00
.. literalinclude:: ../../examples/providers/factory.py
:language: python
2015-06-10 09:53:15 +03:00
2015-09-03 00:24:20 +03:00
Factory providers and __init__ injections
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2015-06-10 09:53:15 +03:00
: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 an instance's arguments.
Such behaviour is very similar to the standard Python ``functools.partial``
object, except of one thing: all injectable values are provided
*"as is"*, except of providers (subclasses of :py:class:`Provider`). Providers
will be called every time, when injection needs to be done. 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.
2015-06-10 09:53:15 +03:00
2015-09-03 00:24:20 +03:00
Example below is a little bit more complicated. It shows how to create
:py:class:`Factory` of particular class with ``__init__()`` argument
injections which injectable values are also provided by another factories:
2015-06-10 09:53:15 +03:00
2015-09-03 00:24:20 +03:00
.. note::
2015-06-10 09:53:15 +03:00
Current positional and keyword argument injections syntax (in the examples
below) is a **simplified one** version of full syntax. Examples of full
syntax and other types of injections could be found in sections below.
2015-06-10 09:53:15 +03:00
While positional / keyword argument injections may be the best way of
passing injections, current simplified syntax might be the preferable one
and could be widely used.
2015-06-10 09:53:15 +03:00
.. image:: /images/providers/factory_init_injections.png
:width: 90%
:align: center
2015-06-10 09:53:15 +03:00
Example of usage positional argument injections:
.. literalinclude:: ../../examples/providers/factory_init_args.py
:language: python
Example of usage keyword argument injections:
.. literalinclude:: ../../examples/providers/factory_init_kwargs.py
:language: python
2015-06-10 09:53:15 +03:00
2015-09-03 00:24:20 +03:00
Factory providers and __init__ injections priority
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Next example shows how :py:class:`Factory` provider deals with positional and
keyword ``__init__()`` context arguments. In few words, :py:class:`Factory`
behaviour here is very like a standard Python ``functools.partial``:
- 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.
So, please, follow the example below:
2015-06-10 09:53:15 +03:00
.. image:: /images/providers/factory_init_injections_and_contexts.png
2015-06-10 09:53:15 +03:00
.. literalinclude:: ../../examples/providers/factory_init_injections_and_contexts.py
:language: python
2015-06-10 09:53:15 +03:00
2015-09-03 00:24:20 +03:00
Factory providers and other types of injections
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Objects can take dependencies in different forms (some objects take init
2015-09-03 00:24:20 +03:00
arguments, other use attributes setting or method calls). It affects how
such objects are created and initialized.
:py:class:`Factory` provider takes various number of positional and keyword
2015-09-03 00:24:20 +03:00
arguments, that define what kinds of dependency injections have to be used.
All of those instructions are defined in
:py:mod:`dependency_injector.injections` module and are subclasses of
:py:class:`dependency_injector.injections.Injection`. There are several types
of injections that are used by :py:class:`Factory` provider:
+ :py:class:`dependency_injector.injections.Arg` - injection is done by
passing injectable value in object's ``__init__()`` method in time of
object's creation as positional argument. Takes injectable value only.
+ :py:class:`dependency_injector.injections.KwArg` - injection is done by
passing injectable value in object's ``__init__()`` method in time of
object's creation as keyword argument. Takes keyword name of
``__init__()`` argument and injectable value.
+ :py:class:`dependency_injector.injections.Attribute` - injection is done
by setting specified attribute with injectable value right after
object's creation. Takes attribute's name and injectable value.
+ :py:class:`dependency_injector.injections.Method` - injection is done by
calling of specified method with injectable value right after object's
creation and attribute injections are done. Takes method name and
injectable value.
All :py:class:`dependency_injector.injections.Injection`'s injectable values
are provided *"as is"*, except of providers (subclasses of
:py:class:`Provider`). Providers will be called every time, when injection
needs to be done.
2015-09-03 00:24:20 +03:00
2015-06-10 09:53:15 +03:00
Factory providers and attribute injections
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Example below shows how to create :py:class:`Factory` of particular class with
2015-06-10 09:53:15 +03:00
attribute injections. Those injections are done by setting specified attributes
with injectable values right after object's creation.
Example:
.. image:: /images/providers/factory_attribute_injections.png
2015-06-10 09:53:15 +03:00
.. literalinclude:: ../../examples/providers/factory_attribute_injections.py
:language: python
2015-06-10 09:53:15 +03:00
Factory providers and method injections
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Current example shows how to create :py:class:`Factory` of particular class
with method injections. Those injections are done by calling of specified
method with injectable value right after object's creation and attribute
injections are done.
2015-06-10 09:53:15 +03:00
Method injections are not very popular in Python due Python best practices
2015-09-02 22:59:06 +03:00
(usage of public attributes instead of setter methods), but they may appear in
2015-06-10 09:53:15 +03:00
some cases.
Example:
.. image:: /images/providers/factory_method_injections.png
2015-06-10 09:53:15 +03:00
.. literalinclude:: ../../examples/providers/factory_method_injections.py
:language: python
2015-06-10 09:53:15 +03:00
2015-07-20 18:46:45 +03:00
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 is done.
: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`. Saying in other words, delegation
of factories - is a way to inject factories themselves, instead of results
of their calls.
2015-07-20 18:46:45 +03:00
Actually, there are two ways of creating factory delegates:
+ ``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.
2015-07-20 18:46:45 +03:00
Example:
.. image:: /images/providers/factory_delegation.png
:width: 85%
:align: center
2015-07-20 18:46:45 +03:00
.. literalinclude:: ../../examples/providers/factory_delegation.py
:language: python
Factory providers specialization
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
:py:class:`Factory` provider could be specialized for any kind of needs via
declaring its subclasses.
One of such features is a limitation to :py:class:`Factory` provided type:
.. literalinclude:: ../../examples/providers/factory_provided_type.py
:language: python