Commit solution thus far, needs to be polished up pre PR

This commit is contained in:
Gleb Nikonorov 2020-06-06 02:38:18 -04:00
parent 19ad588935
commit 2a3c21645e
3 changed files with 108 additions and 6 deletions

View File

@ -1604,3 +1604,13 @@ passed multiple times. The expected format is ``name=value``. For example::
[pytest]
xfail_strict = True
.. confval:: required_plugins
A space seperated list of plugins that must be present for pytest to run
.. code-block:: ini
[pytest]
require_plugins = pluginA pluginB pluginC

View File

@ -952,6 +952,12 @@ class Config:
self._parser.extra_info["inifile"] = self.inifile
self._parser.addini("addopts", "extra command line options", "args")
self._parser.addini("minversion", "minimally required pytest version")
self._parser.addini(
"require_plugins",
"plugins that must be present for pytest to run",
type="args",
default=[],
)
self._override_ini = ns.override_ini or ()
def _consider_importhook(self, args: Sequence[str]) -> None:
@ -1035,7 +1041,8 @@ class Config:
self.known_args_namespace = ns = self._parser.parse_known_args(
args, namespace=copy.copy(self.option)
)
self._validatekeys()
self._validate_keys()
self._validate_plugins()
if self.known_args_namespace.confcutdir is None and self.inifile:
confcutdir = py.path.local(self.inifile).dirname
self.known_args_namespace.confcutdir = confcutdir
@ -1078,12 +1085,26 @@ class Config:
)
)
def _validatekeys(self):
def _validate_keys(self) -> None:
for key in sorted(self._get_unknown_ini_keys()):
message = "Unknown config ini key: {}\n".format(key)
if self.known_args_namespace.strict_config:
fail(message, pytrace=False)
sys.stderr.write("WARNING: {}".format(message))
self._emit_warning_or_fail("Unknown config ini key: {}\n".format(key))
def _validate_plugins(self) -> None:
# so iterate over all required plugins and see if pluginmanager hasplugin
# NOTE: This also account for -p no:<plugin> ( e.g: -p no:celery )
# raise ValueError(self._parser._inidict['requiredplugins'])
# raise ValueError(self.getini("requiredplugins"))
# raise ValueError(self.pluginmanager.hasplugin('debugging'))
for plugin in self.getini("require_plugins"):
if not self.pluginmanager.hasplugin(plugin):
self._emit_warning_or_fail(
"Missing required plugin: {}\n".format(plugin)
)
def _emit_warning_or_fail(self, message: str) -> None:
if self.known_args_namespace.strict_config:
fail(message, pytrace=False)
sys.stderr.write("WARNING: {}".format(message))
def _get_unknown_ini_keys(self) -> List[str]:
parser_inicfg = self._parser._inidict

View File

@ -212,6 +212,77 @@ class TestParseIni:
with pytest.raises(pytest.fail.Exception, match=exception_text):
testdir.runpytest("--strict-config")
@pytest.mark.parametrize(
"ini_file_text, stderr_output, exception_text",
[
(
"""
[pytest]
require_plugins = fakePlugin1 fakePlugin2
""",
[
"WARNING: Missing required plugin: fakePlugin1",
"WARNING: Missing required plugin: fakePlugin2",
],
"Missing required plugin: fakePlugin1",
),
(
"""
[pytest]
require_plugins = a monkeypatch z
""",
[
"WARNING: Missing required plugin: a",
"WARNING: Missing required plugin: z",
],
"Missing required plugin: a",
),
(
"""
[pytest]
require_plugins = a monkeypatch z
addopts = -p no:monkeypatch
""",
[
"WARNING: Missing required plugin: a",
"WARNING: Missing required plugin: monkeypatch",
"WARNING: Missing required plugin: z",
],
"Missing required plugin: a",
),
(
"""
[some_other_header]
require_plugins = wont be triggered
[pytest]
minversion = 5.0.0
""",
[],
"",
),
(
"""
[pytest]
minversion = 5.0.0
""",
[],
"",
),
],
)
def test_missing_required_plugins(
self, testdir, ini_file_text, stderr_output, exception_text
):
testdir.tmpdir.join("pytest.ini").write(textwrap.dedent(ini_file_text))
testdir.parseconfig()
result = testdir.runpytest()
result.stderr.fnmatch_lines(stderr_output)
if stderr_output:
with pytest.raises(pytest.fail.Exception, match=exception_text):
testdir.runpytest("--strict-config")
class TestConfigCmdlineParsing:
def test_parsing_again_fails(self, testdir):