conftest.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. import pytest
  2. import sys
  3. import matplotlib
  4. from matplotlib import cbook
  5. def pytest_configure(config):
  6. # config is initialized here rather than in pytest.ini so that `pytest
  7. # --pyargs matplotlib` (which would not find pytest.ini) works. The only
  8. # entries in pytest.ini set minversion (which is checked earlier),
  9. # testpaths/python_files, as they are required to properly find the tests
  10. for key, value in [
  11. ("markers", "flaky: (Provided by pytest-rerunfailures.)"),
  12. ("markers", "timeout: (Provided by pytest-timeout.)"),
  13. ("markers", "backend: Set alternate Matplotlib backend temporarily."),
  14. ("markers", "style: Set alternate Matplotlib style temporarily."),
  15. ("markers", "baseline_images: Compare output against references."),
  16. ("markers", "pytz: Tests that require pytz to be installed."),
  17. ("markers", "network: Tests that reach out to the network."),
  18. ("filterwarnings", "error"),
  19. ]:
  20. config.addinivalue_line(key, value)
  21. matplotlib.use('agg', force=True)
  22. matplotlib._called_from_pytest = True
  23. matplotlib._init_tests()
  24. def pytest_unconfigure(config):
  25. matplotlib._called_from_pytest = False
  26. @pytest.fixture(autouse=True)
  27. def mpl_test_settings(request):
  28. from matplotlib.testing.decorators import _cleanup_cm
  29. with _cleanup_cm():
  30. backend = None
  31. backend_marker = request.node.get_closest_marker('backend')
  32. if backend_marker is not None:
  33. assert len(backend_marker.args) == 1, \
  34. "Marker 'backend' must specify 1 backend."
  35. backend, = backend_marker.args
  36. skip_on_importerror = backend_marker.kwargs.get(
  37. 'skip_on_importerror', False)
  38. prev_backend = matplotlib.get_backend()
  39. # special case Qt backend importing to avoid conflicts
  40. if backend.lower().startswith('qt4'):
  41. if any(k in sys.modules for k in ('PyQt5', 'PySide2')):
  42. pytest.skip('Qt5 binding already imported')
  43. try:
  44. import PyQt4
  45. # RuntimeError if PyQt5 already imported.
  46. except (ImportError, RuntimeError):
  47. try:
  48. import PySide
  49. except ImportError:
  50. pytest.skip("Failed to import a Qt4 binding.")
  51. elif backend.lower().startswith('qt5'):
  52. if any(k in sys.modules for k in ('PyQt4', 'PySide')):
  53. pytest.skip('Qt4 binding already imported')
  54. try:
  55. import PyQt5
  56. # RuntimeError if PyQt4 already imported.
  57. except (ImportError, RuntimeError):
  58. try:
  59. import PySide2
  60. except ImportError:
  61. pytest.skip("Failed to import a Qt5 binding.")
  62. # Default of cleanup and image_comparison too.
  63. style = ["classic", "_classic_test_patch"]
  64. style_marker = request.node.get_closest_marker('style')
  65. if style_marker is not None:
  66. assert len(style_marker.args) == 1, \
  67. "Marker 'style' must specify 1 style."
  68. style, = style_marker.args
  69. matplotlib.testing.setup()
  70. with cbook._suppress_matplotlib_deprecation_warning():
  71. if backend is not None:
  72. # This import must come after setup() so it doesn't load the
  73. # default backend prematurely.
  74. import matplotlib.pyplot as plt
  75. try:
  76. plt.switch_backend(backend)
  77. except ImportError as exc:
  78. # Should only occur for the cairo backend tests, if neither
  79. # pycairo nor cairocffi are installed.
  80. if 'cairo' in backend.lower() or skip_on_importerror:
  81. pytest.skip("Failed to switch to backend {} ({})."
  82. .format(backend, exc))
  83. else:
  84. raise
  85. matplotlib.style.use(style)
  86. try:
  87. yield
  88. finally:
  89. if backend is not None:
  90. plt.switch_backend(prev_backend)
  91. @pytest.fixture
  92. def mpl_image_comparison_parameters(request, extension):
  93. # This fixture is applied automatically by the image_comparison decorator.
  94. #
  95. # The sole purpose of this fixture is to provide an indirect method of
  96. # obtaining parameters *without* modifying the decorated function
  97. # signature. In this way, the function signature can stay the same and
  98. # pytest won't get confused.
  99. # We annotate the decorated function with any parameters captured by this
  100. # fixture so that they can be used by the wrapper in image_comparison.
  101. baseline_images, = request.node.get_closest_marker('baseline_images').args
  102. if baseline_images is None:
  103. # Allow baseline image list to be produced on the fly based on current
  104. # parametrization.
  105. baseline_images = request.getfixturevalue('baseline_images')
  106. func = request.function
  107. with cbook._setattr_cm(func.__wrapped__,
  108. parameters=(baseline_images, extension)):
  109. yield
  110. @pytest.fixture
  111. def pd():
  112. """Fixture to import and configure pandas."""
  113. pd = pytest.importorskip('pandas')
  114. try:
  115. from pandas.plotting import (
  116. deregister_matplotlib_converters as deregister)
  117. deregister()
  118. except ImportError:
  119. pass
  120. return pd