diff --git a/docs/source/conf.py b/docs/source/conf.py index 096dbb5..299cc18 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -47,7 +47,7 @@ templates_path = ['_templates'] # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path. -exclude_patterns = [] +exclude_patterns = [] # type: ignore # -- Options for HTML output ------------------------------------------------- diff --git a/mypy.ini b/mypy.ini new file mode 100644 index 0000000..976ba02 --- /dev/null +++ b/mypy.ini @@ -0,0 +1,2 @@ +[mypy] +ignore_missing_imports = True diff --git a/pytest.ini b/pytest.ini index 3d6dc59..7bd7c2a 100644 --- a/pytest.ini +++ b/pytest.ini @@ -1,2 +1,2 @@ [pytest] -addopts = --flakes \ No newline at end of file +addopts = --flakes --mypy diff --git a/requirements.txt b/requirements.txt index f2e2e90..35da1fa 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,6 +2,7 @@ pytest==4.2.0 pytest-asyncio==0.10.0 pytest-mock==1.10.3 +pytest-mypy==0.3.2 pytest-flakes==4.0.0 # because of pip bug https://github.com/pypa/pip/issues/4780 aiohttp==3.5.4 diff --git a/src/galaxy/__init__.py b/src/galaxy/__init__.py index 69e3be5..97b69ed 100644 --- a/src/galaxy/__init__.py +++ b/src/galaxy/__init__.py @@ -1 +1 @@ -__path__ = __import__('pkgutil').extend_path(__path__, __name__) +__path__: str = __import__('pkgutil').extend_path(__path__, __name__) diff --git a/src/galaxy/api/errors.py b/src/galaxy/api/errors.py index 6564b48..f53479f 100644 --- a/src/galaxy/api/errors.py +++ b/src/galaxy/api/errors.py @@ -1,6 +1,6 @@ from galaxy.api.jsonrpc import ApplicationError, UnknownError -UnknownError = UnknownError +assert UnknownError class AuthenticationRequired(ApplicationError): def __init__(self, data=None): diff --git a/src/galaxy/proc_tools.py b/src/galaxy/proc_tools.py index bba61d3..b0de0bc 100644 --- a/src/galaxy/proc_tools.py +++ b/src/galaxy/proc_tools.py @@ -1,11 +1,8 @@ -import platform +import sys from dataclasses import dataclass -from typing import Iterable, NewType, Optional, Set +from typing import Iterable, NewType, Optional, List, cast -def is_windows(): - return platform.system() == "Windows" - ProcessId = NewType("ProcessId", int) @@ -16,7 +13,7 @@ class ProcessInfo: binary_path: Optional[str] -if is_windows(): +if sys.platform == "win32": from ctypes import byref, sizeof, windll, create_unicode_buffer, FormatError, WinError from ctypes.wintypes import DWORD @@ -25,14 +22,14 @@ if is_windows(): _PROC_ID_T = DWORD list_size = 4096 - def try_get_pids(list_size: int) -> Set[ProcessId]: + def try_get_pids(list_size: int) -> List[ProcessId]: result_size = DWORD() proc_id_list = (_PROC_ID_T * list_size)() if not windll.psapi.EnumProcesses(byref(proc_id_list), sizeof(proc_id_list), byref(result_size)): - raise WinError(descr="Failed to get process ID list: %s" % FormatError()) + raise WinError(descr="Failed to get process ID list: %s" % FormatError()) # type: ignore - return proc_id_list[:int(result_size.value / sizeof(_PROC_ID_T()))] + return cast(List[ProcessId], proc_id_list[:int(result_size.value / sizeof(_PROC_ID_T()))]) while True: proc_ids = try_get_pids(list_size) @@ -59,7 +56,7 @@ if is_windows(): exe_path_buffer = create_unicode_buffer(_MAX_PATH) exe_path_len = DWORD(len(exe_path_buffer)) - return exe_path_buffer[:exe_path_len.value] if windll.kernel32.QueryFullProcessImageNameW( + return cast(str, exe_path_buffer[:exe_path_len.value]) if windll.kernel32.QueryFullProcessImageNameW( h_process, _WIN32_PATH_FORMAT, exe_path_buffer, byref(exe_path_len) ) else None @@ -86,6 +83,6 @@ else: return process_info -def process_iter() -> Iterable[ProcessInfo]: +def process_iter() -> Iterable[Optional[ProcessInfo]]: for pid in pids(): yield get_process_info(pid) diff --git a/tests/test_http.py b/tests/test_http.py index b9f2a3e..09aa136 100644 --- a/tests/test_http.py +++ b/tests/test_http.py @@ -3,6 +3,8 @@ from http import HTTPStatus import aiohttp import pytest +from multidict import CIMultiDict, CIMultiDictProxy +from yarl import URL from galaxy.api.errors import ( AccessDenied, AuthenticationRequired, BackendTimeout, BackendNotAvailable, BackendError, NetworkError, @@ -10,7 +12,7 @@ from galaxy.api.errors import ( ) from galaxy.http import handle_exception -request_info = aiohttp.RequestInfo("http://o.pl", "GET", {}) +request_info = aiohttp.RequestInfo(URL("http://o.pl"), "GET", CIMultiDictProxy(CIMultiDict())) @pytest.mark.parametrize( "aiohttp_exception,expected_exception_type", @@ -18,15 +20,15 @@ request_info = aiohttp.RequestInfo("http://o.pl", "GET", {}) (asyncio.TimeoutError(), BackendTimeout), (aiohttp.ServerDisconnectedError(), BackendNotAvailable), (aiohttp.ClientConnectionError(), NetworkError), - (aiohttp.ContentTypeError(request_info, []), UnknownBackendResponse), - (aiohttp.ClientResponseError(request_info, [], status=HTTPStatus.UNAUTHORIZED), AuthenticationRequired), - (aiohttp.ClientResponseError(request_info, [], status=HTTPStatus.FORBIDDEN), AccessDenied), - (aiohttp.ClientResponseError(request_info, [], status=HTTPStatus.SERVICE_UNAVAILABLE), BackendNotAvailable), - (aiohttp.ClientResponseError(request_info, [], status=HTTPStatus.TOO_MANY_REQUESTS), TooManyRequests), - (aiohttp.ClientResponseError(request_info, [], status=HTTPStatus.INTERNAL_SERVER_ERROR), BackendError), - (aiohttp.ClientResponseError(request_info, [], status=HTTPStatus.NOT_IMPLEMENTED), BackendError), - (aiohttp.ClientResponseError(request_info, [], status=HTTPStatus.BAD_REQUEST), UnknownError), - (aiohttp.ClientResponseError(request_info, [], status=HTTPStatus.NOT_FOUND), UnknownError), + (aiohttp.ContentTypeError(request_info, ()), UnknownBackendResponse), + (aiohttp.ClientResponseError(request_info, (), status=HTTPStatus.UNAUTHORIZED), AuthenticationRequired), + (aiohttp.ClientResponseError(request_info, (), status=HTTPStatus.FORBIDDEN), AccessDenied), + (aiohttp.ClientResponseError(request_info, (), status=HTTPStatus.SERVICE_UNAVAILABLE), BackendNotAvailable), + (aiohttp.ClientResponseError(request_info, (), status=HTTPStatus.TOO_MANY_REQUESTS), TooManyRequests), + (aiohttp.ClientResponseError(request_info, (), status=HTTPStatus.INTERNAL_SERVER_ERROR), BackendError), + (aiohttp.ClientResponseError(request_info, (), status=HTTPStatus.NOT_IMPLEMENTED), BackendError), + (aiohttp.ClientResponseError(request_info, (), status=HTTPStatus.BAD_REQUEST), UnknownError), + (aiohttp.ClientResponseError(request_info, (), status=HTTPStatus.NOT_FOUND), UnknownError), (aiohttp.ClientError(), UnknownError) ] )