From 126896f69d065b46efbf55e6e2b30865ab4569c0 Mon Sep 17 00:00:00 2001 From: Virgil Dupras Date: Mon, 6 Aug 2018 16:17:24 -0400 Subject: [PATCH] Add option to disable plugin auto-loading If `PYTEST_DISABLE_PLUGIN_AUTOLOAD` is set, disable auto-loading of plugins through setuptools entrypoints. Only plugins that have been explicitly specified are loaded. ref #3784. --- AUTHORS | 1 + changelog/3784.feature.rst | 1 + doc/en/reference.rst | 5 +++++ src/_pytest/config/__init__.py | 9 ++++++++- src/_pytest/helpconfig.py | 1 + testing/test_config.py | 20 ++++++++++++++++++++ 6 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 changelog/3784.feature.rst diff --git a/AUTHORS b/AUTHORS index 49440194e..3b0448371 100644 --- a/AUTHORS +++ b/AUTHORS @@ -207,6 +207,7 @@ Tzu-ping Chung Vasily Kuznetsov Victor Uriarte Vidar T. Fauske +Virgil Dupras Vitaly Lashmanov Vlad Dragos Wil Cooley diff --git a/changelog/3784.feature.rst b/changelog/3784.feature.rst new file mode 100644 index 000000000..87b6cafb6 --- /dev/null +++ b/changelog/3784.feature.rst @@ -0,0 +1 @@ +Add option to disable plugin auto-loading. diff --git a/doc/en/reference.rst b/doc/en/reference.rst index 86d92cf07..6e235e176 100644 --- a/doc/en/reference.rst +++ b/doc/en/reference.rst @@ -866,6 +866,11 @@ Contains comma-separated list of modules that should be loaded as plugins: export PYTEST_PLUGINS=mymodule.plugin,xdist +PYTEST_DISABLE_PLUGIN_AUTOLOAD +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When set, disables plugin auto-loading through setuptools entrypoints. Only explicitly specified plugins will be +loaded. PYTEST_CURRENT_TEST ~~~~~~~~~~~~~~~~~~~ diff --git a/src/_pytest/config/__init__.py b/src/_pytest/config/__init__.py index 421d124e9..3b2d622c3 100644 --- a/src/_pytest/config/__init__.py +++ b/src/_pytest/config/__init__.py @@ -701,6 +701,10 @@ class Config(object): self.pluginmanager.rewrite_hook = hook + if os.environ.get("PYTEST_DISABLE_PLUGIN_AUTOLOAD"): + # We don't autoload from setuptools entry points, no need to continue. + return + # 'RECORD' available for plugins installed normally (pip install) # 'SOURCES.txt' available for plugins installed in dev mode (pip install -e) # for installed plugins 'SOURCES.txt' returns an empty list, and vice-versa @@ -726,7 +730,10 @@ class Config(object): self._checkversion() self._consider_importhook(args) self.pluginmanager.consider_preparse(args) - self.pluginmanager.load_setuptools_entrypoints("pytest11") + if not os.environ.get("PYTEST_DISABLE_PLUGIN_AUTOLOAD"): + # Don't autoload from setuptools entry point. Only explicitly specified + # plugins are going to be loaded. + self.pluginmanager.load_setuptools_entrypoints("pytest11") self.pluginmanager.consider_env() self.known_args_namespace = ns = self._parser.parse_known_args( args, namespace=copy.copy(self.option) diff --git a/src/_pytest/helpconfig.py b/src/_pytest/helpconfig.py index 12c3339c6..85f071e9e 100644 --- a/src/_pytest/helpconfig.py +++ b/src/_pytest/helpconfig.py @@ -156,6 +156,7 @@ def showhelp(config): vars = [ ("PYTEST_ADDOPTS", "extra command line options"), ("PYTEST_PLUGINS", "comma-separated plugins to load during startup"), + ("PYTEST_DISABLE_PLUGIN_AUTOLOAD", "set to disable plugin auto-loading"), ("PYTEST_DEBUG", "set to enable debug tracing of pytest's internals"), ] for name, help in vars: diff --git a/testing/test_config.py b/testing/test_config.py index b507bb8e8..d58bda255 100644 --- a/testing/test_config.py +++ b/testing/test_config.py @@ -605,6 +605,26 @@ def test_plugin_preparse_prevents_setuptools_loading(testdir, monkeypatch, block ) +@pytest.mark.parametrize( + "parse_args,should_load", [(("-p", "mytestplugin"), True), ((), False)] +) +def test_disable_plugin_autoload(testdir, monkeypatch, parse_args, should_load): + pkg_resources = pytest.importorskip("pkg_resources") + + def my_iter(name): + raise AssertionError("Should not be called") + + class PseudoPlugin(object): + x = 42 + + monkeypatch.setenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD", "1") + monkeypatch.setattr(pkg_resources, "iter_entry_points", my_iter) + monkeypatch.setitem(sys.modules, "mytestplugin", PseudoPlugin()) + config = testdir.parseconfig(*parse_args) + has_loaded = config.pluginmanager.get_plugin("mytestplugin") is not None + assert has_loaded == should_load + + def test_cmdline_processargs_simple(testdir): testdir.makeconftest( """