review feedback

This commit is contained in:
Gleb Nikonorov 2020-06-10 00:44:22 -04:00
parent 13add4df43
commit 95cb7fb676
4 changed files with 41 additions and 46 deletions

View File

@ -1,3 +1 @@
New `require_plugins` configuration option allows the user to specify a list of plugins required for pytest to run. Warnings are raised if these plugins are not found when running pytest. New `required_plugins` configuration option allows the user to specify a list of plugins required for pytest to run. An error is raised if any required plugins are not found when running pytest.
The `--strict-config` flag can be used to treat these warnings as errors.

View File

@ -1561,16 +1561,15 @@ passed multiple times. The expected format is ``name=value``. For example::
See :ref:`change naming conventions` for more detailed examples. See :ref:`change naming conventions` for more detailed examples.
.. confval:: require_plugins .. confval:: required_plugins
A space separated list of plugins that must be present for pytest to run. A space separated list of plugins that must be present for pytest to run.
If any one of the plugins is not found, emit a warning. If any one of the plugins is not found, emit a error.
If pytest is run with ``--strict-config`` exceptions are raised in place of warnings.
.. code-block:: ini .. code-block:: ini
[pytest] [pytest]
require_plugins = html xdist required_plugins = pytest-html pytest-xdist
.. confval:: testpaths .. confval:: testpaths

View File

@ -953,7 +953,7 @@ class Config:
self._parser.addini("addopts", "extra command line options", "args") self._parser.addini("addopts", "extra command line options", "args")
self._parser.addini("minversion", "minimally required pytest version") self._parser.addini("minversion", "minimally required pytest version")
self._parser.addini( self._parser.addini(
"require_plugins", "required_plugins",
"plugins that must be present for pytest to run", "plugins that must be present for pytest to run",
type="args", type="args",
default=[], default=[],
@ -1090,11 +1090,21 @@ class Config:
self._emit_warning_or_fail("Unknown config ini key: {}\n".format(key)) self._emit_warning_or_fail("Unknown config ini key: {}\n".format(key))
def _validate_plugins(self) -> None: def _validate_plugins(self) -> None:
for plugin in self.getini("require_plugins"): plugin_info = self.pluginmanager.list_plugin_distinfo()
if not self.pluginmanager.hasplugin(plugin): plugin_dist_names = [
self._emit_warning_or_fail( "{dist.project_name}".format(dist=dist) for _, dist in plugin_info
"Missing required plugin: {}\n".format(plugin) ]
)
required_plugin_list = []
for plugin in sorted(self.getini("required_plugins")):
if plugin not in plugin_dist_names:
required_plugin_list.append(plugin)
if required_plugin_list:
fail(
"Missing required plugins: {}".format(", ".join(required_plugin_list)),
pytrace=False,
)
def _emit_warning_or_fail(self, message: str) -> None: def _emit_warning_or_fail(self, message: str) -> None:
if self.known_args_namespace.strict_config: if self.known_args_namespace.strict_config:

View File

@ -213,51 +213,36 @@ class TestParseIni:
testdir.runpytest("--strict-config") testdir.runpytest("--strict-config")
@pytest.mark.parametrize( @pytest.mark.parametrize(
"ini_file_text, stderr_output, exception_text", "ini_file_text, exception_text",
[ [
( (
""" """
[pytest] [pytest]
require_plugins = fakePlugin1 fakePlugin2 required_plugins = fakePlugin1 fakePlugin2
""", """,
[ "Missing required plugins: fakePlugin1, fakePlugin2",
"WARNING: Missing required plugin: fakePlugin1",
"WARNING: Missing required plugin: fakePlugin2",
],
"Missing required plugin: fakePlugin1",
), ),
( (
""" """
[pytest] [pytest]
require_plugins = a monkeypatch z required_plugins = a pytest-xdist z
""", """,
[ "Missing required plugins: a, z",
"WARNING: Missing required plugin: a",
"WARNING: Missing required plugin: z",
],
"Missing required plugin: a",
), ),
( (
""" """
[pytest] [pytest]
require_plugins = a monkeypatch z required_plugins = a q j b c z
addopts = -p no:monkeypatch
""", """,
[ "Missing required plugins: a, b, c, j, q, z",
"WARNING: Missing required plugin: a",
"WARNING: Missing required plugin: monkeypatch",
"WARNING: Missing required plugin: z",
],
"Missing required plugin: a",
), ),
( (
""" """
[some_other_header] [some_other_header]
require_plugins = wont be triggered required_plugins = wont be triggered
[pytest] [pytest]
minversion = 5.0.0 minversion = 5.0.0
""", """,
[],
"", "",
), ),
( (
@ -265,23 +250,21 @@ class TestParseIni:
[pytest] [pytest]
minversion = 5.0.0 minversion = 5.0.0
""", """,
[],
"", "",
), ),
], ],
) )
def test_missing_required_plugins( def test_missing_required_plugins(self, testdir, ini_file_text, exception_text):
self, testdir, ini_file_text, stderr_output, exception_text pytest.importorskip("xdist")
):
testdir.tmpdir.join("pytest.ini").write(textwrap.dedent(ini_file_text)) testdir.tmpdir.join("pytest.ini").write(textwrap.dedent(ini_file_text))
testdir.parseconfig() testdir.monkeypatch.delenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD")
result = testdir.runpytest() if exception_text:
result.stderr.fnmatch_lines(stderr_output)
if stderr_output:
with pytest.raises(pytest.fail.Exception, match=exception_text): with pytest.raises(pytest.fail.Exception, match=exception_text):
testdir.runpytest("--strict-config") testdir.parseconfig()
else:
testdir.parseconfig()
class TestConfigCmdlineParsing: class TestConfigCmdlineParsing:
@ -681,6 +664,7 @@ def test_preparse_ordering_with_setuptools(testdir, monkeypatch):
class Dist: class Dist:
files = () files = ()
metadata = {"name": "foo"}
entry_points = (EntryPoint(),) entry_points = (EntryPoint(),)
def my_dists(): def my_dists():
@ -711,6 +695,7 @@ def test_setuptools_importerror_issue1479(testdir, monkeypatch):
class Distribution: class Distribution:
version = "1.0" version = "1.0"
files = ("foo.txt",) files = ("foo.txt",)
metadata = {"name": "foo"}
entry_points = (DummyEntryPoint(),) entry_points = (DummyEntryPoint(),)
def distributions(): def distributions():
@ -735,6 +720,7 @@ def test_importlib_metadata_broken_distribution(testdir, monkeypatch):
class Distribution: class Distribution:
version = "1.0" version = "1.0"
files = None files = None
metadata = {"name": "foo"}
entry_points = (DummyEntryPoint(),) entry_points = (DummyEntryPoint(),)
def distributions(): def distributions():
@ -760,6 +746,7 @@ def test_plugin_preparse_prevents_setuptools_loading(testdir, monkeypatch, block
class Distribution: class Distribution:
version = "1.0" version = "1.0"
files = ("foo.txt",) files = ("foo.txt",)
metadata = {"name": "foo"}
entry_points = (DummyEntryPoint(),) entry_points = (DummyEntryPoint(),)
def distributions(): def distributions():
@ -791,6 +778,7 @@ def test_disable_plugin_autoload(testdir, monkeypatch, parse_args, should_load):
return sys.modules[self.name] return sys.modules[self.name]
class Distribution: class Distribution:
metadata = {"name": "foo"}
entry_points = (DummyEntryPoint(),) entry_points = (DummyEntryPoint(),)
files = () files = ()