From e8a77a2493c1f4f58f72fb87ecc3126289e10485 Mon Sep 17 00:00:00 2001 From: Joris Van den Bossche Date: Sun, 11 Sep 2022 16:49:36 +0200 Subject: [PATCH] Compatibility with shapely 2.0 (remove usage of lgeos) --- .circleci/config.yml | 2 +- .github/workflows/ci-testing.yml | 21 ++++++++++++++++++--- .github/workflows/release.yml | 2 +- INSTALL | 4 ++-- environment.yml | 4 ++-- lib/cartopy/feature/__init__.py | 4 +++- lib/cartopy/mpl/patch.py | 2 +- lib/cartopy/trace.pyx | 6 +++--- requirements/default.txt | 2 +- 9 files changed, 32 insertions(+), 15 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 476a13c84..1c2fff434 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -45,7 +45,7 @@ deps-run: &deps-install pyshp \ scipy \ setuptools_scm \ - 'shapely<2' \ + shapely \ $EXTRA_PACKAGES \ --file docs/doc-requirements.txt conda list -n test-environment diff --git a/.github/workflows/ci-testing.yml b/.github/workflows/ci-testing.yml index 8ff698b72..2f22ec357 100644 --- a/.github/workflows/ci-testing.yml +++ b/.github/workflows/ci-testing.yml @@ -12,6 +12,11 @@ jobs: matrix: os: [ubuntu-latest, macos-latest] python-version: [3.8, 3.9, '3.10'] + shapely-dev: [false] + include: + - os: ubuntu-latest + python-version: '3.10' + shapely-dev: true defaults: run: shell: bash -l {0} @@ -33,9 +38,14 @@ jobs: echo "PACKAGES=cython=0.29.15 matplotlib-base=3.2.1 numpy=1.19 owslib=0.19.1 pyproj=3.0 scipy=1.4.0 shapely=1.6.4" >> $GITHUB_ENV - name: Latest packages - if: steps.minimum-packages.conclusion == 'skipped' + if: steps.minimum-packages.conclusion == 'skipped' && !matrix.shapely-dev run: | - echo "PACKAGES=cython fiona matplotlib-base numpy pyproj pykdtree scipy shapely<2" >> $GITHUB_ENV + echo "PACKAGES=cython fiona matplotlib-base numpy pyproj pykdtree scipy shapely" >> $GITHUB_ENV + + - name: Latest packages with Shapely dev + if: steps.minimum-packages.conclusion == 'skipped' && matrix.shapely-dev + run: | + echo "PACKAGES=cython fiona matplotlib-base numpy pyproj pykdtree scipy geos" >> $GITHUB_ENV - name: Coverage packages id: coverage @@ -49,11 +59,16 @@ jobs: - name: Install dependencies run: | PACKAGES="$PACKAGES owslib pep8 pillow pyshp pytest pytest-mpl!=0.16.0" - PACKAGES="$PACKAGES pytest-xdist setuptools_scm shapely<2" + PACKAGES="$PACKAGES pytest-xdist setuptools_scm" conda install $PACKAGES conda info -a conda list + - name: Install Shapely dev + if: matrix.shapely-dev + run: | + python -m pip install git+https://github.com/shapely/shapely.git@main + - name: Install Cartopy id: install run: | diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5a4b0f594..32f4f87c7 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -26,7 +26,7 @@ jobs: run: | PACKAGES="cython fiona matplotlib-base numpy pyproj pykdtree scipy" PACKAGES="$PACKAGES owslib pep8 pillow pyshp pytest" - PACKAGES="$PACKAGES pytest-xdist setuptools_scm shapely<2" + PACKAGES="$PACKAGES pytest-xdist setuptools_scm shapely" conda install $PACKAGES - name: Create sdist diff --git a/INSTALL b/INSTALL index 2562b4209..4b6346d71 100644 --- a/INSTALL +++ b/INSTALL @@ -85,7 +85,7 @@ For macOS, the required dependencies can be installed in the following way:: pip3 install --upgrade pyshp # shapely needs to be built from source to link to geos. If it is already # installed, uninstall it by: pip3 uninstall shapely - pip3 install "shapely<2" --no-binary shapely + pip3 install shapely --no-binary shapely Still on macOS, make sure you have installed pkg-config and set the `PKG_CONFIG_PATH` environment variable as follows:: @@ -117,7 +117,7 @@ Further information about the required dependencies can be found here: GEOS is an API of spatial predicates and functions for processing geometry written in C++. -**Shapely** between 1.6.4 and 1.8.4 (https://github.com/Toblerity/Shapely) +**Shapely** 1.6.4 or later (https://github.com/Toblerity/Shapely) Python package for the manipulation and analysis of planar geometric objects. diff --git a/environment.yml b/environment.yml index 3490886f3..2d5798a78 100644 --- a/environment.yml +++ b/environment.yml @@ -4,13 +4,13 @@ # conda activate cartopy-dev # pip install -e . # -name: cartopy-dev2 +name: cartopy-dev channels: - conda-forge dependencies: - cython>=0.28.5 - numpy>=1.18 - - shapely>=1.6.4,<2 + - shapely>=1.6.4 - geos>=3.7.2 - pyshp>=2.1 - pyproj>=3.0.0 diff --git a/lib/cartopy/feature/__init__.py b/lib/cartopy/feature/__init__.py index 8860c01c2..1342dcade 100644 --- a/lib/cartopy/feature/__init__.py +++ b/lib/cartopy/feature/__init__.py @@ -100,7 +100,9 @@ def intersecting_geometries(self, extent): geometries for this dataset. """ - if extent is not None: + # shapely 2.0 returns tuple of NaNs instead of None for empty geometry + # -> check for both + if extent is not None and not np.isnan(extent[0]): extent_geom = sgeom.box(extent[0], extent[2], extent[1], extent[3]) return (geom for geom in self.geometries() if diff --git a/lib/cartopy/mpl/patch.py b/lib/cartopy/mpl/patch.py index 2e6e1cbc9..045899178 100644 --- a/lib/cartopy/mpl/patch.py +++ b/lib/cartopy/mpl/patch.py @@ -208,7 +208,7 @@ def path_to_geos(path, force_ccw=False): # Remove any zero area Polygons def not_zero_poly(geom): - return ((isinstance(geom, sgeom.Polygon) and not geom._is_empty and + return ((isinstance(geom, sgeom.Polygon) and not geom.is_empty and geom.area != 0) or not isinstance(geom, sgeom.Polygon)) diff --git a/lib/cartopy/trace.pyx b/lib/cartopy/trace.pyx index 49c2d034b..f2d6634e1 100644 --- a/lib/cartopy/trace.pyx +++ b/lib/cartopy/trace.pyx @@ -31,6 +31,7 @@ cdef extern from "geos_c.h": pass ctypedef struct GEOSCoordSequence ctypedef struct GEOSPreparedGeometry + GEOSContextHandle_t GEOS_init_r() nogil GEOSCoordSequence *GEOSCoordSeq_create_r(GEOSContextHandle_t, unsigned int, unsigned int) nogil GEOSGeometry *GEOSGeom_createPoint_r(GEOSContextHandle_t, GEOSCoordSequence *) nogil GEOSGeometry *GEOSGeom_createLineString_r(GEOSContextHandle_t, GEOSCoordSequence *) nogil @@ -53,14 +54,13 @@ import re import warnings import shapely.geometry as sgeom -from shapely.geos import lgeos from pyproj import Geod, Transformer from pyproj.exceptions import ProjError cdef GEOSContextHandle_t get_geos_context_handle(): - cdef ptr handle = lgeos.geos_handle - return handle + cdef GEOSContextHandle_t handle = GEOS_init_r() + return handle cdef GEOSGeometry *geos_from_shapely(shapely_geom) except *: diff --git a/requirements/default.txt b/requirements/default.txt index 45c3493cf..861450c3c 100644 --- a/requirements/default.txt +++ b/requirements/default.txt @@ -1,5 +1,5 @@ numpy>=1.18 matplotlib>=3.1 -shapely>=1.6.4,<2 +shapely>=1.6.4 pyshp>=2.1 pyproj>=3.0.0