Skip to content

Commit

Permalink
Commit solution thus far, needs to be polished up pre PR
Browse files Browse the repository at this point in the history
  • Loading branch information
gnikonorov committed Jun 6, 2020
1 parent 19ad588 commit 2a3c216
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 6 deletions.
10 changes: 10 additions & 0 deletions doc/en/reference.rst
Expand Up @@ -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
33 changes: 27 additions & 6 deletions src/_pytest/config/__init__.py
Expand Up @@ -952,6 +952,12 @@ def _initini(self, args: Sequence[str]) -> None:
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:
Expand Down Expand Up @@ -1035,7 +1041,8 @@ def _preparse(self, args: List[str], addopts: bool = True) -> None:
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
Expand Down Expand Up @@ -1078,12 +1085,26 @@ def _checkversion(self):
)
)

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
Expand Down
71 changes: 71 additions & 0 deletions testing/test_config.py
Expand Up @@ -212,6 +212,77 @@ def test_invalid_ini_keys(
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):
Expand Down

0 comments on commit 2a3c216

Please sign in to comment.