diff --git a/.github/workflows/ci-testing.yml b/.github/workflows/ci-testing.yml index b6de807d5..4ad3bfbeb 100644 --- a/.github/workflows/ci-testing.yml +++ b/.github/workflows/ci-testing.yml @@ -11,7 +11,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, macos-latest] - python-version: [3.7, 3.8, 3.9] + python-version: [3.8, 3.9, '3.10'] defaults: run: shell: bash -l {0} @@ -27,10 +27,10 @@ jobs: - name: Minimum packages # Only run on Linux for now # Conda's linux packages don't grab the testing label of matplotlib causing failures due to freetype differences - if: matrix.python-version == '3.7' && matrix.os == 'ubuntu-latest' + if: matrix.python-version == '3.8' && matrix.os == 'ubuntu-latest' id: minimum-packages run: | - echo "PACKAGES=cython=0.28.5 matplotlib=3.1 numpy=1.18 owslib=0.17 pyproj=3.0 proj=8.0 scipy=1.2.0 shapely=1.6.4" >> $GITHUB_ENV + echo "PACKAGES=cython=0.29.15 matplotlib-base=3.2.1 numpy=1.19 owslib=0.19.1 pyproj=3.0 proj=8.0 scipy=1.4.0 shapely=1.6.4" >> $GITHUB_ENV - name: Latest packages if: steps.minimum-packages.conclusion == 'skipped' @@ -40,7 +40,7 @@ jobs: - name: Coverage packages id: coverage # only want the coverage to be run on the latest ubuntu - if: matrix.python-version == '3.9' && matrix.os == 'ubuntu-latest' + if: matrix.python-version == '3.10' && matrix.os == 'ubuntu-latest' run: | echo "PACKAGES=$PACKAGES pytest-cov coveralls" >> $GITHUB_ENV echo "CYTHON_COVERAGE=1" >> $GITHUB_ENV diff --git a/INSTALL b/INSTALL index fd2c07aaa..a64b418b3 100644 --- a/INSTALL +++ b/INSTALL @@ -106,10 +106,10 @@ to the core packages. Further information about the required dependencies can be found here: -**Python** 3.7 or later (https://www.python.org/) +**Python** 3.8 or later (https://www.python.org/) Python 2 support was removed in v0.19. -**Matplotlib** 3.1 or later (https://matplotlib.org/) +**Matplotlib** 3.2 or later (https://matplotlib.org/) Python package for 2D plotting. Python package required for any graphical capabilities. diff --git a/lib/cartopy/crs.py b/lib/cartopy/crs.py index f1ae00cbe..87c07e9ed 100644 --- a/lib/cartopy/crs.py +++ b/lib/cartopy/crs.py @@ -41,7 +41,7 @@ # Cache the transformer creation method -@lru_cache() +@lru_cache def _get_transformer_from_crs(src_crs, tgt_crs): return Transformer.from_crs(src_crs, tgt_crs, always_xy=True) @@ -57,7 +57,7 @@ def _safe_pj_transform(src_crs, tgt_crs, x, y, z=None, trap=True): return xx, yy, zz -class Globe(object): +class Globe: """ Define an ellipsoid and, optionally, how to relate it to the real world. @@ -564,7 +564,7 @@ def __init__(self, globe=None): """ proj4_params = [('proj', 'lonlat')] globe = globe or Globe(datum='WGS84') - super(Geodetic, self).__init__(proj4_params, globe) + super().__init__(proj4_params, globe) # XXX Implement fwd such as Basemap's Geod. # Would be used in the tissot example. @@ -587,7 +587,7 @@ def __init__(self, globe=None): """ proj4_params = [('proj', 'geocent')] globe = globe or Globe(datum='WGS84') - super(Geocentric, self).__init__(proj4_params, globe) + super().__init__(proj4_params, globe) class RotatedGeodetic(CRS): diff --git a/lib/cartopy/mpl/gridliner.py b/lib/cartopy/mpl/gridliner.py index d54162d4f..58d993c92 100644 --- a/lib/cartopy/mpl/gridliner.py +++ b/lib/cartopy/mpl/gridliner.py @@ -1259,7 +1259,7 @@ def _axes_domain(self, nx=None, ny=None): return lon_range, lat_range -class Label(object): +class Label: """Helper class to manage the attributes for a single label""" def __init__(self, artist, path, xy, loc): diff --git a/lib/cartopy/tests/mpl/test_caching.py b/lib/cartopy/tests/mpl/test_caching.py index 7e5f09ca0..276e182d8 100644 --- a/lib/cartopy/tests/mpl/test_caching.py +++ b/lib/cartopy/tests/mpl/test_caching.py @@ -119,7 +119,7 @@ def test_contourf_transform_path_counting(): with mock.patch('cartopy.mpl.patch.path_to_geos') as path_to_geos_counter: x, y, z = sample_data((30, 60)) cs = ax.contourf(x, y, z, 5, transform=ccrs.PlateCarree()) - n_geom = sum([len(c.get_paths()) for c in cs.collections]) + n_geom = sum(len(c.get_paths()) for c in cs.collections) del cs fig.canvas.draw() diff --git a/lib/cartopy/tests/mpl/test_examples.py b/lib/cartopy/tests/mpl/test_examples.py index 5ae17efb6..c678cc593 100644 --- a/lib/cartopy/tests/mpl/test_examples.py +++ b/lib/cartopy/tests/mpl/test_examples.py @@ -5,7 +5,6 @@ # licensing details. import matplotlib.pyplot as plt -from packaging.version import parse as parse_version import pytest import cartopy.crs as ccrs @@ -35,7 +34,7 @@ def test_global_map(): @pytest.mark.natural_earth @pytest.mark.mpl_image_compare(filename='contour_label.png', tolerance=(9.9 - if MPL_VERSION < parse_version('3.2') + if MPL_VERSION.release[:2] < (3, 3) else 0.5)) def test_contour_label(): from cartopy.tests.mpl.test_caching import sample_data diff --git a/lib/cartopy/tests/mpl/test_mpl_integration.py b/lib/cartopy/tests/mpl/test_mpl_integration.py index 367d46323..6ca0fac53 100644 --- a/lib/cartopy/tests/mpl/test_mpl_integration.py +++ b/lib/cartopy/tests/mpl/test_mpl_integration.py @@ -8,7 +8,6 @@ import numpy as np import matplotlib.pyplot as plt -from packaging.version import parse as parse_version import pytest import cartopy.crs as ccrs @@ -110,9 +109,7 @@ def test_global_scatter_wrap_no_transform(): @pytest.mark.natural_earth -@pytest.mark.mpl_image_compare( - filename='global_hexbin_wrap.png', - tolerance=2 if MPL_VERSION < parse_version('3.2') else 0.5) +@pytest.mark.mpl_image_compare(filename='global_hexbin_wrap.png') def test_global_hexbin_wrap(): ax = plt.axes(projection=ccrs.PlateCarree()) ax.coastlines(zorder=2) @@ -131,7 +128,7 @@ def test_global_hexbin_wrap(): @pytest.mark.natural_earth @pytest.mark.mpl_image_compare( filename='global_hexbin_wrap.png', - tolerance=2 if MPL_VERSION < parse_version('3.2') else 0.5) + tolerance=0.5) def test_global_hexbin_wrap_transform(): ax = plt.axes(projection=ccrs.PlateCarree()) ax.coastlines(zorder=2) @@ -191,8 +188,7 @@ def test_simple_global(): id='TransverseMercator'), ]) @pytest.mark.mpl_image_compare( - tolerance=(2.61 if MPL_VERSION.release[:2] == (3, 1) else - 0.97 if MPL_VERSION.release[:2] < (3, 5) else 0.5), + tolerance=0.97 if MPL_VERSION.release[:2] < (3, 5) else 0.5, style='mpl20') def test_global_map(proj): if isinstance(proj, tuple): @@ -844,8 +840,7 @@ def test_barbs_1d_transformed(): @pytest.mark.natural_earth @pytest.mark.mpl_image_compare( filename='streamplot.png', style='mpl20', - tolerance=(42 if MPL_VERSION.release[:2] < (3, 2) else - 9.77 if MPL_VERSION.release[:2] < (3, 5) else 0.5)) + tolerance=9.77 if MPL_VERSION.release[:2] < (3, 5) else 0.5) def test_streamplot(): x = np.arange(-60, 42.5, 2.5) y = np.arange(30, 72.5, 2.5) diff --git a/lib/cartopy/tests/test_img_nest.py b/lib/cartopy/tests/test_img_nest.py index 1860611bb..4990bd896 100644 --- a/lib/cartopy/tests/test_img_nest.py +++ b/lib/cartopy/tests/test_img_nest.py @@ -149,8 +149,8 @@ def test_intersect(tmp_path): for zoom, image_names in expected: key = [k for k in nic._ancestry.keys() if k[0] == zoom][0] ancestry = nic._ancestry[key] - fnames = sorted([os.path.basename(item[1].filename) - for item in ancestry]) + fnames = sorted(os.path.basename(item[1].filename) + for item in ancestry) assert image_names == fnames # Check image retrieval for specific domain. @@ -234,14 +234,14 @@ def test_nest(nest_from_config): key = ('aerial z0 test', z0.images[0]) assert ('aerial z1 test', img) in nest_z0_z1._ancestry[key] - x1_y0_z1, = [img for img in z1.images - if img.filename.endswith('z_1/x_1_y_0.png')] + x1_y0_z1, = (img for img in z1.images + if img.filename.endswith('z_1/x_1_y_0.png')) assert (1, 0, 1) == _tile_from_img(x1_y0_z1) assert ([(2, 0, 2), (2, 1, 2), (3, 0, 2), (3, 1, 2)] == - sorted([_tile_from_img(img) for z, img in - nest.subtiles(('aerial z1 test', x1_y0_z1))])) + sorted(_tile_from_img(img) for z, img in + nest.subtiles(('aerial z1 test', x1_y0_z1)))) # check that the the images in the nest from configuration are the # same as those created by hand. diff --git a/lib/cartopy/tests/test_img_tiles.py b/lib/cartopy/tests/test_img_tiles.py index 1867242ca..21cf33008 100644 --- a/lib/cartopy/tests/test_img_tiles.py +++ b/lib/cartopy/tests/test_img_tiles.py @@ -377,9 +377,9 @@ def test_cache(cache_dir, tmp_path): assert sorted(files) == [f for x, y, z, f, h in x_y_z_f_h] assert set(files) == gt.cache - assert sorted(hashes.values()) == sorted([ + assert sorted(hashes.values()) == sorted( h for x, y, z, f, h in x_y_z_f_h - ]) + ) # Update images in cache (all white) for f in files: diff --git a/setup.py b/setup.py index 6517b5e41..b12d5f26c 100644 --- a/setup.py +++ b/setup.py @@ -9,11 +9,11 @@ # and/or pip. import sys -PYTHON_MIN_VERSION = (3, 7) +PYTHON_MIN_VERSION = (3, 8) if sys.version_info < PYTHON_MIN_VERSION: error = """ -Beginning with Cartopy 0.19, Python {} or above is required. +Beginning with Cartopy 0.21, Python {} or above is required. You are using Python {}. This may be due to an out of date pip. @@ -57,7 +57,7 @@ try: import numpy as np except ImportError: - raise ImportError('NumPy 1.10+ is required to install cartopy.') + raise ImportError('NumPy 1.19+ is required to install cartopy.') # Please keep in sync with INSTALL file. @@ -379,9 +379,9 @@ def decythonize(extensions, **_ignore): 'Programming Language :: C++', 'Programming Language :: Python', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.10', 'Programming Language :: Python :: 3 :: Only', 'Topic :: Scientific/Engineering', 'Topic :: Scientific/Engineering :: GIS',