From c91b5b7d5fafa56b3c83b4fcd8e5dd76132ea094 Mon Sep 17 00:00:00 2001 From: Sota Sato <63048661+midoriao@users.noreply.github.com> Date: Tue, 4 Nov 2025 18:52:11 +0900 Subject: [PATCH 1/3] docs: clarify Config.getoption docstring --- src/_pytest/config/__init__.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/_pytest/config/__init__.py b/src/_pytest/config/__init__.py index 15b008f9d01..41efa410fe7 100644 --- a/src/_pytest/config/__init__.py +++ b/src/_pytest/config/__init__.py @@ -1845,12 +1845,15 @@ def _getconftest_pathlist( def getoption(self, name: str, default: Any = notset, skip: bool = False): """Return command line option value. - :param name: Name of the option. You may also specify - the literal ``--OPT`` option instead of the "dest" option name. - :param default: Fallback value if no option of that name is **declared** via :hook:`pytest_addoption`. - Note this parameter will be ignored when the option is **declared** even if the option's value is ``None``. - :param skip: If ``True``, raise :func:`pytest.skip` if option is undeclared or has a ``None`` value. - Note that even if ``True``, if a default was specified it will be returned instead of a skip. + :param name: + Name of the option. You may also specify the literal ``--OPT`` option instead of the "dest" option name. + :param default: + Fallback value if the option is not available. + Ignored when the option has been declared (even if its value is ``None``), unless ``skip=True``. + :param skip: + If ``True``, call :func:`pytest.skip` if the option is undeclared or ``None``. + Note that when ``skip=True`` and the ``default`` parameter is provided (even ``None``), + the default value is returned instead of skipping. """ name = self._opt2dest.get(name, name) try: From 8fd741fce16772701b6068d0d2c31e3543fbc60a Mon Sep 17 00:00:00 2001 From: Sota Sato <63048661+midoriao@users.noreply.github.com> Date: Wed, 5 Nov 2025 13:58:29 +0900 Subject: [PATCH 2/3] tests: add cases for getoption with default=None and skip=True --- testing/test_config.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/testing/test_config.py b/testing/test_config.py index f1221cea9d0..45a1c5088c3 100644 --- a/testing/test_config.py +++ b/testing/test_config.py @@ -768,6 +768,7 @@ def pytest_addoption(parser): assert config_novalue.getoption("hello") is None assert config_novalue.getoption("hello", default=1) is None assert config_novalue.getoption("hello", default=1, skip=True) == 1 + assert config_novalue.getoption("hello", default=None, skip=True) is None def test_config_getoption_undeclared_option_name(self, pytester: Pytester) -> None: config = pytester.parseconfig() @@ -775,6 +776,7 @@ def test_config_getoption_undeclared_option_name(self, pytester: Pytester) -> No config.getoption("x") assert config.getoption("x", default=1) == 1 assert config.getoption("x", default=1, skip=True) == 1 + assert config.getoption("x", default=None, skip=True) is None def test_config_getoption_unicode(self, pytester: Pytester) -> None: pytester.makeconftest( From 40671933a8bdf7cd81a0165b87fc807ec65ffcdc Mon Sep 17 00:00:00 2001 From: Sota Sato <63048661+midoriao@users.noreply.github.com> Date: Wed, 5 Nov 2025 18:02:54 +0900 Subject: [PATCH 3/3] changelog: add fragment --- changelog/13879.doc.rst | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 changelog/13879.doc.rst diff --git a/changelog/13879.doc.rst b/changelog/13879.doc.rst new file mode 100644 index 00000000000..8951045f167 --- /dev/null +++ b/changelog/13879.doc.rst @@ -0,0 +1,9 @@ +Clarified `pytest/Config.getoption` docstring to make the exceptional behavior of `default` with `skip=True` explicit. + +The previous docstring implied: + +- The `default` parameter is ignored when the option is declared. + +But actual behavior is: + +- The `default` is **not ignored** even if the option is declared, when `skip=True` and the option has `None` value.