From 98dd9e0787f5fb77d532a750658882881d10ec6f Mon Sep 17 00:00:00 2001 From: Kevin Santana Date: Fri, 10 Dec 2021 00:10:53 -0500 Subject: [PATCH] warn user if addoption is used after configuration and parsing phase. --- changelog/9303.bugfix.rst | 8 +++++++- src/_pytest/config/argparsing.py | 8 ++++++-- testing/test_pluginmanager.py | 15 +++++++++++---- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/changelog/9303.bugfix.rst b/changelog/9303.bugfix.rst index cad5abf1f..ce7009459 100644 --- a/changelog/9303.bugfix.rst +++ b/changelog/9303.bugfix.rst @@ -1,2 +1,8 @@ `Parser.addoption` now throws a value error if an attempt is made at adding an option -after the pre_parsing process without including a default. +after the pre_parsing process without including a default. If the user decides to +provides a default a warning will be given since the option will not be available +for use in the command line. + +This occurs if conftest files aren't in the root directory or any sub directory +matching the `test*` regex. conftest files which match the previous statement +will have their options added after the configuration and parsing phase. diff --git a/src/_pytest/config/argparsing.py b/src/_pytest/config/argparsing.py index bd8b1ceb8..d26094c75 100644 --- a/src/_pytest/config/argparsing.py +++ b/src/_pytest/config/argparsing.py @@ -22,6 +22,7 @@ from _pytest.deprecated import ARGUMENT_PERCENT_DEFAULT from _pytest.deprecated import ARGUMENT_TYPE_STR from _pytest.deprecated import ARGUMENT_TYPE_STR_CHOICE from _pytest.deprecated import check_ispytest +from _pytest.warning_types import PytestConfigWarning if TYPE_CHECKING: from typing import NoReturn @@ -363,9 +364,12 @@ class OptionGroup: accepted **and** the automatic destination is in ``args.twowords``. """ if getattr(self.parser, "after_preparse", False) and "default" not in attrs: - raise ValueError( - "Cannot add options without default after initial conftest discovery" + raise UsageError("Cannot add options after initial conftest discovery") + elif getattr(self.parser, "after_preparse", False): + warn = ("Adding option {option} after configuration phase").format( + option=optnames ) + warnings.warn(PytestConfigWarning(warn), stacklevel=3) conflict = set(optnames).intersection( name for opt in self.options for name in opt.names() diff --git a/testing/test_pluginmanager.py b/testing/test_pluginmanager.py index 3ae997e92..d5fb3d7d1 100644 --- a/testing/test_pluginmanager.py +++ b/testing/test_pluginmanager.py @@ -13,6 +13,7 @@ from _pytest.main import Session from _pytest.monkeypatch import MonkeyPatch from _pytest.pathlib import import_path from _pytest.pytester import Pytester +from _pytest.warning_types import PytestConfigWarning @pytest.fixture @@ -73,9 +74,13 @@ class TestPytestPluginInteractions: default=True) """ ) - config.pluginmanager._importconftest( - p, importmode="prepend", rootpath=pytester.path - ) + with pytest.warns(PytestConfigWarning) as warn: + config.pluginmanager._importconftest( + p, importmode="prepend", rootpath=pytester.path + ) + + assert len(warn) == 1 + assert str(warn[0].message).endswith("after configuration phase") assert config.option.test123 def test_do_option_postinit_nodefault(self, pytester: Pytester) -> None: @@ -87,7 +92,9 @@ class TestPytestPluginInteractions: parser.addoption('--deadbeef', action="store_true") """ ) - with pytest.raises(ValueError): + with pytest.raises( + UsageError, match="^Cannot add options after initial conftest discovery$" + ): config.pluginmanager._importconftest( p, importmode="prepend", rootpath=pytester.path )