From 71e82d576c252f420f47d6c73ce5f7d489ab7610 Mon Sep 17 00:00:00 2001 From: panjianxing <3207880464@qq.com> Date: Thu, 29 Oct 2026 20:58:55 +0800 Subject: [PATCH] fix(config): accept numeric string verbosity values Restore compatibility with pytest 9.1 for TOML verbosity options while keeping plugin-defined int | Literal unions strict. Add regression coverage for getini and get_verbosity with both integer and numeric string TOML values. Co-authored-by: Codex --- AUTHORS | 1 + changelog/15290.bugfix.rst | 3 +++ src/_pytest/config/__init__.py | 21 ++++++++++++++++++++- testing/test_config.py | 8 ++++++-- 4 files changed, 30 insertions(+), 3 deletions(-) create mode 100644 changelog/15290.bugfix.rst diff --git a/AUTHORS b/AUTHORS index 9e4327c7733..6615a4427f9 100644 --- a/AUTHORS +++ b/AUTHORS @@ -292,6 +292,7 @@ Liam DeVoe Llandy Riveron Del Risco Loic Esteve lovetheguitar +Lpk124 Luana Pinho Bueno Penha Lukas Bednar Luke Murphy diff --git a/changelog/15290.bugfix.rst b/changelog/15290.bugfix.rst new file mode 100644 index 00000000000..8a6ee86933e --- /dev/null +++ b/changelog/15290.bugfix.rst @@ -0,0 +1,3 @@ +TOML configuration again accepts numeric strings for the +:confval:`verbosity_assertions`, :confval:`verbosity_subtests`, and +:confval:`verbosity_test_cases` options. diff --git a/src/_pytest/config/__init__.py b/src/_pytest/config/__init__.py index 60ba5f54a89..d518e9daae5 100644 --- a/src/_pytest/config/__init__.py +++ b/src/_pytest/config/__init__.py @@ -1957,10 +1957,29 @@ def _getini(self, name: str): ) # Union: try each member; the first one that accepts the value wins. + coerce_toml_int_strings = name in { + Config._verbosity_ini_name(Config.VERBOSITY_ASSERTIONS), + Config._verbosity_ini_name(Config.VERBOSITY_SUBTESTS), + Config._verbosity_ini_name(Config.VERBOSITY_TEST_CASES), + } for member in type: try: + # Keep accepting numeric strings for built-in verbosity options. + member_value = ( + int(value) + if mode == "toml" + and member == "int" + and isinstance(value, str) + and coerce_toml_int_strings + else value + ) return self._getini_value( - mode, name, canonical_name, member, value, default + mode, + name, + canonical_name, + member, + member_value, + default, ) except (TypeError, ValueError): pass diff --git a/testing/test_config.py b/testing/test_config.py index 282e66409f7..7bb07c6d970 100644 --- a/testing/test_config.py +++ b/testing/test_config.py @@ -3599,8 +3599,11 @@ class TestNativeTomlOptionTypes: ("name", "toml_value", "ini_value", "expected"), [ ("verbosity_assertions", "2", "2", 2), + ("verbosity_assertions", '"2"', "2", 2), ("verbosity_assertions", '"auto"', "auto", "auto"), + ("verbosity_subtests", '"1"', "1", 1), ("verbosity_test_cases", "-1", "-1", -1), + ("verbosity_test_cases", '"-1"', "-1", -1), ("tmp_path_retention_count", "0", "0", 0), ("log_level", "10", "10", 10), ("log_level", '"INFO"', "INFO", "INFO"), @@ -3641,7 +3644,8 @@ def test_invalid_value(self, pytester: Pytester, name: str, value: str) -> None: with pytest.raises(UsageError, match=name): config.getini(name) - def test_get_verbosity(self, pytester: Pytester) -> None: - pytester.maketoml("[pytest]\nverbosity_assertions = 2\n") + @pytest.mark.parametrize("toml_value", ["2", '"2"']) + def test_get_verbosity(self, pytester: Pytester, toml_value: str) -> None: + pytester.maketoml(f"[pytest]\nverbosity_assertions = {toml_value}\n") config = pytester.parseconfig() assert config.get_verbosity(Config.VERBOSITY_ASSERTIONS) == 2