Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Load plugins referencing entry point name provided via config and env var #12616

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,7 @@ Mandeep Bhutani
Manuel Krebber
Marc Mueller
Marc Schlaich
Marcel Telka
Marcelo Duarte Trevisani
Marcin Bachry
Marc Bresson
Expand Down
5 changes: 5 additions & 0 deletions changelog/12624.improvement.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Plugins specified in the :globalvar:`pytest_plugins` config setting and
:envvar:`PYTEST_PLUGINS` environment variable now allow using
:ref:`entry points <pip-installable plugins>` names additionally to the
importable definitions. Prior to this release, these identifiers used to only
work with the ``-p`` CLI option -- by :user:`mtelka` and :user:`webknjaz`.
4 changes: 3 additions & 1 deletion doc/en/reference/reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1153,7 +1153,9 @@ specified plugins will be loaded.

.. envvar:: PYTEST_PLUGINS

Contains comma-separated list of modules that should be loaded as plugins:
Contains comma-separated list of :term:`importable modules <Module>`
or :ref:`entry point names <pip-installable plugins>` that should be
loaded as plugins:

.. code-block:: bash

Expand Down
2 changes: 1 addition & 1 deletion src/_pytest/config/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -828,7 +828,7 @@ def _import_plugin_specs(
) -> None:
plugins = _get_plugin_specs_as_list(spec)
for import_spec in plugins:
self.import_plugin(import_spec)
self.import_plugin(import_spec, consider_entry_points=True)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add tests to prove that it works and demonstrate the difference with the previous behavior.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can probably start with some merge of test_missing_required_plugins (it looks like the pytest11 entry point is created there) and test_early_config_cmdline (some kind of PYTEST_PLUGINS handling). But then some questions arises, for example: why is there the pytester.syspathinsert() call? After reading the doc it looks like the call is just a no-op, but this conclusion is apparently wrong.

I'm very sorry, but I'll need to leave this for somebody else who actually knows Python. Disclaimer: I'm not a Python developer.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd imagine that it sets $PYTHONPATH just for the subprocess invocation of pytest, which is what makes it possible for that subprocess to import <tested_pytest_plugin> residing on that path.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wouldn't merge tests at this point. Maybe, in a separate refactoring. But it's always easier to add a separate one and not care if you break other ones accidentally. Especially, if you're unsure.

As for the tips, using monkeypatch.setenv() should be a way to test the env var bit. It might be a bit more involved with generating a custom config, though. Still, I think it's a good starting point.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, this is really out of my knowledge.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, so don't mark it as resolved because hiding the discussion from people doesn't mean that it shouldn't be solved before merging.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like the right place to put the tests in would be test_pluginmanager.py::TestPytestPluginManager

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's also test_early_load_setuptools_name @ acceptance_test.py


def import_plugin(self, modname: str, consider_entry_points: bool = False) -> None:
"""Import a plugin with ``modname``.
Expand Down
1 change: 1 addition & 0 deletions testing/test_assertion.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ def test_installed_plugin_rewrite(
self, pytester: Pytester, mode, monkeypatch
) -> None:
monkeypatch.delenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD", raising=False)
monkeypatch.delenv("PYTEST_PLUGINS", raising=False)
# Make sure the hook is installed early enough so that plugins
# installed via distribution package are rewritten.
pytester.mkdir("hampkg")
Expand Down
4 changes: 4 additions & 0 deletions testing/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,7 @@ def my_dists():

monkeypatch.setattr(importlib.metadata, "distributions", my_dists)
monkeypatch.delenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD", raising=False)
monkeypatch.delenv("PYTEST_PLUGINS", raising=False)

pytester.makeini(ini_file_text)

Expand Down Expand Up @@ -1143,6 +1144,7 @@ def test_importlib_metadata_broken_distribution(
) -> None:
"""Integration test for broken distributions with 'files' metadata being None (#5389)"""
monkeypatch.delenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD", raising=False)
monkeypatch.delenv("PYTEST_PLUGINS", raising=False)

class DummyEntryPoint:
name = "mytestplugin"
Expand All @@ -1169,6 +1171,7 @@ def test_plugin_preparse_prevents_setuptools_loading(
pytester: Pytester, monkeypatch: MonkeyPatch, block_it: bool
) -> None:
monkeypatch.delenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD", raising=False)
monkeypatch.delenv("PYTEST_PLUGINS", raising=False)

plugin_module_placeholder = object()

Expand Down Expand Up @@ -1237,6 +1240,7 @@ def distributions():
return (Distribution(),)

monkeypatch.setenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD", "1")
monkeypatch.delenv("PYTEST_PLUGINS", raising=False)
monkeypatch.setattr(importlib.metadata, "distributions", distributions)
monkeypatch.setitem(sys.modules, "mytestplugin", PseudoPlugin())
config = pytester.parseconfig(*parse_args)
Expand Down
3 changes: 2 additions & 1 deletion testing/test_helpconfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,15 @@ def pytest_addoption(parser):
)


def test_empty_help_param(pytester: Pytester) -> None:
def test_empty_help_param(pytester: Pytester, monkeypatch) -> None:
"""Test that an empty help param is displayed correctly."""
pytester.makeconftest(
"""
def pytest_addoption(parser):
parser.addini("test_ini", "", default=True, type="bool")
"""
)
monkeypatch.delenv("PYTEST_PLUGINS", raising=False)
result = pytester.runpytest("--help")
assert result.ret == 0
lines = [
Expand Down
Loading