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

212 lines
7.7 KiB
ReStructuredText
Raw Normal View History

2015-06-10 06:53:15 +00:00
Factory providers
-----------------
2015-11-29 21:30:48 +00:00
.. currentmodule:: dependency_injector.providers
:py:class:`Factory` provider creates new instance of specified class on every
call.
2015-06-10 06:53:15 +00:00
Nothing could be better than brief example:
.. image:: /images/providers/factory.png
2015-07-27 22:30:05 +00:00
:width: 80%
:align: center
2015-06-23 13:21:37 +00:00
.. literalinclude:: ../../examples/providers/factory.py
:language: python
:linenos:
2015-06-10 06:53:15 +00:00
2015-09-02 21:24:20 +00:00
Factory providers and __init__ injections
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2015-06-10 06:53:15 +00: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 with several more things:
+ 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 `Factory providers delegation`_.
+ All other injectable values are provided *"as is"*
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 06:53:15 +00:00
2015-09-02 21:24:20 +00: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 06:53:15 +00:00
2015-09-02 21:24:20 +00:00
.. note::
2015-06-10 06:53:15 +00: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 06:53:15 +00: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 06:53:15 +00:00
.. image:: /images/providers/factory_init_injections.png
:width: 90%
:align: center
2015-06-10 06:53:15 +00:00
Example of usage positional argument injections:
.. literalinclude:: ../../examples/providers/factory_init_args.py
:language: python
:linenos:
Example of usage keyword argument injections:
.. literalinclude:: ../../examples/providers/factory_init_kwargs.py
:language: python
:linenos:
2015-06-10 06:53:15 +00:00
2015-09-02 21:24:20 +00: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 06:53:15 +00:00
.. image:: /images/providers/factory_init_injections_and_contexts.png
2015-06-10 06:53:15 +00:00
.. literalinclude:: ../../examples/providers/factory_init_injections_and_contexts.py
:language: python
:linenos:
2015-06-10 06:53:15 +00:00
2015-09-02 21:24:20 +00:00
Factory providers and other types of injections
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Objects can take dependencies in different forms (some objects take init
2015-09-02 21:24:20 +00: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-02 21:24:20 +00: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-02 21:24:20 +00:00
2015-06-10 06:53:15 +00:00
Factory providers and attribute injections
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Example below shows how to create :py:class:`Factory` of particular class with
2015-06-10 06:53:15 +00: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 06:53:15 +00:00
.. literalinclude:: ../../examples/providers/factory_attribute_injections.py
:language: python
:linenos:
2015-06-10 06:53:15 +00: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 06:53:15 +00:00
Method injections are not very popular in Python due Python best practices
2015-09-02 19:59:06 +00:00
(usage of public attributes instead of setter methods), but they may appear in
2015-06-10 06:53:15 +00:00
some cases.
Example:
.. image:: /images/providers/factory_method_injections.png
2015-06-10 06:53:15 +00:00
.. literalinclude:: ../../examples/providers/factory_method_injections.py
:language: python
:linenos:
2015-06-10 06:53:15 +00:00
2015-07-20 15:46:45 +00: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 15:46:45 +00: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 15:46:45 +00:00
Example:
.. image:: /images/providers/factory_delegation.png
:width: 85%
:align: center
2015-07-20 15:46:45 +00:00
.. literalinclude:: ../../examples/providers/factory_delegation.py
:language: python
:linenos:
Alternative way of doing :py:class:`Factory` delegation is an usage of
:py:class:`DelegatedFactory`. :py:class:`DelegatedFactory` is a
:py:class:`Factory` that is always injected "as is".
Example:
.. literalinclude:: ../../examples/providers/delegated_factory.py
:language: python
:linenos:
Factory providers specialization
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
:py:class:`Factory` provider could be specialized for any kind of needs via
declaring its subclasses.
One of such `builtin` features is a limitation to :py:class:`Factory` provided
type:
.. literalinclude:: ../../examples/providers/factory_provided_type.py
:language: python
:linenos: