From 5c63a8b2ddf472eedc8f536b22565e0e07fa0484 Mon Sep 17 00:00:00 2001 From: Carl Oscar Aaro Date: Tue, 16 Jun 2020 01:12:04 +0200 Subject: [PATCH 01/11] Improved support for Python 3.8 --- .gitignore | 3 + .../basic_examples/amqp_middleware_service.py | 3 +- examples/basic_examples/amqp_service.py | 3 +- .../aws_sns_registration_service.py | 3 +- .../aws_sns_sqs_middleware_service.py | 3 +- .../basic_examples/aws_sns_sqs_service.py | 3 +- examples/basic_examples/http_auth_service.py | 8 ++- .../basic_examples/http_middleware_service.py | 10 ++-- .../basic_examples/http_simple_service.py | 10 ++-- examples/basic_examples/scheduler_example.py | 3 +- .../websockets/websocket_service.py | 12 ++-- .../http_service/requirements.txt | 2 +- examples/pubsub_example/service_a.py | 3 +- examples/pubsub_example/service_b.py | 3 +- .../pubsub_example/service_send_message.py | 5 +- pyproject.toml | 2 + requirements.txt | 59 ++++++++++--------- setup.py | 4 +- tests/conftest.py | 5 +- tests/run_example_service.py | 1 + tests/run_test_service_helper.py | 11 ++-- .../amqp_service_invalid_credentials.py | 3 +- .../services/amqp_service_with_credentials.py | 3 +- ...rvice_with_credentials_without_protocol.py | 3 +- tests/services/auto_closing_service.py | 1 + tests/services/auto_closing_service_sigint.py | 1 + ...aws_sns_sqs_service_invalid_credentials.py | 3 +- .../aws_sns_sqs_service_with_credentials.py | 3 +- ...rvice_with_credentials_without_protocol.py | 3 +- tests/services/decorated_functions_service.py | 4 +- tests/services/http_access_log_service.py | 4 +- tests/services/http_service.py | 8 ++- tests/services/http_service_same_port.py | 1 + tests/services/logging_service.py | 3 +- tests/services/os/os.py | 1 + tests/services/relative_service.py | 1 + tests/services/schedule_service.py | 7 ++- .../services/start_process_service_http_1.py | 6 +- .../services/start_process_service_http_2.py | 6 +- .../start_process_service_schedule.py | 5 +- tests/services/test-copy/test-copy.py | 1 + tests/services/test-copy/test.py | 1 + tests/services/test/service.py | 1 + tests/services/test/test.py | 1 + .../test_amqp_service_invalid_credentials.py | 1 + tests/test_amqp_service_with_credentials.py | 6 +- tests/test_amqp_transport.py | 11 +++- ...st_aws_sns_sqs_service_with_credentials.py | 6 +- ...e_with_credentials_with_custom_protocol.py | 6 +- ...rvice_with_credentials_without_protocol.py | 6 +- ...aws_sns_sqs_service_without_credentials.py | 1 + tests/test_aws_sns_sqs_transport.py | 11 +++- tests/test_cli.py | 4 +- tests/test_configs.py | 1 + tests/test_crontab_parser.py | 4 +- tests/test_decorated_functions_service.py | 4 +- tests/test_dummy_service.py | 13 +++- tests/test_empty_service.py | 1 + tests/test_exception_service.py | 4 +- tests/test_http_service.py | 10 ++-- tests/test_invalid_services.py | 4 +- tests/test_logging.py | 1 + tests/test_mock_decorator.py | 1 + tests/test_non_packaged_imported_service.py | 34 +++++++---- tests/test_protocol.py | 55 +++++++++++++---- tests/test_relative_imports.py | 11 +++- tests/test_schedule_service.py | 1 + tests/test_start_process_http_1.py | 4 +- tests/test_start_process_http_2.py | 4 +- tests/test_start_process_schedule.py | 1 + tests/test_validation.py | 11 ++-- tests/test_watcher.py | 5 +- tomodachi/__init__.py | 4 +- tomodachi/__init__.pyi | 27 +++++++-- tomodachi/__version__.py | 2 +- tomodachi/cli/__init__.py | 11 ++-- tomodachi/container.py | 11 ++-- tomodachi/discovery/__init__.py | 2 +- tomodachi/discovery/aws_sns_registration.py | 1 + tomodachi/helpers/crontab.py | 5 +- tomodachi/helpers/logging.py | 2 +- tomodachi/helpers/middleware.py | 2 +- tomodachi/importer.py | 8 +-- tomodachi/invoker/__init__.py | 2 +- tomodachi/invoker/decorator.py | 4 +- tomodachi/launcher.py | 21 ++++--- tomodachi/protocol/__init__.py | 2 + tomodachi/protocol/protobuf_base.py | 4 +- tomodachi/transport/amqp.py | 20 ++++--- tomodachi/transport/aws_sns_sqs.py | 6 +- tomodachi/transport/http.py | 26 ++++---- tomodachi/transport/schedule.py | 12 ++-- tomodachi/watcher.py | 4 +- tox.ini | 9 +++ 94 files changed, 421 insertions(+), 211 deletions(-) create mode 100644 pyproject.toml create mode 100644 tox.ini diff --git a/.gitignore b/.gitignore index 6cfa73eab..f4574b999 100644 --- a/.gitignore +++ b/.gitignore @@ -46,6 +46,9 @@ coverage.xml .hypothesis/ .pytest_cache +# Temporary +tmp/ + # Translations *.mo *.pot diff --git a/examples/basic_examples/amqp_middleware_service.py b/examples/basic_examples/amqp_middleware_service.py index f92994ec8..5aa377592 100644 --- a/examples/basic_examples/amqp_middleware_service.py +++ b/examples/basic_examples/amqp_middleware_service.py @@ -1,6 +1,7 @@ import os +from typing import Any, Callable, Dict + import tomodachi -from typing import Any, Dict, Callable from tomodachi import amqp, amqp_publish from tomodachi.discovery import DummyRegistry from tomodachi.protocol import JsonBase diff --git a/examples/basic_examples/amqp_service.py b/examples/basic_examples/amqp_service.py index e2bd0ec0e..6c8993ad2 100644 --- a/examples/basic_examples/amqp_service.py +++ b/examples/basic_examples/amqp_service.py @@ -1,6 +1,7 @@ import os -import tomodachi from typing import Any, Dict + +import tomodachi from tomodachi import amqp, amqp_publish from tomodachi.discovery import DummyRegistry from tomodachi.protocol import JsonBase diff --git a/examples/basic_examples/aws_sns_registration_service.py b/examples/basic_examples/aws_sns_registration_service.py index 844bd9e80..cfcfeb86b 100644 --- a/examples/basic_examples/aws_sns_registration_service.py +++ b/examples/basic_examples/aws_sns_registration_service.py @@ -1,6 +1,7 @@ import os -import tomodachi from typing import Dict + +import tomodachi from tomodachi import aws_sns_sqs from tomodachi.protocol import JsonBase diff --git a/examples/basic_examples/aws_sns_sqs_middleware_service.py b/examples/basic_examples/aws_sns_sqs_middleware_service.py index 2e5d52180..b7ef2fa21 100644 --- a/examples/basic_examples/aws_sns_sqs_middleware_service.py +++ b/examples/basic_examples/aws_sns_sqs_middleware_service.py @@ -1,6 +1,7 @@ import os +from typing import Any, Callable, Dict + import tomodachi -from typing import Any, Dict, Callable from tomodachi import aws_sns_sqs, aws_sns_sqs_publish from tomodachi.discovery import AWSSNSRegistration from tomodachi.protocol import JsonBase diff --git a/examples/basic_examples/aws_sns_sqs_service.py b/examples/basic_examples/aws_sns_sqs_service.py index e482946e6..58fc1ad5b 100644 --- a/examples/basic_examples/aws_sns_sqs_service.py +++ b/examples/basic_examples/aws_sns_sqs_service.py @@ -1,6 +1,7 @@ import os -import tomodachi from typing import Any, Dict + +import tomodachi from tomodachi import aws_sns_sqs, aws_sns_sqs_publish from tomodachi.discovery import AWSSNSRegistration from tomodachi.protocol import JsonBase diff --git a/examples/basic_examples/http_auth_service.py b/examples/basic_examples/http_auth_service.py index 1c629a382..3f71bc9be 100644 --- a/examples/basic_examples/http_auth_service.py +++ b/examples/basic_examples/http_auth_service.py @@ -1,10 +1,12 @@ -import os import asyncio -import tomodachi +import os import uuid from typing import Any + from aiohttp import web -from tomodachi import http, HttpResponse + +import tomodachi +from tomodachi import HttpResponse, http @tomodachi.decorator diff --git a/examples/basic_examples/http_middleware_service.py b/examples/basic_examples/http_middleware_service.py index 4495d66fb..3fca8076b 100644 --- a/examples/basic_examples/http_middleware_service.py +++ b/examples/basic_examples/http_middleware_service.py @@ -1,9 +1,11 @@ -import os import asyncio -import tomodachi -from typing import Tuple, Callable, Union, Any, Dict +import os +from typing import Any, Callable, Dict, Tuple, Union + from aiohttp import web -from tomodachi import http, http_error, http_static, websocket, HttpResponse + +import tomodachi +from tomodachi import HttpResponse, http, http_error, http_static, websocket from tomodachi.discovery import DummyRegistry diff --git a/examples/basic_examples/http_simple_service.py b/examples/basic_examples/http_simple_service.py index 9fe055f69..f907cf5d1 100644 --- a/examples/basic_examples/http_simple_service.py +++ b/examples/basic_examples/http_simple_service.py @@ -1,9 +1,11 @@ -import os import asyncio -import tomodachi -from typing import Tuple, Callable, Union +import os +from typing import Callable, Tuple, Union + from aiohttp import web -from tomodachi import http, http_error, http_static, websocket, HttpResponse + +import tomodachi +from tomodachi import HttpResponse, http, http_error, http_static, websocket from tomodachi.discovery import DummyRegistry diff --git a/examples/basic_examples/scheduler_example.py b/examples/basic_examples/scheduler_example.py index b787903e7..60854d6ef 100644 --- a/examples/basic_examples/scheduler_example.py +++ b/examples/basic_examples/scheduler_example.py @@ -1,6 +1,7 @@ import os + import tomodachi -from tomodachi import schedule, minutely, hourly +from tomodachi import hourly, minutely, schedule @tomodachi.service diff --git a/examples/basic_examples/websockets/websocket_service.py b/examples/basic_examples/websockets/websocket_service.py index 5828b8e60..31ac37c8b 100644 --- a/examples/basic_examples/websockets/websocket_service.py +++ b/examples/basic_examples/websockets/websocket_service.py @@ -1,12 +1,14 @@ -import os import asyncio -import tomodachi +import os import pathlib import uuid -from aiohttp.web_fileresponse import FileResponse -from typing import Tuple, Callable, Union +from typing import Callable, Tuple, Union + from aiohttp import web -from tomodachi import http_error, http, http_static, websocket +from aiohttp.web_fileresponse import FileResponse + +import tomodachi +from tomodachi import http, http_error, http_static, websocket @tomodachi.service diff --git a/examples/docker_example/http_service/requirements.txt b/examples/docker_example/http_service/requirements.txt index 4adbfab66..d8eec05f1 100644 --- a/examples/docker_example/http_service/requirements.txt +++ b/examples/docker_example/http_service/requirements.txt @@ -1 +1 @@ -tomodachi==0.16.5 \ No newline at end of file +tomodachi==0.17.0 \ No newline at end of file diff --git a/examples/pubsub_example/service_a.py b/examples/pubsub_example/service_a.py index 44c17bab3..70d04ef13 100644 --- a/examples/pubsub_example/service_a.py +++ b/examples/pubsub_example/service_a.py @@ -1,5 +1,6 @@ -import tomodachi from typing import Any + +import tomodachi from tomodachi import aws_sns_sqs, aws_sns_sqs_publish from tomodachi.protocol import JsonBase diff --git a/examples/pubsub_example/service_b.py b/examples/pubsub_example/service_b.py index 732217567..5ac008c14 100644 --- a/examples/pubsub_example/service_b.py +++ b/examples/pubsub_example/service_b.py @@ -1,5 +1,6 @@ -import tomodachi from typing import Any + +import tomodachi from tomodachi import aws_sns_sqs from tomodachi.protocol import JsonBase diff --git a/examples/pubsub_example/service_send_message.py b/examples/pubsub_example/service_send_message.py index 391b0d638..dc4aa0bff 100644 --- a/examples/pubsub_example/service_send_message.py +++ b/examples/pubsub_example/service_send_message.py @@ -1,7 +1,8 @@ -import tomodachi import uuid from typing import Any -from tomodachi import schedule, aws_sns_sqs_publish + +import tomodachi +from tomodachi import aws_sns_sqs_publish, schedule from tomodachi.protocol import JsonBase diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 000000000..55ec8d784 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,2 @@ +[tool.black] +line-length = 120 diff --git a/requirements.txt b/requirements.txt index d83b7fc9c..7af53e979 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,38 +1,39 @@ pycparser==2.19 aioamqp==0.13.0 -aiobotocore==0.10.3 +aiobotocore==0.12.0 aiodns==2.0.0 -aiohttp==3.5.4 +aiohttp==3.6.2 +aioitertools==0.7.0 async-generator==1.10 async-timeout==3.0.1 -attrs==19.1.0 -botocore==1.12.189 -cchardet==2.1.4 +attrs==19.3.0 +botocore==1.15.15 +cchardet==2.1.6 chardet==3.0.4 -codecov==2.0.15 -colorama==0.4.1 -coverage==4.5.4 +codecov==2.1.7 +colorama==0.4.3 +coverage==5.1 docutils==0.15.2 execnet==1.7.1 -jmespath==0.9.4 -multidict==4.5.2 -mypy==0.720 -packaging==19.1 -protobuf==3.9.1 -pycares==3.0.0 -pycodestyle==2.5.0 -py==1.8.0 -pyparsing==2.4.2 -pytest==5.1.1 -pytest-cov==2.7.1 -pytest-forked==1.0.2 -pytest-xdist==1.29.0 -python-dateutil==2.8.0 -pytz==2019.2 -readme-renderer==24.0 -requests==2.22.0 -six==1.12.0 +jmespath==0.10.0 +multidict==4.7.6 +mypy==0.780 +packaging==20.4 +protobuf==3.12.2 +pycares==3.1.1 +pycodestyle==2.6.0 +py==1.8.2 +pyparsing==2.4.7 +pytest==5.4.3 +pytest-cov==2.10.0 +pytest-forked==1.1.3 +pytest-xdist==1.32.0 +python-dateutil==2.8.1 +pytz==2020.1 +readme-renderer==26.0 +requests==2.23.0 +six==1.15.0 typing_extensions==3.7.4 -tzlocal==2.0.0 -uvloop==0.13.0 -yarl==1.3.0 +tzlocal==2.1 +uvloop==0.14.0 +yarl==1.4.2 diff --git a/setup.py b/setup.py index 9fa368623..bdb946b93 100644 --- a/setup.py +++ b/setup.py @@ -8,9 +8,9 @@ install_requires = [ 'pycparser>=2.18', - 'aioamqp>=0.10.0, <0.14.0', + 'aioamqp>=0.10.0, <0.15.0', 'uvloop>=0.8.1', - 'aiobotocore>=0.6.0, <0.11.0', + 'aiobotocore>=0.6.0, <=0.12.0', 'tzlocal>=1.4', 'aiohttp>=3.0.5, <3.6.0', 'yarl>=1.1.0', diff --git a/tests/conftest.py b/tests/conftest.py index 885ad4c29..6d60351a7 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,8 +1,9 @@ -import uvloop import asyncio -import pytest from typing import Generator +import pytest +import uvloop + @pytest.yield_fixture(scope='module') def loop() -> Generator: diff --git a/tests/run_example_service.py b/tests/run_example_service.py index 41d8365ed..0694152ab 100644 --- a/tests/run_example_service.py +++ b/tests/run_example_service.py @@ -1,6 +1,7 @@ import asyncio import os import signal + import tomodachi from tomodachi.discovery.dummy_registry import DummyRegistry from tomodachi.protocol.json_base import JsonBase diff --git a/tests/run_test_service_helper.py b/tests/run_test_service_helper.py index 03c5a386a..38c63bb9a 100644 --- a/tests/run_test_service_helper.py +++ b/tests/run_test_service_helper.py @@ -1,8 +1,11 @@ +import asyncio +import functools import logging import signal -import functools -import asyncio -from typing import Any, Tuple +from typing import Any, Dict, Tuple + +import uvloop + from tomodachi.container import ServiceContainer from tomodachi.importer import ServiceImporter @@ -64,7 +67,7 @@ async def _async() -> None: for service_name, instance, log_level in service.started_waiter.result(): services[service_name] = instance else: - def get_services(): + def get_services() -> Dict: loop.run_until_complete(asyncio.wait([service.started_waiter])) return {service_name: instance for service_name, instance, log_level in service.started_waiter.result()} diff --git a/tests/services/amqp_service_invalid_credentials.py b/tests/services/amqp_service_invalid_credentials.py index 17c5681c5..bdf81bf3a 100644 --- a/tests/services/amqp_service_invalid_credentials.py +++ b/tests/services/amqp_service_invalid_credentials.py @@ -1,8 +1,9 @@ import asyncio import os import signal -import tomodachi from typing import Any + +import tomodachi from tomodachi.protocol.json_base import JsonBase from tomodachi.transport.amqp import amqp diff --git a/tests/services/amqp_service_with_credentials.py b/tests/services/amqp_service_with_credentials.py index 4491299e3..bc020eb92 100644 --- a/tests/services/amqp_service_with_credentials.py +++ b/tests/services/amqp_service_with_credentials.py @@ -1,9 +1,10 @@ import asyncio import os import signal -import tomodachi import uuid from typing import Any + +import tomodachi from tomodachi.protocol.json_base import JsonBase from tomodachi.transport.amqp import amqp, amqp_publish diff --git a/tests/services/amqp_service_with_credentials_without_protocol.py b/tests/services/amqp_service_with_credentials_without_protocol.py index 6993ff269..c819885e2 100644 --- a/tests/services/amqp_service_with_credentials_without_protocol.py +++ b/tests/services/amqp_service_with_credentials_without_protocol.py @@ -1,9 +1,10 @@ import asyncio import os import signal -import tomodachi import uuid from typing import Any + +import tomodachi from tomodachi.transport.amqp import amqp, amqp_publish data_uuid = str(uuid.uuid4()) diff --git a/tests/services/auto_closing_service.py b/tests/services/auto_closing_service.py index 34a78007b..6822597af 100644 --- a/tests/services/auto_closing_service.py +++ b/tests/services/auto_closing_service.py @@ -1,6 +1,7 @@ import asyncio import os import signal + import tomodachi from tomodachi.discovery.dummy_registry import DummyRegistry from tomodachi.protocol.json_base import JsonBase diff --git a/tests/services/auto_closing_service_sigint.py b/tests/services/auto_closing_service_sigint.py index 103ea5ff5..6b064c844 100644 --- a/tests/services/auto_closing_service_sigint.py +++ b/tests/services/auto_closing_service_sigint.py @@ -1,6 +1,7 @@ import asyncio import os import signal + import tomodachi from tomodachi.discovery.dummy_registry import DummyRegistry from tomodachi.protocol.json_base import JsonBase diff --git a/tests/services/aws_sns_sqs_service_invalid_credentials.py b/tests/services/aws_sns_sqs_service_invalid_credentials.py index 091190146..0a36f6b37 100644 --- a/tests/services/aws_sns_sqs_service_invalid_credentials.py +++ b/tests/services/aws_sns_sqs_service_invalid_credentials.py @@ -1,8 +1,9 @@ import asyncio import os import signal -import tomodachi from typing import Any + +import tomodachi from tomodachi.discovery.aws_sns_registration import AWSSNSRegistration from tomodachi.protocol.json_base import JsonBase from tomodachi.transport.aws_sns_sqs import aws_sns_sqs diff --git a/tests/services/aws_sns_sqs_service_with_credentials.py b/tests/services/aws_sns_sqs_service_with_credentials.py index 244e7aaac..d073c6f14 100644 --- a/tests/services/aws_sns_sqs_service_with_credentials.py +++ b/tests/services/aws_sns_sqs_service_with_credentials.py @@ -1,9 +1,10 @@ import asyncio import os import signal -import tomodachi import uuid from typing import Any + +import tomodachi from tomodachi.discovery.aws_sns_registration import AWSSNSRegistration from tomodachi.protocol.json_base import JsonBase from tomodachi.transport.aws_sns_sqs import aws_sns_sqs, aws_sns_sqs_publish diff --git a/tests/services/aws_sns_sqs_service_with_credentials_without_protocol.py b/tests/services/aws_sns_sqs_service_with_credentials_without_protocol.py index f6c61d4f7..bc8ee3f30 100644 --- a/tests/services/aws_sns_sqs_service_with_credentials_without_protocol.py +++ b/tests/services/aws_sns_sqs_service_with_credentials_without_protocol.py @@ -1,9 +1,10 @@ import asyncio import os import signal -import tomodachi import uuid from typing import Any + +import tomodachi from tomodachi.transport.aws_sns_sqs import aws_sns_sqs, aws_sns_sqs_publish data_uuid = str(uuid.uuid4()) diff --git a/tests/services/decorated_functions_service.py b/tests/services/decorated_functions_service.py index 17d9c37f3..a9e9c78dc 100644 --- a/tests/services/decorated_functions_service.py +++ b/tests/services/decorated_functions_service.py @@ -1,9 +1,11 @@ import asyncio import os import signal -import tomodachi from typing import Any + from aiohttp import web + +import tomodachi from tomodachi.transport.http import http diff --git a/tests/services/http_access_log_service.py b/tests/services/http_access_log_service.py index 7e4327d81..fe3a05689 100644 --- a/tests/services/http_access_log_service.py +++ b/tests/services/http_access_log_service.py @@ -1,9 +1,11 @@ import asyncio import os import signal -import tomodachi from typing import Any, Dict, Tuple # noqa + from aiohttp import web + +import tomodachi from tomodachi.transport.http import http, http_error diff --git a/tests/services/http_service.py b/tests/services/http_service.py index a0d2194ff..7f45a3a8e 100644 --- a/tests/services/http_service.py +++ b/tests/services/http_service.py @@ -1,11 +1,13 @@ import asyncio import os import signal -import tomodachi -from typing import Any, Dict, Tuple, Callable, Union # noqa +from typing import Any, Callable, Dict, Tuple, Union # noqa + from aiohttp import web -from tomodachi.transport.http import http, http_error, http_static, websocket, Response, RequestHandler + +import tomodachi from tomodachi.discovery.dummy_registry import DummyRegistry +from tomodachi.transport.http import RequestHandler, Response, http, http_error, http_static, websocket async def middleware_function(func: Callable, service: Any, request: web.Request, context: Dict, *args: Any, **kwargs: Any) -> Any: diff --git a/tests/services/http_service_same_port.py b/tests/services/http_service_same_port.py index 55df69455..53f4134e0 100644 --- a/tests/services/http_service_same_port.py +++ b/tests/services/http_service_same_port.py @@ -1,4 +1,5 @@ from aiohttp import web + import tomodachi from tomodachi.transport.http import http diff --git a/tests/services/logging_service.py b/tests/services/logging_service.py index 1561d6415..3101c5103 100644 --- a/tests/services/logging_service.py +++ b/tests/services/logging_service.py @@ -1,7 +1,8 @@ import asyncio +import logging import os import signal -import logging + import tomodachi diff --git a/tests/services/os/os.py b/tests/services/os/os.py index 6f28d6397..a8a415f7f 100644 --- a/tests/services/os/os.py +++ b/tests/services/os/os.py @@ -1,6 +1,7 @@ import tomodachi from tomodachi.discovery.dummy_registry import DummyRegistry from tomodachi.protocol.json_base import JsonBase + from .code import test_func diff --git a/tests/services/relative_service.py b/tests/services/relative_service.py index 7a478dace..6bd9b93ef 100644 --- a/tests/services/relative_service.py +++ b/tests/services/relative_service.py @@ -1,4 +1,5 @@ import tomodachi + from .relative_import.import_file import noop diff --git a/tests/services/schedule_service.py b/tests/services/schedule_service.py index eb8561b2e..f3e6ea587 100644 --- a/tests/services/schedule_service.py +++ b/tests/services/schedule_service.py @@ -1,9 +1,10 @@ -import os import asyncio +import os import signal -import tomodachi from typing import Any # noqa -from tomodachi.transport.schedule import schedule, heartbeat + +import tomodachi +from tomodachi.transport.schedule import heartbeat, schedule @tomodachi.service diff --git a/tests/services/start_process_service_http_1.py b/tests/services/start_process_service_http_1.py index 9fa6c37aa..ed990badb 100644 --- a/tests/services/start_process_service_http_1.py +++ b/tests/services/start_process_service_http_1.py @@ -1,9 +1,11 @@ -import os import asyncio +import os import signal -import tomodachi from typing import Any # noqa + from aiohttp import web + +import tomodachi from tomodachi.transport.http import http diff --git a/tests/services/start_process_service_http_2.py b/tests/services/start_process_service_http_2.py index 0442793d1..7cc9f7c25 100644 --- a/tests/services/start_process_service_http_2.py +++ b/tests/services/start_process_service_http_2.py @@ -1,9 +1,11 @@ -import os import asyncio +import os import signal -import tomodachi from typing import Any # noqa + from aiohttp import web + +import tomodachi from tomodachi.transport.http import http diff --git a/tests/services/start_process_service_schedule.py b/tests/services/start_process_service_schedule.py index d6dfd9428..43bb06cd2 100644 --- a/tests/services/start_process_service_schedule.py +++ b/tests/services/start_process_service_schedule.py @@ -1,8 +1,9 @@ -import os import asyncio +import os import signal -import tomodachi from typing import Any # noqa + +import tomodachi from tomodachi.transport.schedule import schedule diff --git a/tests/services/test-copy/test-copy.py b/tests/services/test-copy/test-copy.py index 6f28d6397..a8a415f7f 100644 --- a/tests/services/test-copy/test-copy.py +++ b/tests/services/test-copy/test-copy.py @@ -1,6 +1,7 @@ import tomodachi from tomodachi.discovery.dummy_registry import DummyRegistry from tomodachi.protocol.json_base import JsonBase + from .code import test_func diff --git a/tests/services/test-copy/test.py b/tests/services/test-copy/test.py index 6f28d6397..a8a415f7f 100644 --- a/tests/services/test-copy/test.py +++ b/tests/services/test-copy/test.py @@ -1,6 +1,7 @@ import tomodachi from tomodachi.discovery.dummy_registry import DummyRegistry from tomodachi.protocol.json_base import JsonBase + from .code import test_func diff --git a/tests/services/test/service.py b/tests/services/test/service.py index 6f28d6397..a8a415f7f 100644 --- a/tests/services/test/service.py +++ b/tests/services/test/service.py @@ -1,6 +1,7 @@ import tomodachi from tomodachi.discovery.dummy_registry import DummyRegistry from tomodachi.protocol.json_base import JsonBase + from .code import test_func diff --git a/tests/services/test/test.py b/tests/services/test/test.py index 6f28d6397..a8a415f7f 100644 --- a/tests/services/test/test.py +++ b/tests/services/test/test.py @@ -1,6 +1,7 @@ import tomodachi from tomodachi.discovery.dummy_registry import DummyRegistry from tomodachi.protocol.json_base import JsonBase + from .code import test_func diff --git a/tests/test_amqp_service_invalid_credentials.py b/tests/test_amqp_service_invalid_credentials.py index 4035e88fd..29f870a25 100644 --- a/tests/test_amqp_service_invalid_credentials.py +++ b/tests/test_amqp_service_invalid_credentials.py @@ -1,4 +1,5 @@ from typing import Any + from run_test_service_helper import start_service diff --git a/tests/test_amqp_service_with_credentials.py b/tests/test_amqp_service_with_credentials.py index d616ea9ad..f608ec9c8 100644 --- a/tests/test_amqp_service_with_credentials.py +++ b/tests/test_amqp_service_with_credentials.py @@ -1,8 +1,10 @@ -import pytest -import os import asyncio +import os import time from typing import Any + +import pytest + from run_test_service_helper import start_service diff --git a/tests/test_amqp_transport.py b/tests/test_amqp_transport.py index b30ec77ef..09f7f93f4 100644 --- a/tests/test_amqp_transport.py +++ b/tests/test_amqp_transport.py @@ -1,9 +1,11 @@ import os import signal -import pytest from typing import Any -from tomodachi.transport.amqp import AmqpTransport, AmqpException + +import pytest + from run_test_service_helper import start_service +from tomodachi.transport.amqp import AmqpException, AmqpTransport def test_routing_key(monkeypatch: Any) -> None: @@ -59,7 +61,10 @@ def test_publish_invalid_credentials(monkeypatch: Any, capsys: Any, loop: Any) - with pytest.raises(AmqpException): loop.run_until_complete(AmqpTransport.publish(instance, 'data', 'test.topic', wait=True)) - os.kill(os.getpid(), signal.SIGINT) + async def _async_kill(): + os.kill(os.getpid(), signal.SIGINT) + + loop.create_task(_async_kill()) loop.run_until_complete(future) out, err = capsys.readouterr() diff --git a/tests/test_aws_sns_sqs_service_with_credentials.py b/tests/test_aws_sns_sqs_service_with_credentials.py index 1d8d3398d..f2c3d5967 100644 --- a/tests/test_aws_sns_sqs_service_with_credentials.py +++ b/tests/test_aws_sns_sqs_service_with_credentials.py @@ -1,8 +1,10 @@ import asyncio -import pytest -import time import os +import time from typing import Any + +import pytest + from run_test_service_helper import start_service diff --git a/tests/test_aws_sns_sqs_service_with_credentials_with_custom_protocol.py b/tests/test_aws_sns_sqs_service_with_credentials_with_custom_protocol.py index fd34a4805..4026a1c55 100644 --- a/tests/test_aws_sns_sqs_service_with_credentials_with_custom_protocol.py +++ b/tests/test_aws_sns_sqs_service_with_credentials_with_custom_protocol.py @@ -1,8 +1,10 @@ import asyncio -import pytest -import time import os +import time from typing import Any + +import pytest + from run_test_service_helper import start_service diff --git a/tests/test_aws_sns_sqs_service_with_credentials_without_protocol.py b/tests/test_aws_sns_sqs_service_with_credentials_without_protocol.py index 73d68251a..e7f923d96 100644 --- a/tests/test_aws_sns_sqs_service_with_credentials_without_protocol.py +++ b/tests/test_aws_sns_sqs_service_with_credentials_without_protocol.py @@ -1,8 +1,10 @@ import asyncio -import pytest -import time import os +import time from typing import Any + +import pytest + from run_test_service_helper import start_service diff --git a/tests/test_aws_sns_sqs_service_without_credentials.py b/tests/test_aws_sns_sqs_service_without_credentials.py index 3312d2702..cc00c982a 100644 --- a/tests/test_aws_sns_sqs_service_without_credentials.py +++ b/tests/test_aws_sns_sqs_service_without_credentials.py @@ -1,4 +1,5 @@ from typing import Any + from run_test_service_helper import start_service diff --git a/tests/test_aws_sns_sqs_transport.py b/tests/test_aws_sns_sqs_transport.py index 668e8a937..8d595323e 100644 --- a/tests/test_aws_sns_sqs_transport.py +++ b/tests/test_aws_sns_sqs_transport.py @@ -1,9 +1,11 @@ import os import signal -import pytest from typing import Any -from tomodachi.transport.aws_sns_sqs import AWSSNSSQSTransport, AWSSNSSQSException + +import pytest + from run_test_service_helper import start_service +from tomodachi.transport.aws_sns_sqs import AWSSNSSQSException, AWSSNSSQSTransport def test_topic_name(monkeypatch: Any) -> None: @@ -59,7 +61,10 @@ def test_publish_invalid_credentials(monkeypatch: Any, capsys: Any, loop: Any) - with pytest.raises(AWSSNSSQSException): loop.run_until_complete(AWSSNSSQSTransport.publish(instance, 'data', 'test-topic', wait=True)) - os.kill(os.getpid(), signal.SIGINT) + async def _async_kill(): + os.kill(os.getpid(), signal.SIGINT) + + loop.create_task(_async_kill()) loop.run_until_complete(future) if not future.done(): diff --git a/tests/test_cli.py b/tests/test_cli.py index 881695b56..069ae8825 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -1,6 +1,8 @@ -import pytest import logging from typing import Any + +import pytest + import tomodachi import tomodachi.cli diff --git a/tests/test_configs.py b/tests/test_configs.py index 7161ed66f..90243ebde 100644 --- a/tests/test_configs.py +++ b/tests/test_configs.py @@ -1,4 +1,5 @@ from decimal import Decimal + from tomodachi.config import merge_dicts, parse_config_files diff --git a/tests/test_crontab_parser.py b/tests/test_crontab_parser.py index c28de3ffc..875773558 100644 --- a/tests/test_crontab_parser.py +++ b/tests/test_crontab_parser.py @@ -1,6 +1,8 @@ import datetime -import pytz + import pytest +import pytz + from tomodachi.helpers.crontab import get_next_datetime diff --git a/tests/test_decorated_functions_service.py b/tests/test_decorated_functions_service.py index b628361cc..68723f845 100644 --- a/tests/test_decorated_functions_service.py +++ b/tests/test_decorated_functions_service.py @@ -1,5 +1,7 @@ -import aiohttp from typing import Any + +import aiohttp + from run_test_service_helper import start_service diff --git a/tests/test_dummy_service.py b/tests/test_dummy_service.py index 9f4f64bfb..22668c293 100644 --- a/tests/test_dummy_service.py +++ b/tests/test_dummy_service.py @@ -1,7 +1,8 @@ import os import signal -import tomodachi from typing import Any + +import tomodachi from run_test_service_helper import start_service @@ -21,7 +22,10 @@ def test_dummy_service(monkeypatch: Any, capsys: Any, loop: Any) -> None: assert tomodachi.get_service('test_dummy') == instance assert tomodachi.get_service('test_dummy_nonexistant') is None - os.kill(os.getpid(), signal.SIGINT) + async def _async_kill(): + os.kill(os.getpid(), signal.SIGINT) + + loop.create_task(_async_kill()) loop.run_until_complete(future) assert instance.stop is True @@ -33,5 +37,8 @@ def test_dummy_service_without_py_ending(monkeypatch: Any, capsys: Any, loop: An instance = services.get('test_dummy') assert instance is not None - os.kill(os.getpid(), signal.SIGINT) + async def _async_kill(): + os.kill(os.getpid(), signal.SIGINT) + + loop.create_task(_async_kill()) loop.run_until_complete(future) diff --git a/tests/test_empty_service.py b/tests/test_empty_service.py index 305c6aaa7..50ccec723 100644 --- a/tests/test_empty_service.py +++ b/tests/test_empty_service.py @@ -1,4 +1,5 @@ from typing import Any + from run_test_service_helper import start_service diff --git a/tests/test_exception_service.py b/tests/test_exception_service.py index 5aab40bbe..61046019a 100644 --- a/tests/test_exception_service.py +++ b/tests/test_exception_service.py @@ -1,5 +1,7 @@ -import pytest from typing import Any + +import pytest + from run_test_service_helper import start_service diff --git a/tests/test_http_service.py b/tests/test_http_service.py index 70dd46720..e0a313f71 100644 --- a/tests/test_http_service.py +++ b/tests/test_http_service.py @@ -1,12 +1,14 @@ -import aiohttp import asyncio -import pytest -import os import logging -import pathlib import mimetypes +import os +import pathlib from typing import Any + +import aiohttp +import pytest from multidict import CIMultiDictProxy + from run_test_service_helper import start_service diff --git a/tests/test_invalid_services.py b/tests/test_invalid_services.py index 3034dd76a..805974c86 100644 --- a/tests/test_invalid_services.py +++ b/tests/test_invalid_services.py @@ -1,5 +1,7 @@ -import pytest from typing import Any + +import pytest + from run_test_service_helper import start_service diff --git a/tests/test_logging.py b/tests/test_logging.py index c43bcdba1..f8ac7d125 100644 --- a/tests/test_logging.py +++ b/tests/test_logging.py @@ -1,5 +1,6 @@ import os from typing import Any + from run_test_service_helper import start_service diff --git a/tests/test_mock_decorator.py b/tests/test_mock_decorator.py index 62c60e809..4e56a5592 100644 --- a/tests/test_mock_decorator.py +++ b/tests/test_mock_decorator.py @@ -1,4 +1,5 @@ from typing import Any + import services.mock_decorator_service diff --git a/tests/test_non_packaged_imported_service.py b/tests/test_non_packaged_imported_service.py index fb8e92247..78081ecd7 100644 --- a/tests/test_non_packaged_imported_service.py +++ b/tests/test_non_packaged_imported_service.py @@ -1,9 +1,11 @@ import os import signal -import tomodachi -import pytest import sys from typing import Any + +import pytest + +import tomodachi from run_test_service_helper import start_service @@ -18,7 +20,10 @@ def test_non_named_sub_service(monkeypatch: Any, capsys: Any, loop: Any) -> None assert instance.started is True assert instance.stop is False - os.kill(os.getpid(), signal.SIGINT) + async def _async_kill(): + os.kill(os.getpid(), signal.SIGINT) + + loop.create_task(_async_kill()) loop.run_until_complete(future) assert instance.stop is True @@ -30,7 +35,10 @@ def test_non_named_sub_service_without_py_ending(monkeypatch: Any, capsys: Any, instance = services.get('test_dummy') assert instance is not None - os.kill(os.getpid(), signal.SIGINT) + async def _async_kill(): + os.kill(os.getpid(), signal.SIGINT) + + loop.create_task(_async_kill()) loop.run_until_complete(future) @@ -45,7 +53,10 @@ def test_non_named_same_named_sub_service(monkeypatch: Any, capsys: Any, loop: A assert instance.started is True assert instance.stop is False - os.kill(os.getpid(), signal.SIGINT) + async def _async_kill(): + os.kill(os.getpid(), signal.SIGINT) + + loop.create_task(_async_kill()) loop.run_until_complete(future) assert instance.stop is True @@ -57,29 +68,32 @@ def test_non_named_same_named_sub_service_without_py_ending(monkeypatch: Any, ca instance = services.get('test_dummy') assert instance is not None - os.kill(os.getpid(), signal.SIGINT) + async def _async_kill(): + os.kill(os.getpid(), signal.SIGINT) + + loop.create_task(_async_kill()) loop.run_until_complete(future) -@pytest.mark.skipif(sys.version_info >= (3, 7, 0), reason="Test skipped on Python 3.7") +@pytest.mark.skipif(sys.version_info >= (3, 7, 0), reason="Test skipped on Python 3.7+") def test_sub_service(monkeypatch: Any, capsys: Any, loop: Any) -> None: with pytest.raises(tomodachi.importer.ServicePackageError): services, future = start_service('tests/services/test/service.py', monkeypatch) -@pytest.mark.skipif(sys.version_info >= (3, 7, 0), reason="Test skipped on Python 3.7") +@pytest.mark.skipif(sys.version_info >= (3, 7, 0), reason="Test skipped on Python 3.7+") def test_sub_service_without_py_ending(monkeypatch: Any, capsys: Any, loop: Any) -> None: with pytest.raises(tomodachi.importer.ServicePackageError): services, future = start_service('tests/services/test/service', monkeypatch) -@pytest.mark.skipif(sys.version_info >= (3, 7, 0), reason="Test skipped on Python 3.7") +@pytest.mark.skipif(sys.version_info >= (3, 7, 0), reason="Test skipped on Python 3.7+") def test_same_named_sub_service(monkeypatch: Any, capsys: Any, loop: Any) -> None: with pytest.raises(tomodachi.importer.ServicePackageError): services, future = start_service('tests/services/test/test.py', monkeypatch) -@pytest.mark.skipif(sys.version_info >= (3, 7, 0), reason="Test skipped on Python 3.7") +@pytest.mark.skipif(sys.version_info >= (3, 7, 0), reason="Test skipped on Python 3.7+") def test_same_named_sub_service_without_py_ending(monkeypatch: Any, capsys: Any, loop: Any) -> None: with pytest.raises(tomodachi.importer.ServicePackageError): services, future = start_service('tests/services/test/test', monkeypatch) diff --git a/tests/test_protocol.py b/tests/test_protocol.py index 77ad8a8ed..5fdaa1bd4 100644 --- a/tests/test_protocol.py +++ b/tests/test_protocol.py @@ -36,7 +36,10 @@ async def _async() -> None: loop.run_until_complete(_async()) - os.kill(os.getpid(), signal.SIGINT) + async def _async_kill(): + os.kill(os.getpid(), signal.SIGINT) + + loop.create_task(_async_kill()) loop.run_until_complete(future) @@ -63,7 +66,10 @@ async def _async() -> None: loop.run_until_complete(_async()) - os.kill(os.getpid(), signal.SIGINT) + async def _async_kill(): + os.kill(os.getpid(), signal.SIGINT) + + loop.create_task(_async_kill()) loop.run_until_complete(future) @@ -95,7 +101,10 @@ async def _async() -> None: loop.run_until_complete(_async()) - os.kill(os.getpid(), signal.SIGINT) + async def _async_kill(): + os.kill(os.getpid(), signal.SIGINT) + + loop.create_task(_async_kill()) loop.run_until_complete(future) @@ -117,7 +126,10 @@ async def _async() -> None: loop.run_until_complete(_async()) - os.kill(os.getpid(), signal.SIGINT) + async def _async_kill(): + os.kill(os.getpid(), signal.SIGINT) + + loop.create_task(_async_kill()) loop.run_until_complete(future) @@ -136,7 +148,10 @@ async def _async() -> None: with pytest.raises(AttributeError): loop.run_until_complete(_async()) - os.kill(os.getpid(), signal.SIGINT) + async def _async_kill(): + os.kill(os.getpid(), signal.SIGINT) + + loop.create_task(_async_kill()) loop.run_until_complete(future) @@ -151,7 +166,10 @@ async def _async() -> None: with pytest.raises(Exception): loop.run_until_complete(_async()) - os.kill(os.getpid(), signal.SIGINT) + async def _async_kill(): + os.kill(os.getpid(), signal.SIGINT) + + loop.create_task(_async_kill()) loop.run_until_complete(future) @@ -166,7 +184,10 @@ async def _async() -> None: with pytest.raises(Exception): loop.run_until_complete(_async()) - os.kill(os.getpid(), signal.SIGINT) + async def _async_kill(): + os.kill(os.getpid(), signal.SIGINT) + + loop.create_task(_async_kill()) loop.run_until_complete(future) @@ -190,7 +211,10 @@ async def _async() -> None: loop.run_until_complete(_async()) - os.kill(os.getpid(), signal.SIGINT) + async def _async_kill(): + os.kill(os.getpid(), signal.SIGINT) + + loop.create_task(_async_kill()) loop.run_until_complete(future) @@ -215,7 +239,10 @@ async def _async() -> None: loop.run_until_complete(_async()) - os.kill(os.getpid(), signal.SIGINT) + async def _async_kill(): + os.kill(os.getpid(), signal.SIGINT) + + loop.create_task(_async_kill()) loop.run_until_complete(future) @@ -240,7 +267,10 @@ async def _async() -> None: with pytest.raises(RegexMissmatchException): loop.run_until_complete(_async()) - os.kill(os.getpid(), signal.SIGINT) + async def _async_kill(): + os.kill(os.getpid(), signal.SIGINT) + + loop.create_task(_async_kill()) loop.run_until_complete(future) @@ -266,5 +296,8 @@ async def _async() -> None: with pytest.raises(RegexMissmatchException): loop.run_until_complete(_async()) - os.kill(os.getpid(), signal.SIGINT) + async def _async_kill(): + os.kill(os.getpid(), signal.SIGINT) + + loop.create_task(_async_kill()) loop.run_until_complete(future) diff --git a/tests/test_relative_imports.py b/tests/test_relative_imports.py index 8942fb6da..e0237f9d3 100644 --- a/tests/test_relative_imports.py +++ b/tests/test_relative_imports.py @@ -1,6 +1,7 @@ import os import signal from typing import Any + from run_test_service_helper import start_service @@ -15,7 +16,10 @@ def test_relative_import_service(monkeypatch: Any, capsys: Any, loop: Any) -> No assert instance.started is True assert instance.stop is False - os.kill(os.getpid(), signal.SIGINT) + async def _async_kill(): + os.kill(os.getpid(), signal.SIGINT) + + loop.create_task(_async_kill()) loop.run_until_complete(future) assert instance.stop is True @@ -27,5 +31,8 @@ def test_relative_import_service_without_py_ending(monkeypatch: Any, capsys: Any instance = services.get('test_relative') assert instance is not None - os.kill(os.getpid(), signal.SIGINT) + async def _async_kill(): + os.kill(os.getpid(), signal.SIGINT) + + loop.create_task(_async_kill()) loop.run_until_complete(future) diff --git a/tests/test_schedule_service.py b/tests/test_schedule_service.py index 12ec95e40..96e39940a 100644 --- a/tests/test_schedule_service.py +++ b/tests/test_schedule_service.py @@ -1,5 +1,6 @@ import asyncio from typing import Any + from run_test_service_helper import start_service diff --git a/tests/test_start_process_http_1.py b/tests/test_start_process_http_1.py index 5dbb6c119..1bd340394 100644 --- a/tests/test_start_process_http_1.py +++ b/tests/test_start_process_http_1.py @@ -1,6 +1,8 @@ import asyncio -import aiohttp from typing import Any + +import aiohttp + from run_test_service_helper import start_service diff --git a/tests/test_start_process_http_2.py b/tests/test_start_process_http_2.py index faee50c4c..20d68b7e1 100644 --- a/tests/test_start_process_http_2.py +++ b/tests/test_start_process_http_2.py @@ -1,6 +1,8 @@ import asyncio -import aiohttp from typing import Any + +import aiohttp + from run_test_service_helper import start_service diff --git a/tests/test_start_process_schedule.py b/tests/test_start_process_schedule.py index 9ab87d861..10196fa6d 100644 --- a/tests/test_start_process_schedule.py +++ b/tests/test_start_process_schedule.py @@ -1,5 +1,6 @@ import asyncio from typing import Any + from run_test_service_helper import start_service diff --git a/tests/test_validation.py b/tests/test_validation.py index 2a838a643..b6078e81b 100644 --- a/tests/test_validation.py +++ b/tests/test_validation.py @@ -1,9 +1,12 @@ import pytest -from tomodachi.validation.validation import validate_field_regex, \ - RegexMissmatchException -from tomodachi.validation.validation import validate_field_length, \ - TooSmallException, TooLargeException +from tomodachi.validation.validation import ( + RegexMissmatchException, + TooLargeException, + TooSmallException, + validate_field_length, + validate_field_regex, +) def test_regex_success() -> None: diff --git a/tests/test_watcher.py b/tests/test_watcher.py index 5421be1d7..f12ba3746 100644 --- a/tests/test_watcher.py +++ b/tests/test_watcher.py @@ -1,7 +1,8 @@ -import os import asyncio +import os import sys -from typing import Any, Dict, Union, List # noqa +from typing import Any, Dict, List, Union # noqa + from tomodachi.watcher import Watcher diff --git a/tomodachi/__init__.py b/tomodachi/__init__.py index e6da1c6f8..d7796a30a 100644 --- a/tomodachi/__init__.py +++ b/tomodachi/__init__.py @@ -1,6 +1,8 @@ -from typing import Any, Optional import inspect +from typing import Any, Optional + from tomodachi.__version__ import __version__, __version_info__ # noqa + try: import tomodachi.helpers.logging from tomodachi.invoker import decorator diff --git a/tomodachi/__init__.pyi b/tomodachi/__init__.pyi index c0652b562..89d3e1045 100644 --- a/tomodachi/__init__.pyi +++ b/tomodachi/__init__.pyi @@ -1,11 +1,26 @@ -from tomodachi.__version__ import __version__ as __version__, __version_info__ as __version_info__ -from tomodachi.invoker import decorator -from tomodachi.transport.amqp import amqp as amqp, amqp_publish as amqp_publish -from tomodachi.transport.aws_sns_sqs import aws_sns_sqs as aws_sns_sqs, aws_sns_sqs_publish as aws_sns_sqs_publish -from tomodachi.transport.http import HttpException as HttpException, Response as HttpResponse, http as http, http_error as http_error, http_static as http_static, websocket as websocket, get_http_response_status as get_http_response_status -from tomodachi.transport.schedule import daily as daily, heartbeat as heartbeat, hourly as hourly, minutely as minutely, monthly as monthly, schedule as schedule from typing import Any, Optional +from tomodachi.__version__ import __version__ as __version__ +from tomodachi.__version__ import __version_info__ as __version_info__ +from tomodachi.invoker import decorator +from tomodachi.transport.amqp import amqp as amqp +from tomodachi.transport.amqp import amqp_publish as amqp_publish +from tomodachi.transport.aws_sns_sqs import aws_sns_sqs as aws_sns_sqs +from tomodachi.transport.aws_sns_sqs import aws_sns_sqs_publish as aws_sns_sqs_publish +from tomodachi.transport.http import HttpException as HttpException +from tomodachi.transport.http import Response as HttpResponse +from tomodachi.transport.http import get_http_response_status as get_http_response_status +from tomodachi.transport.http import http as http +from tomodachi.transport.http import http_error as http_error +from tomodachi.transport.http import http_static as http_static +from tomodachi.transport.http import websocket as websocket +from tomodachi.transport.schedule import daily as daily +from tomodachi.transport.schedule import heartbeat as heartbeat +from tomodachi.transport.schedule import hourly as hourly +from tomodachi.transport.schedule import minutely as minutely +from tomodachi.transport.schedule import monthly as monthly +from tomodachi.transport.schedule import schedule as schedule + CLASS_ATTRIBUTE: str = ... def service(cls: Any) -> Any: ... diff --git a/tomodachi/__version__.py b/tomodachi/__version__.py index 7ade675a6..54a78c24b 100644 --- a/tomodachi/__version__.py +++ b/tomodachi/__version__.py @@ -1,4 +1,4 @@ -__version_info__ = (0, 16, 6) +__version_info__ = (0, 17, 0) __version__ = ''.join(['.{}'.format(str(n)) if type(n) is int else str(n) for n in __version_info__]).replace('.', '', 1 if type(__version_info__[0]) is int else 0) if __name__ == "__main__": diff --git a/tomodachi/cli/__init__.py b/tomodachi/cli/__init__.py index 1ee8999d9..ec2c0fcfa 100644 --- a/tomodachi/cli/__init__.py +++ b/tomodachi/cli/__init__.py @@ -1,14 +1,14 @@ #!/usr/bin/env python -import os -import sys import getopt import logging +import os +import sys from typing import List, Optional + import tomodachi +from tomodachi.config import parse_config_files from tomodachi.launcher import ServiceLauncher from tomodachi.watcher import Watcher -from tomodachi.config import parse_config_files - try: if ModuleNotFoundError: @@ -212,4 +212,7 @@ def main(self, argv: List[str]) -> None: def cli_entrypoint(argv: Optional[List[str]] = None) -> None: if argv is None: argv = sys.argv + if argv[0].endswith('pytest'): + argv = ['tomodachi'] + CLI().main(argv[1:]) diff --git a/tomodachi/container.py b/tomodachi/container.py index 6d6d64cd8..6658bcb1b 100644 --- a/tomodachi/container.py +++ b/tomodachi/container.py @@ -1,16 +1,17 @@ -import inspect import asyncio -import sys +import inspect import logging import re +import sys import types import uuid -import tomodachi from types import ModuleType, TracebackType -from typing import Dict, Optional, Any +from typing import Any, Dict, Optional + +import tomodachi from tomodachi import CLASS_ATTRIBUTE -from tomodachi.invoker import FUNCTION_ATTRIBUTE, START_ATTRIBUTE from tomodachi.config import merge_dicts +from tomodachi.invoker import FUNCTION_ATTRIBUTE, START_ATTRIBUTE class ServiceContainer(object): diff --git a/tomodachi/discovery/__init__.py b/tomodachi/discovery/__init__.py index 8cb9f55de..93236ef4c 100644 --- a/tomodachi/discovery/__init__.py +++ b/tomodachi/discovery/__init__.py @@ -1,4 +1,4 @@ -from tomodachi.discovery.dummy_registry import DummyRegistry from tomodachi.discovery.aws_sns_registration import AWSSNSRegistration +from tomodachi.discovery.dummy_registry import DummyRegistry __all__ = ['DummyRegistry', 'AWSSNSRegistration'] diff --git a/tomodachi/discovery/aws_sns_registration.py b/tomodachi/discovery/aws_sns_registration.py index 6b85ebb87..93ec71065 100644 --- a/tomodachi/discovery/aws_sns_registration.py +++ b/tomodachi/discovery/aws_sns_registration.py @@ -1,5 +1,6 @@ import logging from typing import Any, Dict # noqa + from tomodachi.transport.aws_sns_sqs import aws_sns_sqs_publish diff --git a/tomodachi/helpers/crontab.py b/tomodachi/helpers/crontab.py index e121ebbe1..268995964 100644 --- a/tomodachi/helpers/crontab.py +++ b/tomodachi/helpers/crontab.py @@ -1,7 +1,8 @@ import datetime -import pytz -from typing import List, Tuple, Dict, Union, Optional, Any, SupportsInt # noqa from calendar import monthrange +from typing import Any, Dict, List, Optional, SupportsInt, Tuple, Union # noqa + +import pytz cron_attributes = [ ('minute', (0, 59), {}), diff --git a/tomodachi/helpers/logging.py b/tomodachi/helpers/logging.py index 774f40503..e6d3770d1 100644 --- a/tomodachi/helpers/logging.py +++ b/tomodachi/helpers/logging.py @@ -1,6 +1,6 @@ import logging from logging.handlers import WatchedFileHandler -from typing import Optional, Union, Any +from typing import Any, Optional, Union class CustomServiceLogHandler(WatchedFileHandler): diff --git a/tomodachi/helpers/middleware.py b/tomodachi/helpers/middleware.py index a5049ed97..92b3e7a82 100644 --- a/tomodachi/helpers/middleware.py +++ b/tomodachi/helpers/middleware.py @@ -1,6 +1,6 @@ import functools import inspect -from typing import Callable, List, Any, Dict +from typing import Any, Callable, Dict, List async def execute_middlewares(func: Callable, routine_func: Callable, middlewares: List, *args: Any) -> Any: diff --git a/tomodachi/importer.py b/tomodachi/importer.py index ce50a6c2a..f3cdec555 100644 --- a/tomodachi/importer.py +++ b/tomodachi/importer.py @@ -1,9 +1,9 @@ -import os -import sys -import re -import logging import importlib import importlib.util +import logging +import os +import re +import sys from types import ModuleType from typing import Any # noqa diff --git a/tomodachi/invoker/__init__.py b/tomodachi/invoker/__init__.py index 4efed0041..b47370512 100644 --- a/tomodachi/invoker/__init__.py +++ b/tomodachi/invoker/__init__.py @@ -1,2 +1,2 @@ -from .base import Invoker, FUNCTION_ATTRIBUTE, START_ATTRIBUTE # noqa +from .base import FUNCTION_ATTRIBUTE, START_ATTRIBUTE, Invoker # noqa from .decorator import decorator diff --git a/tomodachi/invoker/decorator.py b/tomodachi/invoker/decorator.py index 88053f291..07544099d 100644 --- a/tomodachi/invoker/decorator.py +++ b/tomodachi/invoker/decorator.py @@ -1,6 +1,6 @@ -from functools import wraps -from typing import Any, Callable, Awaitable # noqa import types +from functools import wraps +from typing import Any, Awaitable, Callable # noqa class DecorationClass(object): diff --git a/tomodachi/launcher.py b/tomodachi/launcher.py index ab894c48c..3a3b373ec 100644 --- a/tomodachi/launcher.py +++ b/tomodachi/launcher.py @@ -1,22 +1,29 @@ import asyncio -import sys -import signal +import datetime import importlib import logging -import datetime -import uvloop import os +import signal +import sys +from typing import Any, Dict, List, Optional, Union + import multidict # noqa +import uvloop import yarl # noqa -from typing import Dict, Union, Optional, Any, List + +import tomodachi.__version__ import tomodachi.container import tomodachi.importer import tomodachi.invoker -import tomodachi.__version__ import tomodachi.watcher from tomodachi.container import ServiceContainer from tomodachi.importer import ServiceImporter +try: + CancelledError = asyncio.exceptions.CancelledError +except Exception as e: + CancelledError = Exception + class ServiceLauncher(object): _close_waiter = None # type: Union[None, asyncio.Future] @@ -159,5 +166,5 @@ async def _watcher_restart(updated_files: Union[List, set]) -> None: if not watcher_future.done(): # pragma: no cover try: loop.run_until_complete(watcher_future) - except Exception: + except (Exception, CancelledError): pass diff --git a/tomodachi/protocol/__init__.py b/tomodachi/protocol/__init__.py index 5df3c2e37..cfc1c9519 100644 --- a/tomodachi/protocol/__init__.py +++ b/tomodachi/protocol/__init__.py @@ -1,5 +1,7 @@ from typing import Any + from tomodachi.protocol.json_base import JsonBase + try: from tomodachi.protocol.protobuf_base import ProtobufBase # type: ignore except Exception: # pragma: no cover diff --git a/tomodachi/protocol/protobuf_base.py b/tomodachi/protocol/protobuf_base.py index 5f93698a9..6f851bf2d 100644 --- a/tomodachi/protocol/protobuf_base.py +++ b/tomodachi/protocol/protobuf_base.py @@ -1,7 +1,7 @@ +import base64 import logging -import uuid import time -import base64 +import uuid import zlib from typing import Any, Dict, Tuple, Union diff --git a/tomodachi/transport/amqp.py b/tomodachi/transport/amqp.py index 2b60f806f..fc1a334a9 100644 --- a/tomodachi/transport/amqp.py +++ b/tomodachi/transport/amqp.py @@ -1,16 +1,18 @@ -import logging -import aioamqp -import time -import hashlib -import re -import binascii import asyncio -import inspect +import binascii import functools -from typing import Any, Dict, Union, Optional, Callable, Match, Awaitable, List -from tomodachi.invoker import Invoker +import hashlib +import inspect +import logging +import re +import time +from typing import Any, Awaitable, Callable, Dict, List, Match, Optional, Union + +import aioamqp + from tomodachi.helpers.dict import merge_dicts from tomodachi.helpers.middleware import execute_middlewares +from tomodachi.invoker import Invoker MESSAGE_PROTOCOL_DEFAULT = '2594418c-5771-454a-a7f9-8f83ae82812a' MESSAGE_ROUTING_KEY_PREFIX = '38f58822-25f6-458a-985c-52701d40dbbc' diff --git a/tomodachi/transport/aws_sns_sqs.py b/tomodachi/transport/aws_sns_sqs.py index 191795a72..e742d2bbe 100644 --- a/tomodachi/transport/aws_sns_sqs.py +++ b/tomodachi/transport/aws_sns_sqs.py @@ -10,11 +10,11 @@ import uuid from typing import Any, Awaitable, Callable, Dict, List, Match, Optional, Tuple, Union +import aiobotocore +import aiohttp import botocore from botocore.parsers import ResponseParserError -import aiobotocore -import aiohttp from tomodachi.helpers.dict import merge_dicts from tomodachi.helpers.middleware import execute_middlewares from tomodachi.invoker import Invoker @@ -241,7 +241,7 @@ def create_client(cls: Any, name: str, context: Dict) -> None: cls.clients = {} cls.clients_creation_time = {} loop = asyncio.get_event_loop() - session = aiobotocore.get_session(loop=loop) + session = aiobotocore.get_session() config_base = context.get('options', {}).get('aws_sns_sqs', context.get('options', {}).get('aws', {})) aws_config_base = context.get('options', {}).get('aws', {}) diff --git a/tomodachi/transport/http.py b/tomodachi/transport/http.py index 7d513ff87..85a6c537c 100644 --- a/tomodachi/transport/http.py +++ b/tomodachi/transport/http.py @@ -1,25 +1,27 @@ -import re import asyncio -import logging -import time +import functools +import inspect import ipaddress +import logging import os import pathlib -import inspect +import re +import time import uuid -import colorama -import functools from logging.handlers import WatchedFileHandler -from typing import Any, Dict, List, Tuple, Union, Optional, Callable, SupportsInt, Awaitable, Mapping, Iterable # noqa -from multidict import CIMultiDict, CIMultiDictProxy -from aiohttp import web, web_server, web_protocol, web_urldispatcher, hdrs, WSMsgType -from aiohttp.web_fileresponse import FileResponse -from aiohttp.http import HttpVersion +from typing import Any, Awaitable, Callable, Dict, Iterable, List, Mapping, Optional, SupportsInt, Tuple, Union # noqa + +import colorama +from aiohttp import WSMsgType, hdrs, web, web_protocol, web_server, web_urldispatcher from aiohttp.helpers import BasicAuth +from aiohttp.http import HttpVersion from aiohttp.streams import EofStream -from tomodachi.invoker import Invoker +from aiohttp.web_fileresponse import FileResponse +from multidict import CIMultiDict, CIMultiDictProxy + from tomodachi.helpers.dict import merge_dicts from tomodachi.helpers.middleware import execute_middlewares +from tomodachi.invoker import Invoker class HttpException(Exception): diff --git a/tomodachi/transport/schedule.py b/tomodachi/transport/schedule.py index d7dc6a167..65a16f48a 100644 --- a/tomodachi/transport/schedule.py +++ b/tomodachi/transport/schedule.py @@ -1,13 +1,15 @@ -import datetime import asyncio +import datetime +import inspect +import logging import time +from typing import Any, Awaitable, Callable, Dict, List, Optional, Tuple, Union # noqa + import pytz import tzlocal -import inspect -import logging -from typing import Any, Dict, List, Union, Optional, Callable, Tuple, Awaitable # noqa -from tomodachi.invoker import Invoker + from tomodachi.helpers.crontab import get_next_datetime +from tomodachi.invoker import Invoker class Scheduler(Invoker): diff --git a/tomodachi/watcher.py b/tomodachi/watcher.py index 585eaedea..536094e99 100644 --- a/tomodachi/watcher.py +++ b/tomodachi/watcher.py @@ -1,9 +1,9 @@ import asyncio +import logging import os import sys import zlib -import logging -from typing import Any, Dict, List, Optional, Callable +from typing import Any, Callable, Dict, List, Optional def crc(file_path: str) -> str: diff --git a/tox.ini b/tox.ini new file mode 100644 index 000000000..309d5a82f --- /dev/null +++ b/tox.ini @@ -0,0 +1,9 @@ +[pytest] +filterwarnings = + ignore:"@coroutine" decorator is deprecated since Python 3[.]8:DeprecationWarning + ignore:The loop argument is deprecated since Python 3[.]8:DeprecationWarning + +[flake8] +ignore = E203, W503 +exclude = .git,__pycache__,build,dist,.vscode,.pytest_cache,.mypy_cache +max-line-length = 120 From d8de7dea41b59393de242cf350f19a1bc74cc995 Mon Sep 17 00:00:00 2001 From: Carl Oscar Aaro Date: Tue, 16 Jun 2020 03:09:55 +0200 Subject: [PATCH 02/11] Graceful termination of active HTTP requests when stopping service --- tomodachi/transport/http.py | 53 +++++++++++++++++++++++++++++++++---- 1 file changed, 48 insertions(+), 5 deletions(-) diff --git a/tomodachi/transport/http.py b/tomodachi/transport/http.py index 85a6c537c..9cb75f2f9 100644 --- a/tomodachi/transport/http.py +++ b/tomodachi/transport/http.py @@ -23,6 +23,11 @@ from tomodachi.helpers.middleware import execute_middlewares from tomodachi.invoker import Invoker +try: + CancelledError = asyncio.exceptions.CancelledError +except Exception as e: + CancelledError = Exception + class HttpException(Exception): def __init__(self, *args: Any, **kwargs: Any) -> None: @@ -246,6 +251,9 @@ async def routine_func(*a: Any, **kw: Any) -> Union[str, bytes, Dict, List, Tupl return_value = (await routine) if isinstance(routine, Awaitable) else routine # type: Union[str, bytes, Dict, List, Tuple, web.Response, Response] return return_value + if not context.get('_http_accept_new_requests'): + raise web.HTTPServiceUnavailable() + if pre_handler_func: await pre_handler_func(obj, request) @@ -598,7 +606,17 @@ async def func() -> web.Response: return response - return await asyncio.shield(func()) + task = asyncio.ensure_future(asyncio.shield(func())) + context['_http_active_requests'] = context.get('_http_active_requests', set()) + context['_http_active_requests'].add(task) + try: + result = await task + except (Exception, CancelledError): + context['_http_active_requests'].remove(task) + raise + context['_http_active_requests'].remove(task) + + return task.result() app = web.Application(middlewares=[middleware], # type: ignore client_max_size=(1024 ** 2) * 100) # type: web.Application @@ -617,6 +635,7 @@ async def func() -> web.Response: resource.add_route('HEAD', handler, expect_handler=None) # type: ignore resource.add_route(method.upper(), handler, expect_handler=None) # type: ignore + context['_http_accept_new_requests'] = True port = context.get('options', {}).get('http', {}).get('port', 9700) host = context.get('options', {}).get('http', {}).get('host', '0.0.0.0') @@ -625,6 +644,7 @@ async def func() -> web.Response: server_task = loop.create_server(Server(app._handle, request_factory=app._make_request, server_header=server_header or '', access_log=access_log, keepalive_timeout=0, tcp_keepalive=False), host, port) # type: ignore server = await server_task # type: ignore except OSError as e: + context['_http_accept_new_requests'] = False error_message = re.sub('.*: ', '', e.strerror) logging.getLogger('transport.http').warning('Unable to bind service [http] to http://{}:{}/ ({})'.format('127.0.0.1' if host == '0.0.0.0' else host, port, error_message)) raise HttpException(str(e), log_level=context.get('log_level')) from e @@ -635,15 +655,38 @@ async def func() -> web.Response: stop_method = getattr(obj, '_stop_service', None) async def stop_service(*args: Any, **kwargs: Any) -> None: + context['_http_accept_new_requests'] = False + server.close() if stop_method: await stop_method(*args, **kwargs) + open_websockets = context.get('_http_open_websockets', [])[:] - for websocket in open_websockets: + if open_websockets: + logging.getLogger('transport.http').info('Closing websocket connections') + tasks = [] + for websocket in open_websockets: + try: + tasks.append(asyncio.ensure_future(websocket.close())) + except Exception: + pass try: - await websocket.close() - except Exception: + results = await asyncio.wait_for(asyncio.gather(*tasks, return_exceptions=True), timeout=10) + except (Exception, asyncio.TimeoutError) as e: pass - server.close() + context['_http_open_websockets'] = [] + + active_requests = context.get('_http_active_requests', set()) + if active_requests: + termination_grace_period_seconds = context.get('options', {}).get('http', {}).get('termination_grace_period_seconds', 30) + logging.getLogger('transport.http').info('Waiting for active requests to complete - grace period of {} seconds'.format(termination_grace_period_seconds)) + try: + results = await asyncio.wait_for(asyncio.gather(*active_requests, return_exceptions=True), timeout=termination_grace_period_seconds) + await asyncio.sleep(1) + except (Exception, asyncio.TimeoutError) as e: + logging.getLogger('transport.http').warning('All active requests did not gracefully finish their execution') + pass + context['_http_active_requests'] = set() + await app.shutdown() if logger_handler: logging.getLogger('transport.http').removeHandler(logger_handler) From 362f00213704ea325571d2ac0dc9aa1df0b2c28e Mon Sep 17 00:00:00 2001 From: Carl Oscar Aaro Date: Tue, 16 Jun 2020 03:16:00 +0200 Subject: [PATCH 03/11] Ignore temporary files --- Makefile | 2 +- tox.ini | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index f90b983df..6cdf355d6 100644 --- a/Makefile +++ b/Makefile @@ -33,7 +33,7 @@ uninstall: pip uninstall -y tomodachi lint: - pycodestyle --ignore E501 --exclude proto_build,build . + pycodestyle --ignore E501 --exclude proto_build,build,tmp . mypy ./ @echo "ok" diff --git a/tox.ini b/tox.ini index 309d5a82f..c60a1e422 100644 --- a/tox.ini +++ b/tox.ini @@ -5,5 +5,5 @@ filterwarnings = [flake8] ignore = E203, W503 -exclude = .git,__pycache__,build,dist,.vscode,.pytest_cache,.mypy_cache +exclude = .git,__pycache__,build,dist,.vscode,.pytest_cache,.mypy_cache,tmp max-line-length = 120 From 286cdc47707dc1f111f17c561b68a9f941a107b5 Mon Sep 17 00:00:00 2001 From: Carl Oscar Aaro Date: Tue, 16 Jun 2020 03:41:01 +0200 Subject: [PATCH 04/11] Fixed type hinting and linting --- tomodachi/cli/__init__.py | 3 ++- tomodachi/container.py | 6 +++--- tomodachi/helpers/middleware.py | 5 ++++- tomodachi/launcher.py | 9 +++++---- tomodachi/transport/http.py | 12 ++++++++---- 5 files changed, 22 insertions(+), 13 deletions(-) diff --git a/tomodachi/cli/__init__.py b/tomodachi/cli/__init__.py index ec2c0fcfa..6e83375ba 100644 --- a/tomodachi/cli/__init__.py +++ b/tomodachi/cli/__init__.py @@ -105,7 +105,8 @@ def test_dependencies(self, fail_on_errors: bool = True, output_versions: bool = # Optional import google.protobuf if output_versions: - print('protobuf/{}'.format(google.protobuf.__version__)) + protobuf_version = google.protobuf.__version__.decode() if isinstance(google.protobuf.__version__, bytes) else str(google.protobuf.__version__) + print('protobuf/{}'.format(protobuf_version)) except ModuleNotFoundError as e: # pragma: no cover pass except Exception as e: # pragma: no cover diff --git a/tomodachi/container.py b/tomodachi/container.py index 6658bcb1b..b9ca605d0 100644 --- a/tomodachi/container.py +++ b/tomodachi/container.py @@ -6,7 +6,7 @@ import types import uuid from types import ModuleType, TracebackType -from typing import Any, Dict, Optional +from typing import Any, Dict, Optional, cast import tomodachi from tomodachi import CLASS_ATTRIBUTE @@ -118,12 +118,12 @@ def invoker_function_sorter(m: str) -> int: start_task_results = await asyncio.wait([asyncio.ensure_future(func()) for func in start_futures if func]) exception = [v.exception() for v in [value for value in start_task_results if value][0] if v.exception()] if exception: - raise exception[0] + raise cast(Exception, exception[0]) if invoker_tasks: task_results = await asyncio.wait([asyncio.ensure_future(func()) for func in (await asyncio.gather(*invoker_tasks)) if func]) exception = [v.exception() for v in [value for value in task_results if value][0] if v.exception()] if exception: - raise exception[0] + raise cast(Exception, exception[0]) for name, instance, log_level in services_started: for registry in getattr(instance, 'discovery', []): diff --git a/tomodachi/helpers/middleware.py b/tomodachi/helpers/middleware.py index 92b3e7a82..bad50873b 100644 --- a/tomodachi/helpers/middleware.py +++ b/tomodachi/helpers/middleware.py @@ -17,7 +17,10 @@ async def _func(*a: Any, **kw: Any) -> Any: middleware = middlewares[idx] # type: Callable - arg_len = len(inspect.getfullargspec(middleware).args) - (len(inspect.getfullargspec(middleware).defaults) if inspect.getfullargspec(middleware).defaults else 0) + arg_len = len(inspect.getfullargspec(middleware).args) + defaults = inspect.getfullargspec(middleware).defaults + if defaults: + arg_len = arg_len - len(defaults) middleware_arguments = [_func, *args, middleware_context][0:arg_len] return await middleware(*middleware_arguments, *ma, **mkw) diff --git a/tomodachi/launcher.py b/tomodachi/launcher.py index 3a3b373ec..a6cc1eb3e 100644 --- a/tomodachi/launcher.py +++ b/tomodachi/launcher.py @@ -5,7 +5,7 @@ import os import signal import sys -from typing import Any, Dict, List, Optional, Union +from typing import Any, Dict, List, Optional, Union, cast import multidict # noqa import uvloop @@ -20,9 +20,10 @@ from tomodachi.importer import ServiceImporter try: - CancelledError = asyncio.exceptions.CancelledError + CancelledError = asyncio.exceptions.CancelledError # type: ignore except Exception as e: - CancelledError = Exception + class CancelledError(Exception): # type: ignore + pass class ServiceLauncher(object): @@ -127,7 +128,7 @@ async def _watcher_restart(updated_files: Union[List, set]) -> None: result = loop.run_until_complete(asyncio.wait([asyncio.ensure_future(service.run_until_complete()) for service in cls.services])) exception = [v.exception() for v in [value for value in result if value][0] if v.exception()] if exception: - raise exception[0] + raise cast(Exception, exception[0]) except tomodachi.importer.ServicePackageError as e: pass except Exception as e: diff --git a/tomodachi/transport/http.py b/tomodachi/transport/http.py index 9cb75f2f9..dcc1bb5ba 100644 --- a/tomodachi/transport/http.py +++ b/tomodachi/transport/http.py @@ -24,9 +24,10 @@ from tomodachi.invoker import Invoker try: - CancelledError = asyncio.exceptions.CancelledError + CancelledError = asyncio.exceptions.CancelledError # type: ignore except Exception as e: - CancelledError = Exception + class CancelledError(Exception): # type: ignore + pass class HttpException(Exception): @@ -117,7 +118,7 @@ def handle_error(self, request: Any, status: int = 500, exc: Any = None, message request.headers.get('User-Agent', '').replace('"', '') )) - headers = {} + headers = CIMultiDict({}) # type: CIMultiDict headers[hdrs.CONTENT_TYPE] = 'text/plain; charset=utf-8' msg = '' if status == 500 or not message else message @@ -649,7 +650,10 @@ async def func() -> web.Response: logging.getLogger('transport.http').warning('Unable to bind service [http] to http://{}:{}/ ({})'.format('127.0.0.1' if host == '0.0.0.0' else host, port, error_message)) raise HttpException(str(e), log_level=context.get('log_level')) from e - port = int(server.sockets[0].getsockname()[1]) + if server.sockets: + socket_address = server.sockets[0].getsockname() + if socket_address: + port = int(socket_address[1]) context['_http_port'] = port stop_method = getattr(obj, '_stop_service', None) From 53b6749ae06569274df2417baac4bcd88cd701bc Mon Sep 17 00:00:00 2001 From: Carl Oscar Aaro Date: Tue, 16 Jun 2020 03:45:56 +0200 Subject: [PATCH 05/11] Added Python 3.8 classifiers --- README.rst | 2 +- setup.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 2126a57f9..1d344c2b0 100644 --- a/README.rst +++ b/README.rst @@ -366,7 +366,7 @@ If the decorator would return anything else than ``True`` or ``None`` (or not sp Requirements 👍 --------------- -* Python_ (``3.5.3+``, ``3.6+``, ``3.7+``) +* Python_ (``3.5.3+``, ``3.6+``, ``3.7+``, ``3.8+``) * aiohttp_ * aiobotocore_ * aioamqp_ diff --git a/setup.py b/setup.py index bdb946b93..e88983833 100644 --- a/setup.py +++ b/setup.py @@ -35,6 +35,7 @@ def read(f: str) -> str: 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', 'License :: OSI Approved :: MIT License', 'Development Status :: 3 - Alpha', 'Topic :: Software Development :: Libraries :: Application Frameworks', From 8eb6349f327de9861dda65c0dbe0b321cdd6c916 Mon Sep 17 00:00:00 2001 From: Carl Oscar Aaro Date: Tue, 16 Jun 2020 03:54:56 +0200 Subject: [PATCH 06/11] Dropped support for Python 3.5 --- .travis.yml | 4 ++-- README.rst | 2 +- setup.py | 10 +++++----- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9ef9f75f1..5731dd81b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,14 +1,14 @@ language: python sudo: required python: - - 3.5.3 - - 3.5.5 - 3.6.1 - 3.6.2 - 3.6.3 - 3.6.4 - 3.6.5 - 3.6.6 + - 3.7.7 + - 3.8.3 services: - rabbitmq install: diff --git a/README.rst b/README.rst index 1d344c2b0..dfe08d639 100644 --- a/README.rst +++ b/README.rst @@ -366,7 +366,7 @@ If the decorator would return anything else than ``True`` or ``None`` (or not sp Requirements 👍 --------------- -* Python_ (``3.5.3+``, ``3.6+``, ``3.7+``, ``3.8+``) +* Python_ (``3.6+``, ``3.7+``, ``3.8+``) * aiohttp_ * aiobotocore_ * aioamqp_ diff --git a/setup.py b/setup.py index e88983833..0fb68567a 100644 --- a/setup.py +++ b/setup.py @@ -19,8 +19,8 @@ PY_VER = sys.version_info -if not PY_VER >= (3, 5, 3): - raise RuntimeError("tomodachi doesn't support Python earlier than 3.5.3") +if not PY_VER >= (3, 6, 1): + raise RuntimeError("tomodachi doesn't support Python earlier than 3.6.1") def read(f: str) -> str: @@ -32,14 +32,14 @@ def read(f: str) -> str: 'Intended Audience :: System Administrators', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3 :: Only', - 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'License :: OSI Approved :: MIT License', - 'Development Status :: 3 - Alpha', + 'Development Status :: 4 - Beta', 'Topic :: Software Development :: Libraries :: Application Frameworks', - 'Topic :: Software Development :: Libraries :: Python Modules' + 'Topic :: Software Development :: Libraries :: Python Modules', + 'Typing :: Typed' ] setup(name='tomodachi', From 8863cf449037c22daf82788907ef20b162bb9733 Mon Sep 17 00:00:00 2001 From: Carl Oscar Aaro Date: Tue, 16 Jun 2020 03:59:56 +0200 Subject: [PATCH 07/11] Updated values for pycodestyle --- .travis.yml | 2 +- tox.ini | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5731dd81b..85bcb1122 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,7 +16,7 @@ install: - travis_retry pip install -Ur requirements.txt - pip freeze script: - - pycodestyle --ignore E501 --exclude proto_build . + - pycodestyle --ignore E203,W503,E501 --exclude proto_build,build,tmp . - travis_retry py.test --cov=./ tests/ - tomodachi run tests/run_example_service.py - python tomodachi.py -v diff --git a/tox.ini b/tox.ini index c60a1e422..3cbd1481c 100644 --- a/tox.ini +++ b/tox.ini @@ -4,6 +4,6 @@ filterwarnings = ignore:The loop argument is deprecated since Python 3[.]8:DeprecationWarning [flake8] -ignore = E203, W503 +ignore = E203, W503, E501 exclude = .git,__pycache__,build,dist,.vscode,.pytest_cache,.mypy_cache,tmp max-line-length = 120 From 0f28ad6d3a865803a3b28a42bc6953be5927cfa5 Mon Sep 17 00:00:00 2001 From: Carl Oscar Aaro Date: Tue, 16 Jun 2020 04:00:53 +0200 Subject: [PATCH 08/11] No need to test a lot of older versions of Python 3.6 --- .travis.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 85bcb1122..a912a2b7e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,11 +1,6 @@ language: python sudo: required python: - - 3.6.1 - - 3.6.2 - - 3.6.3 - - 3.6.4 - - 3.6.5 - 3.6.6 - 3.7.7 - 3.8.3 From 1bc26ce41f5eeb22fecc337e965ca5fc79bc4e72 Mon Sep 17 00:00:00 2001 From: Carl Oscar Aaro Date: Tue, 16 Jun 2020 04:17:20 +0200 Subject: [PATCH 09/11] Updated URL for asyncio to point to Python 3.8 documentation --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index dfe08d639..74efbc90e 100644 --- a/README.rst +++ b/README.rst @@ -373,7 +373,7 @@ Requirements 👍 * uvloop_ .. _Python: https://www.python.org -.. _asyncio: http://docs.python.org/3.5/library/asyncio.html +.. _asyncio: http://docs.python.org/3.8/library/asyncio.html .. _aiohttp: https://github.com/aio-libs/aiohttp .. _aiobotocore: https://github.com/aio-libs/aiobotocore .. _aioamqp: https://github.com/Polyconseil/aioamqp From a5c4bbe17336108b75254899810c8fd7f1844ba0 Mon Sep 17 00:00:00 2001 From: Carl Oscar Aaro Date: Tue, 16 Jun 2020 04:17:37 +0200 Subject: [PATCH 10/11] Added changelog for 0.17.0 --- CHANGES.rst | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/CHANGES.rst b/CHANGES.rst index 9dd2a88bf..313906de5 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,6 +1,27 @@ Changes ======= +0.17.0 (2020-06-16) +------------------- +- Proper support for Python 3.8. Now correctly handles + `CancelledError` exceptions that previously sent a lot of + unwanted output on service shutdown or restart. + +- Updated dependencies across the board, utilizing + package versions that supports Python 3.8. + +- Dropped support for Python 3.5. + +- Now gracefully handles shutdown for HTTP based services, + by awaiting active requests and giving them time to finish. + By default the ongoing HTTP requests will have 30 seconds to + complete their work, which can also be configured via + ``options.http.termination_grace_period_seconds``. + +- Taking steps into making the codebase following more modern + patterns. Additional updates to be followed in a later release. + + 0.16.6 (2020-02-25) ------------------- - Removes the dependency on ``ujson``. From f95d8eb72b375e869889c56627923bccb6b22d4a Mon Sep 17 00:00:00 2001 From: Carl Oscar Aaro Date: Tue, 16 Jun 2020 04:21:52 +0200 Subject: [PATCH 11/11] Updated minimum Python requirement --- tomodachi.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tomodachi.py b/tomodachi.py index edc6c7e2f..6538026f3 100755 --- a/tomodachi.py +++ b/tomodachi.py @@ -6,8 +6,8 @@ import sys if __name__ == "__main__": - if not sys.version_info >= (3, 5): - print("tomodachi doesn't support Python earlier than 3.5") + if not sys.version_info >= (3, 6): + print("tomodachi doesn't support Python earlier than 3.6") sys.exit(1) import tomodachi.cli