diff --git a/AUTHORS b/AUTHORS index 0d7b43ba711..229e4315078 100644 --- a/AUTHORS +++ b/AUTHORS @@ -19,6 +19,7 @@ Alejandro Villate Alessio Izzo Alex Jones Alex Lambson +Alex Chen Alexander Johnson Alexander King Alexei Kozlenok diff --git a/changelog/14724.improvement.rst b/changelog/14724.improvement.rst new file mode 100644 index 00000000000..cc4bac6ea8c --- /dev/null +++ b/changelog/14724.improvement.rst @@ -0,0 +1,4 @@ +``--no-summary`` now only applies directly to pytest's own summary. + +The flag no longer skips the ``pytest_terminal_summary`` hook, so third-party +plugins (for example coverage) can still write their terminal summaries. diff --git a/src/_pytest/terminal.py b/src/_pytest/terminal.py index b9a65ff191e..e46f8fb4c20 100644 --- a/src/_pytest/terminal.py +++ b/src/_pytest/terminal.py @@ -968,7 +968,10 @@ def pytest_sessionfinish( ExitCode.NO_TESTS_COLLECTED, ExitCode.MAX_WARNINGS_ERROR, ) - if exitstatus in summary_exit_codes and not self.no_summary: + # Always invoke pytest_terminal_summary so third-party plugins can report + # (e.g. coverage). --no-summary only suppresses TerminalReporter's own + # built-in summary sections; see TerminalReporter.pytest_terminal_summary. + if exitstatus in summary_exit_codes: self.config.hook.pytest_terminal_summary( terminalreporter=self, exitstatus=exitstatus, config=self.config ) @@ -995,18 +998,23 @@ def pytest_sessionfinish( @hookimpl(wrapper=True) def pytest_terminal_summary(self) -> Generator[None]: - self.summary_errors() - self.summary_failures() - self.summary_xfailures() - self.summary_warnings() - self.summary_passes() - self.summary_xpasses() + # With --no-summary, still yield so other plugins run their terminal + # summaries, but skip pytest's own FAILURES/ERRORS/... sections. + show_summary = not self.no_summary + if show_summary: + self.summary_errors() + self.summary_failures() + self.summary_xfailures() + self.summary_warnings() + self.summary_passes() + self.summary_xpasses() try: return (yield) finally: - self.short_test_summary() - # Display any extra warnings from teardown here (if any). - self.summary_warnings() + if show_summary: + self.short_test_summary() + # Display any extra warnings from teardown here (if any). + self.summary_warnings() def pytest_keyboard_interrupt(self, excinfo: ExceptionInfo[BaseException]) -> None: self._keyboardinterrupt_memo = excinfo.getrepr(funcargs=True) diff --git a/testing/test_terminal.py b/testing/test_terminal.py index 3053f5ef9a1..de1dfbbda3d 100644 --- a/testing/test_terminal.py +++ b/testing/test_terminal.py @@ -1015,6 +1015,21 @@ def test_no_summary(): result = pytester.runpytest(p1, "--no-summary") result.stdout.no_fnmatch_line("*= FAILURES =*") + def test_no_summary_still_runs_terminal_summary_hook( + self, pytester: Pytester + ) -> None: + """--no-summary must not skip pytest_terminal_summary for plugins (#14724).""" + pytester.makeconftest( + """ + def pytest_terminal_summary(terminalreporter, exitstatus, config): + terminalreporter.write_line("PLUGIN_TERMINAL_SUMMARY_RAN") + """ + ) + p1 = pytester.makepyfile("def test_ok(): assert True") + result = pytester.runpytest(p1, "--no-summary") + result.stdout.fnmatch_lines(["PLUGIN_TERMINAL_SUMMARY_RAN"]) + result.stdout.no_fnmatch_line("*= FAILURES =*") + def test_showlocals(self, pytester: Pytester) -> None: p1 = pytester.makepyfile( """