From 57dcfb7f332138ea4ef8005726bcc6c6985ef492 Mon Sep 17 00:00:00 2001 From: Sharad Nair <134932980+SharadNair7@users.noreply.github.com> Date: Tue, 7 Nov 2023 18:23:23 +0530 Subject: [PATCH] Fixes issue #11282 --- changelog/11282.bugfix.rst | 3 ++ src/_pytest/config/__init__.py | 6 +--- src/_pytest/config/argparsing.py | 24 +++++++++++++++- testing/test_config.py | 47 ++++++++++++++++++++++++++++++++ 4 files changed, 74 insertions(+), 6 deletions(-) create mode 100644 changelog/11282.bugfix.rst diff --git a/changelog/11282.bugfix.rst b/changelog/11282.bugfix.rst new file mode 100644 index 000000000..5b7a8b48a --- /dev/null +++ b/changelog/11282.bugfix.rst @@ -0,0 +1,3 @@ +Fixed returning "None" as the default value for a config option when "None" is explicitly +provided as the default while creating the config option. If no default value is provided +at the time of creating the config option, then a default based on the option type is returned \ No newline at end of file diff --git a/src/_pytest/config/__init__.py b/src/_pytest/config/__init__.py index 447ebc42a..24ef491cd 100644 --- a/src/_pytest/config/__init__.py +++ b/src/_pytest/config/__init__.py @@ -1521,11 +1521,7 @@ class Config: try: value = self.inicfg[name] except KeyError: - if default is not None: - return default - if type is None: - return "" - return [] + return default else: value = override_value # Coerce the values based on types. diff --git a/src/_pytest/config/argparsing.py b/src/_pytest/config/argparsing.py index e345de016..664367d6c 100644 --- a/src/_pytest/config/argparsing.py +++ b/src/_pytest/config/argparsing.py @@ -27,6 +27,14 @@ from _pytest.deprecated import check_ispytest FILE_OR_DIR = "file_or_dir" +class Notset: + def __repr__(self) -> str: + return "" + + +notset = Notset() + + @final class Parser: """Parser for command line arguments and ini-file values. @@ -176,7 +184,7 @@ class Parser: type: Optional[ Literal["string", "paths", "pathlist", "args", "linelist", "bool"] ] = None, - default: Any = None, + default: Any = notset, ) -> None: """Register an ini-file option. @@ -203,6 +211,20 @@ class Parser: :py:func:`config.getini(name) `. """ assert type in (None, "string", "paths", "pathlist", "args", "linelist", "bool") + if default is notset: + if type is None: + default = "" + else: + if type in ["paths", "pathlist", "args", "linelist"]: + default = [] + elif type == "bool": + default = False + elif type == "string": + default = "" + else: + # unknown type will default to None + default = None + self._inidict[name] = (help, type, default) self._ininames.append(name) diff --git a/testing/test_config.py b/testing/test_config.py index ded307901..52fb1e0ae 100644 --- a/testing/test_config.py +++ b/testing/test_config.py @@ -857,6 +857,53 @@ class TestConfigAPI: assert len(values) == 2 assert values == ["456", "123"] + def test_addini_default_values(self, pytester: Pytester) -> None: + """Tests the default values for configuration based on + config type + """ + + pytester.makeconftest( + """ + def pytest_addoption(parser): + parser.addini("linelist1", "", type="linelist") + parser.addini("paths1", "", type="paths") + parser.addini("pathlist1", "", type="pathlist") + parser.addini("args1", "", type="args") + parser.addini("bool1", "", type="bool") + parser.addini("string1", "", type="string") + parser.addini("none_1", "", type="linelist", default=None) + parser.addini("none_2", "", default=None) + parser.addini("no_type", "") + """ + ) + + config = pytester.parseconfig() + # default for linelist, paths, pathlist and args is [] + value = config.getini("linelist1") + assert value == [] + value = config.getini("paths1") + assert value == [] + value = config.getini("pathlist1") + assert value == [] + value = config.getini("args1") + assert value == [] + # default for bool is False + value = config.getini("bool1") + assert value is False + # default for string is "" + value = config.getini("string1") + assert value == "" + # should return None if None is explicity set as default value + # irrespective of the type argument + value = config.getini("none_1") + assert value is None + value = config.getini("none_2") + assert value is None + # in case no type is provided and no default set + # treat it as string and default value will be "" + value = config.getini("no_type") + assert value == "" + def test_confcutdir_check_isdir(self, pytester: Pytester) -> None: """Give an error if --confcutdir is not a valid directory (#2078)""" exp_match = r"^--confcutdir must be a directory, given: "