From 23c43a37e0f98310a3bf6a679fcff40fe130c18f Mon Sep 17 00:00:00 2001 From: Ronny Pfannschmidt Date: Fri, 28 Feb 2020 10:33:59 +0100 Subject: [PATCH] summarize warning summaries if the number of locations is high --- changelog/6834.feature.rst | 1 + src/_pytest/terminal.py | 30 ++++++++++++++----- .../test_group_warnings_by_message_summary.py | 21 +++++++++++++ testing/test_warnings.py | 18 +++++++++++ 4 files changed, 63 insertions(+), 7 deletions(-) create mode 100644 changelog/6834.feature.rst create mode 100644 testing/example_scripts/warnings/test_group_warnings_by_message_summary.py diff --git a/changelog/6834.feature.rst b/changelog/6834.feature.rst new file mode 100644 index 000000000..506814ef6 --- /dev/null +++ b/changelog/6834.feature.rst @@ -0,0 +1 @@ +Excess warning summaries are now collapsed per file to ensure readable display of warning summaries. diff --git a/src/_pytest/terminal.py b/src/_pytest/terminal.py index 4be5b8513..ed3576ed9 100644 --- a/src/_pytest/terminal.py +++ b/src/_pytest/terminal.py @@ -825,16 +825,32 @@ class TerminalReporter: for wr in warning_reports: reports_grouped_by_message.setdefault(wr.message, []).append(wr) - title = "warnings summary (final)" if final else "warnings summary" - self.write_sep("=", title, yellow=True, bold=False) - for message, warning_reports in reports_grouped_by_message.items(): - has_any_location = False + def collapsed_location_report(reports: List[WarningReport]): + locations = [] for w in warning_reports: location = w.get_location(self.config) if location: - self._tw.line(str(location)) - has_any_location = True - if has_any_location: + locations.append(location) + + if len(locations) < 10: + return "\n".join(map(str, locations)) + + counts_by_filename = collections.Counter( + str(loc).split("::", 1)[0] for loc in locations + ) + return "\n".join( + "{0}: {1} test{2} with warning{2}".format( + k, v, "s" if v > 1 else "" + ) + for k, v in counts_by_filename.items() + ) + + title = "warnings summary (final)" if final else "warnings summary" + self.write_sep("=", title, yellow=True, bold=False) + for message, warning_reports in reports_grouped_by_message.items(): + maybe_location = collapsed_location_report(warning_reports) + if maybe_location: + self._tw.line(maybe_location) lines = message.splitlines() indented = "\n".join(" " + x for x in lines) message = indented.rstrip() diff --git a/testing/example_scripts/warnings/test_group_warnings_by_message_summary.py b/testing/example_scripts/warnings/test_group_warnings_by_message_summary.py new file mode 100644 index 000000000..4f7df3d6d --- /dev/null +++ b/testing/example_scripts/warnings/test_group_warnings_by_message_summary.py @@ -0,0 +1,21 @@ +import warnings + +import pytest + + +def func(): + warnings.warn(UserWarning("foo")) + + +@pytest.fixture(params=range(20), autouse=True) +def repeat_hack(request): + return request.param + + +@pytest.mark.parametrize("i", range(5)) +def test_foo(i): + func() + + +def test_bar(): + func() diff --git a/testing/test_warnings.py b/testing/test_warnings.py index b05816073..5387c8d44 100644 --- a/testing/test_warnings.py +++ b/testing/test_warnings.py @@ -584,6 +584,24 @@ def test_group_warnings_by_message(testdir): assert result.stdout.str().count(warning_code) == 1 +@pytest.mark.filterwarnings("ignore::pytest.PytestExperimentalApiWarning") +@pytest.mark.filterwarnings("always") +def test_group_warnings_by_message_summary(testdir): + testdir.copy_example("warnings/test_group_warnings_by_message_summary.py") + result = testdir.runpytest() + result.stdout.fnmatch_lines( + [ + "*== %s ==*" % WARNINGS_SUMMARY_HEADER, + "test_group_warnings_by_message_summary.py: 120 tests with warnings", + "*test_group_warnings_by_message_summary.py:7: UserWarning: foo", + ], + consecutive=True, + ) + warning_code = 'warnings.warn(UserWarning("foo"))' + assert warning_code in result.stdout.str() + assert result.stdout.str().count(warning_code) == 1 + + def test_pytest_configure_warning(testdir, recwarn): """Issue 5115.""" testdir.makeconftest(