diff --git a/lib/cartopy/tests/conftest.py b/lib/cartopy/tests/conftest.py index c94a87f45..8dde284fa 100644 --- a/lib/cartopy/tests/conftest.py +++ b/lib/cartopy/tests/conftest.py @@ -3,6 +3,29 @@ # This file is part of Cartopy and is released under the LGPL license. # See COPYING and COPYING.LESSER in the root of the repository for full # licensing details. +import pytest + + +_HAS_PYKDTREE = True +_HAS_SCIPY = True + +try: + import pykdtree # noqa: F401 +except ImportError: + _HAS_PYKDTREE = False + +try: + import scipy # noqa: F401 +except ImportError: + _HAS_SCIPY = False + +requires_scipy = pytest.mark.skipif( + not _HAS_SCIPY, + reason="scipy is required") +requires_pykdtree = pytest.mark.skipif( + not _HAS_PYKDTREE, + reason="pykdtree is required") +_HAS_PYKDTREE_OR_SCIPY = _HAS_PYKDTREE or _HAS_SCIPY def pytest_configure(config): diff --git a/lib/cartopy/tests/io/test_ogc_clients.py b/lib/cartopy/tests/io/test_ogc_clients.py index 2782fcca5..7cab18cd0 100644 --- a/lib/cartopy/tests/io/test_ogc_clients.py +++ b/lib/cartopy/tests/io/test_ogc_clients.py @@ -21,6 +21,13 @@ import pytest import cartopy.crs as ccrs +from cartopy.tests.conftest import _HAS_PYKDTREE_OR_SCIPY + + +if not _HAS_PYKDTREE_OR_SCIPY: + pytest.skip('pykdtree or scipy is required', allow_module_level=True) + + import cartopy.io.ogc_clients as ogc from cartopy.io.ogc_clients import _OWSLIB_AVAILABLE diff --git a/lib/cartopy/tests/mpl/test_caching.py b/lib/cartopy/tests/mpl/test_caching.py index 110d674a4..688dfda0a 100644 --- a/lib/cartopy/tests/mpl/test_caching.py +++ b/lib/cartopy/tests/mpl/test_caching.py @@ -17,7 +17,12 @@ import pytest import cartopy.crs as ccrs -from cartopy.io.ogc_clients import _OWSLIB_AVAILABLE, WMTSRasterSource +from cartopy.tests.conftest import _HAS_PYKDTREE_OR_SCIPY + + +if _HAS_PYKDTREE_OR_SCIPY: + from cartopy.io.ogc_clients import _OWSLIB_AVAILABLE, WMTSRasterSource + import cartopy.io.shapereader from cartopy.mpl import _MPL_38 from cartopy.mpl.feature_artist import FeatureArtist @@ -149,7 +154,8 @@ def test_contourf_transform_path_counting(): @pytest.mark.filterwarnings("ignore:TileMatrixLimits") @pytest.mark.network -@pytest.mark.skipif(not _OWSLIB_AVAILABLE, reason='OWSLib is unavailable.') +@pytest.mark.skipif(not _HAS_PYKDTREE_OR_SCIPY or not _OWSLIB_AVAILABLE, + reason='OWSLib and at least one of pykdtree or scipy is required') def test_wmts_tile_caching(): image_cache = WMTSRasterSource._shared_image_cache image_cache.clear() diff --git a/lib/cartopy/tests/mpl/test_contour.py b/lib/cartopy/tests/mpl/test_contour.py index ff03125de..a02cf2f58 100644 --- a/lib/cartopy/tests/mpl/test_contour.py +++ b/lib/cartopy/tests/mpl/test_contour.py @@ -8,10 +8,9 @@ import numpy as np from numpy.testing import assert_array_almost_equal import pytest -from scipy.interpolate import NearestNDInterpolator -from scipy.signal import convolve2d import cartopy.crs as ccrs +from cartopy.tests.conftest import requires_scipy def test_contour_plot_bounds(): @@ -72,8 +71,12 @@ def test_plot_after_contour_doesnt_shrink(func): assert_array_almost_equal(ax.get_extent(), expected) +@requires_scipy def test_contour_linear_ring(): """Test contourf with a section that only has 3 points.""" + from scipy.interpolate import NearestNDInterpolator + from scipy.signal import convolve2d + ax = plt.axes([0.01, 0.05, 0.898, 0.85], projection=ccrs.Mercator(), aspect='equal') ax.set_extent([-99.6, -89.0, 39.8, 45.5]) diff --git a/lib/cartopy/tests/mpl/test_examples.py b/lib/cartopy/tests/mpl/test_examples.py index cc171221d..b8f5cb8f5 100644 --- a/lib/cartopy/tests/mpl/test_examples.py +++ b/lib/cartopy/tests/mpl/test_examples.py @@ -9,6 +9,11 @@ import cartopy.crs as ccrs from cartopy.mpl import _MPL_38 +from cartopy.tests.conftest import _HAS_PYKDTREE_OR_SCIPY + + +if not _HAS_PYKDTREE_OR_SCIPY: + pytest.skip('pykdtree or scipy is required', allow_module_level=True) @pytest.mark.natural_earth diff --git a/lib/cartopy/tests/mpl/test_features.py b/lib/cartopy/tests/mpl/test_features.py index 07a66f8a9..960a9c021 100644 --- a/lib/cartopy/tests/mpl/test_features.py +++ b/lib/cartopy/tests/mpl/test_features.py @@ -10,7 +10,11 @@ import cartopy.crs as ccrs import cartopy.feature as cfeature -from cartopy.io.ogc_clients import _OWSLIB_AVAILABLE +from cartopy.tests.conftest import _HAS_PYKDTREE_OR_SCIPY + + +if _HAS_PYKDTREE_OR_SCIPY: + from cartopy.io.ogc_clients import _OWSLIB_AVAILABLE @pytest.mark.filterwarnings("ignore:Downloading") @@ -43,6 +47,7 @@ def test_natural_earth_custom(): return ax.figure +@pytest.mark.skipif(not _HAS_PYKDTREE_OR_SCIPY, reason='pykdtree or scipy is required') @pytest.mark.mpl_image_compare(filename='gshhs_coastlines.png', tolerance=0.95) def test_gshhs(): ax = plt.axes(projection=ccrs.Mollweide()) @@ -58,7 +63,8 @@ def test_gshhs(): @pytest.mark.network -@pytest.mark.skipif(not _OWSLIB_AVAILABLE, reason='OWSLib is unavailable.') +@pytest.mark.skipif(not _HAS_PYKDTREE_OR_SCIPY or not _OWSLIB_AVAILABLE, + reason='OWSLib and at least one of pykdtree or scipy is required') @pytest.mark.xfail(raises=ParseError, reason="Bad XML returned from the URL") @pytest.mark.mpl_image_compare(filename='wfs.png') @@ -73,7 +79,8 @@ def test_wfs(): @pytest.mark.network -@pytest.mark.skipif(not _OWSLIB_AVAILABLE, reason='OWSLib is unavailable.') +@pytest.mark.skipif(not _HAS_PYKDTREE_OR_SCIPY or not _OWSLIB_AVAILABLE, + reason='OWSLib and at least one of pykdtree or scipy is required') @pytest.mark.xfail(raises=ParseError, reason="Bad XML returned from the URL") @pytest.mark.mpl_image_compare(filename='wfs_france.png') diff --git a/lib/cartopy/tests/mpl/test_images.py b/lib/cartopy/tests/mpl/test_images.py index 9e1ac7277..4dda7362e 100644 --- a/lib/cartopy/tests/mpl/test_images.py +++ b/lib/cartopy/tests/mpl/test_images.py @@ -16,9 +16,14 @@ from cartopy import config import cartopy.crs as ccrs import cartopy.io.img_tiles as cimgt +from cartopy.tests.conftest import _HAS_PYKDTREE_OR_SCIPY import cartopy.tests.test_img_tiles as ctest_tiles +if not _HAS_PYKDTREE_OR_SCIPY: + pytest.skip('pykdtree or scipy is required', allow_module_level=True) + + NATURAL_EARTH_IMG = (config["repo_data_dir"] / 'raster' / 'natural_earth' / '50-natural-earth-1-downsampled.png') REGIONAL_IMG = (config['repo_data_dir'] / 'raster' / 'sample' diff --git a/lib/cartopy/tests/mpl/test_img_transform.py b/lib/cartopy/tests/mpl/test_img_transform.py index e73724ca6..1fc85b7cb 100644 --- a/lib/cartopy/tests/mpl/test_img_transform.py +++ b/lib/cartopy/tests/mpl/test_img_transform.py @@ -14,6 +14,12 @@ from cartopy import config import cartopy.crs as ccrs +from cartopy.tests.conftest import _HAS_PYKDTREE_OR_SCIPY + + +if not _HAS_PYKDTREE_OR_SCIPY: + pytest.skip('pykdtree or scipy is required', allow_module_level=True) + import cartopy.img_transform as im_trans diff --git a/lib/cartopy/tests/mpl/test_mpl_integration.py b/lib/cartopy/tests/mpl/test_mpl_integration.py index cc4e1ca5b..7fec03b95 100644 --- a/lib/cartopy/tests/mpl/test_mpl_integration.py +++ b/lib/cartopy/tests/mpl/test_mpl_integration.py @@ -13,6 +13,7 @@ import cartopy.crs as ccrs from cartopy.mpl import _MPL_38 +from cartopy.tests.conftest import requires_scipy @pytest.mark.natural_earth @@ -817,6 +818,7 @@ def test_quiver_rotated_pole(): return fig +@requires_scipy @pytest.mark.natural_earth @pytest.mark.mpl_image_compare(filename='quiver_regrid.png') def test_quiver_regrid(): @@ -836,6 +838,7 @@ def test_quiver_regrid(): return fig +@requires_scipy @pytest.mark.natural_earth @pytest.mark.mpl_image_compare(filename='quiver_regrid_with_extent.png', tolerance=0.54) @@ -857,6 +860,7 @@ def test_quiver_regrid_with_extent(): return fig +@requires_scipy @pytest.mark.natural_earth @pytest.mark.mpl_image_compare(filename='barbs_plate_carree.png') def test_barbs(): @@ -880,6 +884,7 @@ def test_barbs(): return fig +@requires_scipy @pytest.mark.natural_earth @pytest.mark.mpl_image_compare(filename='barbs_regrid.png') def test_barbs_regrid(): @@ -899,6 +904,7 @@ def test_barbs_regrid(): return fig +@requires_scipy @pytest.mark.natural_earth @pytest.mark.mpl_image_compare(filename='barbs_regrid_with_extent.png', tolerance=0.54) @@ -955,6 +961,7 @@ def test_barbs_1d_transformed(): return fig +@requires_scipy @pytest.mark.natural_earth @pytest.mark.mpl_image_compare(filename='streamplot.png', style='mpl20') def test_streamplot(): diff --git a/lib/cartopy/tests/mpl/test_web_services.py b/lib/cartopy/tests/mpl/test_web_services.py index 1a2963f0e..c4968e44e 100644 --- a/lib/cartopy/tests/mpl/test_web_services.py +++ b/lib/cartopy/tests/mpl/test_web_services.py @@ -7,6 +7,13 @@ import matplotlib.pyplot as plt import pytest +from cartopy.tests.conftest import _HAS_PYKDTREE_OR_SCIPY + + +if not _HAS_PYKDTREE_OR_SCIPY: + pytest.skip('pykdtree or scipy is required', allow_module_level=True) + + import cartopy.crs as ccrs from cartopy.io.ogc_clients import _OWSLIB_AVAILABLE diff --git a/lib/cartopy/tests/test_img_transform.py b/lib/cartopy/tests/test_img_transform.py index 78762be53..0ff0efc96 100644 --- a/lib/cartopy/tests/test_img_transform.py +++ b/lib/cartopy/tests/test_img_transform.py @@ -7,8 +7,16 @@ import numpy as np from numpy.testing import assert_array_equal import pytest -import scipy.spatial +from cartopy.tests.conftest import ( + _HAS_PYKDTREE_OR_SCIPY, + requires_pykdtree, + requires_scipy, +) + + +if not _HAS_PYKDTREE_OR_SCIPY: + pytest.skip("pykdtree or scipy are required", allow_module_level=True) import cartopy.crs as ccrs import cartopy.img_transform as img_trans @@ -113,7 +121,8 @@ def test_gridding_data_outside_projection(): @pytest.mark.parametrize("target_prj", (ccrs.Mollweide(), ccrs.Orthographic())) -@pytest.mark.parametrize("use_scipy", (True, False)) +@pytest.mark.parametrize("use_scipy", (pytest.param(True, marks=requires_scipy), + pytest.param(False, marks=requires_pykdtree))) def test_regridding_with_invalid_extent(target_prj, use_scipy, monkeypatch): # tests that when a valid extent results in invalid points in the # transformed coordinates, the regridding does not error. @@ -128,6 +137,7 @@ def test_regridding_with_invalid_extent(target_prj, use_scipy, monkeypatch): if use_scipy: monkeypatch.setattr(img_trans, "_is_pykdtree", False) + import scipy.spatial monkeypatch.setattr(img_trans, "_kdtreeClass", scipy.spatial.cKDTree) _ = img_trans.regrid(data, lons, lats, data_trans, target_prj, target_x, target_y) diff --git a/lib/cartopy/tests/test_vector_transform.py b/lib/cartopy/tests/test_vector_transform.py index 8a790a4c4..cf0c19386 100644 --- a/lib/cartopy/tests/test_vector_transform.py +++ b/lib/cartopy/tests/test_vector_transform.py @@ -6,6 +6,14 @@ import numpy as np from numpy.testing import assert_array_almost_equal, assert_array_equal +import pytest + + +try: + import scipy # noqa: F401 +except ImportError: + pytest.skip("scipy is required for vector transforms", allow_module_level=True) + import cartopy.crs as ccrs import cartopy.vector_transform as vec_trans