Skip to content

Commit 139ca47

Browse files
authored
Merge pull request #182 from dmtucker/refactor-warning
Remove MypyWarning
2 parents e84607e + 8c794f2 commit 139ca47

File tree

2 files changed

+47
-34
lines changed

2 files changed

+47
-34
lines changed

Diff for: src/pytest_mypy/__init__.py

+41-30
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
from pathlib import Path
88
from tempfile import NamedTemporaryFile
99
import typing
10-
import warnings
1110

1211
from filelock import FileLock
1312
import mypy.api
@@ -227,28 +226,34 @@ def repr_failure(
227226
return super().repr_failure(excinfo)
228227

229228

229+
def _error_severity(error: str) -> str:
230+
components = [component.strip() for component in error.split(":")]
231+
# The second component is either the line or the severity:
232+
# demo/note.py:2: note: By default the bodies of untyped functions are not checked
233+
# demo/sub/conftest.py: error: Duplicate module named "conftest"
234+
return components[2] if components[1].isdigit() else components[1]
235+
236+
230237
class MypyFileItem(MypyItem):
231238
"""A check for Mypy errors in a File."""
232239

233240
def runtest(self) -> None:
234241
"""Raise an exception if mypy found errors for this item."""
235242
results = MypyResults.from_session(self.session)
236-
abspath = str(self.path.absolute())
237-
errors = results.abspath_errors.get(abspath)
238-
if errors:
239-
if not all(
240-
error.partition(":")[2].partition(":")[0].strip() == "note"
241-
for error in errors
242-
):
243-
if self.session.config.option.mypy_xfail:
244-
self.add_marker(
245-
pytest.mark.xfail(
246-
raises=MypyError,
247-
reason="mypy errors are expected by --mypy-xfail.",
248-
)
243+
abspath = str(self.path.resolve())
244+
errors = [
245+
error.partition(":")[2].strip()
246+
for error in results.abspath_errors.get(abspath, [])
247+
]
248+
if errors and not all(_error_severity(error) == "note" for error in errors):
249+
if self.session.config.option.mypy_xfail:
250+
self.add_marker(
251+
pytest.mark.xfail(
252+
raises=MypyError,
253+
reason="mypy errors are expected by --mypy-xfail.",
249254
)
250-
raise MypyError(file_error_formatter(self, results, errors))
251-
warnings.warn("\n" + "\n".join(errors), MypyWarning)
255+
)
256+
raise MypyError(file_error_formatter(self, results, errors))
252257

253258
def reportinfo(self) -> Tuple[str, None, str]:
254259
"""Produce a heading for the test report."""
@@ -312,7 +317,7 @@ def from_mypy(
312317
if opts is None:
313318
opts = mypy_argv[:]
314319
abspath_errors = {
315-
str(path.absolute()): [] for path in paths
320+
str(path.resolve()): [] for path in paths
316321
} # type: MypyResults._abspath_errors_type
317322

318323
cwd = Path.cwd()
@@ -325,9 +330,9 @@ def from_mypy(
325330
if not line:
326331
continue
327332
path, _, error = line.partition(":")
328-
abspath = str(Path(path).absolute())
333+
abspath = str(Path(path).resolve())
329334
try:
330-
abspath_errors[abspath].append(error)
335+
abspath_errors[abspath].append(line)
331336
except KeyError:
332337
unmatched_lines.append(line)
333338

@@ -368,10 +373,6 @@ class MypyError(Exception):
368373
"""
369374

370375

371-
class MypyWarning(pytest.PytestWarning):
372-
"""A non-failure message regarding the mypy run."""
373-
374-
375376
class MypyControllerPlugin:
376377
"""A plugin that is not registered on xdist worker processes."""
377378

@@ -388,15 +389,25 @@ def pytest_terminal_summary(
388389
except FileNotFoundError:
389390
# No MypyItems executed.
390391
return
391-
if config.option.mypy_xfail or results.unmatched_stdout or results.stderr:
392-
terminalreporter.section(terminal_summary_title)
392+
if not results.stdout and not results.stderr:
393+
return
394+
terminalreporter.section(terminal_summary_title)
395+
if results.stdout:
393396
if config.option.mypy_xfail:
394397
terminalreporter.write(results.stdout)
395-
elif results.unmatched_stdout:
396-
color = {"red": True} if results.status else {"green": True}
397-
terminalreporter.write_line(results.unmatched_stdout, **color)
398-
if results.stderr:
399-
terminalreporter.write_line(results.stderr, yellow=True)
398+
else:
399+
for note in (
400+
unreported_note
401+
for errors in results.abspath_errors.values()
402+
if all(_error_severity(error) == "note" for error in errors)
403+
for unreported_note in errors
404+
):
405+
terminalreporter.write_line(note)
406+
if results.unmatched_stdout:
407+
color = {"red": True} if results.status else {"green": True}
408+
terminalreporter.write_line(results.unmatched_stdout, **color)
409+
if results.stderr:
410+
terminalreporter.write_line(results.stderr, yellow=True)
400411

401412
def pytest_unconfigure(self, config: pytest.Config) -> None:
402413
"""Clean up the mypy results path."""

Diff for: tests/test_pytest_mypy.py

+6-4
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,9 @@ def pyfunc(x):
130130
mypy_checks = mypy_file_checks + mypy_status_check
131131
outcomes = {"passed": mypy_checks}
132132
result.assert_outcomes(**outcomes)
133-
result.stdout.fnmatch_lines(["*MypyWarning*"])
133+
result.stdout.fnmatch_lines(
134+
["*:2: note: By default the bodies of untyped functions are not checked*"]
135+
)
134136
assert result.ret == pytest.ExitCode.OK
135137

136138

@@ -552,7 +554,7 @@ def test_py_typed(testdir):
552554

553555
def test_mypy_no_status_check(testdir, xdist_args):
554556
"""Verify that --mypy-no-status-check disables MypyStatusItem collection."""
555-
testdir.makepyfile(thon="one: int = 1")
557+
testdir.makepyfile("one: int = 1")
556558
result = testdir.runpytest_subprocess("--mypy", *xdist_args)
557559
mypy_file_checks = 1
558560
mypy_status_check = 1
@@ -565,7 +567,7 @@ def test_mypy_no_status_check(testdir, xdist_args):
565567

566568
def test_mypy_xfail_passes(testdir, xdist_args):
567569
"""Verify that --mypy-xfail passes passes."""
568-
testdir.makepyfile(thon="one: int = 1")
570+
testdir.makepyfile("one: int = 1")
569571
result = testdir.runpytest_subprocess("--mypy", *xdist_args)
570572
mypy_file_checks = 1
571573
mypy_status_check = 1
@@ -578,7 +580,7 @@ def test_mypy_xfail_passes(testdir, xdist_args):
578580

579581
def test_mypy_xfail_xfails(testdir, xdist_args):
580582
"""Verify that --mypy-xfail xfails failures."""
581-
testdir.makepyfile(thon="one: str = 1")
583+
testdir.makepyfile("one: str = 1")
582584
result = testdir.runpytest_subprocess("--mypy", *xdist_args)
583585
mypy_file_checks = 1
584586
mypy_status_check = 1

0 commit comments

Comments
 (0)