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

Fix module name retrieval in backend.plugins.remove_duplicates(), plugin tests #5959

Merged
merged 9 commits into from
Nov 15, 2021
6 changes: 6 additions & 0 deletions doc/whats-new.rst
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ Bug fixes
~~~~~~~~~
- Fix plot.line crash for data of shape ``(1, N)`` in _title_for_slice on format_item (:pull:`5948`).
By `Sebastian Weigand <https://github.com/s-weigand>`_.
- Fix a regression in the removal of duplicate backend entrypoints (:issue:`5944`, :pull:`5959`)
By `Kai Mühlbauer <https://github.com/kmuehlbauer>`_.

Documentation
~~~~~~~~~~~~~
Expand All @@ -49,6 +51,10 @@ Documentation
Internal Changes
~~~~~~~~~~~~~~~~

- Use ``importlib`` to replace functionality of ``pkg_resources`` in
backend plugins tests. (:pull:`5959`).
By `Kai Mühlbauer <https://github.com/kmuehlbauer>`_.


.. _whats-new.0.20.1:

Expand Down
10 changes: 6 additions & 4 deletions xarray/backends/plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,17 @@ def remove_duplicates(entrypoints):
# check if there are multiple entrypoints for the same name
unique_entrypoints = []
for name, matches in entrypoints_grouped:
matches = list(matches)
# remove equal entrypoints
matches = list(set(matches))
unique_entrypoints.append(matches[0])
matches_len = len(matches)
if matches_len > 1:
selected_module_name = matches[0].module_name
all_module_names = [e.module_name for e in matches]
all_module_names = [e.value.split(":")[0] for e in matches]
selected_module_name = all_module_names[0]
warnings.warn(
f"Found {matches_len} entrypoints for the engine name {name}:"
f"\n {all_module_names}.\n It will be used: {selected_module_name}.",
f"\n {all_module_names}.\n "
f"The entrypoint {selected_module_name} will be used.",
RuntimeWarning,
)
return unique_entrypoints
Expand Down
53 changes: 31 additions & 22 deletions xarray/tests/test_plugins.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
from unittest import mock

import pkg_resources
import pytest

from xarray.backends import common, plugins

try:
from importlib.metadata import EntryPoint

importlib_metadata_mock = "importlib.metadata"
except ImportError:
# if the fallback library is missing, we are doomed.
from importlib_metadata import EntryPoint # type: ignore[no-redef]
kmuehlbauer marked this conversation as resolved.
Show resolved Hide resolved

importlib_metadata_mock = "importlib_metadata"
kmuehlbauer marked this conversation as resolved.
Show resolved Hide resolved


class DummyBackendEntrypointArgs(common.BackendEntrypoint):
def open_dataset(filename_or_obj, *args):
Expand All @@ -29,12 +38,12 @@ def open_dataset(self, filename_or_obj, *, decoder):
@pytest.fixture
def dummy_duplicated_entrypoints():
specs = [
"engine1 = xarray.tests.test_plugins:backend_1",
"engine1 = xarray.tests.test_plugins:backend_2",
"engine2 = xarray.tests.test_plugins:backend_1",
"engine2 = xarray.tests.test_plugins:backend_2",
["engine1", "xarray.tests.test_plugins:backend_1", "xarray.backends"],
["engine1", "xarray.tests.test_plugins:backend_2", "xarray.backends"],
["engine2", "xarray.tests.test_plugins:backend_1", "xarray.backends"],
["engine2", "xarray.tests.test_plugins:backend_2", "xarray.backends"],
]
eps = [pkg_resources.EntryPoint.parse(spec) for spec in specs]
eps = [EntryPoint(name, value, group) for name, value, group in specs]
return eps


Expand All @@ -46,8 +55,10 @@ def test_remove_duplicates(dummy_duplicated_entrypoints) -> None:


def test_broken_plugin() -> None:
broken_backend = pkg_resources.EntryPoint.parse(
"broken_backend = xarray.tests.test_plugins:backend_1"
broken_backend = EntryPoint(
"broken_backend",
"xarray.tests.test_plugins:backend_1",
"xarray.backends",
)
with pytest.warns(RuntimeWarning) as record:
_ = plugins.build_engines([broken_backend])
Expand All @@ -68,13 +79,15 @@ def test_remove_duplicates_warnings(dummy_duplicated_entrypoints) -> None:
assert "entrypoints" in message1


@mock.patch("pkg_resources.EntryPoint.load", mock.MagicMock(return_value=None))
@mock.patch(
f"{importlib_metadata_mock}.EntryPoint.load", mock.MagicMock(return_value=None)
)
def test_backends_dict_from_pkg() -> None:
specs = [
"engine1 = xarray.tests.test_plugins:backend_1",
"engine2 = xarray.tests.test_plugins:backend_2",
["engine1", "xarray.tests.test_plugins:backend_1", "xarray.backends"],
["engine2", "xarray.tests.test_plugins:backend_2", "xarray.backends"],
]
entrypoints = [pkg_resources.EntryPoint.parse(spec) for spec in specs]
entrypoints = [EntryPoint(name, value, group) for name, value, group in specs]
engines = plugins.backends_dict_from_pkg(entrypoints)
assert len(engines) == 2
assert engines.keys() == set(("engine1", "engine2"))
Expand Down Expand Up @@ -114,12 +127,12 @@ def test_set_missing_parameters_raise_error() -> None:


@mock.patch(
"pkg_resources.EntryPoint.load",
f"{importlib_metadata_mock}.EntryPoint.load",
mock.MagicMock(return_value=DummyBackendEntrypoint1),
)
def test_build_engines() -> None:
dummy_pkg_entrypoint = pkg_resources.EntryPoint.parse(
"cfgrib = xarray.tests.test_plugins:backend_1"
dummy_pkg_entrypoint = EntryPoint(
"cfgrib", "xarray.tests.test_plugins:backend_1", "xarray_backends"
)
backend_entrypoints = plugins.build_engines([dummy_pkg_entrypoint])

Expand All @@ -131,17 +144,13 @@ def test_build_engines() -> None:


@mock.patch(
"pkg_resources.EntryPoint.load",
f"{importlib_metadata_mock}.EntryPoint.load",
mock.MagicMock(return_value=DummyBackendEntrypoint1),
)
def test_build_engines_sorted() -> None:
dummy_pkg_entrypoints = [
pkg_resources.EntryPoint.parse(
"dummy2 = xarray.tests.test_plugins:backend_1",
),
pkg_resources.EntryPoint.parse(
"dummy1 = xarray.tests.test_plugins:backend_1",
),
EntryPoint("dummy2", "xarray.tests.test_plugins:backend_1", "xarray.backends"),
EntryPoint("dummy1", "xarray.tests.test_plugins:backend_1", "xarray.backends"),
]
backend_entrypoints = plugins.build_engines(dummy_pkg_entrypoints)
backend_entrypoints = list(backend_entrypoints)
Expand Down