138 lines
5.4 KiB
Python
138 lines
5.4 KiB
Python
|
import pytest
|
||
|
import sys
|
||
|
import matplotlib
|
||
|
from matplotlib import cbook
|
||
|
|
||
|
|
||
|
def pytest_configure(config):
|
||
|
# config is initialized here rather than in pytest.ini so that `pytest
|
||
|
# --pyargs matplotlib` (which would not find pytest.ini) works. The only
|
||
|
# entries in pytest.ini set minversion (which is checked earlier),
|
||
|
# testpaths/python_files, as they are required to properly find the tests
|
||
|
for key, value in [
|
||
|
("markers", "flaky: (Provided by pytest-rerunfailures.)"),
|
||
|
("markers", "timeout: (Provided by pytest-timeout.)"),
|
||
|
("markers", "backend: Set alternate Matplotlib backend temporarily."),
|
||
|
("markers", "style: Set alternate Matplotlib style temporarily."),
|
||
|
("markers", "baseline_images: Compare output against references."),
|
||
|
("markers", "pytz: Tests that require pytz to be installed."),
|
||
|
("markers", "network: Tests that reach out to the network."),
|
||
|
("filterwarnings", "error"),
|
||
|
]:
|
||
|
config.addinivalue_line(key, value)
|
||
|
|
||
|
matplotlib.use('agg', force=True)
|
||
|
matplotlib._called_from_pytest = True
|
||
|
matplotlib._init_tests()
|
||
|
|
||
|
|
||
|
def pytest_unconfigure(config):
|
||
|
matplotlib._called_from_pytest = False
|
||
|
|
||
|
|
||
|
@pytest.fixture(autouse=True)
|
||
|
def mpl_test_settings(request):
|
||
|
from matplotlib.testing.decorators import _cleanup_cm
|
||
|
|
||
|
with _cleanup_cm():
|
||
|
|
||
|
backend = None
|
||
|
backend_marker = request.node.get_closest_marker('backend')
|
||
|
if backend_marker is not None:
|
||
|
assert len(backend_marker.args) == 1, \
|
||
|
"Marker 'backend' must specify 1 backend."
|
||
|
backend, = backend_marker.args
|
||
|
skip_on_importerror = backend_marker.kwargs.get(
|
||
|
'skip_on_importerror', False)
|
||
|
prev_backend = matplotlib.get_backend()
|
||
|
|
||
|
# special case Qt backend importing to avoid conflicts
|
||
|
if backend.lower().startswith('qt4'):
|
||
|
if any(k in sys.modules for k in ('PyQt5', 'PySide2')):
|
||
|
pytest.skip('Qt5 binding already imported')
|
||
|
try:
|
||
|
import PyQt4
|
||
|
# RuntimeError if PyQt5 already imported.
|
||
|
except (ImportError, RuntimeError):
|
||
|
try:
|
||
|
import PySide
|
||
|
except ImportError:
|
||
|
pytest.skip("Failed to import a Qt4 binding.")
|
||
|
elif backend.lower().startswith('qt5'):
|
||
|
if any(k in sys.modules for k in ('PyQt4', 'PySide')):
|
||
|
pytest.skip('Qt4 binding already imported')
|
||
|
try:
|
||
|
import PyQt5
|
||
|
# RuntimeError if PyQt4 already imported.
|
||
|
except (ImportError, RuntimeError):
|
||
|
try:
|
||
|
import PySide2
|
||
|
except ImportError:
|
||
|
pytest.skip("Failed to import a Qt5 binding.")
|
||
|
|
||
|
# Default of cleanup and image_comparison too.
|
||
|
style = ["classic", "_classic_test_patch"]
|
||
|
style_marker = request.node.get_closest_marker('style')
|
||
|
if style_marker is not None:
|
||
|
assert len(style_marker.args) == 1, \
|
||
|
"Marker 'style' must specify 1 style."
|
||
|
style, = style_marker.args
|
||
|
|
||
|
matplotlib.testing.setup()
|
||
|
with cbook._suppress_matplotlib_deprecation_warning():
|
||
|
if backend is not None:
|
||
|
# This import must come after setup() so it doesn't load the
|
||
|
# default backend prematurely.
|
||
|
import matplotlib.pyplot as plt
|
||
|
try:
|
||
|
plt.switch_backend(backend)
|
||
|
except ImportError as exc:
|
||
|
# Should only occur for the cairo backend tests, if neither
|
||
|
# pycairo nor cairocffi are installed.
|
||
|
if 'cairo' in backend.lower() or skip_on_importerror:
|
||
|
pytest.skip("Failed to switch to backend {} ({})."
|
||
|
.format(backend, exc))
|
||
|
else:
|
||
|
raise
|
||
|
matplotlib.style.use(style)
|
||
|
try:
|
||
|
yield
|
||
|
finally:
|
||
|
if backend is not None:
|
||
|
plt.switch_backend(prev_backend)
|
||
|
|
||
|
|
||
|
@pytest.fixture
|
||
|
def mpl_image_comparison_parameters(request, extension):
|
||
|
# This fixture is applied automatically by the image_comparison decorator.
|
||
|
#
|
||
|
# The sole purpose of this fixture is to provide an indirect method of
|
||
|
# obtaining parameters *without* modifying the decorated function
|
||
|
# signature. In this way, the function signature can stay the same and
|
||
|
# pytest won't get confused.
|
||
|
# We annotate the decorated function with any parameters captured by this
|
||
|
# fixture so that they can be used by the wrapper in image_comparison.
|
||
|
baseline_images, = request.node.get_closest_marker('baseline_images').args
|
||
|
if baseline_images is None:
|
||
|
# Allow baseline image list to be produced on the fly based on current
|
||
|
# parametrization.
|
||
|
baseline_images = request.getfixturevalue('baseline_images')
|
||
|
|
||
|
func = request.function
|
||
|
with cbook._setattr_cm(func.__wrapped__,
|
||
|
parameters=(baseline_images, extension)):
|
||
|
yield
|
||
|
|
||
|
|
||
|
@pytest.fixture
|
||
|
def pd():
|
||
|
"""Fixture to import and configure pandas."""
|
||
|
pd = pytest.importorskip('pandas')
|
||
|
try:
|
||
|
from pandas.plotting import (
|
||
|
deregister_matplotlib_converters as deregister)
|
||
|
deregister()
|
||
|
except ImportError:
|
||
|
pass
|
||
|
return pd
|