mirror of
https://github.com/ets-labs/python-dependency-injector.git
synced 2024-11-25 02:53:56 +03:00
Update DI Demo 2
This commit is contained in:
parent
e479e2cb94
commit
e0fa746d7f
103
README.rst
103
README.rst
|
@ -52,7 +52,7 @@ What is ``Dependency Injector``?
|
||||||
|
|
||||||
``Dependency Injector`` is a dependency injection framework for Python.
|
``Dependency Injector`` is a dependency injection framework for Python.
|
||||||
|
|
||||||
It helps you implement the dependency injection principle.
|
It helps you in implementing the dependency injection principle.
|
||||||
|
|
||||||
What is dependency injection?
|
What is dependency injection?
|
||||||
-----------------------------
|
-----------------------------
|
||||||
|
@ -70,6 +70,9 @@ Before:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
class ApiClient:
|
class ApiClient:
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
@ -82,10 +85,18 @@ Before:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.api_client = ApiClient()
|
self.api_client = ApiClient()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
service = Service()
|
||||||
|
|
||||||
|
|
||||||
After:
|
After:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
class ApiClient:
|
class ApiClient:
|
||||||
|
|
||||||
def __init__(self, api_key: str, timeout: int):
|
def __init__(self, api_key: str, timeout: int):
|
||||||
|
@ -98,48 +109,82 @@ After:
|
||||||
def __init__(self, api_client: ApiClient):
|
def __init__(self, api_client: ApiClient):
|
||||||
self.api_client = api_client
|
self.api_client = api_client
|
||||||
|
|
||||||
Who creates the objects now? Look at the next section.
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
service = Service(ApiClient(os.getenv('API_KEY'), os.getenv('TIMEOUT')))
|
||||||
|
|
||||||
|
|
||||||
|
Flexibility comes with a price: now you need to assemble your objects like this
|
||||||
|
``Service(ApiClient(os.getenv('API_KEY'), os.getenv('TIMEOUT')))``. The assembly code might get
|
||||||
|
duplicated and it'll become harder to change the application structure.
|
||||||
|
|
||||||
What does Dependency Injector do?
|
What does Dependency Injector do?
|
||||||
---------------------------------
|
---------------------------------
|
||||||
|
|
||||||
``Dependency Injector`` provides you with the container and the providers that help you build
|
``Dependency Injector`` helps you assemble the objects.
|
||||||
your application objects when you apply dependency injection principle:
|
|
||||||
|
It provides you the container and the providers that help you describe objects assembly. When you
|
||||||
|
need an object you get it from the container. The rest of the assembly work is done by the
|
||||||
|
framework:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
from dependency_injector import containers, providers
|
from dependency_injector import containers, providers
|
||||||
from unittest import mock
|
|
||||||
|
|
||||||
from .example_di import ApiClient, Service
|
|
||||||
|
|
||||||
|
|
||||||
class Container(containers.DeclarativeContainer):
|
class ApiClient:
|
||||||
|
|
||||||
config = providers.Configuration()
|
def __init__(self, api_key: str, timeout: int):
|
||||||
|
self.api_key = api_key
|
||||||
api_client = providers.Singleton(
|
self.timeout = timeout
|
||||||
ApiClient,
|
|
||||||
api_key=config.api_key,
|
|
||||||
timeout=config.timeout,
|
|
||||||
)
|
|
||||||
|
|
||||||
service = providers.Factory(
|
|
||||||
Service,
|
|
||||||
api_client=api_client,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
class Service:
|
||||||
container = Container()
|
|
||||||
container.config.from_yaml('config.yml')
|
|
||||||
|
|
||||||
service = container.service()
|
def __init__(self, api_client: ApiClient):
|
||||||
assert isinstance(service.api_client, ApiClient)
|
self.api_client = api_client
|
||||||
|
|
||||||
with container.api_client.override(mock.Mock()):
|
|
||||||
service = container.service()
|
class Container(containers.DeclarativeContainer):
|
||||||
assert isinstance(service.api_client, mock.Mock)
|
|
||||||
|
config = providers.Configuration()
|
||||||
|
|
||||||
|
api_client = providers.Singleton(
|
||||||
|
ApiClient,
|
||||||
|
api_key=config.api_key,
|
||||||
|
timeout=config.timeout,
|
||||||
|
)
|
||||||
|
|
||||||
|
service = providers.Factory(
|
||||||
|
Service,
|
||||||
|
api_client=api_client,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
container = Container()
|
||||||
|
container.config.api_key.from_env('API_KEY')
|
||||||
|
container.config.timeout.from_env('TIMEOUT')
|
||||||
|
|
||||||
|
service = container.service()
|
||||||
|
assert isinstance(service.api_client, ApiClient)
|
||||||
|
|
||||||
|
Retrieving of the ``Service`` instance now is done like this ``container.service()``.
|
||||||
|
|
||||||
|
Also ``Dependency Injector`` provides a bonus in overriding any of the providers with the
|
||||||
|
``.override()`` method:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
|
|
||||||
|
with container.api_client.override(mock.Mock()):
|
||||||
|
service = container.service()
|
||||||
|
assert isinstance(service.api_client, mock.Mock)
|
||||||
|
|
||||||
|
It helps in a testing. Also you can use it for configuring project for the different environments:
|
||||||
|
replace an API client with a stub on the dev or stage.
|
||||||
|
|
||||||
`More examples <https://github.com/ets-labs/python-dependency-injector/tree/master/examples>`_
|
`More examples <https://github.com/ets-labs/python-dependency-injector/tree/master/examples>`_
|
||||||
|
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
api_key: test-key
|
|
||||||
timeout: 5
|
|
|
@ -1,7 +1,17 @@
|
||||||
from dependency_injector import containers, providers
|
from dependency_injector import containers, providers
|
||||||
from unittest import mock
|
|
||||||
|
|
||||||
from .example_di import ApiClient, Service
|
|
||||||
|
class ApiClient:
|
||||||
|
|
||||||
|
def __init__(self, api_key: str, timeout: int):
|
||||||
|
self.api_key = api_key
|
||||||
|
self.timeout = timeout
|
||||||
|
|
||||||
|
|
||||||
|
class Service:
|
||||||
|
|
||||||
|
def __init__(self, api_client: ApiClient):
|
||||||
|
self.api_client = api_client
|
||||||
|
|
||||||
|
|
||||||
class Container(containers.DeclarativeContainer):
|
class Container(containers.DeclarativeContainer):
|
||||||
|
@ -22,11 +32,8 @@ class Container(containers.DeclarativeContainer):
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
container = Container()
|
container = Container()
|
||||||
container.config.from_yaml('config.yml')
|
container.config.api_key.from_env('API_KEY')
|
||||||
|
container.config.timeout.from_env('TIMEOUT')
|
||||||
|
|
||||||
service = container.service()
|
service = container.service()
|
||||||
assert isinstance(service.api_client, ApiClient)
|
assert isinstance(service.api_client, ApiClient)
|
||||||
|
|
||||||
with container.api_client.override(mock.Mock()):
|
|
||||||
service = container.service()
|
|
||||||
assert isinstance(service.api_client, mock.Mock)
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
class ApiClient:
|
class ApiClient:
|
||||||
|
@ -11,3 +12,7 @@ class Service:
|
||||||
|
|
||||||
def __init__(self, api_client: ApiClient):
|
def __init__(self, api_client: ApiClient):
|
||||||
self.api_client = api_client
|
self.api_client = api_client
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
service = Service(ApiClient(os.getenv('API_KEY'), os.getenv('TIMEOUT')))
|
||||||
|
|
|
@ -12,3 +12,7 @@ class Service:
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.api_client = ApiClient()
|
self.api_client = ApiClient()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
service = Service()
|
||||||
|
|
11
examples/di_demo2/test.py
Normal file
11
examples/di_demo2/test.py
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
|
from demo import Container
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
container = Container()
|
||||||
|
|
||||||
|
with container.api_client.override(mock.Mock()):
|
||||||
|
service = container.service()
|
||||||
|
assert isinstance(service.api_client, mock.Mock)
|
Loading…
Reference in New Issue
Block a user