Skip to content

Commit 66eab40

Browse files
authored
Merge pull request #193 from dmtucker/reporting
Add --mypy-report-style
2 parents fadc662 + 9824747 commit 66eab40

File tree

2 files changed

+49
-21
lines changed

2 files changed

+49
-21
lines changed

src/pytest_mypy/__init__.py

+16-9
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,12 @@ def default_test_name_formatter(*, item: MypyFileItem) -> str:
6868
def default_file_error_formatter(
6969
item: MypyItem,
7070
results: MypyResults,
71-
errors: List[str],
71+
lines: List[str],
7272
) -> str:
7373
"""Create a string to be displayed when mypy finds errors in a file."""
74-
return "\n".join(errors)
74+
if item.config.option.mypy_report_style == "mypy":
75+
return "\n".join(lines)
76+
return "\n".join(line.partition(":")[2].strip() for line in lines)
7577

7678

7779
file_error_formatter = default_file_error_formatter
@@ -92,6 +94,16 @@ def pytest_addoption(parser: pytest.Parser) -> None:
9294
type=str,
9395
help="adds custom mypy config file",
9496
)
97+
styles = {
98+
"mypy": "modify the original mypy output as little as possible",
99+
"no-path": "(default) strip the path prefix from mypy errors",
100+
}
101+
group.addoption(
102+
"--mypy-report-style",
103+
choices=list(styles),
104+
help="change the way mypy output is reported:\n"
105+
+ "\n".join(f"- {name}: {desc}" for name, desc in styles.items()),
106+
)
95107
group.addoption(
96108
"--mypy-no-status-check",
97109
action="store_true",
@@ -175,6 +187,7 @@ def pytest_configure(config: pytest.Config) -> None:
175187
[
176188
config.option.mypy,
177189
config.option.mypy_config_file,
190+
config.option.mypy_report_style,
178191
config.option.mypy_ignore_missing_imports,
179192
config.option.mypy_no_status_check,
180193
config.option.mypy_xfail,
@@ -268,13 +281,7 @@ def runtest(self) -> None:
268281
reason="mypy errors are expected by --mypy-xfail.",
269282
)
270283
)
271-
raise MypyError(
272-
file_error_formatter(
273-
self,
274-
results,
275-
errors=[line.partition(":")[2].strip() for line in lines],
276-
)
277-
)
284+
raise MypyError(file_error_formatter(self, results, lines))
278285

279286
def reportinfo(self) -> Tuple[Path, None, str]:
280287
"""Produce a heading for the test report."""

tests/test_pytest_mypy.py

+33-12
Original file line numberDiff line numberDiff line change
@@ -399,32 +399,27 @@ def pyfunc(x: int) -> str:
399399
assert result.ret == pytest.ExitCode.TESTS_FAILED
400400

401401

402-
def test_api_error_formatter(testdir, xdist_args):
403-
"""Ensure that the plugin can be configured in a conftest.py."""
402+
def test_api_file_error_formatter(testdir, xdist_args):
403+
"""Ensure that the file_error_formatter can be replaced in a conftest.py."""
404404
testdir.makepyfile(
405405
bad="""
406406
def pyfunc(x: int) -> str:
407407
return x * 2
408408
""",
409409
)
410+
file_error = "UnmistakableFileError"
410411
testdir.makepyfile(
411-
conftest="""
412-
def custom_file_error_formatter(item, results, errors):
413-
return '\\n'.join(
414-
'{path}:{error}'.format(
415-
path=item.fspath,
416-
error=error,
417-
)
418-
for error in errors
419-
)
412+
conftest=f"""
413+
def custom_file_error_formatter(item, results, lines):
414+
return '{file_error}'
420415
421416
def pytest_configure(config):
422417
plugin = config.pluginmanager.getplugin('mypy')
423418
plugin.file_error_formatter = custom_file_error_formatter
424419
""",
425420
)
426421
result = testdir.runpytest_subprocess("--mypy", *xdist_args)
427-
result.stdout.fnmatch_lines(["*/bad.py:2: error: Incompatible return value*"])
422+
result.stdout.fnmatch_lines([f"*{file_error}*"])
428423
assert result.ret == pytest.ExitCode.TESTS_FAILED
429424

430425

@@ -671,3 +666,29 @@ def pytest_configure(config):
671666
def test_error_severity():
672667
"""Verify that non-error lines produce no severity."""
673668
assert pytest_mypy._error_severity("arbitrary line with no error") is None
669+
670+
671+
def test_mypy_report_style(testdir, xdist_args):
672+
"""Verify that --mypy-report-style functions correctly."""
673+
module_name = "unmistakable_module_name"
674+
testdir.makepyfile(
675+
**{
676+
module_name: """
677+
def pyfunc(x: int) -> str:
678+
return x * 2
679+
"""
680+
},
681+
)
682+
result = testdir.runpytest_subprocess("--mypy-report-style", "no-path", *xdist_args)
683+
mypy_file_checks = 1
684+
mypy_status_check = 1
685+
mypy_checks = mypy_file_checks + mypy_status_check
686+
result.assert_outcomes(failed=mypy_checks)
687+
result.stdout.fnmatch_lines(["2: error: Incompatible return value*"])
688+
assert result.ret == pytest.ExitCode.TESTS_FAILED
689+
result = testdir.runpytest_subprocess("--mypy-report-style", "mypy", *xdist_args)
690+
result.assert_outcomes(failed=mypy_checks)
691+
result.stdout.fnmatch_lines(
692+
[f"{module_name}.py:2: error: Incompatible return value*"]
693+
)
694+
assert result.ret == pytest.ExitCode.TESTS_FAILED

0 commit comments

Comments
 (0)