File size: 5,950 Bytes
7aa7deb | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 | from collections.abc import Sequence
from typing import Any
import pytest
import matplotlib as mpl
from matplotlib.backends import BackendFilter, backend_registry
@pytest.fixture
def clear_backend_registry():
# Fixture that clears the singleton backend_registry before and after use
# so that the test state remains isolated.
backend_registry._clear()
yield
backend_registry._clear()
def has_duplicates(seq: Sequence[Any]) -> bool:
return len(seq) > len(set(seq))
@pytest.mark.parametrize(
'framework,expected',
[
('qt', 'qtagg'),
('gtk3', 'gtk3agg'),
('gtk4', 'gtk4agg'),
('wx', 'wxagg'),
('tk', 'tkagg'),
('macosx', 'macosx'),
('headless', 'agg'),
('does not exist', None),
]
)
def test_backend_for_gui_framework(framework, expected):
assert backend_registry.backend_for_gui_framework(framework) == expected
def test_list_builtin():
backends = backend_registry.list_builtin()
assert not has_duplicates(backends)
# Compare using sets as order is not important
assert {*backends} == {
'gtk3agg', 'gtk3cairo', 'gtk4agg', 'gtk4cairo', 'macosx', 'nbagg', 'notebook',
'qtagg', 'qtcairo', 'qt5agg', 'qt5cairo', 'tkagg',
'tkcairo', 'webagg', 'wx', 'wxagg', 'wxcairo', 'agg', 'cairo', 'pdf', 'pgf',
'ps', 'svg', 'template',
}
@pytest.mark.parametrize(
'filter,expected',
[
(BackendFilter.INTERACTIVE,
['gtk3agg', 'gtk3cairo', 'gtk4agg', 'gtk4cairo', 'macosx', 'nbagg', 'notebook',
'qtagg', 'qtcairo', 'qt5agg', 'qt5cairo', 'tkagg',
'tkcairo', 'webagg', 'wx', 'wxagg', 'wxcairo']),
(BackendFilter.NON_INTERACTIVE,
['agg', 'cairo', 'pdf', 'pgf', 'ps', 'svg', 'template']),
]
)
def test_list_builtin_with_filter(filter, expected):
backends = backend_registry.list_builtin(filter)
assert not has_duplicates(backends)
# Compare using sets as order is not important
assert {*backends} == {*expected}
def test_list_gui_frameworks():
frameworks = backend_registry.list_gui_frameworks()
assert not has_duplicates(frameworks)
# Compare using sets as order is not important
assert {*frameworks} == {
"gtk3", "gtk4", "macosx", "qt", "qt5", "qt6", "tk", "wx",
}
@pytest.mark.parametrize("backend, is_valid", [
("agg", True),
("QtAgg", True),
("module://anything", True),
("made-up-name", False),
])
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):
mpl.rcsetup.interactive_bk
with pytest.warns(mpl.MatplotlibDeprecationWarning, match=match):
mpl.rcsetup.non_interactive_bk
with pytest.warns(mpl.MatplotlibDeprecationWarning, match=match):
mpl.rcsetup.all_backends
def test_entry_points_inline():
pytest.importorskip('matplotlib_inline')
backends = backend_registry.list_all()
assert 'inline' in backends
def test_entry_points_ipympl():
pytest.importorskip('ipympl')
backends = backend_registry.list_all()
assert 'ipympl' in backends
assert 'widget' in backends
def test_entry_point_name_shadows_builtin(clear_backend_registry):
with pytest.raises(RuntimeError):
backend_registry._validate_and_store_entry_points(
[('qtagg', 'module1')])
def test_entry_point_name_duplicate(clear_backend_registry):
with pytest.raises(RuntimeError):
backend_registry._validate_and_store_entry_points(
[('some_name', 'module1'), ('some_name', 'module2')])
def test_entry_point_identical(clear_backend_registry):
# Issue https://github.com/matplotlib/matplotlib/issues/28367
# Multiple entry points with the same name and value (value is the module)
# are acceptable.
n = len(backend_registry._name_to_module)
backend_registry._validate_and_store_entry_points(
[('some_name', 'some.module'), ('some_name', 'some.module')])
assert len(backend_registry._name_to_module) == n+1
assert backend_registry._name_to_module['some_name'] == 'module://some.module'
def test_entry_point_name_is_module(clear_backend_registry):
with pytest.raises(RuntimeError):
backend_registry._validate_and_store_entry_points(
[('module://backend.something', 'module1')])
@pytest.mark.parametrize('backend', [
'agg',
'module://matplotlib.backends.backend_agg',
])
def test_load_entry_points_only_if_needed(clear_backend_registry, backend):
assert not backend_registry._loaded_entry_points
check = backend_registry.resolve_backend(backend)
assert check == (backend, None)
assert not backend_registry._loaded_entry_points
backend_registry.list_all() # Force load of entry points
assert backend_registry._loaded_entry_points
@pytest.mark.parametrize(
'gui_or_backend, expected_backend, expected_gui',
[
('agg', 'agg', None),
('qt', 'qtagg', 'qt'),
('TkCairo', 'tkcairo', 'tk'),
]
)
def test_resolve_gui_or_backend(gui_or_backend, expected_backend, expected_gui):
backend, gui = backend_registry.resolve_gui_or_backend(gui_or_backend)
assert backend == expected_backend
assert gui == expected_gui
def test_resolve_gui_or_backend_invalid():
match = "is not a recognised GUI loop or backend name"
with pytest.raises(RuntimeError, match=match):
backend_registry.resolve_gui_or_backend('no-such-name')
|