deprecated pytest_plugins in non-top-level conftest
This commit is contained in:
parent
d6ddeb395b
commit
54b15f5826
|
@ -201,6 +201,8 @@ class PytestPluginManager(PluginManager):
|
||||||
|
|
||||||
# Config._consider_importhook will set a real object if required.
|
# Config._consider_importhook will set a real object if required.
|
||||||
self.rewrite_hook = _pytest.assertion.DummyRewriteHook()
|
self.rewrite_hook = _pytest.assertion.DummyRewriteHook()
|
||||||
|
# Used to know when we are importing conftests after the pytest_configure stage
|
||||||
|
self._configured = False
|
||||||
|
|
||||||
def addhooks(self, module_or_class):
|
def addhooks(self, module_or_class):
|
||||||
"""
|
"""
|
||||||
|
@ -276,6 +278,7 @@ class PytestPluginManager(PluginManager):
|
||||||
config.addinivalue_line("markers",
|
config.addinivalue_line("markers",
|
||||||
"trylast: mark a hook implementation function such that the "
|
"trylast: mark a hook implementation function such that the "
|
||||||
"plugin machinery will try to call it last/as late as possible.")
|
"plugin machinery will try to call it last/as late as possible.")
|
||||||
|
self._configured = True
|
||||||
|
|
||||||
def _warn(self, message):
|
def _warn(self, message):
|
||||||
kwargs = message if isinstance(message, dict) else {
|
kwargs = message if isinstance(message, dict) else {
|
||||||
|
@ -366,6 +369,9 @@ class PytestPluginManager(PluginManager):
|
||||||
_ensure_removed_sysmodule(conftestpath.purebasename)
|
_ensure_removed_sysmodule(conftestpath.purebasename)
|
||||||
try:
|
try:
|
||||||
mod = conftestpath.pyimport()
|
mod = conftestpath.pyimport()
|
||||||
|
if hasattr(mod, 'pytest_plugins') and self._configured:
|
||||||
|
from _pytest.deprecated import PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST
|
||||||
|
warnings.warn(PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST)
|
||||||
except Exception:
|
except Exception:
|
||||||
raise ConftestImportFailure(conftestpath, sys.exc_info())
|
raise ConftestImportFailure(conftestpath, sys.exc_info())
|
||||||
|
|
||||||
|
|
|
@ -56,3 +56,9 @@ METAFUNC_ADD_CALL = (
|
||||||
"Metafunc.addcall is deprecated and scheduled to be removed in pytest 4.0.\n"
|
"Metafunc.addcall is deprecated and scheduled to be removed in pytest 4.0.\n"
|
||||||
"Please use Metafunc.parametrize instead."
|
"Please use Metafunc.parametrize instead."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST = RemovedInPytest4Warning(
|
||||||
|
"Defining pytest_plugins in a non-top-level conftest is deprecated, "
|
||||||
|
"because it affects the entire directory tree in a non-explicit way.\n"
|
||||||
|
"Please move it to the top level conftest file instead."
|
||||||
|
)
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Defining ``pytest_plugins`` is now deprecated in non-top-level conftest.py files, because they "leak" to the entire directory tree.
|
|
@ -79,6 +79,12 @@ will be loaded as well.
|
||||||
|
|
||||||
which will import the specified module as a ``pytest`` plugin.
|
which will import the specified module as a ``pytest`` plugin.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
Requiring plugins using a ``pytest_plugins`` variable in non-root
|
||||||
|
``conftest.py`` files is deprecated. See
|
||||||
|
:ref:`full explanation <requiring plugins in non-noot conftests>`
|
||||||
|
in the Writing plugins section.
|
||||||
|
|
||||||
.. _`findpluginname`:
|
.. _`findpluginname`:
|
||||||
|
|
||||||
Finding out which plugins are active
|
Finding out which plugins are active
|
||||||
|
|
|
@ -254,6 +254,18 @@ application modules:
|
||||||
if ``myapp.testsupport.myplugin`` also declares ``pytest_plugins``, the contents
|
if ``myapp.testsupport.myplugin`` also declares ``pytest_plugins``, the contents
|
||||||
of the variable will also be loaded as plugins, and so on.
|
of the variable will also be loaded as plugins, and so on.
|
||||||
|
|
||||||
|
.. _`requiring plugins in non-noot conftests`:
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
Requiring plugins using a ``pytest_plugins`` variable in non-root
|
||||||
|
``conftest.py`` files is deprecated.
|
||||||
|
|
||||||
|
This is important because ``conftest.py`` files implement per-directory
|
||||||
|
hook implementations, but once a plugin is imported, it will affect the
|
||||||
|
entire directory tree. In order to avoid confusion, defining
|
||||||
|
``pytest_plugins`` in any ``conftest.py`` file which is not located in the
|
||||||
|
tests root directory is deprecated, and will raise a warning.
|
||||||
|
|
||||||
This mechanism makes it easy to share fixtures within applications or even
|
This mechanism makes it easy to share fixtures within applications or even
|
||||||
external applications without the need to create external plugins using
|
external applications without the need to create external plugins using
|
||||||
the ``setuptools``'s entry point technique.
|
the ``setuptools``'s entry point technique.
|
||||||
|
|
|
@ -134,3 +134,70 @@ def test_pytest_catchlog_deprecated(testdir, plugin):
|
||||||
"*pytest-*log plugin has been merged into the core*",
|
"*pytest-*log plugin has been merged into the core*",
|
||||||
"*1 passed, 1 warnings*",
|
"*1 passed, 1 warnings*",
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
|
def test_pytest_plugins_in_non_top_level_conftest_deprecated(testdir):
|
||||||
|
from _pytest.deprecated import PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST
|
||||||
|
subdirectory = testdir.tmpdir.join("subdirectory")
|
||||||
|
subdirectory.mkdir()
|
||||||
|
# create the inner conftest with makeconftest and then move it to the subdirectory
|
||||||
|
testdir.makeconftest("""
|
||||||
|
pytest_plugins=['capture']
|
||||||
|
""")
|
||||||
|
testdir.tmpdir.join("conftest.py").move(subdirectory.join("conftest.py"))
|
||||||
|
# make the top level conftest
|
||||||
|
testdir.makeconftest("""
|
||||||
|
import warnings
|
||||||
|
warnings.filterwarnings('always', category=DeprecationWarning)
|
||||||
|
""")
|
||||||
|
testdir.makepyfile("""
|
||||||
|
def test_func():
|
||||||
|
pass
|
||||||
|
""")
|
||||||
|
res = testdir.runpytest_subprocess()
|
||||||
|
assert res.ret == 0
|
||||||
|
res.stderr.fnmatch_lines('*' + str(PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST).splitlines()[0])
|
||||||
|
|
||||||
|
|
||||||
|
def test_pytest_plugins_in_non_top_level_conftest_deprecated_no_top_level_conftest(testdir):
|
||||||
|
from _pytest.deprecated import PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST
|
||||||
|
subdirectory = testdir.tmpdir.join('subdirectory')
|
||||||
|
subdirectory.mkdir()
|
||||||
|
testdir.makeconftest("""
|
||||||
|
import warnings
|
||||||
|
warnings.filterwarnings('always', category=DeprecationWarning)
|
||||||
|
pytest_plugins=['capture']
|
||||||
|
""")
|
||||||
|
testdir.tmpdir.join("conftest.py").move(subdirectory.join("conftest.py"))
|
||||||
|
|
||||||
|
testdir.makepyfile("""
|
||||||
|
def test_func():
|
||||||
|
pass
|
||||||
|
""")
|
||||||
|
|
||||||
|
res = testdir.runpytest_subprocess()
|
||||||
|
assert res.ret == 0
|
||||||
|
res.stderr.fnmatch_lines('*' + str(PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST).splitlines()[0])
|
||||||
|
|
||||||
|
|
||||||
|
def test_pytest_plugins_in_non_top_level_conftest_deprecated_no_false_positives(testdir):
|
||||||
|
from _pytest.deprecated import PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST
|
||||||
|
subdirectory = testdir.tmpdir.join('subdirectory')
|
||||||
|
subdirectory.mkdir()
|
||||||
|
testdir.makeconftest("""
|
||||||
|
pass
|
||||||
|
""")
|
||||||
|
testdir.tmpdir.join("conftest.py").move(subdirectory.join("conftest.py"))
|
||||||
|
|
||||||
|
testdir.makeconftest("""
|
||||||
|
import warnings
|
||||||
|
warnings.filterwarnings('always', category=DeprecationWarning)
|
||||||
|
pytest_plugins=['capture']
|
||||||
|
""")
|
||||||
|
testdir.makepyfile("""
|
||||||
|
def test_func():
|
||||||
|
pass
|
||||||
|
""")
|
||||||
|
res = testdir.runpytest_subprocess()
|
||||||
|
assert res.ret == 0
|
||||||
|
assert str(PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST).splitlines()[0] not in res.stderr.str()
|
||||||
|
|
Loading…
Reference in New Issue