Update Factory docs about positional and keyword arguments

This commit is contained in:
Roman Mogilatov 2015-10-19 17:26:59 +03:00
parent 9b4a7bd28c
commit cc29d68337
5 changed files with 82 additions and 32 deletions

View File

@ -11,15 +11,17 @@ follows `Semantic versioning`_
Development version
-------------------
- Add functionality for decorating classes with ``@di.inject``.
- Add functionality for creating ``di.AbstractCatalog`` provider bundles.
- Add enhancement for ``di.AbstractCatalog`` inheritance.
- Enhance ``di.AbstractCatalog`` inheritance.
- Add images for catalog "Writing catalogs" and "Operating with catalogs"
examples.
- Add support of Python 3.5.
- Add support of six 1.10.0.
- Add functionality for using positional argument injections with
``di.Factory`` and ``di.Singleton`` providers.
- Add optimization for ``di.Injection.value`` property that will compute
type of injection once, instead of doing this on every call.
- Add functionality for decorating classes with ``@di.inject``.
- Add support of Python 3.5.
- Add support of six 1.10.0.
- Add minor refactorings and code style fixes.
0.9.5

View File

@ -15,46 +15,57 @@ Nothing could be better than brief example:
Factory providers and __init__ injections
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
``di.Factory`` takes a various number of keyword arguments that are
transformed into keyword argument injections. Every time, when ``di.Factory``
creates new one instance, keyword argument injections would be passed as an
instance's keyword arguments.
``di.Factory`` takes a various number of positional and keyword arguments that
are used as ``__init__()`` injections. Every time, when ``di.Factory``
creates new one instance, positional and keyword argument injections would be
passed as an instance's arguments.
All injectable values are provided *"as is"*, except of providers (subclasses
of ``di.Provider``). Providers will be called every time, when injection needs
to be done. For example, if injectable value of keyword argument injection is a
``di.Factory``, it will provide new one instance (as a result of its call) as
an injectable value every time, when injection needs to be done.
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 ``di.Provider``). Providers
will be called every time, when injection needs to be done. For example,
if injectable value of injection is a ``di.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
``di.Factory`` of particular class with ``__init__`` keyword argument
injections which injectable values are also provided by another factories:
``di.Factory`` of particular class with ``__init__()`` argument injections
which injectable values are also provided by another factories:
.. note::
Current keyword argument injections syntax (in an example below) is a
**simplified one**. Full syntax and other types of injections could be
found in sections below.
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.
While keyword argument injections may be the best way of passing
injections, current simplified syntax might be the preferable one and
could be widely used.
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.
.. image:: /images/providers/factory_init_injections.png
:width: 90%
:align: center
.. literalinclude:: ../../examples/providers/factory_init_injections.py
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
Factory providers and __init__ injections priority
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Next example shows how ``di.Factory`` provider deals with positional and
keyword ``__init__`` context arguments. In few words, ``di.Factory``
provider fully passes positional context arguments to class's ``__init__``
method, but keyword context arguments have priority on predefined keyword
argument injections.
keyword ``__init__()`` context arguments. In few words, ``di.Factory``
behaviour here is very like a standard Python ``functools.partial``:
- Positional context arguments will be appended after ``di.Factory``
positional injections.
- Keyword context arguments have priority on ``di.Factory`` keyword injections
and will be merged over them.
So, please, follow the example below:
@ -67,7 +78,7 @@ So, please, follow the example below:
Factory providers and other types of injections
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Objects can take dependencies in different forms(some objects take init
Objects can take dependencies in different forms (some objects take init
arguments, other use attributes setting or method calls). It affects how
such objects are created and initialized.
@ -78,8 +89,11 @@ All of those instructions are defined in ``di.injections`` module and are
subclasses of ``di.injections.Injection`` (shortcut ``di.Injection``). There
are several types of injections that are used by ``di.Factory`` provider:
+ ``di.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.
+ ``di.KwArg`` - injection is done by passing injectable value in object's
``__init__()`` method in time of object's creation via keyword argument.
``__init__()`` method in time of object's creation as keyword argument.
Takes keyword name of ``__init__()`` argument and injectable value.
+ ``di.Attribute`` - injection is done by setting specified attribute with
injectable value right after object's creation. Takes attribute's name

View File

@ -0,0 +1,34 @@
"""`di.Factory` providers with init positional injections example."""
import dependency_injector as di
class User(object):
"""Example class User."""
def __init__(self, main_photo):
"""Initializer."""
self.main_photo = main_photo
super(User, self).__init__()
class Photo(object):
"""Example class Photo."""
# User and Photo factories:
photos_factory = di.Factory(Photo)
users_factory = di.Factory(User, photos_factory)
# Creating several User objects:
user1 = users_factory() # Same as: user1 = User(Photo())
user2 = users_factory() # Same as: user2 = User(Photo())
# Making some asserts:
assert isinstance(user1, User)
assert isinstance(user1.main_photo, Photo)
assert isinstance(user2, User)
assert isinstance(user2.main_photo, Photo)
assert user1 is not user2
assert user1.main_photo is not user2.main_photo

View File

@ -62,7 +62,8 @@ assert user1.credit_card is not user2.credit_card
main_photo_mock = Photo()
credit_card_mock = CreditCard()
user3 = users_factory(3, main_photo=main_photo_mock,
user3 = users_factory(3,
main_photo=main_photo_mock,
credit_card=credit_card_mock)
assert user3.id == 3

View File

@ -1,4 +1,4 @@
"""`di.Factory` providers with init injections example."""
"""`di.Factory` providers with init keyword injections example."""
import dependency_injector as di
@ -17,8 +17,7 @@ class Photo(object):
# User and Photo factories:
photos_factory = di.Factory(Photo)
users_factory = di.Factory(User,
main_photo=photos_factory)
users_factory = di.Factory(User, main_photo=photos_factory)
# Creating several User objects:
user1 = users_factory() # Same as: user1 = User(main_photo=Photo())