From 80715e48832b8523cd42f671ed2d2cb25569630e Mon Sep 17 00:00:00 2001 From: Thomas Grainger Date: Thu, 10 Mar 2022 10:19:36 +0000 Subject: [PATCH] CLN/DOC: fix test_register_entrypoint by cleaning up all outdated references to pkg_resources --- asv_bench/benchmarks/plotting.py | 60 ++++++++++++++++++++------- pandas/plotting/_core.py | 2 +- pandas/tests/plotting/test_backend.py | 41 +++++++----------- setup.cfg | 2 + 4 files changed, 63 insertions(+), 42 deletions(-) diff --git a/asv_bench/benchmarks/plotting.py b/asv_bench/benchmarks/plotting.py index 249a8f3f556a1..789bb8d8533b1 100644 --- a/asv_bench/benchmarks/plotting.py +++ b/asv_bench/benchmarks/plotting.py @@ -1,9 +1,14 @@ -import importlib +import contextlib +import importlib.machinery +import importlib.util +import os +import pathlib import sys +import tempfile +from unittest import mock import matplotlib import numpy as np -import pkg_resources from pandas import ( DataFrame, @@ -111,22 +116,49 @@ class BackendLoading: warmup_time = 0 def setup(self): - dist = pkg_resources.get_distribution("pandas") - spec = importlib.machinery.ModuleSpec("my_backend", None) - mod = importlib.util.module_from_spec(spec) + mod = importlib.util.module_from_spec( + importlib.machinery.ModuleSpec("pandas_dummy_backend", None) + ) mod.plot = lambda *args, **kwargs: 1 - backends = pkg_resources.get_entry_map("pandas") - my_entrypoint = pkg_resources.EntryPoint( - "pandas_plotting_backend", mod.__name__, dist=dist - ) - backends["pandas_plotting_backends"][mod.__name__] = my_entrypoint - for i in range(10): - backends["pandas_plotting_backends"][str(i)] = my_entrypoint - sys.modules["my_backend"] = mod + with contextlib.ExitStack() as stack: + stack.enter_context( + mock.patch.dict(sys.modules, {"pandas_dummy_backend": mod}) + ) + tmp_path = pathlib.Path(stack.enter_context(tempfile.TemporaryDirectory())) + + sys.path.insert(0, os.fsdecode(tmp_path)) + stack.callback(sys.path.remove, os.fsdecode(tmp_path)) + + dist_info = tmp_path / "my_backend-0.0.0.dist-info" + dist_info.mkdir() + (dist_info / "entry_points.txt").write_bytes( + b"[pandas_plotting_backends]\n" + b"my_ep_backend = pandas_dummy_backend\n" + b"my_ep_backend0 = pandas_dummy_backend\n" + b"my_ep_backend1 = pandas_dummy_backend\n" + b"my_ep_backend2 = pandas_dummy_backend\n" + b"my_ep_backend3 = pandas_dummy_backend\n" + b"my_ep_backend4 = pandas_dummy_backend\n" + b"my_ep_backend5 = pandas_dummy_backend\n" + b"my_ep_backend6 = pandas_dummy_backend\n" + b"my_ep_backend7 = pandas_dummy_backend\n" + b"my_ep_backend8 = pandas_dummy_backend\n" + b"my_ep_backend9 = pandas_dummy_backend\n" + ) + self.stack = stack.pop_all() + + def teardown(self): + self.stack.close() def time_get_plot_backend(self): - _get_plot_backend("my_backend") + # finds the first my_ep_backend + _get_plot_backend("my_ep_backend") + + def time_get_plot_backend_fallback(self): + # iterates through all the my_ep_backend[0-9] before falling back + # to importlib.import_module + _get_plot_backend("pandas_dummy_backend") from .pandas_vb_common import setup # noqa: F401 isort:skip diff --git a/pandas/plotting/_core.py b/pandas/plotting/_core.py index 85bc3121f5e4e..bd1ead8b51b49 100644 --- a/pandas/plotting/_core.py +++ b/pandas/plotting/_core.py @@ -1769,7 +1769,7 @@ def _load_backend(backend: str) -> types.ModuleType: ---------- backend : str The identifier for the backend. Either an entrypoint item registered - with pkg_resources, "matplotlib", or a module name. + with importlib.metadata, "matplotlib", or a module name. Returns ------- diff --git a/pandas/tests/plotting/test_backend.py b/pandas/tests/plotting/test_backend.py index 82e82781e894b..c087d3be293e7 100644 --- a/pandas/tests/plotting/test_backend.py +++ b/pandas/tests/plotting/test_backend.py @@ -1,7 +1,6 @@ import sys import types -import pkg_resources import pytest import pandas.util._test_decorators as td @@ -45,40 +44,28 @@ def test_backend_can_be_set_in_plot_call(monkeypatch, restore_backend): assert df.plot(backend="pandas_dummy_backend") == "used_dummy" -@td.skip_if_no_mpl -def test_register_entrypoint(restore_backend): - - dist = pkg_resources.get_distribution("pandas") - if dist.module_path not in pandas.__file__: - # We are running from a non-installed pandas, and this test is invalid - pytest.skip("Testing a non-installed pandas") - - mod = types.ModuleType("my_backend") - mod.plot = lambda *args, **kwargs: 1 +def test_register_entrypoint(restore_backend, tmp_path, monkeypatch): + monkeypatch.syspath_prepend(tmp_path) + monkeypatch.setitem(sys.modules, "pandas_dummy_backend", dummy_backend) - backends = pkg_resources.get_entry_map("pandas") - my_entrypoint = pkg_resources.EntryPoint( - "pandas_plotting_backend", mod.__name__, dist=dist + dist_info = tmp_path / "my_backend-0.0.0.dist-info" + dist_info.mkdir() + # entry_point name should not match module name - otherwise pandas will + # fall back to backend lookup by module name + (dist_info / "entry_points.txt").write_bytes( + b"[pandas_plotting_backends]\nmy_ep_backend = pandas_dummy_backend\n" ) - backends["pandas_plotting_backends"]["my_backend"] = my_entrypoint - # TODO: the docs recommend importlib.util.module_from_spec. But this works for now. - sys.modules["my_backend"] = mod - - result = pandas.plotting._core._get_plot_backend("my_backend") - assert result is mod - # TODO(GH#27517): https://github.com/pandas-dev/pandas/issues/27517 - # Remove the td.skip_if_no_mpl - with pandas.option_context("plotting.backend", "my_backend"): - result = pandas.plotting._core._get_plot_backend() + assert pandas.plotting._core._get_plot_backend("my_ep_backend") is dummy_backend - assert result is mod + with pandas.option_context("plotting.backend", "my_ep_backend"): + assert pandas.plotting._core._get_plot_backend() is dummy_backend -def test_setting_backend_without_plot_raises(): +def test_setting_backend_without_plot_raises(monkeypatch): # GH-28163 module = types.ModuleType("pandas_plot_backend") - sys.modules["pandas_plot_backend"] = module + monkeypatch.setitem(sys.modules, "pandas_plot_backend", module) assert pandas.options.plotting.backend == "matplotlib" with pytest.raises( diff --git a/setup.cfg b/setup.cfg index 27a5c51d2f2aa..34c9f56f06371 100644 --- a/setup.cfg +++ b/setup.cfg @@ -125,6 +125,8 @@ per-file-ignores = doc/make.py:PDF008 # import from pandas._testing pandas/testing.py:PDF014 + # can't use fixtures in asv + asv_bench/*:PDF016 [flake8-rst]