diff --git a/changelog.md b/changelog.md index 7fdccf1..d0393fe 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,8 @@ # Changelog +## [0.10.3](https://github.com/dbader/pytest-mypy/milestone/21) +* Stop failing if mypy only produces notes. + ## [0.10.2](https://github.com/dbader/pytest-mypy/milestone/20) * Update and loosen [build-system] requirements. diff --git a/src/pytest_mypy.py b/src/pytest_mypy.py index 668e9f1..faa02a7 100644 --- a/src/pytest_mypy.py +++ b/src/pytest_mypy.py @@ -5,6 +5,7 @@ from pathlib import Path from tempfile import NamedTemporaryFile from typing import Dict, List, Optional, TextIO +import warnings import attr from filelock import FileLock # type: ignore @@ -202,7 +203,13 @@ def runtest(self): abspath = os.path.abspath(str(self.fspath)) errors = results.abspath_errors.get(abspath) if errors: - raise MypyError(file_error_formatter(self, results, errors)) + if not all( + error.partition(":")[2].partition(":")[0].strip() == "note" + for error in errors + ): + raise MypyError(file_error_formatter(self, results, errors)) + # This line cannot be easily covered on mypy < 0.990: + warnings.warn("\n" + "\n".join(errors), MypyWarning) # pragma: no cover def reportinfo(self): """Produce a heading for the test report.""" @@ -314,6 +321,10 @@ class MypyError(Exception): """ +class MypyWarning(pytest.PytestWarning): + """A non-failure message regarding the mypy run.""" + + def pytest_terminal_summary(terminalreporter, config): """Report stderr and unrecognized lines from stdout.""" try: diff --git a/tests/test_pytest_mypy.py b/tests/test_pytest_mypy.py index 0f10dc5..6e86af3 100644 --- a/tests/test_pytest_mypy.py +++ b/tests/test_pytest_mypy.py @@ -98,6 +98,33 @@ def pyfunc(x: int) -> str: assert result.ret != 0 +def test_mypy_annotation_unchecked(testdir, xdist_args): + """Verify that annotation-unchecked warnings do not manifest as an error.""" + testdir.makepyfile( + """ + def pyfunc(x): + y: int = 2 + return x * y + """, + ) + result = testdir.runpytest_subprocess(*xdist_args) + result.assert_outcomes() + result = testdir.runpytest_subprocess("--mypy", *xdist_args) + mypy_file_checks = 1 + mypy_status_check = 1 + mypy_checks = mypy_file_checks + mypy_status_check + outcomes = {"passed": mypy_checks} + # mypy doesn't emit annotation-unchecked warnings until 0.990: + min_mypy_version = Version("0.990") + if MYPY_VERSION >= min_mypy_version and PYTEST_VERSION >= Version("7.0"): + # assert_outcomes does not support `warnings` until 7.x. + outcomes["warnings"] = 1 + result.assert_outcomes(**outcomes) + if MYPY_VERSION >= min_mypy_version: + result.stdout.fnmatch_lines(["*MypyWarning*"]) + assert result.ret == 0 + + def test_mypy_ignore_missings_imports(testdir, xdist_args): """ Verify that --mypy-ignore-missing-imports