From 4c2b1287327c085972042e4d0de36ef476017c40 Mon Sep 17 00:00:00 2001 From: Maxim Kurnikov Date: Fri, 13 Dec 2019 12:34:28 +0300 Subject: [PATCH] enable mypy strict checks --- mypy.ini | 7 ++++++- pytest_mypy/collect.py | 15 +++++++++++---- pytest_mypy/item.py | 8 +++++--- pytest_mypy/utils.py | 23 ++++++++++++----------- 4 files changed, 34 insertions(+), 19 deletions(-) diff --git a/mypy.ini b/mypy.ini index 49836a7..0d40d3b 100644 --- a/mypy.ini +++ b/mypy.ini @@ -1,3 +1,8 @@ [mypy] ignore_missing_imports = True -strict_optional = True \ No newline at end of file +# strict checks +strict_optional = True +disallow_any_generics = True +disallow_untyped_defs = True +warn_unused_ignores = True +strict_equality = True \ No newline at end of file diff --git a/pytest_mypy/collect.py b/pytest_mypy/collect.py index ae26c67..c9fe53f 100644 --- a/pytest_mypy/collect.py +++ b/pytest_mypy/collect.py @@ -1,13 +1,19 @@ import tempfile -from typing import Any, Dict, List +from typing import Any, Dict, List, Iterator, TYPE_CHECKING, Optional import pytest import yaml from _pytest.config.argparsing import Parser +from _pytest.nodes import Node +from py._path.local import LocalPath from pytest_mypy import utils from pytest_mypy.utils import string_to_bool +if TYPE_CHECKING: + from pytest_mypy.item import YamlTestItem + + class File: def __init__(self, path: str, content: str): @@ -36,7 +42,7 @@ def parse_environment_variables(env_vars: List[str]) -> Dict[str, str]: class SafeLineLoader(yaml.SafeLoader): - def construct_mapping(self, node, deep=False): + def construct_mapping(self, node: yaml.Node, deep: bool = False) -> None: mapping = super().construct_mapping(node, deep=deep) # Add 1 so line numbering starts at 1 starting_line = node.start_mark.line + 1 @@ -48,7 +54,7 @@ def construct_mapping(self, node, deep=False): class YamlTestFile(pytest.File): - def collect(self): + def collect(self) -> Iterator['YamlTestItem']: from pytest_mypy.item import YamlTestItem parsed_file = yaml.load(stream=self.fspath.read_text('utf8'), Loader=SafeLineLoader) @@ -93,9 +99,10 @@ def collect(self): mypy_config=additional_mypy_config) -def pytest_collect_file(path, parent): +def pytest_collect_file(path: LocalPath, parent: Node) -> Optional[YamlTestFile]: if path.ext in {'.yaml', '.yml'} and path.basename.startswith(('test-', 'test_')): return YamlTestFile(path, parent=parent, config=parent.config) + return None def pytest_addoption(parser: Parser) -> None: diff --git a/pytest_mypy/item.py b/pytest_mypy/item.py index 39e28d1..41f7896 100644 --- a/pytest_mypy/item.py +++ b/pytest_mypy/item.py @@ -14,6 +14,8 @@ from mypy import build from mypy.fscache import FileSystemCache from mypy.main import process_options +from py._io.terminalwriter import TerminalWriter + from pytest_mypy import utils from pytest_mypy.collect import File, YamlTestFile from pytest_mypy.utils import ( @@ -25,7 +27,7 @@ class TraceLastReprEntry(ReprEntry): - def toterminal(self, tw): + def toterminal(self, tw: TerminalWriter) -> None: self.reprfileloc.toterminal(tw) for line in self.lines: red = line.startswith("E ") @@ -199,7 +201,7 @@ def execute_extension_hook(self) -> None: extension_hook = getattr(module, func_name) extension_hook(self) - def runtest(self): + def runtest(self) -> None: try: temp_dir = tempfile.TemporaryDirectory(prefix='pytest-mypy-', dir=self.root_directory) @@ -309,5 +311,5 @@ def repr_failure(self, excinfo: ExceptionInfo) -> str: else: return super().repr_failure(excinfo, style='native') - def reportinfo(self): + def reportinfo(self) -> Tuple[str, Optional[str], str]: return self.fspath, None, self.name diff --git a/pytest_mypy/utils.py b/pytest_mypy/utils.py index 98b908c..a680c9f 100644 --- a/pytest_mypy/utils.py +++ b/pytest_mypy/utils.py @@ -7,13 +7,13 @@ import re import sys from pathlib import Path -from typing import Callable, Iterator, List, Optional, Tuple +from typing import Callable, Iterator, List, Optional, Tuple, Union from decorator import contextmanager @contextmanager -def temp_environ(): +def temp_environ() -> Iterator[None]: """Allow the ability to set os.environ temporarily""" environ = dict(os.environ) try: @@ -24,7 +24,7 @@ def temp_environ(): @contextmanager -def temp_path(): +def temp_path() -> Iterator[None]: """A context manager which allows the ability to set sys.path temporarily""" path = sys.path[:] try: @@ -34,7 +34,7 @@ def temp_path(): @contextmanager -def temp_sys_modules(): +def temp_sys_modules() -> Iterator[None]: sys_modules = sys.modules.copy() try: yield @@ -56,14 +56,14 @@ def fname_to_module(fpath: Path, root_path: Path) -> Optional[str]: class TypecheckAssertionError(AssertionError): - def __init__(self, error_message: Optional[str] = None, lineno: int = 0): - self.error_message = error_message + def __init__(self, error_message: Optional[str] = None, lineno: int = 0) -> None: + self.error_message = error_message or '' self.lineno = lineno - def first_line(self): + def first_line(self) -> str: return self.__class__.__name__ + '(message="Invalid output")' - def __str__(self): + def __str__(self) -> str: return self.error_message @@ -258,7 +258,8 @@ def assert_string_arrays_equal(expected: List[str], actual: List[str]) -> None: lineno=lineno) -def build_output_line(fname: str, lnum: int, severity: str, message: str, col=None) -> str: +def build_output_line(fname: str, lnum: int, severity: str, message: str, + col: Optional[str] = None) -> str: if col is None: return f'{fname}:{lnum + 1}: {severity}: {message}' else: @@ -294,7 +295,7 @@ def extract_errors_from_comments(fname: str, input_lines: List[str]) -> List[str def get_func_first_lnum(attr: Callable[..., None]) -> Optional[Tuple[int, List[str]]]: - lines, _ = inspect.getsourcelines(attr) # type: ignore[arg-type] + lines, _ = inspect.getsourcelines(attr) for lnum, line in enumerate(lines): no_space_line = line.strip() if f'def {attr.__name__}' in no_space_line: @@ -303,7 +304,7 @@ def get_func_first_lnum(attr: Callable[..., None]) -> Optional[Tuple[int, List[s @contextmanager -def cd(path): +def cd(path: Union[str, Path]) -> Iterator[None]: """Context manager to temporarily change working directories""" if not path: return