mirror of
https://github.com/ets-labs/python-dependency-injector.git
synced 2025-05-22 21:46:17 +03:00
Edit Dependency provider docs
This commit is contained in:
parent
9e6b52aad4
commit
6fac06fd91
Binary file not shown.
Before Width: | Height: | Size: 42 KiB |
|
@ -10,7 +10,7 @@ follows `Semantic versioning`_
|
||||||
Development version
|
Development version
|
||||||
-------------------
|
-------------------
|
||||||
- Update documentation and rework examples for: ``Singleton``, ``Callable``, ``Coroutine``,
|
- Update documentation and rework examples for: ``Singleton``, ``Callable``, ``Coroutine``,
|
||||||
``Object``, ``List``, ``Configuration``, ``Selector`` providers.
|
``Object``, ``List``, ``Configuration``, ``Selector``, and ``Dependency`` providers.
|
||||||
- Fix mypy stub of the ``DeclarativeContainer`` to specify the ``__init__`` interface.
|
- Fix mypy stub of the ``DeclarativeContainer`` to specify the ``__init__`` interface.
|
||||||
|
|
||||||
3.34.0
|
3.34.0
|
||||||
|
|
|
@ -1,43 +1,21 @@
|
||||||
Dependency providers
|
Dependency provider
|
||||||
--------------------
|
-------------------
|
||||||
|
|
||||||
.. currentmodule:: dependency_injector.providers
|
.. currentmodule:: dependency_injector.providers
|
||||||
|
|
||||||
:py:class:`Dependency` provider can be useful for development of
|
:py:class:`Dependency` provider is a placeholder for the dependency of the specified type.
|
||||||
self-sufficient libraries / modules / applications that have required external
|
|
||||||
dependencies.
|
|
||||||
|
|
||||||
For example, you have created self-sufficient library / module / application,
|
The first argument of the ``Dependency`` provider specifies a type of the dependency. It is
|
||||||
that has dependency on *database connection*.
|
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
|
The ``Dependency`` provider must be overridden before usage. It can be overridden by any type of
|
||||||
reusable by wide amount of developers and to be easily integrated into many
|
the provider. The only rule is that overriding provider must return an instance of ``instance_of``
|
||||||
applications.
|
dependency type.
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/providers/dependency.py
|
.. literalinclude:: ../../examples/providers/dependency.py
|
||||||
:language: python
|
:language: python
|
||||||
|
:lines: 3-
|
||||||
|
:emphasize-lines: 26
|
||||||
|
|
||||||
.. disqus::
|
.. disqus::
|
||||||
|
|
|
@ -1,73 +1,50 @@
|
||||||
"""`Dependency` providers example."""
|
"""`Dependency` provider example."""
|
||||||
|
|
||||||
import sqlite3
|
import abc
|
||||||
import contextlib
|
import dataclasses
|
||||||
|
|
||||||
import dependency_injector.providers as providers
|
from dependency_injector import containers, providers, errors
|
||||||
|
|
||||||
|
|
||||||
class UsersService:
|
class DbAdapter(metaclass=abc.ABCMeta):
|
||||||
"""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()
|
|
||||||
|
|
||||||
|
|
||||||
# Database and UsersService providers:
|
class SqliteDbAdapter(DbAdapter):
|
||||||
database = providers.Dependency(instance_of=sqlite3.dbapi2.Connection)
|
...
|
||||||
users_service_factory = providers.Factory(UsersService,
|
|
||||||
database=database)
|
|
||||||
|
|
||||||
# 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:
|
class PostgresDbAdapter(DbAdapter):
|
||||||
users_service = users_service_factory()
|
...
|
||||||
|
|
||||||
# Initializing UsersService database:
|
|
||||||
users_service.init_database()
|
|
||||||
|
|
||||||
# Creating test user and retrieving full information about him:
|
@dataclasses.dataclass
|
||||||
test_user_id = users_service.create(name='test_user')
|
class UserService:
|
||||||
test_user = users_service.get_by_id(test_user_id)
|
database: DbAdapter
|
||||||
|
|
||||||
# Making some asserts:
|
|
||||||
assert test_user['id'] == 1
|
class Container(containers.DeclarativeContainer):
|
||||||
assert test_user['name'] == 'test_user'
|
|
||||||
|
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'>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user