Update asyncio-daemon example and tutorial

This commit is contained in:
Roman Mogylatov 2021-10-31 20:25:13 -04:00
parent 29d0900970
commit 0bd4dc58ed
6 changed files with 80 additions and 89 deletions

View File

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

View File

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

View File

@ -65,22 +65,22 @@ The output should be something like:
.. code-block:: .. 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 rootdir: /code
plugins: asyncio-0.14.0, cov-2.10.0 plugins: asyncio-0.16.0, cov-3.0.0
collected 2 items collected 2 items
monitoringdaemon/tests.py .. [100%] monitoringdaemon/tests.py .. [100%]
----------- coverage: platform linux, python 3.9 ----------- ---------- coverage: platform linux, python 3.10.0-final-0 -----------
Name Stmts Miss Cover Name Stmts Miss Cover
---------------------------------------------------- ----------------------------------------------------
monitoringdaemon/__init__.py 0 0 100% 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/containers.py 11 0 100%
monitoringdaemon/dispatcher.py 44 5 89% monitoringdaemon/dispatcher.py 45 5 89%
monitoringdaemon/http.py 6 3 50% monitoringdaemon/http.py 6 3 50%
monitoringdaemon/monitors.py 23 1 96% 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__": if __name__ == "__main__":
container = Container() container = Container()
container.config.from_yaml("config.yml")
container.init_resources() container.init_resources()
container.wire(modules=[__name__]) container.wire(modules=[__name__])

View File

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

View File

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