Update examples to use config __init__ args (#527)

* Update application-single-container example

* Update application-multiple-containers example

* Update decoupled-packages example

* Update movie lister example

* Update CLI tutorial

* Update sanic example

* Update sanic example with wiring_config

* Update fastapi example

* Update fastapi-simple example

* Update fastapi-sqlalchemy example

* Update flask-blueprints example

* Update flask example and tutorial

* Update aiohttp example and tutorial

* Update asyncio-daemon example and tutorial
This commit is contained in:
Roman Mogylatov 2021-10-31 20:31:39 -04:00 committed by GitHub
parent 6030950596
commit fe01ad41d9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
42 changed files with 310 additions and 364 deletions

View File

@ -127,8 +127,6 @@ Now it's time to install the project requirements. We will use next packages:
- ``dependency-injector`` - the dependency injection framework
- ``aiohttp`` - the web framework
- ``aiohttp-devtools`` - the helper library that will provide a development server with live
reloading
- ``pyyaml`` - the YAML files parsing library, used for the reading of the configuration files
- ``pytest-aiohttp`` - the helper library for the testing of the ``aiohttp`` application
- ``pytest-cov`` - the helper library for measuring the test coverage
@ -139,7 +137,6 @@ Put next lines into the ``requirements.txt`` file:
dependency-injector
aiohttp
aiohttp-devtools
pyyaml
pytest-aiohttp
pytest-cov
@ -232,26 +229,31 @@ Put next into the ``application.py``:
])
return app
if __name__ == "__main__":
app = create_app()
web.run_app(app)
Now we're ready to run our application
Do next in the terminal:
.. code-block:: bash
adev runserver giphynavigator/application.py --livereload
python -m giphynavigator.application
The output should be something like:
.. code-block:: bash
[18:52:59] Starting aux server at http://localhost:8001 ◆
[18:52:59] Starting dev server at http://localhost:8000 ●
======== Running on http://0.0.0.0:8080 ========
(Press CTRL+C to quit)
Let's check that it works. Open another terminal session and use ``httpie``:
.. code-block:: bash
http http://127.0.0.1:8000/
http http://0.0.0.0:8080/
You should see:
@ -261,7 +263,7 @@ You should see:
Content-Length: 844
Content-Type: application/json; charset=utf-8
Date: Wed, 29 Jul 2020 21:01:50 GMT
Server: Python/3.9 aiohttp/3.6.2
Server: Python/3.10 aiohttp/3.6.2
{
"gifs": [],
@ -328,8 +330,10 @@ Now we need to add ``GiphyClient`` into the container. The ``GiphyClient`` has t
that have to be injected: the API key and the request timeout. We will need to use two more
providers from the ``dependency_injector.providers`` module:
- ``Factory`` provider that will create the ``GiphyClient`` client.
- ``Configuration`` provider that will provide the API key and the request timeout.
- ``Factory`` provider. It will create a ``GiphyClient`` client.
- ``Configuration`` provider. It will provide an API key and a request timeout for the ``GiphyClient``
client. We will specify the location of the configuration file. The configuration provider will parse
the configuration file when we create a container instance.
Edit ``containers.py``:
@ -345,7 +349,7 @@ Edit ``containers.py``:
class Container(containers.DeclarativeContainer):
config = providers.Configuration()
config = providers.Configuration(yaml_files=["config.yml"])
giphy_client = providers.Factory(
giphy.GiphyClient,
@ -353,18 +357,8 @@ Edit ``containers.py``:
timeout=config.giphy.request_timeout,
)
.. note::
We have used the configuration value before it was defined. That's the principle how the
``Configuration`` provider works.
Use first, define later.
Now let's add the configuration file.
We will use YAML.
Create an empty file ``config.yml`` in the root root of the project:
Now let's add the configuration file. We will use YAML. Create an empty file ``config.yml`` in
the root root of the project:
.. code-block:: bash
:emphasize-lines: 9
@ -387,17 +381,14 @@ and put next into it:
giphy:
request_timeout: 10
We will use an environment variable ``GIPHY_API_KEY`` to provide the API key.
Now we need to edit ``create_app()`` to make two things when application starts:
- Load the configuration file the ``config.yml``.
- Load the API key from the ``GIPHY_API_KEY`` environment variable.
We will use the ``GIPHY_API_KEY`` environment variable to provide the API key. Lets edit
``create_app()`` to fetch the key value from it.
Edit ``application.py``:
.. code-block:: python
:emphasize-lines: 11-12
:emphasize-lines: 11
"""Application module."""
@ -409,7 +400,6 @@ Edit ``application.py``:
def create_app() -> web.Application:
container = Container()
container.config.from_yaml("config.yml")
container.config.giphy.api_key.from_env("GIPHY_API_KEY")
app = web.Application()
@ -420,6 +410,10 @@ Edit ``application.py``:
return app
if __name__ == "__main__":
app = create_app()
web.run_app(app)
Now we need to create an API key and set it to the environment variable.
As for now, dont worry, just take this one:
@ -502,7 +496,7 @@ Edit ``containers.py``:
class Container(containers.DeclarativeContainer):
config = providers.Configuration()
config = providers.Configuration(yaml_files=["config.yml"])
giphy_client = providers.Factory(
giphy.GiphyClient,
@ -555,47 +549,50 @@ Edit ``handlers.py``:
},
)
To make the injection work we need to wire the container instance with the ``handlers`` module.
This needs to be done once. After it's done we can use ``Provide`` markers to specify as many
injections as needed for any handler.
To make the injection work we need to wire the container with the ``handlers`` module.
Let's configure the container to automatically make wiring with the ``handlers`` module when we
create a container instance.
Edit ``application.py``:
Edit ``containers.py``:
.. code-block:: python
:emphasize-lines: 13
:emphasize-lines: 10
"""Application module."""
"""Containers module."""
from aiohttp import web
from dependency_injector import containers, providers
from .containers import Container
from . import handlers
from . import giphy, services
def create_app() -> web.Application:
container = Container()
container.config.from_yaml("config.yml")
container.config.giphy.api_key.from_env("GIPHY_API_KEY")
container.wire(modules=[handlers])
class Container(containers.DeclarativeContainer):
app = web.Application()
app.container = container
app.add_routes([
web.get("/", handlers.index),
])
return app
wiring_config = containers.WiringConfiguration(modules=[".handlers"])
Make sure the app is running or use:
config = providers.Configuration(yaml_files=["config.yml"])
giphy_client = providers.Factory(
giphy.GiphyClient,
api_key=config.giphy.api_key,
timeout=config.giphy.request_timeout,
)
search_service = providers.Factory(
services.SearchService,
giphy_client=giphy_client,
)
Make sure the app is running:
.. code-block:: bash
adev runserver giphynavigator/application.py --livereload
python -m giphynavigator.application
and make a request to the API in the terminal:
.. code-block:: bash
http http://localhost:8000/ query=="wow,it works" limit==5
http http://0.0.0.0:8080/ query=="wow,it works" limit==5
You should see:
@ -605,7 +602,7 @@ You should see:
Content-Length: 492
Content-Type: application/json; charset=utf-8
Date: Fri, 09 Oct 2020 01:35:48 GMT
Server: Python/3.9 aiohttp/3.6.2
Server: Python/3.10 aiohttp/3.6.2
{
"gifs": [
@ -810,24 +807,24 @@ You should see:
.. code-block::
platform darwin -- Python 3.9, pytest-5.4.3, py-1.9.0, pluggy-0.13.1
plugins: cov-2.10.0, aiohttp-0.3.0, asyncio-0.14.0
platform darwin -- Python 3.10.0, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
plugins: asyncio-0.16.0, anyio-3.3.4, aiohttp-0.3.0, cov-3.0.0
collected 3 items
giphynavigator/tests.py ... [100%]
---------- coverage: platform darwin, python 3.9 -----------
---------- coverage: platform darwin, python 3.10.0-final-0 ----------
Name Stmts Miss Cover
---------------------------------------------------
giphynavigator/__init__.py 0 0 100%
giphynavigator/application.py 12 0 100%
giphynavigator/containers.py 6 0 100%
giphynavigator/application.py 13 2 85%
giphynavigator/containers.py 7 0 100%
giphynavigator/giphy.py 14 9 36%
giphynavigator/handlers.py 10 0 100%
giphynavigator/services.py 9 1 89%
giphynavigator/tests.py 37 0 100%
---------------------------------------------------
TOTAL 88 10 89%
TOTAL 90 12 87%
.. note::

View File

@ -135,7 +135,7 @@ Put next lines into the ``Dockerfile`` file:
.. code-block:: bash
FROM python:3.9-buster
FROM python:3.10-buster
ENV PYTHONUNBUFFERED=1
@ -204,11 +204,11 @@ Logging and configuration
In this section we will configure the logging and configuration file parsing.
Let's start with the the main part of our application - the container. Container will keep all of
Let's start with the the main part of our application the container. Container will keep all of
the application components and their dependencies.
First two components that we're going to add are the config object and the provider for
configuring the logging.
First two components that we're going to add are the configuration provider and the resource provider
for configuring the logging.
Put next lines into the ``containers.py`` file:
@ -224,7 +224,7 @@ Put next lines into the ``containers.py`` file:
class Container(containers.DeclarativeContainer):
config = providers.Configuration()
config = providers.Configuration(yaml_files=["config.yml"])
logging = providers.Resource(
logging.basicConfig,
@ -233,16 +233,7 @@ Put next lines into the ``containers.py`` file:
format=config.log.format,
)
.. note::
We have used the configuration value before it was defined. That's the principle how the
``Configuration`` provider works.
Use first, define later.
The configuration file will keep the logging settings.
Put next lines into the ``config.yml`` file:
The configuration file will keep the logging settings. Put next lines into the ``config.yml`` file:
.. code-block:: yaml
@ -250,9 +241,10 @@ Put next lines into the ``config.yml`` file:
level: "INFO"
format: "[%(asctime)s] [%(levelname)s] [%(name)s]: %(message)s"
Now let's create the function that will run our daemon. It's traditionally called
``main()``. The ``main()`` function will create the container. Then it will use the container
to parse the ``config.yml`` file and call the logging configuration provider.
Now let's create the function that will run our daemon. It's traditionally called ``main()``.
The ``main()`` function will start the dispatcher, but we will keep it empty for now.
We will create the container instance before calling ``main()`` in ``if __name__ == "__main__"``.
Container instance will parse ``config.yml`` and then we will call the logging configuration provider.
Put next lines into the ``__main__.py`` file:
@ -269,7 +261,6 @@ Put next lines into the ``__main__.py`` file:
if __name__ == "__main__":
container = Container()
container.config.from_yaml("config.yml")
container.init_resources()
main()
@ -419,7 +410,7 @@ Edit ``containers.py``:
class Container(containers.DeclarativeContainer):
config = providers.Configuration()
config = providers.Configuration(yaml_files=["config.yml"])
logging = providers.Resource(
logging.basicConfig,
@ -442,7 +433,7 @@ and call the ``run()`` method. We will use :ref:`wiring` feature.
Edit ``__main__.py``:
.. code-block:: python
:emphasize-lines: 3-5,9-11,18
:emphasize-lines: 3-5,9-11,17
"""Main module."""
@ -459,7 +450,6 @@ Edit ``__main__.py``:
if __name__ == "__main__":
container = Container()
container.config.from_yaml("config.yml")
container.init_resources()
container.wire(modules=[__name__])
@ -559,7 +549,7 @@ Edit ``containers.py``:
class Container(containers.DeclarativeContainer):
config = providers.Configuration()
config = providers.Configuration(yaml_files=["config.yml"])
logging = providers.Resource(
logging.basicConfig,
@ -664,7 +654,7 @@ Edit ``containers.py``:
class Container(containers.DeclarativeContainer):
config = providers.Configuration()
config = providers.Configuration(yaml_files=["config.yml"])
logging = providers.Resource(
logging.basicConfig,
@ -763,7 +753,7 @@ Edit ``containers.py``:
class Container(containers.DeclarativeContainer):
config = providers.Configuration()
config = providers.Configuration(yaml_files=["config.yml"])
logging = providers.Resource(
logging.basicConfig,
@ -888,7 +878,7 @@ Create ``tests.py`` in the ``monitoringdaemon`` package:
and put next into it:
.. code-block:: python
:emphasize-lines: 54,70-71
:emphasize-lines: 54,70-73
"""Tests module."""
@ -909,28 +899,28 @@ and put next into it:
@pytest.fixture
def container():
container = Container()
container.config.from_dict({
"log": {
"level": "INFO",
"formant": "[%(asctime)s] [%(levelname)s] [%(name)s]: %(message)s",
},
"monitors": {
"example": {
"method": "GET",
"url": "http://fake-example.com",
"timeout": 1,
"check_every": 1,
return Container(
config={
"log": {
"level": "INFO",
"formant": "[%(asctime)s] [%(levelname)s] [%(name)s]: %(message)s",
},
"httpbin": {
"method": "GET",
"url": "https://fake-httpbin.org/get",
"timeout": 1,
"check_every": 1,
"monitors": {
"example": {
"method": "GET",
"url": "http://fake-example.com",
"timeout": 1,
"check_every": 1,
},
"httpbin": {
"method": "GET",
"url": "https://fake-httpbin.org/get",
"timeout": 1,
"check_every": 1,
},
},
},
})
return container
}
)
@pytest.mark.asyncio
@ -959,9 +949,10 @@ and put next into it:
example_monitor_mock = mock.AsyncMock()
httpbin_monitor_mock = mock.AsyncMock()
with container.example_monitor.override(example_monitor_mock), \
container.httpbin_monitor.override(httpbin_monitor_mock):
with container.override_providers(
example_monitor=example_monitor_mock,
httpbin_monitor=httpbin_monitor_mock,
):
dispatcher = container.dispatcher()
event_loop.create_task(dispatcher.start())
await asyncio.sleep(0.1)
@ -980,25 +971,25 @@ You should see:
.. code-block:: bash
platform linux -- Python 3.9, pytest-6.0.1, py-1.9.0, pluggy-0.13.1
platform linux -- Python 3.10.0, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
rootdir: /code
plugins: asyncio-0.14.0, cov-2.10.0
plugins: asyncio-0.16.0, cov-3.0.0
collected 2 items
monitoringdaemon/tests.py .. [100%]
----------- coverage: platform linux, python 3.9 -----------
---------- coverage: platform linux, python 3.10.0-final-0 -----------
Name Stmts Miss Cover
----------------------------------------------------
monitoringdaemon/__init__.py 0 0 100%
monitoringdaemon/__main__.py 13 13 0%
monitoringdaemon/__main__.py 11 11 0%
monitoringdaemon/containers.py 11 0 100%
monitoringdaemon/dispatcher.py 44 5 89%
monitoringdaemon/dispatcher.py 45 5 89%
monitoringdaemon/http.py 6 3 50%
monitoringdaemon/monitors.py 23 1 96%
monitoringdaemon/tests.py 37 0 100%
monitoringdaemon/tests.py 35 0 100%
----------------------------------------------------
TOTAL 134 22 84%
TOTAL 131 20 85%
.. note::

View File

@ -428,7 +428,7 @@ Edit ``containers.py``:
class Container(containers.DeclarativeContainer):
config = providers.Configuration()
config = providers.Configuration(yaml_files=["config.yml"])
movie = providers.Factory(entities.Movie)
@ -445,15 +445,9 @@ This is also called the delegation of the provider. If we just pass the movie fa
as the dependency, it will be called when csv finder is created and the ``Movie`` instance will
be injected. With the ``.provider`` attribute the provider itself will be injected.
The csv finder also has a few dependencies on the configuration options. We added configuration
provider to provide these dependencies.
.. note::
We have used the configuration value before it was defined. That's the principle how the
Configuration provider works.
Use first, define later.
The csv finder also has a few dependencies on the configuration options. We added a configuration
provider to provide these dependencies and specified the location of the configuration file.
The configuration provider will parse the configuration file when we create a container instance.
Not let's define the configuration values.
@ -467,29 +461,7 @@ Edit ``config.yml``:
path: "data/movies.csv"
delimiter: ","
The configuration file is ready. Now let's update the ``main()`` function to specify its location.
Edit ``__main__.py``:
.. code-block:: python
:emphasize-lines: 12
"""Main module."""
from .containers import Container
def main() -> None:
...
if __name__ == "__main__":
container = Container()
container.config.from_yaml("config.yml")
main()
Move on to the lister.
The configuration file is ready. Move on to the lister.
Create the ``listers.py`` in the ``movies`` package:
@ -552,7 +524,7 @@ and edit ``containers.py``:
class Container(containers.DeclarativeContainer):
config = providers.Configuration()
config = providers.Configuration(yaml_files=["config.yml"])
movie = providers.Factory(entities.Movie)
@ -575,7 +547,7 @@ Let's inject the ``lister`` into the ``main()`` function.
Edit ``__main__.py``:
.. code-block:: python
:emphasize-lines: 3-5,9-10,17
:emphasize-lines: 3-5,9-10,16
"""Main module."""
@ -592,7 +564,6 @@ Edit ``__main__.py``:
if __name__ == "__main__":
container = Container()
container.config.from_yaml("config.yml")
container.wire(modules=[__name__])
main()
@ -628,7 +599,6 @@ Edit ``__main__.py``:
if __name__ == "__main__":
container = Container()
container.config.from_yaml("config.yml")
container.wire(modules=[__name__])
main()
@ -733,7 +703,7 @@ Edit ``containers.py``:
class Container(containers.DeclarativeContainer):
config = providers.Configuration()
config = providers.Configuration(yaml_files=["config.yml"])
movie = providers.Factory(entities.Movie)
@ -822,7 +792,7 @@ Edit ``containers.py``:
class Container(containers.DeclarativeContainer):
config = providers.Configuration()
config = providers.Configuration(yaml_files=["config.yml"])
movie = providers.Factory(entities.Movie)
@ -859,7 +829,7 @@ Now we need to read the value of the ``config.finder.type`` option from the envi
Edit ``__main__.py``:
.. code-block:: python
:emphasize-lines: 23
:emphasize-lines: 22
"""Main module."""
@ -882,7 +852,6 @@ Edit ``__main__.py``:
if __name__ == "__main__":
container = Container()
container.config.from_yaml("config.yml")
container.config.finder.type.from_env("MOVIE_FINDER_TYPE")
container.wire(modules=[sys.modules[__name__]])
@ -942,7 +911,7 @@ Create ``tests.py`` in the ``movies`` package:
and put next into it:
.. code-block:: python
:emphasize-lines: 35,50
:emphasize-lines: 36,51
"""Tests module."""
@ -955,19 +924,20 @@ and put next into it:
@pytest.fixture
def container():
container = Container()
container.config.from_dict({
"finder": {
"type": "csv",
"csv": {
"path": "/fake-movies.csv",
"delimiter": ",",
},
"sqlite": {
"path": "/fake-movies.db",
container = Container(
config={
"finder": {
"type": "csv",
"csv": {
"path": "/fake-movies.csv",
"delimiter": ",",
},
"sqlite": {
"path": "/fake-movies.db",
},
},
},
})
)
return container
@ -1010,24 +980,24 @@ You should see:
.. code-block::
platform darwin -- Python 3.9, pytest-5.4.3, py-1.9.0, pluggy-0.13.1
plugins: cov-2.10.0
platform darwin -- Python 3.10.0, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
plugins: cov-3.0.0
collected 2 items
movies/tests.py .. [100%]
---------- coverage: platform darwin, python 3.9 -----------
---------- coverage: platform darwin, python 3.10 -----------
Name Stmts Miss Cover
------------------------------------------
movies/__init__.py 0 0 100%
movies/__main__.py 18 18 0%
movies/__main__.py 16 16 0%
movies/containers.py 9 0 100%
movies/entities.py 7 1 86%
movies/finders.py 26 13 50%
movies/listers.py 8 0 100%
movies/tests.py 24 0 100%
movies/tests.py 23 0 100%
------------------------------------------
TOTAL 92 32 65%
TOTAL 89 30 66%
.. note::
@ -1047,7 +1017,7 @@ We've used the ``Dependency Injector`` as a dependency injection framework.
With a help of :ref:`containers` and :ref:`providers` we have defined how to assemble application components.
``Selector`` provider served as a switch for selecting the database format based on a configuration.
:ref:`configuration-provider` helped to deal with reading YAML file and environment variable.
:ref:`configuration-provider` helped to deal with reading a YAML file and environment variables.
We used :ref:`wiring` feature to inject the dependencies into the ``main()`` function.
:ref:`provider-overriding` feature helped in testing.

View File

@ -112,7 +112,7 @@ You should see something like:
(venv) $ python -c "import dependency_injector; print(dependency_injector.__version__)"
4.37.0
(venv) $ python -c "import flask; print(flask.__version__)"
1.1.2
2.0.2
*Versions can be different. That's fine.*
@ -444,9 +444,10 @@ and run in the terminal:
Now we need to add Github API client the container. We will need to add two more providers from
the ``dependency_injector.providers`` module:
- ``Factory`` provider that will create ``Github`` client.
- ``Configuration`` provider that will be used for providing the API token and the request timeout
for the ``Github`` client.
- ``Factory`` provider. It will create a ``Github`` client.
- ``Configuration`` provider. It will provide an API token and a request timeout for the ``Github`` client.
We will specify the location of the configuration file. The configuration provider will parse
the configuration file when we create a container instance.
Edit ``containers.py``:
@ -461,7 +462,7 @@ Edit ``containers.py``:
class Container(containers.DeclarativeContainer):
config = providers.Configuration()
config = providers.Configuration(yaml_files=["config.yml"])
github_client = providers.Factory(
Github,
@ -469,23 +470,14 @@ Edit ``containers.py``:
timeout=config.github.request_timeout,
)
.. note::
We have used the configuration value before it was defined. That's the principle how
``Configuration`` provider works.
Use first, define later.
.. note::
Don't forget to remove the Ellipsis ``...`` from the container. We don't need it anymore
since we container is not empty.
Now let's add the configuration file.
We will use YAML.
Create an empty file ``config.yml`` in the root of the project:
Now let's add the configuration file. We will use YAML. Create an empty file ``config.yml``
in the root of the project:
.. code-block:: bash
:emphasize-lines: 11
@ -530,17 +522,13 @@ and install it:
pip install -r requirements.txt
We will use environment variable ``GITHUB_TOKEN`` to provide the API token.
Now we need to edit ``create_app()`` to make two things when application starts:
- Load the configuration file the ``config.yml``.
- Load the API token from the ``GITHUB_TOKEN`` environment variable.
We will use the ``GITHUB_TOKEN`` environment variable to provide the API token. Let's edit
``create_app()`` to fetch the token value from it.
Edit ``application.py``:
.. code-block:: python
:emphasize-lines: 12-13
:emphasize-lines: 12
"""Application module."""
@ -553,7 +541,6 @@ Edit ``application.py``:
def create_app() -> Flask:
container = Container()
container.config.from_yaml("config.yml")
container.config.github.auth_token.from_env("GITHUB_TOKEN")
app = Flask(__name__)
@ -684,7 +671,7 @@ Edit ``containers.py``:
class Container(containers.DeclarativeContainer):
config = providers.Configuration()
config = providers.Configuration(yaml_files=["config.yml"])
github_client = providers.Factory(
Github,
@ -732,38 +719,39 @@ Edit ``views.py``:
repositories=repositories,
)
To make the injection work we need to wire the container instance with the ``views`` module.
This needs to be done once. After it's done we can use ``Provide`` markers to specify as many
injections as needed for any view.
To make the injection work we need to wire the container with the ``views`` module.
Let's configure the container to automatically make wiring with the ``views`` module when we
create a container instance.
Edit ``application.py``:
Edit ``containers.py``:
.. code-block:: python
:emphasize-lines: 14
:emphasize-lines: 11
"""Application module."""
"""Containers module."""
from flask import Flask
from flask_bootstrap import Bootstrap
from dependency_injector import containers, providers
from github import Github
from .containers import Container
from . import views
from . import services
def create_app() -> Flask:
container = Container()
container.config.from_yaml("config.yml")
container.config.github.auth_token.from_env("GITHUB_TOKEN")
container.wire(modules=[views])
class Container(containers.DeclarativeContainer):
app = Flask(__name__)
app.container = container
app.add_url_rule("/", "index", views.index)
wiring_config = containers.WiringConfiguration(modules=[".views"])
bootstrap = Bootstrap()
bootstrap.init_app(app)
config = providers.Configuration(yaml_files=["config.yml"])
return app
github_client = providers.Factory(
Github,
login_or_token=config.github.auth_token,
timeout=config.github.request_timeout,
)
search_service = providers.Factory(
services.SearchService,
github_client=github_client,
)
Make sure the app is running or use ``flask run`` and open ``http://127.0.0.1:5000/``.
@ -960,23 +948,23 @@ You should see:
.. code-block:: bash
platform darwin -- Python 3.9, pytest-5.4.3, py-1.9.0, pluggy-0.13.1
plugins: flask-1.0.0, cov-2.10.0
platform darwin -- Python 3.10.0, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
plugins: cov-3.0.0, flask-1.2.0
collected 2 items
githubnavigator/tests.py .. [100%]
---------- coverage: platform darwin, python 3.9 -----------
---------- coverage: platform darwin, python 3.10.0-final-0 ----------
Name Stmts Miss Cover
----------------------------------------------------
githubnavigator/__init__.py 0 0 100%
githubnavigator/application.py 15 0 100%
githubnavigator/containers.py 7 0 100%
githubnavigator/application.py 13 0 100%
githubnavigator/containers.py 8 0 100%
githubnavigator/services.py 14 0 100%
githubnavigator/tests.py 34 0 100%
githubnavigator/views.py 10 0 100%
----------------------------------------------------
TOTAL 80 0 100%
TOTAL 79 0 100%
.. note::

View File

@ -27,16 +27,16 @@ To run the application do:
.. code-block:: bash
export GIPHY_API_KEY=wBJ2wZG7SRqfrU9nPgPiWvORmloDyuL0
adev runserver giphynavigator/application.py --livereload
python -m giphynavigator.application
The output should be something like:
.. code-block::
[18:52:59] Starting aux server at http://localhost:8001 ◆
[18:52:59] Starting dev server at http://localhost:8000 ●
======== Running on http://0.0.0.0:8080 ========
(Press CTRL+C to quit)
After that visit http://127.0.0.1:8000/ in your browser or use CLI command (``curl``, ``httpie``,
After that visit http://0.0.0.0:8080/ in your browser or use CLI command (``curl``, ``httpie``,
etc). You should see something like:
.. code-block:: json
@ -98,21 +98,21 @@ The output should be something like:
.. code-block::
platform darwin -- Python 3.9, pytest-5.4.3, py-1.9.0, pluggy-0.13.1
plugins: cov-2.10.0, aiohttp-0.3.0, asyncio-0.14.0
platform darwin -- Python 3.10.0, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
plugins: asyncio-0.16.0, anyio-3.3.4, aiohttp-0.3.0, cov-3.0.0
collected 3 items
giphynavigator/tests.py ... [100%]
---------- coverage: platform darwin, python 3.9 -----------
---------- coverage: platform darwin, python 3.10.0-final-0 ----------
Name Stmts Miss Cover
---------------------------------------------------
giphynavigator/__init__.py 0 0 100%
giphynavigator/application.py 12 0 100%
giphynavigator/containers.py 6 0 100%
giphynavigator/application.py 13 2 85%
giphynavigator/containers.py 7 0 100%
giphynavigator/giphy.py 14 9 36%
giphynavigator/handlers.py 10 0 100%
giphynavigator/services.py 9 1 89%
giphynavigator/tests.py 37 0 100%
---------------------------------------------------
TOTAL 88 10 89%
TOTAL 90 12 87%

View File

@ -8,9 +8,7 @@ from . import handlers
def create_app() -> web.Application:
container = Container()
container.config.from_yaml("config.yml")
container.config.giphy.api_key.from_env("GIPHY_API_KEY")
container.wire(modules=[handlers])
app = web.Application()
app.container = container
@ -18,3 +16,8 @@ def create_app() -> web.Application:
web.get("/", handlers.index),
])
return app
if __name__ == "__main__":
app = create_app()
web.run_app(app)

View File

@ -7,7 +7,9 @@ from . import giphy, services
class Container(containers.DeclarativeContainer):
config = providers.Configuration()
wiring_config = containers.WiringConfiguration(modules=[".handlers"])
config = providers.Configuration(yaml_files=["config.yml"])
giphy_client = providers.Factory(
giphy.GiphyClient,

View File

@ -1,6 +1,5 @@
dependency-injector
aiohttp
aiohttp-devtools
pyyaml
pytest-aiohttp
pytest-cov

View File

@ -24,7 +24,6 @@ def main(
if __name__ == "__main__":
application = Application()
application.config.from_yaml("config.yml")
application.core.init_resources()
application.wire(modules=[__name__])

View File

@ -61,7 +61,7 @@ class Services(containers.DeclarativeContainer):
class Application(containers.DeclarativeContainer):
config = providers.Configuration()
config = providers.Configuration(yaml_files=["config.yml"])
core = providers.Container(
Core,

View File

@ -25,7 +25,6 @@ def main(
if __name__ == "__main__":
container = Container()
container.init_resources()
container.config.from_ini("config.ini")
container.wire(modules=[__name__])
main(*sys.argv[1:])

View File

@ -11,7 +11,7 @@ from . import services
class Container(containers.DeclarativeContainer):
config = providers.Configuration()
config = providers.Configuration(ini_files=["config.ini"])
logging = providers.Resource(
logging.config.fileConfig,

View File

@ -1,4 +1,4 @@
FROM python:3.9-buster
FROM python:3.10-buster
ENV PYTHONUNBUFFERED=1

View File

@ -65,22 +65,22 @@ The output should be something like:
.. code-block::
platform linux -- Python 3.9, pytest-6.0.1, py-1.9.0, pluggy-0.13.1
platform linux -- Python 3.10.0, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
rootdir: /code
plugins: asyncio-0.14.0, cov-2.10.0
plugins: asyncio-0.16.0, cov-3.0.0
collected 2 items
monitoringdaemon/tests.py .. [100%]
----------- coverage: platform linux, python 3.9 -----------
---------- coverage: platform linux, python 3.10.0-final-0 -----------
Name Stmts Miss Cover
----------------------------------------------------
monitoringdaemon/__init__.py 0 0 100%
monitoringdaemon/__main__.py 13 13 0%
monitoringdaemon/__main__.py 11 11 0%
monitoringdaemon/containers.py 11 0 100%
monitoringdaemon/dispatcher.py 44 5 89%
monitoringdaemon/dispatcher.py 45 5 89%
monitoringdaemon/http.py 6 3 50%
monitoringdaemon/monitors.py 23 1 96%
monitoringdaemon/tests.py 37 0 100%
monitoringdaemon/tests.py 35 0 100%
----------------------------------------------------
TOTAL 134 22 84%
TOTAL 131 20 85%

View File

@ -13,7 +13,6 @@ def main(dispatcher: Dispatcher = Provide[Container.dispatcher]) -> None:
if __name__ == "__main__":
container = Container()
container.config.from_yaml("config.yml")
container.init_resources()
container.wire(modules=[__name__])

View File

@ -10,7 +10,7 @@ from . import http, monitors, dispatcher
class Container(containers.DeclarativeContainer):
config = providers.Configuration()
config = providers.Configuration(yaml_files=["config.yml"])
logging = providers.Resource(
logging.basicConfig,

View File

@ -17,28 +17,28 @@ class RequestStub:
@pytest.fixture
def container():
container = Container()
container.config.from_dict({
"log": {
"level": "INFO",
"formant": "[%(asctime)s] [%(levelname)s] [%(name)s]: %(message)s",
},
"monitors": {
"example": {
"method": "GET",
"url": "http://fake-example.com",
"timeout": 1,
"check_every": 1,
return Container(
config={
"log": {
"level": "INFO",
"formant": "[%(asctime)s] [%(levelname)s] [%(name)s]: %(message)s",
},
"httpbin": {
"method": "GET",
"url": "https://fake-httpbin.org/get",
"timeout": 1,
"check_every": 1,
"monitors": {
"example": {
"method": "GET",
"url": "http://fake-example.com",
"timeout": 1,
"check_every": 1,
},
"httpbin": {
"method": "GET",
"url": "https://fake-httpbin.org/get",
"timeout": 1,
"check_every": 1,
},
},
},
})
return container
}
)
@pytest.mark.asyncio
@ -67,9 +67,10 @@ async def test_dispatcher(container, caplog, event_loop):
example_monitor_mock = mock.AsyncMock()
httpbin_monitor_mock = mock.AsyncMock()
with container.example_monitor.override(example_monitor_mock), \
container.httpbin_monitor.override(httpbin_monitor_mock):
with container.override_providers(
example_monitor=example_monitor_mock,
httpbin_monitor=httpbin_monitor_mock,
):
dispatcher = container.dispatcher()
event_loop.create_task(dispatcher.start())
await asyncio.sleep(0.1)

View File

@ -35,7 +35,6 @@ def main(
if __name__ == "__main__":
application = ApplicationContainer()
application.config.from_ini("config.ini")
application.wire(modules=[__name__])
main()

View File

@ -12,7 +12,7 @@ from .analytics.containers import AnalyticsContainer
class ApplicationContainer(containers.DeclarativeContainer):
config = providers.Configuration()
config = providers.Configuration(ini_files=["config.ini"])
sqlite = providers.Singleton(sqlite3.connect, config.database.dsn)

View File

@ -7,10 +7,9 @@ from fastapi_di_example import app, container, Service
@pytest.fixture
def client(event_loop):
client = AsyncClient(app=app, base_url="http://test")
yield client
event_loop.run_until_complete(client.aclose())
async def client(event_loop):
async with AsyncClient(app=app, base_url="http://test") as client:
yield client
@pytest.mark.asyncio

View File

@ -1,4 +1,4 @@
FROM python:3.9-buster
FROM python:3.10-buster
ENV PYTHONUNBUFFERED=1
ENV HOST=0.0.0.0

View File

@ -73,19 +73,19 @@ The output should be something like:
.. code-block::
platform linux -- Python 3.9.1, pytest-6.2.2, py-1.10.0, pluggy-0.13.1
platform linux -- Python 3.10.0, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
rootdir: /code
plugins: cov-2.11.1
plugins: cov-3.0.0
collected 7 items
webapp/tests.py ....... [100%]
----------- coverage: platform linux, python 3.9.1-final-0 -----------
---------- coverage: platform linux, python 3.10.0-final-0 ----------
Name Stmts Miss Cover
--------------------------------------------
webapp/__init__.py 0 0 100%
webapp/application.py 14 0 100%
webapp/containers.py 9 0 100%
webapp/application.py 12 0 100%
webapp/containers.py 10 0 100%
webapp/database.py 24 8 67%
webapp/endpoints.py 32 0 100%
webapp/models.py 10 1 90%
@ -93,4 +93,4 @@ The output should be something like:
webapp/services.py 16 0 100%
webapp/tests.py 59 0 100%
--------------------------------------------
TOTAL 200 29 86%
TOTAL 199 29 85%

View File

@ -8,8 +8,6 @@ from . import endpoints
def create_app() -> FastAPI:
container = Container()
container.config.from_yaml("config.yml")
container.wire(modules=[endpoints])
db = container.db()
db.create_database()

View File

@ -9,7 +9,9 @@ from .services import UserService
class Container(containers.DeclarativeContainer):
config = providers.Configuration()
wiring_config = containers.WiringConfiguration(modules=[".endpoints"])
config = providers.Configuration(yaml_files=["config.yml"])
db = providers.Singleton(Database, db_url=config.db.url)

View File

@ -101,21 +101,21 @@ The output should be something like:
.. code-block::
platform darwin -- Python 3.9, pytest-5.4.3, py-1.9.0, pluggy-0.13.1
plugins: cov-2.10.0, asyncio-0.14.0
platform darwin -- Python 3.10.0, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
plugins: asyncio-0.16.0, cov-3.0.0
collected 3 items
giphynavigator/tests.py ... [100%]
---------- coverage: platform darwin, python 3.9 -----------
---------- coverage: platform darwin, python 3.10.0-final-0 ----------
Name Stmts Miss Cover
---------------------------------------------------
giphynavigator/__init__.py 0 0 100%
giphynavigator/application.py 13 0 100%
giphynavigator/containers.py 6 0 100%
giphynavigator/application.py 11 0 100%
giphynavigator/containers.py 7 0 100%
giphynavigator/endpoints.py 20 0 100%
giphynavigator/giphy.py 14 9 36%
giphynavigator/services.py 9 1 89%
giphynavigator/tests.py 38 0 100%
giphynavigator/tests.py 37 0 100%
---------------------------------------------------
TOTAL 100 10 90%
TOTAL 98 10 90%

View File

@ -8,9 +8,7 @@ from . import endpoints
def create_app() -> FastAPI:
container = Container()
container.config.from_yaml("config.yml")
container.config.giphy.api_key.from_env("GIPHY_API_KEY")
container.wire(modules=[endpoints])
app = FastAPI()
app.container = container

View File

@ -7,7 +7,9 @@ from . import giphy, services
class Container(containers.DeclarativeContainer):
config = providers.Configuration()
wiring_config = containers.WiringConfiguration(modules=[".endpoints"])
config = providers.Configuration(yaml_files=["config.yml"])
giphy_client = providers.Factory(
giphy.GiphyClient,

View File

@ -10,10 +10,9 @@ from giphynavigator.giphy import GiphyClient
@pytest.fixture
def client(event_loop):
client = AsyncClient(app=app, base_url="http://test")
yield client
event_loop.run_until_complete(client.aclose())
async def client():
async with AsyncClient(app=app, base_url="http://test") as client:
yield client
@pytest.mark.asyncio

View File

@ -81,20 +81,21 @@ The output should be something like:
.. code-block::
platform darwin -- Python 3.9, pytest-5.4.3, py-1.9.0, pluggy-0.13.1
plugins: flask-1.0.0, cov-2.10.0
platform darwin -- Python 3.10.0, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
plugins: cov-3.0.0, flask-1.2.0
collected 2 items
githubnavigator/tests.py .. [100%]
---------- coverage: platform darwin, python 3.9 -----------
Name Stmts Miss Cover
----------------------------------------------------
githubnavigator/__init__.py 0 0 100%
githubnavigator/application.py 15 0 100%
githubnavigator/blueprints/example.py 12 0 100%
githubnavigator/containers.py 7 0 100%
githubnavigator/services.py 14 0 100%
githubnavigator/tests.py 34 0 100%
-----------------------------------------------------------
TOTAL 82 0 100%
---------- coverage: platform darwin, python 3.10.0-final-0 ----------
Name Stmts Miss Cover
------------------------------------------------------------
githubnavigator/__init__.py 0 0 100%
githubnavigator/application.py 13 0 100%
githubnavigator/blueprints/__init__.py 0 0 100%
githubnavigator/blueprints/example.py 12 0 100%
githubnavigator/containers.py 8 0 100%
githubnavigator/services.py 14 0 100%
githubnavigator/tests.py 34 0 100%
------------------------------------------------------------
TOTAL 81 0 100%

View File

@ -9,9 +9,7 @@ from .blueprints import example
def create_app() -> Flask:
container = Container()
container.config.from_yaml("config.yml")
container.config.github.auth_token.from_env("GITHUB_TOKEN")
container.wire(modules=[example])
app = Flask(__name__)
app.container = container

View File

@ -8,7 +8,9 @@ from . import services
class Container(containers.DeclarativeContainer):
config = providers.Configuration()
wiring_config = containers.WiringConfiguration(packages=[".blueprints"])
config = providers.Configuration(yaml_files=["config.yml"])
github_client = providers.Factory(
Github,

View File

@ -81,20 +81,20 @@ The output should be something like:
.. code-block::
platform darwin -- Python 3.9, pytest-5.4.3, py-1.9.0, pluggy-0.13.1
plugins: flask-1.0.0, cov-2.10.0
platform darwin -- Python 3.10.0, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
plugins: cov-3.0.0, flask-1.2.0
collected 2 items
githubnavigator/tests.py .. [100%]
---------- coverage: platform darwin, python 3.9 -----------
---------- coverage: platform darwin, python 3.10.0-final-0 ----------
Name Stmts Miss Cover
----------------------------------------------------
githubnavigator/__init__.py 0 0 100%
githubnavigator/application.py 15 0 100%
githubnavigator/containers.py 7 0 100%
githubnavigator/application.py 13 0 100%
githubnavigator/containers.py 8 0 100%
githubnavigator/services.py 14 0 100%
githubnavigator/tests.py 34 0 100%
githubnavigator/views.py 10 0 100%
----------------------------------------------------
TOTAL 80 0 100%
TOTAL 79 0 100%

View File

@ -9,9 +9,7 @@ from . import views
def create_app() -> Flask:
container = Container()
container.config.from_yaml("config.yml")
container.config.github.auth_token.from_env("GITHUB_TOKEN")
container.wire(modules=[views])
app = Flask(__name__)
app.container = container

View File

@ -8,7 +8,9 @@ from . import services
class Container(containers.DeclarativeContainer):
config = providers.Configuration()
wiring_config = containers.WiringConfiguration(modules=[".views"])
config = providers.Configuration(yaml_files=["config.yml"])
github_client = providers.Factory(
Github,

View File

@ -58,21 +58,21 @@ The output should be something like:
.. code-block::
platform darwin -- Python 3.9, pytest-5.4.3, py-1.9.0, pluggy-0.13.1
plugins: cov-2.10.0
platform darwin -- Python 3.10.0, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
plugins: cov-3.0.0
collected 2 items
movies/tests.py .. [100%]
---------- coverage: platform darwin, python 3.9 -----------
---------- coverage: platform darwin, python 3.10 -----------
Name Stmts Miss Cover
------------------------------------------
movies/__init__.py 0 0 100%
movies/__main__.py 18 18 0%
movies/__main__.py 16 16 0%
movies/containers.py 9 0 100%
movies/entities.py 7 1 86%
movies/finders.py 26 13 50%
movies/listers.py 8 0 100%
movies/tests.py 24 0 100%
movies/tests.py 23 0 100%
------------------------------------------
TOTAL 92 32 65%
TOTAL 89 30 66%

View File

@ -19,7 +19,6 @@ def main(lister: MovieLister = Provide[Container.lister]) -> None:
if __name__ == "__main__":
container = Container()
container.config.from_yaml("config.yml")
container.config.finder.type.from_env("MOVIE_FINDER_TYPE")
container.wire(modules=[__name__])

View File

@ -7,7 +7,7 @@ from . import finders, listers, entities
class Container(containers.DeclarativeContainer):
config = providers.Configuration()
config = providers.Configuration(yaml_files=["config.yml"])
movie = providers.Factory(entities.Movie)

View File

@ -9,19 +9,20 @@ from .containers import Container
@pytest.fixture
def container():
container = Container()
container.config.from_dict({
"finder": {
"type": "csv",
"csv": {
"path": "/fake-movies.csv",
"delimiter": ",",
},
"sqlite": {
"path": "/fake-movies.db",
container = Container(
config={
"finder": {
"type": "csv",
"csv": {
"path": "/fake-movies.csv",
"delimiter": ",",
},
"sqlite": {
"path": "/fake-movies.db",
},
},
},
})
)
return container

View File

@ -98,22 +98,22 @@ The output should be something like:
.. code-block::
platform darwin -- Python 3.9, pytest-6.2.2, py-1.10.0, pluggy-0.13.1
plugins: cov-2.12.1, sanic-1.8.1, anyio-3.3.2
platform darwin -- Python 3.10.0, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
plugins: sanic-1.9.1, anyio-3.3.4, cov-3.0.0
collected 3 items
giphynavigator/tests.py ... [100%]
---------- coverage: platform darwin, python 3.9 -----------
---------- coverage: platform darwin, python 3.10.0-final-0 ----------
Name Stmts Miss Cover
---------------------------------------------------
giphynavigator/__init__.py 0 0 100%
giphynavigator/__main__.py 4 4 0%
giphynavigator/application.py 12 0 100%
giphynavigator/containers.py 6 0 100%
giphynavigator/application.py 10 0 100%
giphynavigator/containers.py 7 0 100%
giphynavigator/giphy.py 14 9 36%
giphynavigator/handlers.py 11 0 100%
giphynavigator/services.py 9 1 89%
giphynavigator/tests.py 39 0 100%
---------------------------------------------------
TOTAL 95 14 85%
TOTAL 94 14 85%

View File

@ -9,9 +9,7 @@ from . import handlers
def create_app() -> Sanic:
"""Create and return Sanic application."""
container = Container()
container.config.from_yaml("config.yml")
container.config.giphy.api_key.from_env("GIPHY_API_KEY")
container.wire(modules=[handlers])
app = Sanic("giphy-navigator")
app.ctx.container = container

View File

@ -7,7 +7,9 @@ from . import giphy, services
class Container(containers.DeclarativeContainer):
config = providers.Configuration()
wiring_config = containers.WiringConfiguration(modules=[".handlers"])
config = providers.Configuration(yaml_files=["config.yml"])
giphy_client = providers.Factory(
giphy.GiphyClient,

View File

@ -1,5 +1,5 @@
dependency-injector
sanic
sanic<=21.6
aiohttp
pyyaml
pytest-sanic