From 7e5c1b631df47629b62171f856bdcd1c684eae81 Mon Sep 17 00:00:00 2001 From: Julian Valentin <128477611+JulianJvn@users.noreply.github.com> Date: Thu, 2 Jan 2025 08:31:08 +0100 Subject: [PATCH 1/6] Fix -vv overriding --durations-min (#12938) --- AUTHORS | 1 + changelog/12938.bugfix.rst | 1 + src/_pytest/runner.py | 14 +++++++++--- testing/acceptance_test.py | 44 ++++++++++++++++++++++++-------------- 4 files changed, 41 insertions(+), 19 deletions(-) create mode 100644 changelog/12938.bugfix.rst diff --git a/AUTHORS b/AUTHORS index 9629e00bcfb..f9bade5f0fa 100644 --- a/AUTHORS +++ b/AUTHORS @@ -225,6 +225,7 @@ Joseph Hunkeler Joseph Sawaya Josh Karpel Joshua Bronson +Julian Valentin Jurko Gospodnetić Justice Ndou Justyna Janczyszyn diff --git a/changelog/12938.bugfix.rst b/changelog/12938.bugfix.rst new file mode 100644 index 00000000000..d54d73bdbf5 --- /dev/null +++ b/changelog/12938.bugfix.rst @@ -0,0 +1 @@ +Fixed ``--durations-min`` argument not respected if ``-vv`` is used. diff --git a/src/_pytest/runner.py b/src/_pytest/runner.py index d2b7fda8c2a..973892f2c92 100644 --- a/src/_pytest/runner.py +++ b/src/_pytest/runner.py @@ -61,7 +61,7 @@ def pytest_addoption(parser: Parser) -> None: "--durations-min", action="store", type=float, - default=0.005, + default=None, metavar="N", help="Minimal duration in seconds for inclusion in slowest list. " "Default: 0.005.", @@ -74,6 +74,8 @@ def pytest_terminal_summary(terminalreporter: TerminalReporter) -> None: verbose = terminalreporter.config.get_verbosity() if durations is None: return + if durations_min is None: + durations_min = 0.005 if verbose < 2 else 0.0 tr = terminalreporter dlist = [] for replist in tr.stats.values(): @@ -90,10 +92,16 @@ def pytest_terminal_summary(terminalreporter: TerminalReporter) -> None: dlist = dlist[:durations] for i, rep in enumerate(dlist): - if verbose < 2 and rep.duration < durations_min: + if rep.duration < durations_min: tr.write_line("") tr.write_line( - f"({len(dlist) - i} durations < {durations_min:g}s hidden. Use -vv to show these durations.)" + f"({len(dlist) - i} durations < {durations_min:g}s hidden." + + ( + " Use -vv to show these durations." + if terminalreporter.config.option.durations_min is None + else "" + ) + + ")" ) break tr.write_line(f"{rep.duration:02.2f}s {rep.when:<8} {rep.nodeid}") diff --git a/testing/acceptance_test.py b/testing/acceptance_test.py index ba1f86f02d9..a42940c9f6a 100644 --- a/testing/acceptance_test.py +++ b/testing/acceptance_test.py @@ -1,6 +1,7 @@ # mypy: allow-untyped-defs from __future__ import annotations +from collections.abc import Sequence import dataclasses import importlib.metadata import os @@ -970,28 +971,39 @@ def test_calls_showall(self, pytester: Pytester, mock_timing) -> None: pytester.makepyfile(self.source) result = pytester.runpytest_inprocess("--durations=0") assert result.ret == 0 - - tested = "3" - for x in tested: - for y in ("call",): # 'setup', 'call', 'teardown': - for line in result.stdout.lines: - if (f"test_{x}") in line and y in line: - break - else: - raise AssertionError(f"not found {x} {y}") + print(result.stdout) + TestDurations.check_tests_in_output(result.stdout.lines, "23") def test_calls_showall_verbose(self, pytester: Pytester, mock_timing) -> None: pytester.makepyfile(self.source) result = pytester.runpytest_inprocess("--durations=0", "-vv") assert result.ret == 0 + TestDurations.check_tests_in_output(result.stdout.lines, "123") - for x in "123": - for y in ("call",): # 'setup', 'call', 'teardown': - for line in result.stdout.lines: - if (f"test_{x}") in line and y in line: - break - else: - raise AssertionError(f"not found {x} {y}") + def test_calls_showall_durationsmin(self, pytester: Pytester, mock_timing) -> None: + pytester.makepyfile(self.source) + result = pytester.runpytest_inprocess("--durations=0", "--durations-min=0.015") + assert result.ret == 0 + TestDurations.check_tests_in_output(result.stdout.lines, "3") + + def test_calls_showall_durationsmin_verbose( + self, pytester: Pytester, mock_timing + ) -> None: + pytester.makepyfile(self.source) + result = pytester.runpytest_inprocess( + "--durations=0", "--durations-min=0.015", "-vv" + ) + assert result.ret == 0 + TestDurations.check_tests_in_output(result.stdout.lines, "3") + + @staticmethod + def check_tests_in_output(lines: Sequence[str], expected_test_numbers: str) -> None: + found_test_numbers = "".join( + test_number + for test_number in "123" + if any(f"test_{test_number}" in line and " call " in line for line in lines) + ) + assert found_test_numbers == expected_test_numbers def test_with_deselected(self, pytester: Pytester, mock_timing) -> None: pytester.makepyfile(self.source) From 30e7ad9aed0989a1047f1beeec198ba12eda51a4 Mon Sep 17 00:00:00 2001 From: Julian Valentin <128477611+JulianJvn@users.noreply.github.com> Date: Thu, 2 Jan 2025 18:39:52 +0100 Subject: [PATCH 2/6] Remove leftover debug print in acceptance_test --- testing/acceptance_test.py | 1 - 1 file changed, 1 deletion(-) diff --git a/testing/acceptance_test.py b/testing/acceptance_test.py index a42940c9f6a..4fed0f015d1 100644 --- a/testing/acceptance_test.py +++ b/testing/acceptance_test.py @@ -971,7 +971,6 @@ def test_calls_showall(self, pytester: Pytester, mock_timing) -> None: pytester.makepyfile(self.source) result = pytester.runpytest_inprocess("--durations=0") assert result.ret == 0 - print(result.stdout) TestDurations.check_tests_in_output(result.stdout.lines, "23") def test_calls_showall_verbose(self, pytester: Pytester, mock_timing) -> None: From 61b4f7a157cab3da8e444bd3b5c81a9413a39b7b Mon Sep 17 00:00:00 2001 From: Julian Valentin <128477611+JulianJvn@users.noreply.github.com> Date: Thu, 2 Jan 2025 18:39:52 +0100 Subject: [PATCH 3/6] Clarify --durations-min default in help text --- src/_pytest/runner.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/_pytest/runner.py b/src/_pytest/runner.py index 973892f2c92..98090f3b4c6 100644 --- a/src/_pytest/runner.py +++ b/src/_pytest/runner.py @@ -64,7 +64,7 @@ def pytest_addoption(parser: Parser) -> None: default=None, metavar="N", help="Minimal duration in seconds for inclusion in slowest list. " - "Default: 0.005.", + "Default: 0.005 (or 0.0 if -vv is given).", ) From a811765b21bc428273fc054f553d8be5b19da2b0 Mon Sep 17 00:00:00 2001 From: Julian Valentin <128477611+JulianJvn@users.noreply.github.com> Date: Thu, 2 Jan 2025 18:39:52 +0100 Subject: [PATCH 4/6] Simplify message formatting --- src/_pytest/runner.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/_pytest/runner.py b/src/_pytest/runner.py index 98090f3b4c6..f0543289267 100644 --- a/src/_pytest/runner.py +++ b/src/_pytest/runner.py @@ -94,15 +94,11 @@ def pytest_terminal_summary(terminalreporter: TerminalReporter) -> None: for i, rep in enumerate(dlist): if rep.duration < durations_min: tr.write_line("") - tr.write_line( - f"({len(dlist) - i} durations < {durations_min:g}s hidden." - + ( - " Use -vv to show these durations." - if terminalreporter.config.option.durations_min is None - else "" - ) - + ")" - ) + message = f"({len(dlist) - i} durations < {durations_min:g}s hidden." + if terminalreporter.config.option.durations_min is None: + message += " Use -vv to show these durations." + message += ")" + tr.write_line(message) break tr.write_line(f"{rep.duration:02.2f}s {rep.when:<8} {rep.nodeid}") From 071bfb3d04408d2ccb9c7966347eda061b3a8762 Mon Sep 17 00:00:00 2001 From: Julian Valentin <128477611+JulianJvn@users.noreply.github.com> Date: Tue, 7 Jan 2025 08:39:40 +0100 Subject: [PATCH 5/6] Supply test numbers instead of string Use `endswith()` because the code would break for `number_of_tests >= 10` (as `test_10` also contains `test_1`). --- testing/acceptance_test.py | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/testing/acceptance_test.py b/testing/acceptance_test.py index 4fed0f015d1..06b97c34707 100644 --- a/testing/acceptance_test.py +++ b/testing/acceptance_test.py @@ -971,19 +971,19 @@ def test_calls_showall(self, pytester: Pytester, mock_timing) -> None: pytester.makepyfile(self.source) result = pytester.runpytest_inprocess("--durations=0") assert result.ret == 0 - TestDurations.check_tests_in_output(result.stdout.lines, "23") + TestDurations.check_tests_in_output(result.stdout.lines, 2, 3) def test_calls_showall_verbose(self, pytester: Pytester, mock_timing) -> None: pytester.makepyfile(self.source) result = pytester.runpytest_inprocess("--durations=0", "-vv") assert result.ret == 0 - TestDurations.check_tests_in_output(result.stdout.lines, "123") + TestDurations.check_tests_in_output(result.stdout.lines, 1, 2, 3) def test_calls_showall_durationsmin(self, pytester: Pytester, mock_timing) -> None: pytester.makepyfile(self.source) result = pytester.runpytest_inprocess("--durations=0", "--durations-min=0.015") assert result.ret == 0 - TestDurations.check_tests_in_output(result.stdout.lines, "3") + TestDurations.check_tests_in_output(result.stdout.lines, 3) def test_calls_showall_durationsmin_verbose( self, pytester: Pytester, mock_timing @@ -993,16 +993,22 @@ def test_calls_showall_durationsmin_verbose( "--durations=0", "--durations-min=0.015", "-vv" ) assert result.ret == 0 - TestDurations.check_tests_in_output(result.stdout.lines, "3") + TestDurations.check_tests_in_output(result.stdout.lines, 3) @staticmethod - def check_tests_in_output(lines: Sequence[str], expected_test_numbers: str) -> None: - found_test_numbers = "".join( + def check_tests_in_output( + lines: Sequence[str], *expected_test_numbers: int + ) -> None: + number_of_tests = 3 + found_test_numbers = set( test_number - for test_number in "123" - if any(f"test_{test_number}" in line and " call " in line for line in lines) + for test_number in range(1, number_of_tests + 1) + if any( + line.endswith(f"test_{test_number}") and " call " in line + for line in lines + ) ) - assert found_test_numbers == expected_test_numbers + assert found_test_numbers == set(expected_test_numbers) def test_with_deselected(self, pytester: Pytester, mock_timing) -> None: pytester.makepyfile(self.source) From 0d077e640cb7d347f63c44026659b2ec46ab3e59 Mon Sep 17 00:00:00 2001 From: Julian Valentin <128477611+JulianJvn@users.noreply.github.com> Date: Tue, 7 Jan 2025 14:22:27 +0100 Subject: [PATCH 6/6] Move number_of_tests to parameters --- testing/acceptance_test.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/testing/acceptance_test.py b/testing/acceptance_test.py index 06b97c34707..ffd1dcce219 100644 --- a/testing/acceptance_test.py +++ b/testing/acceptance_test.py @@ -997,9 +997,8 @@ def test_calls_showall_durationsmin_verbose( @staticmethod def check_tests_in_output( - lines: Sequence[str], *expected_test_numbers: int + lines: Sequence[str], *expected_test_numbers: int, number_of_tests: int = 3 ) -> None: - number_of_tests = 3 found_test_numbers = set( test_number for test_number in range(1, number_of_tests + 1)