Providers docs update (#289)

* Update callable provider docs

* Update coroutine provider docs

* Edit object docs

* Edit list provider docs

* Edit configuration provider docs

* Edit selector provider docs

* Fix mypy stub of the ``DeclarativeContainer`` to specify the ``__init__`` interface

* Edit Dependency provider docs
This commit is contained in:
Roman Mogylatov 2020-09-01 21:39:23 -04:00 committed by GitHub
parent 995b2165df
commit c4b33749d2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 217 additions and 394 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

View File

@ -9,8 +9,9 @@ follows `Semantic versioning`_
Development version
-------------------
- Update ``Singleton`` provider documentation.
- Rework ``Singleton`` provider examples.
- Update documentation and rework examples for: ``Singleton``, ``Callable``, ``Coroutine``,
``Object``, ``List``, ``Configuration``, ``Selector``, and ``Dependency`` providers.
- Fix mypy stub of the ``DeclarativeContainer`` to specify the ``__init__`` interface.
3.34.0
------

View File

@ -1,69 +1,20 @@
Callable providers
------------------
Callable provider
-----------------
.. meta::
:keywords: Python,DI,Dependency injection,IoC,Inversion of Control,Function,Method,Example
:description: Callable provider helps to make dependencies injection into functions. This page
demonstrates how to use a Callable provider.
.. currentmodule:: dependency_injector.providers
:py:class:`Callable` provider calls wrapped callable on every call.
:py:class:`Callable` provider calls a function, a method or another callable.
Callable providers and injections
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
:py:class:`Callable` provider takes a various number of positional and keyword
arguments that are used as wrapped callable injections. Every time, when
:py:class:`Callable` provider is called, positional and keyword argument
injections would be passed as callable 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:`callable_providers_delegation`.
+ All other injectable values are provided *"as is"*.
+ Positional context arguments will be appended after :py:class:`Callable`
positional injections.
+ Keyword context arguments have priority on :py:class:`Callable` keyword
injections and will be merged over them.
Example that shows usage of :py:class:`Callable` with positional argument
injections:
.. literalinclude:: ../../examples/providers/callable_args.py
.. literalinclude:: ../../examples/providers/callable.py
:language: python
:lines: 3-
Next one example shows usage of :py:class:`Callable` with keyword argument
injections:
.. image:: /images/providers/callable.png
:width: 100%
:align: center
.. literalinclude:: ../../examples/providers/callable_kwargs.py
:language: python
.. _callable_providers_delegation:
Callable providers delegation
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
:py:class:`Callable` provider could be delegated to any other provider via
any kind of injection.
Delegation of :py:class:`Callable` providers is the same as
:py:class:`Factory` providers delegation, please follow
:ref:`factory_providers_delegation` section for examples (with exception
of using :py:class:`DelegatedCallable` instead of
:py:class:`DelegatedFactory`).
Abstract callable providers
~~~~~~~~~~~~~~~~~~~~~~~~~~~
:py:class:`AbstractCallable` provider is a :py:class:`Callable` provider that
must be explicitly overridden before calling.
Behaviour of :py:class:`AbstractCallable` providers is the same as of
:py:class:`AbstractFactory`, please follow :ref:`abstract_factory_providers`
section for examples (with exception of using :py:class:`AbstractCallable`
provider instead of :py:class:`AbstractFactory`).
``Callable`` provider handles an injection of the dependencies the same way like a
:ref:`factory-provider`.
.. disqus::

View File

@ -1,5 +1,12 @@
Configuration providers
-----------------------
Configuration provider
----------------------
.. meta::
:keywords: Python,DI,Dependency injection,IoC,Inversion of Control,Configuration,Injection,
Option,Ini,Json,Yaml,Dict,Environment Variable,Load,Read,Get
:description: Configuration provides configuration options to the other providers. This page
demonstrates how to use Configuration provider to inject the dependencies, load
a configuration from an ini or yaml file, dictionary or an environment variable.
.. currentmodule:: dependency_injector.providers
@ -10,13 +17,13 @@ Configuration providers
:emphasize-lines: 4,9-10
:lines: 4-14
It implements "use first, define later" principle.
It implements the principle "use first, define later".
Loading from ``ini`` file
~~~~~~~~~~~~~~~~~~~~~~~~~
Loading from an INI file
~~~~~~~~~~~~~~~~~~~~~~~~
:py:class:`Configuration` provider can load configuration from ``ini`` file using
:py:meth:`Configuration.from_ini`:
``Configuration`` provider can load configuration from an ``ini`` file using the
:py:meth:`Configuration.from_ini` method:
.. literalinclude:: ../../examples/providers/configuration/configuration_ini.py
:language: python
@ -28,15 +35,15 @@ where ``examples/providers/configuration/config.ini`` is:
.. literalinclude:: ../../examples/providers/configuration/config.ini
:language: ini
:py:meth:`Configuration.from_ini` supports environment variables interpolation. Use
``${ENV_NAME}`` format in the configuration file to substitute value of environment
:py:meth:`Configuration.from_ini` method supports environment variables interpolation. Use
``${ENV_NAME}`` format in the configuration file to substitute value of the environment
variable ``ENV_NAME``.
Loading from ``yaml`` file
~~~~~~~~~~~~~~~~~~~~~~~~~~
Loading from a YAML file
~~~~~~~~~~~~~~~~~~~~~~~~
:py:class:`Configuration` provider can load configuration from ``yaml`` file using
:py:meth:`Configuration.from_yaml`:
``Configuration`` provider can load configuration from a ``yaml`` file using the
:py:meth:`Configuration.from_yaml` method:
.. literalinclude:: ../../examples/providers/configuration/configuration_yaml.py
:language: python
@ -48,43 +55,51 @@ where ``examples/providers/configuration/config.yml`` is:
.. literalinclude:: ../../examples/providers/configuration/config.yml
:language: ini
:py:meth:`Configuration.from_yaml` supports environment variables interpolation. Use
``${ENV_NAME}`` format in the configuration file to substitute value of environment
:py:meth:`Configuration.from_yaml` method supports environment variables interpolation. Use
``${ENV_NAME}`` format in the configuration file to substitute value of the environment
variable ``ENV_NAME``.
.. note::
Loading configuration from yaml requires ``PyYAML`` package. You can install
`Dependency Injector` with extras ``pip install dependency-injector[yaml]`` or install
``PyYAML`` separately ``pip install pyyaml``.
Loading of a yaml configuration requires ``PyYAML`` package.
Loading from ``dict``
~~~~~~~~~~~~~~~~~~~~~
You can install the ``Dependency Injector`` with an extra dependency::
:py:class:`Configuration` provider can load configuration from Python ``dict`` using
:py:meth:`Configuration.from_dict`:
pip install dependency-injector[yaml]
or install ``PyYAML`` directly::
pip install pyyaml
*Don't forget to mirror the changes in the requirements file.*
Loading from a dictionary
~~~~~~~~~~~~~~~~~~~~~~~~~
``Configuration`` provider can load configuration from a Python ``dict`` using the
:py:meth:`Configuration.from_dict` method:
.. literalinclude:: ../../examples/providers/configuration/configuration_dict.py
:language: python
:lines: 3-5,6-
:emphasize-lines: 6-13
Loading from environment variable
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Loading from an environment variable
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
:py:class:`Configuration` provider can load configuration from environment variable using
:py:meth:`Configuration.from_env`:
``Configuration`` provider can load configuration from an environment variable using the
:py:meth:`Configuration.from_env` method:
.. literalinclude:: ../../examples/providers/configuration/configuration_env.py
:language: python
:lines: 5-7,13-21
:emphasize-lines: 6-8
Loading from multiple sources
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Loading from the multiple sources
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
:py:class:`Configuration` provider can load configuration from multiple sources. Loaded
configuration is merged recursively over existing configuration.
``Configuration`` provider can load configuration from the multiple sources. Loaded
configuration is merged recursively over the existing configuration.
.. literalinclude:: ../../examples/providers/configuration/configuration_multiple.py
:language: python
@ -96,12 +111,12 @@ where ``examples/providers/configuration/config.local.yml`` is:
.. literalinclude:: ../../examples/providers/configuration/config.local.yml
:language: ini
Specifying value type
~~~~~~~~~~~~~~~~~~~~~
Specifying the value type
~~~~~~~~~~~~~~~~~~~~~~~~~
You can specify the type of the injected configuration value explicitly.
This helps when you read the value from the ini file or the environment variable and need to
This helps when you read the value from an ini file or an environment variable and need to
convert it into an ``int`` or a ``float``.
.. literalinclude:: ../../examples/providers/configuration/configuration_type.py
@ -109,20 +124,20 @@ convert it into an ``int`` or a ``float``.
:lines: 3-
:emphasize-lines: 17
:py:class:`Configuration` provider has next helper methods:
``Configuration`` provider has next helper methods:
- ``.as_int()``
- ``.as_float()``
- ``.as_(callback, *args, **kwargs)``
The last method ``.as_(callback, *args, **kwargs)`` helps to implement a other conversions.
The last method ``.as_(callback, *args, **kwargs)`` helps to implement other conversions.
.. literalinclude:: ../../examples/providers/configuration/configuration_type_custom.py
:language: python
:lines: 3-
:emphasize-lines: 16
With the ``.as_(callback, *args, **kwargs)`` you can specify the function that will be called
With the ``.as_(callback, *args, **kwargs)`` you can specify a function that will be called
before the injection. The value from the config will be passed as a first argument. The returned
value will be injected. Parameters ``*args`` and ``**kwargs`` are handled as any other injections.

View File

@ -1,72 +1,27 @@
Coroutine providers
-------------------
Coroutine provider
------------------
.. meta::
:keywords: Python,DI,Dependency injection,IoC,Inversion of Control,Coroutine,Asynchronous,
Asyncio,Example
:description: Coroutine provider creates a coroutine. This page demonstrates how to use a
Coroutine provider.
.. currentmodule:: dependency_injector.providers
:py:class:`Coroutine` provider create wrapped coroutine on every call.
:py:class:`Coroutine` provider creates a coroutine.
:py:class:`Coroutine` provider is designed for making better integration with
``asyncio`` coroutines. In particular, :py:class:`Coroutine` provider returns
``True`` for ``asyncio.iscoroutinefunction()`` checks.
.. note::
:py:class:`Coroutine` provider works only for Python 3.4+.
Example of usage :py:class:`Coroutine` provider with ``async / await``-based
coroutine:
.. literalinclude:: ../../examples/providers/coroutine_async_await.py
.. literalinclude:: ../../examples/providers/coroutine.py
:language: python
Coroutine providers and injections
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
:py:class:`Coroutine` provider takes a various number of positional and keyword
arguments that are used as wrapped coroutine injections. Every time, when
:py:class:`Coroutine` provider is called, positional and keyword argument
injections would be passed as coroutine 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:`coroutine_providers_delegation`.
+ All other injectable values are provided *"as is"*.
+ Positional context arguments will be appended after :py:class:`Coroutine`
positional injections.
+ Keyword context arguments have priority on :py:class:`Coroutine` keyword
injections and will be merged over them.
:lines: 3-
.. note::
The example works on Python 3.7+. For earlier versions use ``loop.run_until_complete()``.
Examples of making injections could be found in API docs -
:py:class:`Coroutine`.
``Coroutine`` provider handles an injection of the dependencies the same way like a
:ref:`factory-provider`.
.. _coroutine_providers_delegation:
Coroutine providers delegation
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
:py:class:`Coroutine` provider could be delegated to any other provider via
any kind of injection.
Delegation of :py:class:`Coroutine` providers is the same as
:py:class:`Factory` providers delegation, please follow
:ref:`factory_providers_delegation` section for examples (with exception
of using :py:class:`DelegatedCoroutine` instead of
:py:class:`DelegatedFactory`).
Abstract coroutine providers
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
:py:class:`AbstractCoroutine` provider is a :py:class:`Coroutine` provider that
must be explicitly overridden before calling.
Behaviour of :py:class:`AbstractCoroutine` providers is the same as of
:py:class:`AbstractFactory`, please follow :ref:`abstract_factory_providers`
section for examples (with exception of using :py:class:`AbstractCoroutine`
provider instead of :py:class:`AbstractFactory`).
.. note::
``Coroutine`` provider returns ``True`` for ``asyncio.iscoroutinefunction()`` check.
.. disqus::

View File

@ -1,43 +1,21 @@
Dependency providers
--------------------
Dependency provider
-------------------
.. currentmodule:: dependency_injector.providers
:py:class:`Dependency` provider can be useful for development of
self-sufficient libraries / modules / applications that have required external
dependencies.
:py:class:`Dependency` provider is a placeholder for the dependency of the specified type.
For example, you have created self-sufficient library / module / application,
that has dependency on *database connection*.
The first argument of the ``Dependency`` provider specifies a type of the dependency. It is
called ``instance_of``. ``Dependency`` provider controls the type of the returned object to be an
instance of the ``instance_of`` type.
Second step you want to do is to make this software component to be easy
reusable by wide amount of developers and to be easily integrated into many
applications.
It may be good idea, to move all external dependencies (like
*database connection*) to the top level and make them to be injected on your
software component's initialization. It will make third party developers feel
themselves free about integration of your component in their applications,
because they would be able to find right place / right way for doing this
in their application's architectures.
At the same time, you can be sure, that your external dependency will be
satisfied with appropriate instance.
Example:
.. note::
Class ``UsersService`` is a part of some library. ``UsersService`` has
dependency on database connection, which can be satisfied with any
DBAPI 2.0 database connection. Being a self-sufficient library,
``UsersService`` doesn't hardcode any kind of database management logic.
Instead of this, ``UsersService`` has external dependency, that has to
be satisfied by client's code, out of library's scope.
.. image:: /images/providers/dependency.png
The ``Dependency`` provider must be overridden before usage. It can be overridden by any type of
the provider. The only rule is that overriding provider must return an instance of ``instance_of``
dependency type.
.. literalinclude:: ../../examples/providers/dependency.py
:language: python
:lines: 3-
:emphasize-lines: 26
.. disqus::

View File

@ -1,5 +1,10 @@
List providers
--------------
List provider
-------------
.. meta::
:keywords: Python,DI,Dependency injection,IoC,Inversion of Control,List,Injection
:description: List provider helps to inject a list of the dependencies. This page demonstrates
how to use a List provider.
.. currentmodule:: dependency_injector.providers
@ -7,28 +12,12 @@ List providers
.. literalinclude:: ../../examples/providers/list.py
:language: python
:emphasize-lines: 6-9
:lines: 6-8, 23-29
:py:class:`List` provider is needed for injecting a list of dependencies. It handles
positional argument injections the same way as :py:class:`Factory` provider:
+ 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 explicitly. Check out
:ref:`factory_providers_delegation`.
+ All other values are injected *"as is"*.
+ Positional context arguments will be appended after :py:class:`List` positional injections.
Full example:
.. literalinclude:: ../../examples/providers/list.py
:language: python
:emphasize-lines: 23-26
:lines: 3-
:emphasize-lines: 19-22
``List`` provider handles positional arguments the same way as a :ref:`factory-provider`.
.. note::
Keyword argument injections are not supported.
Keyword argument are not supported.
.. disqus::

View File

@ -1,14 +1,17 @@
Object providers
----------------
Object provider
---------------
.. meta::
:keywords: Python,DI,Dependency injection,IoC,Inversion of Control,Object
:description: Object provider provides an object "as is". This page demonstrates how to use an
Object provider.
.. currentmodule:: dependency_injector.providers
:py:class:`Object` provider returns provided instance "as is".
Example:
:py:class:`Object` provider returns an object "as is".
.. literalinclude:: ../../examples/providers/object.py
:language: python
:lines: 3-
.. disqus::

View File

@ -3,29 +3,31 @@
Selector providers
------------------
.. meta::
:keywords: Python,DI,Dependency injection,IoC,Inversion of Control,Configuration,Injection,
Selector,Polymorphism,Environment Variable,Flexibility
:description: Selector selects provider based on a configuration value or another callable.
This page demonstrates how to implement the polymorphism and increase the
flexibility of your application using the Selector provider.
.. currentmodule:: dependency_injector.providers
:py:class:`Selector` provider selects provider based on the configuration value or other callable.
:py:class:`Selector` provider selects provider based on a configuration value or another callable.
.. literalinclude:: ../../examples/providers/selector.py
:language: python
:emphasize-lines: 6-10
:lines: 3-5,14-20
:py:class:`Selector` provider has a callable called ``selector`` and a dictionary of providers.
The ``selector`` callable is provided as a first positional argument. It can be
:py:class:`Configuration` provider or any other callable. It has to return a string value.
This value is used as a key for selecting the provider from the dictionary of providers.
The providers are provided as keyword arguments. Argument name is used as a key for
selecting the provider.
Full example:
.. literalinclude:: ../../examples/providers/selector.py
:language: python
:emphasize-lines: 14-18
:lines: 3-
:emphasize-lines: 14-18
The first argument of the ``Selector`` provider is called ``selector``. It can be an option of
a ``Configuration`` provider or any other callable. The ``selector`` callable has to return a
string value. This value is used as a key for selecting the provider.
The providers are provided as keyword arguments. Argument name is used as a key for selecting the
provider.
When a ``Selector`` provider is called, it gets a ``selector`` value and delegates the work to
the provider with a matching name. The ``selector`` callable works as a switch: when the returned
value is changed the ``Selector`` provider will delegate the work to another provider.
.. disqus::

View File

@ -0,0 +1,18 @@
"""`Callable` provider example."""
import passlib.hash
from dependency_injector import providers
password_hasher = providers.Callable(
passlib.hash.sha256_crypt.hash,
salt_size=16,
rounds=10000,
)
password_verifier = providers.Callable(passlib.hash.sha256_crypt.verify)
if __name__ == '__main__':
hashed_password = password_hasher('super secret')
assert password_verifier('super secret', hashed_password)

View File

@ -1,16 +0,0 @@
"""`Callable` providers with positional arguments example."""
import dependency_injector.providers as providers
# Creating even and odd filter providers:
even_filter = providers.Callable(filter, lambda x: x % 2 == 0)
odd_filter = providers.Callable(filter, lambda x: x % 2 != 0)
# Creating even and odd ranges using range() and filter providers:
even_range = even_filter(range(1, 10))
odd_range = odd_filter(range(1, 10))
# Making some asserts:
assert even_range == [2, 4, 6, 8]
assert odd_range == [1, 3, 5, 7, 9]

View File

@ -1,16 +0,0 @@
"""`Callable` providers with keyword arguments example."""
import passlib.hash
import dependency_injector.providers as providers
# Password hasher and verifier providers:
password_hasher = providers.Callable(passlib.hash.sha256_crypt.encrypt,
salt_size=16,
rounds=10000)
password_verifier = providers.Callable(passlib.hash.sha256_crypt.verify)
# Making some asserts:
hashed_password = password_hasher('super secret')
assert password_verifier('super secret', hashed_password)

View File

@ -1,26 +1,19 @@
"""`Coroutine` providers example with @asyncio.coroutine decorator.
Current example works only fot Python 3.4+.
"""
"""`Coroutine` providers example with async / await syntax."""
import asyncio
import dependency_injector.providers as providers
from dependency_injector import providers
@asyncio.coroutine
def coroutine_function(arg1, arg2):
"""Sample coroutine function."""
yield from asyncio.sleep(0.1)
async def coroutine(arg1, arg2):
await asyncio.sleep(0.1)
return arg1, arg2
coroutine_provider = providers.Coroutine(coroutine_function, arg1=1, arg2=2)
coroutine_provider = providers.Coroutine(coroutine, arg1=1, arg2=2)
if __name__ == '__main__':
loop = asyncio.get_event_loop()
arg1, arg2 = loop.run_until_complete(coroutine_provider())
arg1, arg2 = asyncio.run(coroutine_provider())
assert (arg1, arg2) == (1, 2)
assert asyncio.iscoroutinefunction(coroutine_provider)

View File

@ -1,25 +0,0 @@
"""`Coroutine` providers example with async / await syntax.
Current example works only fot Python 3.5+.
"""
import asyncio
import dependency_injector.providers as providers
async def coroutine_function(arg1, arg2):
"""Sample coroutine function."""
await asyncio.sleep(0.1)
return arg1, arg2
coroutine_provider = providers.Coroutine(coroutine_function, arg1=1, arg2=2)
if __name__ == '__main__':
loop = asyncio.get_event_loop()
arg1, arg2 = loop.run_until_complete(coroutine_provider())
assert (arg1, arg2) == (1, 2)
assert asyncio.iscoroutinefunction(coroutine_provider)

View File

@ -1,73 +1,50 @@
"""`Dependency` providers example."""
"""`Dependency` provider example."""
import sqlite3
import contextlib
import abc
import dataclasses
import dependency_injector.providers as providers
from dependency_injector import containers, providers, errors
class UsersService:
"""Example class UsersService.
UsersService has dependency on DBAPI 2.0 database connection.
"""
def __init__(self, database):
"""Initialize instance.
:param database: Database connection.
:type database: sqlite3.dbapi2.Connection
"""
self.database = database
self.database.row_factory = sqlite3.dbapi2.Row
def init_database(self):
"""Initialize database, if it has not been initialized yet."""
with contextlib.closing(self.database.cursor()) as cursor:
cursor.execute("""
CREATE TABLE IF NOT EXISTS users(
id INTEGER PRIMARY KEY AUTOINCREMENT,
name VARCHAR(32)
)
""")
def create(self, name):
"""Create user with provided name and return his id."""
with contextlib.closing(self.database.cursor()) as cursor:
cursor.execute('INSERT INTO users(name) VALUES (?)', (name,))
return cursor.lastrowid
def get_by_id(self, id):
"""Return user info by user id."""
with contextlib.closing(self.database.cursor()) as cursor:
cursor.execute('SELECT id, name FROM users WHERE id=?', (id,))
return cursor.fetchone()
class DbAdapter(metaclass=abc.ABCMeta):
...
# Database and UsersService providers:
database = providers.Dependency(instance_of=sqlite3.dbapi2.Connection)
users_service_factory = providers.Factory(UsersService,
database=database)
class SqliteDbAdapter(DbAdapter):
...
# Out of library's scope.
#
# Setting database provider:
database.provided_by(providers.Singleton(sqlite3.dbapi2.Connection,
database=':memory:',
timeout=30,
detect_types=True,
isolation_level='EXCLUSIVE'))
# Creating UsersService instance:
users_service = users_service_factory()
class PostgresDbAdapter(DbAdapter):
...
# Initializing UsersService database:
users_service.init_database()
# Creating test user and retrieving full information about him:
test_user_id = users_service.create(name='test_user')
test_user = users_service.get_by_id(test_user_id)
@dataclasses.dataclass
class UserService:
database: DbAdapter
# Making some asserts:
assert test_user['id'] == 1
assert test_user['name'] == 'test_user'
class Container(containers.DeclarativeContainer):
database = providers.Dependency(instance_of=DbAdapter)
user_service = providers.Factory(
UserService,
database=database,
)
if __name__ == '__main__':
container1 = Container(database=providers.Singleton(SqliteDbAdapter))
container2 = Container(database=providers.Singleton(PostgresDbAdapter))
assert isinstance(container1.user_service().database, SqliteDbAdapter)
assert isinstance(container2.user_service().database, PostgresDbAdapter)
container3 = Container(database=providers.Singleton(object))
try:
container3.user_service()
except errors.Error as exception:
print(exception)
# The output is:
# <object object at 0x107ce5c40> is not an
# instance of <class '__main__.DbAdapter'>

View File

@ -8,15 +8,11 @@ from dependency_injector import providers
@dataclasses.dataclass
class Module:
"""Example module."""
name: str
@dataclasses.dataclass
class Dispatcher:
"""Example dispatcher."""
modules: List[Module]
@ -28,6 +24,7 @@ dispatcher_factory = providers.Factory(
),
)
if __name__ == '__main__':
dispatcher = dispatcher_factory()
@ -35,11 +32,10 @@ if __name__ == '__main__':
assert dispatcher.modules[0].name == 'm1'
assert dispatcher.modules[1].name == 'm2'
# Call of dispatcher_factory() is equivalent to:
dispatcher = Dispatcher(
modules=[
Module(name='m1'),
Module(name='m2'),
],
)
# Call "dispatcher = dispatcher_factory()" is an equivalent for:
# dispatcher = Dispatcher(
# modules=[
# Module(name='m1'),
# Module(name='m2'),
# ],
# )

View File

@ -1,10 +1,10 @@
"""Object providers example."""
"""`Object` provider example."""
import dependency_injector.providers as providers
from dependency_injector import providers
# Creating object provider:
object_provider = providers.Object(1)
# Making some asserts:
assert object_provider() == 1
if __name__ == '__main__':
assert object_provider() == 1

View File

@ -19,10 +19,11 @@ selector = providers.Selector(
another=providers.Factory(SomeOtherClass),
)
config.override({'one_or_another': 'one'})
instance_1 = selector()
assert isinstance(instance_1, SomeClass)
if __name__ == '__main__':
config.override({'one_or_another': 'one'})
instance_1 = selector()
assert isinstance(instance_1, SomeClass)
config.override({'one_or_another': 'another'})
instance_2 = selector()
assert isinstance(instance_2, SomeOtherClass)
config.override({'one_or_another': 'another'})
instance_2 = selector()
assert isinstance(instance_2, SomeOtherClass)

View File

@ -24,6 +24,7 @@ class DynamicContainer(Container): ...
class DeclarativeContainer(Container):
cls_providers: ClassVar[Dict[str, Provider]]
inherited_providers: ClassVar[Dict[str, Provider]]
def __init__(self, **overriding_providers: Provider) -> None: ...
def override(container: Container) -> _Callable[[Container], Container]: ...