diff --git a/changelog/14808.deprecation.rst b/changelog/14808.deprecation.rst new file mode 100644 index 00000000000..ad53b0084a9 --- /dev/null +++ b/changelog/14808.deprecation.rst @@ -0,0 +1 @@ +Passing a non-string value to a ``string``-typed ini option now emits a ``pytest.PytestRemovedIn10Warning``. This affects ``[tool.pytest.ini_options]`` in ``pyproject.toml``, where TOML arrays are kept as lists by ``make_scalar`` instead of being converted to strings. In pytest 10 this will raise a ``TypeError``, matching the behavior of the corresponding TOML config path. diff --git a/src/_pytest/config/__init__.py b/src/_pytest/config/__init__.py index 688cc8a9054..f11cc309170 100644 --- a/src/_pytest/config/__init__.py +++ b/src/_pytest/config/__init__.py @@ -1878,6 +1878,11 @@ def _getini_ini( elif type == "bool": return _strtobool(str(value).strip()) elif type == "string": + if not isinstance(value, str): + warnings.warn( + _pytest.deprecated.INI_STRING_TYPE_NON_STR_VALUE, + stacklevel=2, + ) return value elif type == "int": if not isinstance(value, str): diff --git a/src/_pytest/deprecated.py b/src/_pytest/deprecated.py index f46b036affe..85a98cd1f95 100644 --- a/src/_pytest/deprecated.py +++ b/src/_pytest/deprecated.py @@ -96,6 +96,14 @@ "See https://docs.pytest.org/en/stable/deprecations.html#the-pastebin-option" ) +INI_STRING_TYPE_NON_STR_VALUE = PytestRemovedIn10Warning( + "Passing a value that is not a string to a 'string'-typed ini option is deprecated.\n" + "In a future version this will raise a TypeError, matching the behavior of the " + "corresponding TOML config path.\n" + "If your plugin intentionally accepts non-string values, declare an explicit type " + '(e.g. type="args") instead of relying on the implicit string default.' +) + # You want to make some `__init__` or function "private". # # def my_private_function(some, args): diff --git a/testing/test_config.py b/testing/test_config.py index 5d19627bca7..751b7ea76e7 100644 --- a/testing/test_config.py +++ b/testing/test_config.py @@ -1089,6 +1089,30 @@ def pytest_addoption(parser): ): _ = config.getini("ini_param") + def test_addini_string_non_str_deprecated(self, pytester: Pytester) -> None: + """Passing a non-string value to a 'string'-typed ini option emits a + deprecation warning. The value is still returned as-is for now, but will + raise TypeError in pytest 10.""" + pytester.makeconftest( + """ + def pytest_addoption(parser): + parser.addini("myname", "", type="string") + """ + ) + pytester.makepyprojecttoml( + """ + [tool.pytest.ini_options] + myname = ["value1", "value2"] + """ + ) + config = pytester.parseconfig() + with pytest.warns( + pytest.PytestRemovedIn10Warning, + match="Passing a value that is not a string to a 'string'-typed ini option", + ): + result = config.getini("myname") + assert result == ["value1", "value2"] + UNION_CONFTEST = """ def pytest_addoption(parser): parser.addini("ini_param", "", type=int | str, default=None)