diff --git a/.appveyor.yml b/.appveyor.yml index cfb916a53..1d702c469 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -16,8 +16,7 @@ install: - conda config --add channels conda-forge/label/testing - set ENV_NAME=test-environment - set PACKAGES=%PACKAGES% flufl.lock owslib pep8 pillow pyshp pytest - - set PACKAGES=%PACKAGES% requests setuptools_scm setuptools_scm_git_archive - - set PACKAGES=%PACKAGES% shapely + - set PACKAGES=%PACKAGES% requests setuptools_scm shapely - conda create -n %ENV_NAME% python=%PYTHON_VERSION% %PACKAGES% - activate %ENV_NAME% - set INCLUDE=%CONDA_PREFIX%\Library\include;%INCLUDE% diff --git a/.circleci/config.yml b/.circleci/config.yml index d9807a81d..cc9c1b318 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -46,7 +46,6 @@ deps-run: &deps-install requests \ scipy \ setuptools_scm \ - setuptools_scm_git_archive \ shapely \ $EXTRA_PACKAGES \ --file docs/doc-requirements.txt diff --git a/.git_archival.txt b/.git_archival.txt deleted file mode 100644 index 95cb3eea4..000000000 --- a/.git_archival.txt +++ /dev/null @@ -1 +0,0 @@ -ref-names: $Format:%D$ diff --git a/.github/workflows/ci-testing.yml b/.github/workflows/ci-testing.yml index 6ef1be700..5cf4593e5 100644 --- a/.github/workflows/ci-testing.yml +++ b/.github/workflows/ci-testing.yml @@ -48,8 +48,7 @@ jobs: - name: Install dependencies run: | PACKAGES="$PACKAGES flufl.lock owslib pep8 pillow pyshp pytest" - PACKAGES="$PACKAGES pytest-xdist requests setuptools_scm" - PACKAGES="$PACKAGES setuptools_scm_git_archive shapely" + PACKAGES="$PACKAGES pytest-xdist requests setuptools_scm shapely" # openssl 3.0 updated the legacy renegotiation default, which causes # failures in NASA's WMTS server. They will need to update their # server before we can use a newer openssl. diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index fd09d9024..85b52b05d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -26,8 +26,7 @@ jobs: run: | PACKAGES="cython fiona matplotlib-base numpy pyproj pykdtree scipy" PACKAGES="$PACKAGES flufl.lock owslib pep8 pillow pyshp pytest" - PACKAGES="$PACKAGES pytest-xdist requests setuptools_scm" - PACKAGES="$PACKAGES setuptools_scm_git_archive shapely" + PACKAGES="$PACKAGES pytest-xdist requests setuptools_scm shapely" conda install $PACKAGES - name: Create sdist diff --git a/lib/cartopy/feature/nightshade.py b/lib/cartopy/feature/nightshade.py index b8a613474..8a8f28858 100644 --- a/lib/cartopy/feature/nightshade.py +++ b/lib/cartopy/feature/nightshade.py @@ -77,8 +77,12 @@ def __init__(self, date=None, delta=0.1, refraction=-0.83, # Solve the generalized equation for omega0, which is the # angle of sunrise/sunset from solar noon - omega0 = np.rad2deg(np.arccos(np.sin(np.deg2rad(refraction)) / - np.cos(np.deg2rad(y)))) + # We need to clip the input to arccos to [-1, 1] due to floating + # point precision and arccos creating nans for values outside + # of the domain + arccos_tmp = np.clip(np.sin(np.deg2rad(refraction)) / + np.cos(np.deg2rad(y)), -1, 1) + omega0 = np.rad2deg(np.arccos(arccos_tmp)) # Fill the longitude values from the offset for midnight. # This needs to be a closed loop to fill the polygon. diff --git a/lib/cartopy/tests/crs/test_interrupted_goode_homolosine.py b/lib/cartopy/tests/crs/test_interrupted_goode_homolosine.py index 4b51492f0..30383073b 100644 --- a/lib/cartopy/tests/crs/test_interrupted_goode_homolosine.py +++ b/lib/cartopy/tests/crs/test_interrupted_goode_homolosine.py @@ -9,7 +9,7 @@ """ import numpy as np -from numpy.testing import assert_almost_equal +from numpy.testing import assert_allclose import pytest import cartopy.crs as ccrs @@ -24,10 +24,10 @@ def test_default(emphasis): check_proj_params("igh", igh, other_args) elif emphasis == "ocean": check_proj_params("igh_o", igh, other_args) - assert_almost_equal( + assert_allclose( np.array(igh.x_limits), [-20037508.3427892, 20037508.3427892] ) - assert_almost_equal( + assert_allclose( np.array(igh.y_limits), [-8683259.7164347, 8683259.7164347] ) @@ -42,8 +42,8 @@ def test_eccentric_globe(emphasis): elif emphasis == "ocean": check_proj_params("igh_o", igh, other_args) - assert_almost_equal(np.array(igh.x_limits), [-3141.5926536, 3141.5926536]) - assert_almost_equal(np.array(igh.y_limits), [-1361.410035, 1361.410035]) + assert_allclose(np.array(igh.x_limits), [-3141.5926536, 3141.5926536]) + assert_allclose(np.array(igh.y_limits), [-1361.410035, 1361.410035]) @pytest.mark.parametrize( @@ -60,11 +60,10 @@ def test_central_longitude(emphasis, lon): elif emphasis == "ocean": check_proj_params("igh_o", igh, other_args) - assert_almost_equal( + assert_allclose( np.array(igh.x_limits), [-20037508.3427892, 20037508.3427892], - decimal=5, ) - assert_almost_equal( + assert_allclose( np.array(igh.y_limits), [-8683259.7164347, 8683259.7164347] ) diff --git a/lib/cartopy/tests/crs/test_mollweide.py b/lib/cartopy/tests/crs/test_mollweide.py index 540fa8826..58cbd4ecc 100644 --- a/lib/cartopy/tests/crs/test_mollweide.py +++ b/lib/cartopy/tests/crs/test_mollweide.py @@ -9,7 +9,7 @@ """ import numpy as np -from numpy.testing import assert_almost_equal +from numpy.testing import assert_allclose import pytest import cartopy.crs as ccrs @@ -21,10 +21,10 @@ def test_default(): other_args = {'a=6378137.0', 'lon_0=0'} check_proj_params('moll', moll, other_args) - assert_almost_equal(np.array(moll.x_limits), - [-18040095.6961473, 18040095.6961473]) - assert_almost_equal(np.array(moll.y_limits), - [-9020047.8480736, 9020047.8480736]) + assert_allclose(np.array(moll.x_limits), + [-18040095.6961473, 18040095.6961473]) + assert_allclose(np.array(moll.y_limits), + [-9020047.8480736, 9020047.8480736]) def test_sphere_globe(): @@ -33,8 +33,8 @@ def test_sphere_globe(): other_args = {'a=1000', 'lon_0=0'} check_proj_params('moll', moll, other_args) - assert_almost_equal(moll.x_limits, [-2828.4271247, 2828.4271247]) - assert_almost_equal(moll.y_limits, [-1414.2135624, 1414.2135624]) + assert_allclose(moll.x_limits, [-2828.4271247, 2828.4271247]) + assert_allclose(moll.y_limits, [-1414.2135624, 1414.2135624]) def test_ellipse_globe(): @@ -48,8 +48,8 @@ def test_ellipse_globe(): check_proj_params('moll', moll, other_args) # Limits are the same as default since ellipses are not supported. - assert_almost_equal(moll.x_limits, [-18040095.6961473, 18040095.6961473]) - assert_almost_equal(moll.y_limits, [-9020047.8480736, 9020047.8480736]) + assert_allclose(moll.x_limits, [-18040095.6961473, 18040095.6961473]) + assert_allclose(moll.y_limits, [-9020047.8480736, 9020047.8480736]) def test_eccentric_globe(): @@ -64,8 +64,8 @@ def test_eccentric_globe(): check_proj_params('moll', moll, other_args) # Limits are the same as spheres since ellipses are not supported. - assert_almost_equal(moll.x_limits, [-2828.4271247, 2828.4271247]) - assert_almost_equal(moll.y_limits, [-1414.2135624, 1414.2135624]) + assert_allclose(moll.x_limits, [-2828.4271247, 2828.4271247]) + assert_allclose(moll.y_limits, [-1414.2135624, 1414.2135624]) def test_offset(): @@ -83,11 +83,10 @@ def test_central_longitude(lon): other_args = {'a=6378137.0', f'lon_0={lon}'} check_proj_params('moll', moll, other_args) - assert_almost_equal(np.array(moll.x_limits), - [-18040095.6961473, 18040095.6961473], - decimal=5) - assert_almost_equal(np.array(moll.y_limits), - [-9020047.8480736, 9020047.8480736]) + assert_allclose(np.array(moll.x_limits), + [-18040095.6961473, 18040095.6961473]) + assert_allclose(np.array(moll.y_limits), + [-9020047.8480736, 9020047.8480736]) def test_grid(): @@ -100,10 +99,8 @@ def test_grid(): other_args = {'a=0.7071067811865476', 'b=0.7071067811865476', 'lon_0=0'} check_proj_params('moll', moll, other_args) - assert_almost_equal(np.array(moll.x_limits), - [-2, 2]) - assert_almost_equal(np.array(moll.y_limits), - [-1, 1]) + assert_allclose(np.array(moll.x_limits), [-2, 2]) + assert_allclose(np.array(moll.y_limits), [-1, 1]) lats = np.arange(0, 91, 5)[::-1] lons = np.full_like(lats, 90) @@ -114,14 +111,14 @@ def test_grid(): 0.75894, 0.80591, 0.84739, 0.88362, 0.91477, 0.94096, 0.96229, 0.97882, 0.99060, 0.99765, 1.00000, ]) - assert_almost_equal(result[:, 0], expected_x, decimal=5) + assert_allclose(result[:, 0], expected_x, atol=1e-5) expected_y = np.array([ 1.00000, 0.97837, 0.94539, 0.90606, 0.86191, 0.81382, 0.76239, 0.70804, 0.65116, 0.59204, 0.53097, 0.46820, 0.40397, 0.33850, 0.27201, 0.20472, 0.13681, 0.06851, 0.00000, ]) - assert_almost_equal(result[:, 1], expected_y, decimal=5) + assert_allclose(result[:, 1], expected_y, atol=1e-5) def test_sphere_transform(): @@ -135,14 +132,13 @@ def test_sphere_transform(): other_args = {'a=1.0', 'b=1.0', 'lon_0=-90.0'} check_proj_params('moll', moll, other_args) - assert_almost_equal(np.array(moll.x_limits), - [-2.8284271247461903, 2.8284271247461903], - decimal=2) - assert_almost_equal(np.array(moll.y_limits), - [-1.4142135623730951, 1.4142135623730951]) + assert_allclose(np.array(moll.x_limits), + [-2.8284271247461903, 2.8284271247461903]) + assert_allclose(np.array(moll.y_limits), + [-1.4142135623730951, 1.4142135623730951]) result = moll.transform_point(-75.0, -50.0, geodetic) - assert_almost_equal(result, [0.1788845, -0.9208758]) + assert_allclose(result, [0.1788845, -0.9208758]) inverse_result = geodetic.transform_point(result[0], result[1], moll) - assert_almost_equal(inverse_result, [-75.0, -50.0]) + assert_allclose(inverse_result, [-75.0, -50.0]) diff --git a/lib/cartopy/tests/feature/test_nightshade.py b/lib/cartopy/tests/feature/test_nightshade.py index 8764943df..062f91eab 100644 --- a/lib/cartopy/tests/feature/test_nightshade.py +++ b/lib/cartopy/tests/feature/test_nightshade.py @@ -8,7 +8,7 @@ import pytest -from cartopy.feature.nightshade import _julian_day, _solar_position +from cartopy.feature.nightshade import _julian_day, _solar_position, Nightshade def test_julian_day(): @@ -44,3 +44,12 @@ def test_solar_position(dt, true_lat, true_lon): lat, lon = _solar_position(dt) assert pytest.approx(true_lat, 0.1) == lat assert pytest.approx(true_lon, 0.1) == lon + + +def test_nightshade_floating_point(): + # Smoke test for clipping nightshade floating point values + date = datetime(1999, 12, 31, 12) + + # This can cause an error with floating point precision if it is + # set to exactly -6 and arccos input is not clipped to [-1, 1] + Nightshade(date, refraction=-6.0, color='none') diff --git a/lib/cartopy/tests/mpl/baseline_images/mpl/test_crs/igh_land.png b/lib/cartopy/tests/mpl/baseline_images/mpl/test_crs/igh_land.png index e83ddd1c3..4d523ca9b 100644 Binary files a/lib/cartopy/tests/mpl/baseline_images/mpl/test_crs/igh_land.png and b/lib/cartopy/tests/mpl/baseline_images/mpl/test_crs/igh_land.png differ diff --git a/lib/cartopy/tests/mpl/baseline_images/mpl/test_crs/igh_ocean.png b/lib/cartopy/tests/mpl/baseline_images/mpl/test_crs/igh_ocean.png index 565ba1d36..a470d4210 100644 Binary files a/lib/cartopy/tests/mpl/baseline_images/mpl/test_crs/igh_ocean.png and b/lib/cartopy/tests/mpl/baseline_images/mpl/test_crs/igh_ocean.png differ diff --git a/lib/cartopy/tests/mpl/test_crs.py b/lib/cartopy/tests/mpl/test_crs.py index c61ac83be..e1a36506e 100644 --- a/lib/cartopy/tests/mpl/test_crs.py +++ b/lib/cartopy/tests/mpl/test_crs.py @@ -9,11 +9,13 @@ import pytest import cartopy.crs as ccrs -from cartopy.tests.mpl import ImageTesting +from cartopy.tests.mpl import ImageTesting, MPL_VERSION @pytest.mark.natural_earth -@ImageTesting(["igh_land"]) +@ImageTesting(["igh_land"], + tolerance=(3.6 if MPL_VERSION.release[:2] < (3, 5) + or ccrs.PROJ_VERSION < (9, 0, 1) else 0.5)) def test_igh_land(): crs = ccrs.InterruptedGoodeHomolosine(emphasis="land") ax = plt.axes(projection=crs) @@ -22,7 +24,9 @@ def test_igh_land(): @pytest.mark.natural_earth -@ImageTesting(["igh_ocean"]) +@ImageTesting(["igh_ocean"], + tolerance=(4.5 if MPL_VERSION.release[:2] < (3, 5) + or ccrs.PROJ_VERSION < (9, 0, 1) else 0.5)) def test_igh_ocean(): crs = ccrs.InterruptedGoodeHomolosine( central_longitude=-160, emphasis="ocean" diff --git a/pyproject.toml b/pyproject.toml index 9738a040c..b905cf90a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,6 @@ requires = [ "setuptools >= 40.6.0", "Cython >= 0.29.13", "oldest-supported-numpy", - "setuptools_scm", - "setuptools_scm_git_archive", + "setuptools_scm >= 7.0.0", ] build-backend = "setuptools.build_meta"