.. _provider:
Provider
****************
**Provider** is an object whose members are used to construct dependencies. ``Provider`` contains different factories and other entities and then is used to create a ``Container``. You can have multiple providers in one application combining them in different ways to make it more modular.
To configure provider you can either inherit and use decorators on your methods or just create an instance and use its methods.
For example, imagine you have two classes: connection which is retrieved from external library and a dao which requires such a connection.
.. code-block:: python
class Connection:
pass
class DAO:
def __init__(self, conn: Connection):
pass
You can configure ``Provider`` with code like this:
.. code-block:: python
from dishka import make_container, Provider, Scope
def get_connection() -> Iterable[Connection]:
conn = connect(uri)
yield conn
conn.close()
provider = Provider(scope=Scope.APP)
provider.provide(get_connection)
provider.provide(DAO)
container = make_container(provider)
Or using inheritance:
.. code-block:: python
from dishka import make_container, Provider, provide, Scope
class MyProvider(Provider):
@provide
def get_connection(self) -> Iterable[Connection]:
conn = connect(uri)
yield conn
conn.close()
dao = provide(DAO)
container = make_container(MyProvider(scope=Scope.APP))
Your class-based provider can have ``__init__`` method and methods accessing ``self`` as usual. It can be useful for passing configuration:
.. code-block:: python
class MyProvider(Provider):
def __init__(self, uri: str, scope: Scope):
super().__init__(scope=scope) # do not forget `super`
self.uri = uri
@provide
def get_connection(self) -> Iterable[Connection]:
conn = connect(self.uri) # use passed configuration
yield conn
conn.close()
dao = provide(DAO)
provider = MyProvider(uri=os.getenv("DB_URI"), scope=Scope.APP)
container = make_container(provider)
Dependencies have scope and there are three places to set it (from highest to lowest priority):
* When registering single factory passing to ``provide`` method:
.. code-block:: python
class MyProvider(Provider):
dao = provide(DAO, scope=Scope.APP)
* When instantiating provider:
.. code-block:: python
provider = Provider(scope=Scope.APP)
* Inside class:
.. code-block:: python
class MyProvider(Provider):
scope = Scope.APP
.. raw:: html
.. warning::
Provider internally defines attributes like ``factories``, ``aliases``, ``decorators``, and ``context_vars``.
Overriding them in your subclass will break dependency resolution. Use another name.
.. code-block:: python
class MyProvider(Provider):
scope = ...
factories = provide(SomeClass) # ERROR
.. raw:: html
Though it is a normal object, not all attributes are analyzed by ``Container``, but only those which are marked with special functions:
.. toctree::
provide
provide_all
alias
from_context
decorate