From 162c0c436a0650b46d68559ea79a5a307a282dbf Mon Sep 17 00:00:00 2001 From: Mike Fiedler Date: Wed, 8 Apr 2026 19:15:56 -0400 Subject: [PATCH 1/6] Add --max-warnings option to fail test runs Allow users to set a maximum number of allowed warnings via --max-warnings CLI option or max_warnings config option. When the warning count exceeds the threshold and all tests pass, pytest exits with a new WARNINGS_ERROR exit code (6). This supports gradually ratcheting down warnings in a codebase without converting them all to errors. Based on the pytest-max-warnings plugin by @miketheman, with improvements: a dedicated ExitCode instead of an arbitrary exit code, and INI config support. Closes #14371 Signed-off-by: Mike Fiedler --- AUTHORS | 1 + changelog/14371.feature.rst | 1 + doc/en/how-to/capture-warnings.rst | 36 +++++++++++++ doc/en/reference/exit-codes.rst | 3 +- doc/en/reference/reference.rst | 36 +++++++++++++ src/_pytest/config/__init__.py | 2 + src/_pytest/main.py | 13 +++++ src/_pytest/terminal.py | 22 ++++++++ testing/test_warnings.py | 85 ++++++++++++++++++++++++++++++ 9 files changed, 198 insertions(+), 1 deletion(-) create mode 100644 changelog/14371.feature.rst diff --git a/AUTHORS b/AUTHORS index f3c8d016c28..c33cf5fafbd 100644 --- a/AUTHORS +++ b/AUTHORS @@ -325,6 +325,7 @@ Michał Zięba Mickey Pashov Mihai Capotă Mihail Milushev +Mike Fiedler (miketheman) Mike Hoyle (hoylemd) Mike Lundy Milan Lesnek diff --git a/changelog/14371.feature.rst b/changelog/14371.feature.rst new file mode 100644 index 00000000000..dbfd8636d9f --- /dev/null +++ b/changelog/14371.feature.rst @@ -0,0 +1 @@ +Added :option:`--max-warnings` command-line option and :confval:`max_warnings` configuration option to fail the test run when the number of warnings exceeds a given threshold. diff --git a/doc/en/how-to/capture-warnings.rst b/doc/en/how-to/capture-warnings.rst index daaf8937e1a..7ce588d7298 100644 --- a/doc/en/how-to/capture-warnings.rst +++ b/doc/en/how-to/capture-warnings.rst @@ -204,6 +204,42 @@ decorator or to all tests in a module by setting the :globalvar:`pytestmark` var .. _`pytest-warnings`: https://github.com/fschulze/pytest-warnings +Setting a maximum number of warnings +------------------------------------- + +You can use the :option:`--max-warnings` command-line option to fail the test run +if the total number of warnings exceeds a given threshold: + +.. code-block:: bash + + pytest --max-warnings 10 + +If the number of warnings exceeds the threshold, pytest will exit with code ``6`` +(:class:`~pytest.ExitCode` ``WARNINGS_ERROR``). This is useful for gradually +ratcheting down warnings in a codebase. + +The threshold can also be set in the configuration file using :confval:`max_warnings`: + +.. tab:: toml + + .. code-block:: toml + + [pytest] + max_warnings = 10 + +.. tab:: ini + + .. code-block:: ini + + [pytest] + max_warnings = 10 + +.. note:: + + If tests fail, the exit code will be ``1`` (:class:`~pytest.ExitCode` ``TESTS_FAILED``) + regardless of the warning count. ``WARNINGS_ERROR`` is only reported when all tests pass + but the warning threshold is exceeded. + Disabling warnings summary -------------------------- diff --git a/doc/en/reference/exit-codes.rst b/doc/en/reference/exit-codes.rst index 49aaca19121..485bd4fe20a 100644 --- a/doc/en/reference/exit-codes.rst +++ b/doc/en/reference/exit-codes.rst @@ -3,7 +3,7 @@ Exit codes ======================================================== -Running ``pytest`` can result in six different exit codes: +Running ``pytest`` can result in seven different exit codes: :Exit code 0: All tests were collected and passed successfully :Exit code 1: Tests were collected and run but some of the tests failed @@ -11,6 +11,7 @@ Running ``pytest`` can result in six different exit codes: :Exit code 3: Internal error happened while executing tests :Exit code 4: pytest command line usage error :Exit code 5: No tests were collected +:Exit code 6: Maximum number of warnings exceeded (see :option:`--max-warnings`) They are represented by the :class:`pytest.ExitCode` enum. The exit codes being a part of the public API can be imported and accessed directly using: diff --git a/doc/en/reference/reference.rst b/doc/en/reference/reference.rst index c1df110e822..0b347cc08ef 100644 --- a/doc/en/reference/reference.rst +++ b/doc/en/reference/reference.rst @@ -1630,6 +1630,31 @@ passed multiple times. The expected format is ``name=value``. For example:: into errors. For more information please refer to :ref:`warnings`. +.. confval:: max_warnings + :type: ``int`` + + Maximum number of warnings allowed before the test run is considered a failure. + When the total number of warnings exceeds this value, pytest exits with + :class:`pytest.ExitCode` ``WARNINGS_ERROR`` (code ``6``). + + .. tab:: toml + + .. code-block:: toml + + [pytest] + max_warnings = 10 + + .. tab:: ini + + .. code-block:: ini + + [pytest] + max_warnings = 10 + + Can also be set via the :option:`--max-warnings` command-line option. + For more information please refer to :ref:`warnings`. + + .. confval:: junit_duration_report :type: ``str`` :default: ``"total"`` @@ -3121,6 +3146,12 @@ Warnings Set which warnings to report, see ``-W`` option of Python itself. Can be specified multiple times. +.. option:: --max-warnings=NUM + + Exit with :class:`pytest.ExitCode` ``WARNINGS_ERROR`` (code ``6``) if the number + of warnings exceeds the given threshold. By default there is no limit. + Can also be set via the :confval:`max_warnings` configuration option. + Doctest ~~~~~~~ @@ -3409,6 +3440,8 @@ All the command-line flags can also be obtained by running ``pytest --help``:: -W, --pythonwarnings PYTHONWARNINGS Set which warnings to report, see -W option of Python itself + --max-warnings=num Exit with error if the number of warnings exceeds + this threshold collection: --collect-only, --co Only collect tests, don't execute them @@ -3531,6 +3564,9 @@ All the command-line flags can also be obtained by running ``pytest --help``:: Each line specifies a pattern for warnings.filterwarnings. Processed after -W/--pythonwarnings. + max_warnings (string): + Maximum number of warnings allowed before failing + the test run norecursedirs (args): Directory patterns to avoid for recursion testpaths (args): Directories to search for tests when no files or directories are given on the command line diff --git a/src/_pytest/config/__init__.py b/src/_pytest/config/__init__.py index f7c4de5d7e9..0936201b1fb 100644 --- a/src/_pytest/config/__init__.py +++ b/src/_pytest/config/__init__.py @@ -117,6 +117,8 @@ class ExitCode(enum.IntEnum): USAGE_ERROR = 4 #: pytest couldn't find tests. NO_TESTS_COLLECTED = 5 + #: Maximum number of warnings exceeded. + WARNINGS_ERROR = 6 __module__ = "pytest" diff --git a/src/_pytest/main.py b/src/_pytest/main.py index 02c7fb373fd..50d3bb80974 100644 --- a/src/_pytest/main.py +++ b/src/_pytest/main.py @@ -125,6 +125,15 @@ def pytest_addoption(parser: Parser) -> None: action="append", help="Set which warnings to report, see -W option of Python itself", ) + group.addoption( + "--max-warnings", + action="store", + type=int, + default=None, + metavar="num", + dest="max_warnings", + help="Exit with error if the number of warnings exceeds this threshold", + ) parser.addini( "filterwarnings", type="linelist", @@ -132,6 +141,10 @@ def pytest_addoption(parser: Parser) -> None: "warnings.filterwarnings. " "Processed after -W/--pythonwarnings.", ) + parser.addini( + "max_warnings", + help="Maximum number of warnings allowed before failing the test run", + ) group = parser.getgroup("collect", "collection") group.addoption( diff --git a/src/_pytest/terminal.py b/src/_pytest/terminal.py index e9049bb82ec..a0d46a566c9 100644 --- a/src/_pytest/terminal.py +++ b/src/_pytest/terminal.py @@ -966,11 +966,23 @@ def pytest_sessionfinish( ExitCode.INTERRUPTED, ExitCode.USAGE_ERROR, ExitCode.NO_TESTS_COLLECTED, + ExitCode.WARNINGS_ERROR, ) if exitstatus in summary_exit_codes and not self.no_summary: self.config.hook.pytest_terminal_summary( terminalreporter=self, exitstatus=exitstatus, config=self.config ) + # Check --max-warnings threshold after all warnings have been collected. + max_warnings = self._get_max_warnings() + if max_warnings is not None and session.exitstatus == ExitCode.OK: + warning_count = len(self.stats.get("warnings", [])) + if warning_count > max_warnings: + session.exitstatus = ExitCode.WARNINGS_ERROR + self.write_line( + f"Maximum allowed warnings exceeded: " + f"{warning_count} > {max_warnings}", + red=True, + ) if session.shouldfail: self.write_sep("!", str(session.shouldfail), red=True) if exitstatus == ExitCode.INTERRUPTED: @@ -1057,6 +1069,16 @@ def _getcrashline(self, rep): except AttributeError: return "" + def _get_max_warnings(self) -> int | None: + """Return the max_warnings threshold, from CLI or INI, or None if unset.""" + value = self.config.option.max_warnings + if value is not None: + return int(value) + ini_value = self.config.getini("max_warnings") + if ini_value: + return int(ini_value) + return None + # # Summaries for sessionfinish. # diff --git a/testing/test_warnings.py b/testing/test_warnings.py index 2625f0959e6..0b7a5104fe0 100644 --- a/testing/test_warnings.py +++ b/testing/test_warnings.py @@ -5,6 +5,7 @@ import sys import warnings +from _pytest.config import ExitCode from _pytest.fixtures import FixtureRequest from _pytest.pytester import Pytester import pytest @@ -885,3 +886,87 @@ def test_resource_warning(tmp_path): else [] ) result.stdout.fnmatch_lines([*expected_extra, "*1 passed*"]) + + +class TestMaxWarnings: + """Tests for the --max-warnings feature.""" + + PYFILE = """ + import warnings + def test_one(): + warnings.warn(UserWarning("warning one")) + def test_two(): + warnings.warn(UserWarning("warning two")) + """ + + @pytest.mark.filterwarnings("default::UserWarning") + def test_max_warnings_not_set(self, pytester: Pytester) -> None: + """Without --max-warnings, warnings don't affect exit code.""" + pytester.makepyfile(self.PYFILE) + result = pytester.runpytest() + result.assert_outcomes(passed=2, warnings=2) + assert result.ret == ExitCode.OK + + @pytest.mark.filterwarnings("default::UserWarning") + def test_max_warnings_not_exceeded(self, pytester: Pytester) -> None: + """When warning count is below the threshold, exit code is OK.""" + pytester.makepyfile(self.PYFILE) + result = pytester.runpytest("--max-warnings", "10") + result.assert_outcomes(passed=2, warnings=2) + assert result.ret == ExitCode.OK + + @pytest.mark.filterwarnings("default::UserWarning") + def test_max_warnings_exceeded(self, pytester: Pytester) -> None: + """When warning count exceeds threshold, exit code is WARNINGS_ERROR.""" + pytester.makepyfile(self.PYFILE) + result = pytester.runpytest("--max-warnings", "1") + assert result.ret == ExitCode.WARNINGS_ERROR + + @pytest.mark.filterwarnings("default::UserWarning") + def test_max_warnings_equal_to_count(self, pytester: Pytester) -> None: + """When warning count equals threshold exactly, exit code is OK.""" + pytester.makepyfile(self.PYFILE) + result = pytester.runpytest("--max-warnings", "2") + result.assert_outcomes(passed=2, warnings=2) + assert result.ret == ExitCode.OK + + @pytest.mark.filterwarnings("default::UserWarning") + def test_max_warnings_zero(self, pytester: Pytester) -> None: + """--max-warnings 0 means no warnings are allowed.""" + pytester.makepyfile(self.PYFILE) + result = pytester.runpytest("--max-warnings", "0") + assert result.ret == ExitCode.WARNINGS_ERROR + + @pytest.mark.filterwarnings("default::UserWarning") + def test_max_warnings_exceeded_message(self, pytester: Pytester) -> None: + """Verify the output message when max warnings is exceeded.""" + pytester.makepyfile(self.PYFILE) + result = pytester.runpytest("--max-warnings", "1") + result.stdout.fnmatch_lines(["*Maximum allowed warnings exceeded: 2 > 1*"]) + + @pytest.mark.filterwarnings("default::UserWarning") + def test_max_warnings_ini_option(self, pytester: Pytester) -> None: + """max_warnings can be set via INI configuration.""" + pytester.makeini( + """ + [pytest] + max_warnings = 1 + """ + ) + pytester.makepyfile(self.PYFILE) + result = pytester.runpytest() + assert result.ret == ExitCode.WARNINGS_ERROR + + @pytest.mark.filterwarnings("default::UserWarning") + def test_max_warnings_with_test_failure(self, pytester: Pytester) -> None: + """When tests fail AND warnings exceed max, TESTS_FAILED takes priority.""" + pytester.makepyfile( + """ + import warnings + def test_fail(): + warnings.warn(UserWarning("a warning")) + assert False + """ + ) + result = pytester.runpytest("--max-warnings", "0") + assert result.ret == ExitCode.TESTS_FAILED From 60e336cbd8f06c5279f2a099a12d3a0671a5fe84 Mon Sep 17 00:00:00 2001 From: Mike Fiedler Date: Sat, 11 Apr 2026 09:16:41 -0400 Subject: [PATCH 2/6] apply suggestions from feedback - documentation improvements - test cases with filterwarnings Signed-off-by: Mike Fiedler --- changelog/14371.feature.rst | 2 +- doc/en/how-to/capture-warnings.rst | 6 ++- doc/en/reference/reference.rst | 7 +-- src/_pytest/config/__init__.py | 2 +- src/_pytest/main.py | 4 +- src/_pytest/terminal.py | 2 +- testing/test_warnings.py | 70 +++++++++++++++++++++++++++++- 7 files changed, 82 insertions(+), 11 deletions(-) diff --git a/changelog/14371.feature.rst b/changelog/14371.feature.rst index dbfd8636d9f..2993b8c536f 100644 --- a/changelog/14371.feature.rst +++ b/changelog/14371.feature.rst @@ -1 +1 @@ -Added :option:`--max-warnings` command-line option and :confval:`max_warnings` configuration option to fail the test run when the number of warnings exceeds a given threshold. +Added :option:`--max-warnings` command-line option and :confval:`max_warnings` configuration option to fail the test run when the number of warnings exceeds a given threshold -- by :user:`miketheman`. diff --git a/doc/en/how-to/capture-warnings.rst b/doc/en/how-to/capture-warnings.rst index 7ce588d7298..37443288ac2 100644 --- a/doc/en/how-to/capture-warnings.rst +++ b/doc/en/how-to/capture-warnings.rst @@ -212,12 +212,14 @@ if the total number of warnings exceeds a given threshold: .. code-block:: bash - pytest --max-warnings 10 + pytest --max-warnings=10 -If the number of warnings exceeds the threshold, pytest will exit with code ``6`` +If all tests pass but the number of warnings exceeds the threshold, pytest will exit with code ``6`` (:class:`~pytest.ExitCode` ``WARNINGS_ERROR``). This is useful for gradually ratcheting down warnings in a codebase. +Note that :confval:`filtered warnings ` do not count toward this maximum total. + The threshold can also be set in the configuration file using :confval:`max_warnings`: .. tab:: toml diff --git a/doc/en/reference/reference.rst b/doc/en/reference/reference.rst index 0b347cc08ef..e9cd92f4f52 100644 --- a/doc/en/reference/reference.rst +++ b/doc/en/reference/reference.rst @@ -1634,7 +1634,7 @@ passed multiple times. The expected format is ``name=value``. For example:: :type: ``int`` Maximum number of warnings allowed before the test run is considered a failure. - When the total number of warnings exceeds this value, pytest exits with + When all tests pass, but the total number of warnings exceeds this value, pytest exits with :class:`pytest.ExitCode` ``WARNINGS_ERROR`` (code ``6``). .. tab:: toml @@ -1651,8 +1651,9 @@ passed multiple times. The expected format is ``name=value``. For example:: [pytest] max_warnings = 10 + Note that :confval:`filtered warnings ` do not count toward this maximum total. + Can also be set via the :option:`--max-warnings` command-line option. - For more information please refer to :ref:`warnings`. .. confval:: junit_duration_report @@ -3148,7 +3149,7 @@ Warnings .. option:: --max-warnings=NUM - Exit with :class:`pytest.ExitCode` ``WARNINGS_ERROR`` (code ``6``) if the number + Exit with :class:`pytest.ExitCode` ``WARNINGS_ERROR`` (code ``6``) if all the tests pass, but the number of warnings exceeds the given threshold. By default there is no limit. Can also be set via the :confval:`max_warnings` configuration option. diff --git a/src/_pytest/config/__init__.py b/src/_pytest/config/__init__.py index 0936201b1fb..60430c79f88 100644 --- a/src/_pytest/config/__init__.py +++ b/src/_pytest/config/__init__.py @@ -117,7 +117,7 @@ class ExitCode(enum.IntEnum): USAGE_ERROR = 4 #: pytest couldn't find tests. NO_TESTS_COLLECTED = 5 - #: Maximum number of warnings exceeded. + #: All tests pass, but maximum number of warnings exceeded. WARNINGS_ERROR = 6 __module__ = "pytest" diff --git a/src/_pytest/main.py b/src/_pytest/main.py index 50d3bb80974..c4df4e46983 100644 --- a/src/_pytest/main.py +++ b/src/_pytest/main.py @@ -132,7 +132,7 @@ def pytest_addoption(parser: Parser) -> None: default=None, metavar="num", dest="max_warnings", - help="Exit with error if the number of warnings exceeds this threshold", + help="Exit with error if all tests pass but the number of warnings exceeds this threshold", ) parser.addini( "filterwarnings", @@ -143,7 +143,7 @@ def pytest_addoption(parser: Parser) -> None: ) parser.addini( "max_warnings", - help="Maximum number of warnings allowed before failing the test run", + help="Exit with error if all tests pass but the number of warnings exceeds this threshold", ) group = parser.getgroup("collect", "collection") diff --git a/src/_pytest/terminal.py b/src/_pytest/terminal.py index a0d46a566c9..c3ef3d07de5 100644 --- a/src/_pytest/terminal.py +++ b/src/_pytest/terminal.py @@ -979,7 +979,7 @@ def pytest_sessionfinish( if warning_count > max_warnings: session.exitstatus = ExitCode.WARNINGS_ERROR self.write_line( - f"Maximum allowed warnings exceeded: " + "Tests pass, but maximum allowed warnings exceeded: " f"{warning_count} > {max_warnings}", red=True, ) diff --git a/testing/test_warnings.py b/testing/test_warnings.py index 0b7a5104fe0..c7c6e82a257 100644 --- a/testing/test_warnings.py +++ b/testing/test_warnings.py @@ -942,7 +942,9 @@ def test_max_warnings_exceeded_message(self, pytester: Pytester) -> None: """Verify the output message when max warnings is exceeded.""" pytester.makepyfile(self.PYFILE) result = pytester.runpytest("--max-warnings", "1") - result.stdout.fnmatch_lines(["*Maximum allowed warnings exceeded: 2 > 1*"]) + result.stdout.fnmatch_lines( + ["*Tests pass, but maximum allowed warnings exceeded: 2 > 1*"] + ) @pytest.mark.filterwarnings("default::UserWarning") def test_max_warnings_ini_option(self, pytester: Pytester) -> None: @@ -970,3 +972,69 @@ def test_fail(): ) result = pytester.runpytest("--max-warnings", "0") assert result.ret == ExitCode.TESTS_FAILED + + @pytest.mark.filterwarnings("default::UserWarning") + def test_max_warnings_with_filterwarnings_ignore(self, pytester: Pytester) -> None: + """Filtered (ignored) warnings don't count toward max_warnings.""" + pytester.makepyfile( + """ + import warnings + def test_one(): + warnings.warn(UserWarning("counted")) + warnings.warn(RuntimeWarning("ignored")) + """ + ) + result = pytester.runpytest( + "--max-warnings", + "1", + "-W", + "ignore::RuntimeWarning", + ) + result.assert_outcomes(passed=1, warnings=1) + assert result.ret == ExitCode.OK + + @pytest.mark.filterwarnings("default::UserWarning") + def test_max_warnings_with_filterwarnings_error(self, pytester: Pytester) -> None: + """Warnings turned into errors via filterwarnings don't count as warnings.""" + pytester.makepyfile( + """ + import warnings + def test_one(): + warnings.warn(UserWarning("still a warning")) + def test_two(): + warnings.warn(RuntimeWarning("becomes an error")) + """ + ) + result = pytester.runpytest( + "--max-warnings", + "0", + "-W", + "error::RuntimeWarning", + ) + # The RuntimeWarning becomes a test error, so TESTS_FAILED takes priority. + assert result.ret == ExitCode.TESTS_FAILED + + @pytest.mark.filterwarnings("default::UserWarning") + def test_max_warnings_with_filterwarnings_ini_ignore( + self, pytester: Pytester + ) -> None: + """Warnings ignored via ini filterwarnings don't count toward max_warnings.""" + pytester.makeini( + """ + [pytest] + filterwarnings = + ignore::RuntimeWarning + max_warnings = 1 + """ + ) + pytester.makepyfile( + """ + import warnings + def test_one(): + warnings.warn(UserWarning("counted")) + warnings.warn(RuntimeWarning("ignored by ini")) + """ + ) + result = pytester.runpytest() + result.assert_outcomes(passed=1, warnings=1) + assert result.ret == ExitCode.OK From efb27c99d9ca91e78da2973a40d8ce7aff351de6 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Sat, 11 Apr 2026 10:50:26 -0300 Subject: [PATCH 3/6] Apply suggestion from @nicoddemus --- doc/en/how-to/capture-warnings.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/en/how-to/capture-warnings.rst b/doc/en/how-to/capture-warnings.rst index 37443288ac2..5ee2ff44d20 100644 --- a/doc/en/how-to/capture-warnings.rst +++ b/doc/en/how-to/capture-warnings.rst @@ -207,6 +207,8 @@ decorator or to all tests in a module by setting the :globalvar:`pytestmark` var Setting a maximum number of warnings ------------------------------------- +.. versionadded:: 9.1 + You can use the :option:`--max-warnings` command-line option to fail the test run if the total number of warnings exceeds a given threshold: From 06ac3d5d01179fcec63a55cad2fb1ecf6217b288 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Sat, 11 Apr 2026 10:51:10 -0300 Subject: [PATCH 4/6] Apply suggestion from @nicoddemus --- doc/en/reference/reference.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/en/reference/reference.rst b/doc/en/reference/reference.rst index e9cd92f4f52..dc4345ad727 100644 --- a/doc/en/reference/reference.rst +++ b/doc/en/reference/reference.rst @@ -1632,6 +1632,8 @@ passed multiple times. The expected format is ``name=value``. For example:: .. confval:: max_warnings :type: ``int`` + + .. versionadded:: 9.1 Maximum number of warnings allowed before the test run is considered a failure. When all tests pass, but the total number of warnings exceeds this value, pytest exits with From 72e2e77dee808800430af43b522aa3eab21b9414 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 11 Apr 2026 13:51:28 +0000 Subject: [PATCH 5/6] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- doc/en/reference/reference.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/en/reference/reference.rst b/doc/en/reference/reference.rst index dc4345ad727..b49746b8df5 100644 --- a/doc/en/reference/reference.rst +++ b/doc/en/reference/reference.rst @@ -1632,7 +1632,7 @@ passed multiple times. The expected format is ``name=value``. For example:: .. confval:: max_warnings :type: ``int`` - + .. versionadded:: 9.1 Maximum number of warnings allowed before the test run is considered a failure. From 38d2b0fe28babd690abcdf2371bd1a8551a7f0b7 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Sat, 11 Apr 2026 11:17:10 -0300 Subject: [PATCH 6/6] Rename ExitCode.WARNINGS_ERROR to ExitCode.MAX_WARNINGS_ERROR --- doc/en/how-to/capture-warnings.rst | 4 ++-- doc/en/reference/reference.rst | 4 ++-- src/_pytest/config/__init__.py | 2 +- src/_pytest/terminal.py | 4 ++-- testing/test_warnings.py | 8 ++++---- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/doc/en/how-to/capture-warnings.rst b/doc/en/how-to/capture-warnings.rst index 5ee2ff44d20..462146a1c2b 100644 --- a/doc/en/how-to/capture-warnings.rst +++ b/doc/en/how-to/capture-warnings.rst @@ -217,7 +217,7 @@ if the total number of warnings exceeds a given threshold: pytest --max-warnings=10 If all tests pass but the number of warnings exceeds the threshold, pytest will exit with code ``6`` -(:class:`~pytest.ExitCode` ``WARNINGS_ERROR``). This is useful for gradually +(:class:`~pytest.ExitCode` ``MAX_WARNINGS_ERROR``). This is useful for gradually ratcheting down warnings in a codebase. Note that :confval:`filtered warnings ` do not count toward this maximum total. @@ -241,7 +241,7 @@ The threshold can also be set in the configuration file using :confval:`max_warn .. note:: If tests fail, the exit code will be ``1`` (:class:`~pytest.ExitCode` ``TESTS_FAILED``) - regardless of the warning count. ``WARNINGS_ERROR`` is only reported when all tests pass + regardless of the warning count. ``MAX_WARNINGS_ERROR`` is only reported when all tests pass but the warning threshold is exceeded. Disabling warnings summary diff --git a/doc/en/reference/reference.rst b/doc/en/reference/reference.rst index b49746b8df5..a24c41b34c3 100644 --- a/doc/en/reference/reference.rst +++ b/doc/en/reference/reference.rst @@ -1637,7 +1637,7 @@ passed multiple times. The expected format is ``name=value``. For example:: Maximum number of warnings allowed before the test run is considered a failure. When all tests pass, but the total number of warnings exceeds this value, pytest exits with - :class:`pytest.ExitCode` ``WARNINGS_ERROR`` (code ``6``). + :class:`pytest.ExitCode` ``MAX_WARNINGS_ERROR`` (code ``6``). .. tab:: toml @@ -3151,7 +3151,7 @@ Warnings .. option:: --max-warnings=NUM - Exit with :class:`pytest.ExitCode` ``WARNINGS_ERROR`` (code ``6``) if all the tests pass, but the number + Exit with :class:`pytest.ExitCode` ``MAX_WARNINGS_ERROR`` (code ``6``) if all the tests pass, but the number of warnings exceeds the given threshold. By default there is no limit. Can also be set via the :confval:`max_warnings` configuration option. diff --git a/src/_pytest/config/__init__.py b/src/_pytest/config/__init__.py index 60430c79f88..47e85df0951 100644 --- a/src/_pytest/config/__init__.py +++ b/src/_pytest/config/__init__.py @@ -118,7 +118,7 @@ class ExitCode(enum.IntEnum): #: pytest couldn't find tests. NO_TESTS_COLLECTED = 5 #: All tests pass, but maximum number of warnings exceeded. - WARNINGS_ERROR = 6 + MAX_WARNINGS_ERROR = 6 __module__ = "pytest" diff --git a/src/_pytest/terminal.py b/src/_pytest/terminal.py index c3ef3d07de5..b9a65ff191e 100644 --- a/src/_pytest/terminal.py +++ b/src/_pytest/terminal.py @@ -966,7 +966,7 @@ def pytest_sessionfinish( ExitCode.INTERRUPTED, ExitCode.USAGE_ERROR, ExitCode.NO_TESTS_COLLECTED, - ExitCode.WARNINGS_ERROR, + ExitCode.MAX_WARNINGS_ERROR, ) if exitstatus in summary_exit_codes and not self.no_summary: self.config.hook.pytest_terminal_summary( @@ -977,7 +977,7 @@ def pytest_sessionfinish( if max_warnings is not None and session.exitstatus == ExitCode.OK: warning_count = len(self.stats.get("warnings", [])) if warning_count > max_warnings: - session.exitstatus = ExitCode.WARNINGS_ERROR + session.exitstatus = ExitCode.MAX_WARNINGS_ERROR self.write_line( "Tests pass, but maximum allowed warnings exceeded: " f"{warning_count} > {max_warnings}", diff --git a/testing/test_warnings.py b/testing/test_warnings.py index c7c6e82a257..d4a5038d5d2 100644 --- a/testing/test_warnings.py +++ b/testing/test_warnings.py @@ -917,10 +917,10 @@ def test_max_warnings_not_exceeded(self, pytester: Pytester) -> None: @pytest.mark.filterwarnings("default::UserWarning") def test_max_warnings_exceeded(self, pytester: Pytester) -> None: - """When warning count exceeds threshold, exit code is WARNINGS_ERROR.""" + """When warning count exceeds threshold, exit code is MAX_WARNINGS_ERROR.""" pytester.makepyfile(self.PYFILE) result = pytester.runpytest("--max-warnings", "1") - assert result.ret == ExitCode.WARNINGS_ERROR + assert result.ret == ExitCode.MAX_WARNINGS_ERROR @pytest.mark.filterwarnings("default::UserWarning") def test_max_warnings_equal_to_count(self, pytester: Pytester) -> None: @@ -935,7 +935,7 @@ def test_max_warnings_zero(self, pytester: Pytester) -> None: """--max-warnings 0 means no warnings are allowed.""" pytester.makepyfile(self.PYFILE) result = pytester.runpytest("--max-warnings", "0") - assert result.ret == ExitCode.WARNINGS_ERROR + assert result.ret == ExitCode.MAX_WARNINGS_ERROR @pytest.mark.filterwarnings("default::UserWarning") def test_max_warnings_exceeded_message(self, pytester: Pytester) -> None: @@ -957,7 +957,7 @@ def test_max_warnings_ini_option(self, pytester: Pytester) -> None: ) pytester.makepyfile(self.PYFILE) result = pytester.runpytest() - assert result.ret == ExitCode.WARNINGS_ERROR + assert result.ret == ExitCode.MAX_WARNINGS_ERROR @pytest.mark.filterwarnings("default::UserWarning") def test_max_warnings_with_test_failure(self, pytester: Pytester) -> None: