diff --git a/lib/matplotlib/backends/registry.py b/lib/matplotlib/backends/registry.py index 47d5f65e350e..e08817bb089b 100644 --- a/lib/matplotlib/backends/registry.py +++ b/lib/matplotlib/backends/registry.py @@ -93,6 +93,9 @@ def __init__(self): } def _backend_module_name(self, backend): + if backend.startswith("module://"): + return backend[9:] + # Return name of module containing the specified backend. # Does not check if the backend is valid, use is_valid_backend for that. backend = backend.lower() @@ -224,7 +227,8 @@ def is_valid_backend(self, backend): bool True if backend is valid, False otherwise. """ - backend = backend.lower() + if not backend.startswith("module://"): + backend = backend.lower() # For backward compatibility, convert ipympl and matplotlib-inline long # module:// names to their shortened forms. @@ -342,7 +346,8 @@ def resolve_backend(self, backend): The GUI framework, which will be None for a backend that is non-interactive. """ if isinstance(backend, str): - backend = backend.lower() + if not backend.startswith("module://"): + backend = backend.lower() else: # Might be _auto_backend_sentinel or None # Use whatever is already running... from matplotlib import get_backend @@ -395,7 +400,8 @@ def resolve_gui_or_backend(self, gui_or_backend): framework : str or None The GUI framework, which will be None for a backend that is non-interactive. """ - gui_or_backend = gui_or_backend.lower() + if not gui_or_backend.startswith("module://"): + gui_or_backend = gui_or_backend.lower() # First check if it is a gui loop name. backend = self.backend_for_gui_framework(gui_or_backend) diff --git a/lib/matplotlib/tests/test_backend_registry.py b/lib/matplotlib/tests/test_backend_registry.py index 141ffd69c266..80c2ce4fc51a 100644 --- a/lib/matplotlib/tests/test_backend_registry.py +++ b/lib/matplotlib/tests/test_backend_registry.py @@ -86,6 +86,15 @@ def test_is_valid_backend(backend, is_valid): assert backend_registry.is_valid_backend(backend) == is_valid +@pytest.mark.parametrize("backend, normalized", [ + ("agg", "matplotlib.backends.backend_agg"), + ("QtAgg", "matplotlib.backends.backend_qtagg"), + ("module://Anything", "Anything"), +]) +def test_backend_normalization(backend, normalized): + assert backend_registry._backend_module_name(backend) == normalized + + def test_deprecated_rcsetup_attributes(): match = "was deprecated in Matplotlib 3.9" with pytest.warns(mpl.MatplotlibDeprecationWarning, match=match): diff --git a/lib/matplotlib/tests/test_backend_template.py b/lib/matplotlib/tests/test_backend_template.py index d7e2a5cd1266..964d15c1559a 100644 --- a/lib/matplotlib/tests/test_backend_template.py +++ b/lib/matplotlib/tests/test_backend_template.py @@ -49,3 +49,14 @@ def test_show_old_global_api(monkeypatch): mpl.use("module://mpl_test_backend") plt.show() mock_show.assert_called_with() + + +def test_load_case_sensitive(monkeypatch): + mpl_test_backend = SimpleNamespace(**vars(backend_template)) + mock_show = MagicMock() + monkeypatch.setattr( + mpl_test_backend.FigureManagerTemplate, "pyplot_show", mock_show) + monkeypatch.setitem(sys.modules, "mpl_Test_Backend", mpl_test_backend) + mpl.use("module://mpl_Test_Backend") + plt.show() + mock_show.assert_called_with()