Repository: Toblerity/Shapely
Pull request #1076 (2021-01-26 08:59:27)

CI: move Travis linux builds to Github Actions
Following up on https://github.com/Toblerity/Shapely/pull/1041/, and the work that @mwtoews and I did in pygeos. This should currently keep the exact set of environments as we have on Travis (only the numpy versions, if installed, are now also pinned, copied that from pygeos).

(Travis CI is already disabled due to negative credit balance ..)

jorisvandenbossche: OK, this seems to be working ;) 
See https://github.com/jorisvandenbossche/Shapely/runs/1768150753?check_suite_focus=true on my fork for an example build
sgillies: Great! I'll cherry pick for the other branches.
jorisvandenbossche: If this looks OK, shall I directly remove the travis configuration as well?
jorisvandenbossche: Actually, they are failing .. See eg https://github.com/jorisvandenbossche/Shapely/runs/1768150929?check_suite_focus=true#step:9:223. But now the tests at least run, and it are only a few, actual failures that we can investigate/solve, and not the plain error running the tests as on Travis.

That's one of the annoying things with github actions, IMO, they don't have a good "allowed failures" like Travis. The build with GEOS master is allowed to fail (`continue-on-error`), but then you don't really notice if there is a failure ..
mwtoews: It seems that I was looking at a bright green check icon for pass/fail! Indeed, these look like actual failures worth investigating further.

Patch:
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 745913d..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,126 +0,0 @@
-language: python
-dist: xenial
-
-cache:
-  directories:
-    - $HOME/geosinstall
-    - ~/.cache/pip
-
-matrix:
-  include:
-    - python: "3.5"
-      env:
-        GEOS_VERSION="3.5.2"
-        SPEEDUPS=1
-        NUMPY=1
-    - python: "3.5"
-      env:
-        GEOS_VERSION="3.5.2"
-        SPEEDUPS=0
-        NUMPY=1
-    - python: "3.5"
-      env:
-        GEOS_VERSION="3.5.2"
-        SPEEDUPS=0
-        NUMPY=0
-    - python: "3.6"
-      env:
-        GEOS_VERSION="3.6.4"
-        SPEEDUPS=1
-        NUMPY=1
-    - python: "3.6"
-      env:
-        GEOS_VERSION="3.6.4"
-        SPEEDUPS=0
-        NUMPY=1
-    - python: "3.6"
-      env:
-        GEOS_VERSION="3.6.4"
-        SPEEDUPS=0
-        NUMPY=0
-    - python: "3.7"
-      env:
-        GEOS_VERSION="3.7.3"
-        SPEEDUPS=1
-        NUMPY=1
-    - python: "3.7"
-      env:
-        GEOS_VERSION="3.7.3"
-        SPEEDUPS=0
-        NUMPY=1
-    - python: "3.7"
-      env:
-        GEOS_VERSION="3.7.3"
-        SPEEDUPS=0
-        NUMPY=0
-    - python: "3.8"
-      env:
-        GEOS_VERSION="3.8.1"
-        SPEEDUPS=1
-        NUMPY=1
-    - python: "3.8"
-      env:
-        GEOS_VERSION="3.8.1"
-        SPEEDUPS=0
-        NUMPY=1
-    - python: "3.8"
-      env:
-        GEOS_VERSION="3.8.1"
-        SPEEDUPS=0
-        NUMPY=0
-    - python: "3.9"
-      env:
-        GEOS_VERSION="3.9.0beta2"
-        SPEEDUPS=1
-        NUMPY=1
-    - python: "3.9"
-      env:
-        GEOS_VERSION="3.9.0beta2"
-        SPEEDUPS=0
-        NUMPY=1
-    - python: "3.9"
-      env:
-        GEOS_VERSION="3.9.0beta2"
-        SPEEDUPS=0
-        NUMPY=0
-    - python: "3.9-dev"
-      env:
-        GEOS_VERSION="master"
-        SPEEDUPS=1
-        NUMPY=1
-  allow_failures:
-    - python: "3.9-dev"
-      env:
-        GEOS_VERSION="master"
-        SPEEDUPS=1
-        NUMPY=1
-
-before_install:
-  - export GEOS_INSTALL=$HOME/geosinstall/geos-$GEOS_VERSION
-  - ./ci/install_geos.sh
-  - pip install --disable-pip-version-check --upgrade pip
-  - pip install --upgrade wheel
-  # if building with speedups install cython
-  - if [ "$SPEEDUPS" == "1" ]; then pip install --install-option="--no-cython-compile" cython; fi
-  # if testing without numpy explicitly remove it
-  - if [ "$NUMPY" == "0" ]; then pip uninstall --yes numpy; fi
-  # convert SPEEDUPS to --with-speedups/--without-speedups
-  - if [ "$SPEEDUPS" == "1" ]; then SPEEDUPS_FLAG=--with-speedups; else SPEEDUPS_FLAG=--without-speedups; fi
-  - pip install --upgrade coveralls pytest-cov pytest>=3.8
-
-install:
-  - export GEOS_CONFIG=$HOME/geosinstall/geos-$GEOS_VERSION/bin/geos-config
-  - pip install -v -e .[all]
-
-script:
-  - export LD_LIBRARY_PATH=$HOME/geosinstall/geos-$GEOS_VERSION/lib
-  - export DYLD_LIBRARY_PATH=$HOME/geosinstall/geos-$GEOS_VERSION/lib
-  - python -c "from shapely.geos import geos_version; print(geos_version)"
-  - python -m pytest --cov shapely --cov-report term-missing "${SPEEDUPS_FLAG}"
-  - if [[ "$TRAVIS_PYTHON_VERSION" == "3.8" && "$NUMPY" == "1" && "$SPEEDUPS" == "1" ]]; then python -m pytest shapely --doctest-modules; fi
-
-after_success:
-  - coveralls || echo "!! intermittent coveralls failure"
-
-notifications:
-    email: false
diff --git a/README.rst b/README.rst
index 4adbb71..3005d66 100644
--- a/README.rst
+++ b/README.rst
@@ -2,10 +2,10 @@
 Shapely
 =======
 
-|travis| |appveyor| |coveralls|
+|github-actions| |appveyor| |coveralls|
 
-.. |travis| image:: https://travis-ci.org/Toblerity/Shapely.svg?branch=master
-   :target: https://travis-ci.org/Toblerity/Shapely
+.. |github-actions| image:: https://github.com/Toblerity/Shapely/workflows/Tests%20(Linux)/badge.svg
+   :target: https://github.com/Toblerity/Shapely/actions
 
 .. |appveyor| image:: https://ci.appveyor.com/api/projects/status/github/Toblerity/Shapely?branch=master&svg=true
    :target: https://ci.appveyor.com/project/frsci/shapely?branch=master
diff --git a/shapely/iterops.py b/shapely/iterops.py
index a0c7deb..4011e6d 100644
--- a/shapely/iterops.py
+++ b/shapely/iterops.py
@@ -1,7 +1,9 @@
 """
 Iterative forms of operations
 """
+import warnings
 
+from shapely.errors import ShapelyDeprecationWarning
 from shapely.topology import Delegating
 
 
@@ -11,6 +13,10 @@ class IterOp(Delegating):
     """
 
     def __call__(self, context, iterator, value=True):
+        warnings.warn(
+            "The '{0}' function is deprecated and will be removed in "
+            "Shapely 2.0".format(self._name),
+            ShapelyDeprecationWarning, stacklevel=2)
         if context._geom is None:
             raise ValueError("Null geometry supports no operations")
         for item in iterator:
diff --git a/shapely/topology.py b/shapely/topology.py
index 1618046..d4e56b1 100644
--- a/shapely/topology.py
+++ b/shapely/topology.py
@@ -23,6 +23,7 @@ class Validating(object):
 class Delegating(Validating):
 
     def __init__(self, name):
+        self._name = name
         self.fn = lgeos.methods[name]
 
     def _check_topology(self, err, *geoms):


Test patch:
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
new file mode 100644
index 0000000..e34c5e0
--- /dev/null
+++ b/.github/workflows/tests.yml
@@ -0,0 +1,175 @@
+name: Tests (Linux)
+
+on: [push, pull_request]
+
+jobs:
+  test:
+    name: Python ${{ matrix.python }} (GEOS ${{ matrix.geos }}, speedups ${{ matrix.speedups }}, numpy ${{ matrix.numpy || 'not installed' }})
+    # runs-on: ubuntu-latest
+    runs-on: ubuntu-16.04
+    strategy:
+      fail-fast: false
+      matrix:
+        include:
+          # 2015
+          - python: 3.5
+            geos: 3.5.2
+            numpy: 1.10.4
+            speedups: 1
+          - python: 3.5
+            geos: 3.5.2
+            numpy: 1.10.4
+            speedups: 0
+          - python: 3.5
+            geos: 3.5.2
+            speedups: 0
+          # 2017
+          - python: 3.6
+            geos: 3.6.4
+            numpy: 1.13.3
+            speeedups: 1
+          - python: 3.6
+            geos: 3.6.4
+            numpy: 1.13.3
+            speeedups: 0
+          - python: 3.6
+            geos: 3.6.4
+            speeedups: 0
+          # 2018
+          - python: 3.7
+            geos: 3.7.3
+            numpy: 1.15.4
+            speedups: 1
+          - python: 3.7
+            geos: 3.7.3
+            numpy: 1.15.4
+            speedups: 0
+          - python: 3.7
+            geos: 3.7.3
+            speedups: 0
+          # 2019
+          - python: 3.8
+            geos: 3.8.1
+            numpy: 1.17.5
+            speedups: 1
+          - python: 3.8
+            geos: 3.8.1
+            numpy: 1.17.5
+            speedups: 0
+          - python: 3.8
+            geos: 3.8.1
+            speedups: 0
+          # 2020
+          - python: 3.9
+            geos: 3.9.0
+            numpy: 1.19.5
+            speedups: 1
+          - python: 3.9
+            geos: 3.9.0
+            numpy: 1.19.5
+            speedups: 0
+          - python: 3.9
+            geos: 3.9.0
+            speedups: 0
+          # dev
+          - python: 3.9
+            geos: master
+            speedups: 1
+
+    env:
+      GEOS_VERSION: ${{ matrix.geos }}
+      GEOS_INSTALL: ${{ github.workspace }}/geosinstall/geos-${{ matrix.geos }}
+      SPEEDUPS: ${{ matrix.speedups }}
+
+    steps:
+      - uses: actions/checkout@v2
+
+      - name: Set up Python ${{ matrix.python }}
+        uses: actions/setup-python@v2
+        with:
+          python-version: ${{ matrix.python }}
+
+      - name: Cache GEOS and pip packages
+        uses: actions/cache@v2
+        with:
+          key: ${{ runner.os }}-geos-${{ matrix.geos }}
+          path: |
+            ~/.cache/pip
+            ${{ github.workspace }}/geosinstall
+
+      - name: Install GEOS
+        shell: bash
+        run: |
+          ./ci/install_geos.sh
+          cd ${{ github.workspace }}
+
+      - name: Install python dependencies
+        shell: bash
+        run: |
+          pip install --disable-pip-version-check --upgrade pip
+          pip install --upgrade wheel
+          if [ "$GEOS_VERSION" = "master" ]; then
+            pip install --upgrade --pre Cython numpy;
+          elif [ "$SPEEDUPS" == "1" ]; then
+            pip install --install-option="--no-cython-compile" cython;
+            pip install --upgrade numpy==${{ matrix.numpy }};
+          elif [ -n "${{ matrix.numpy }}" ]; then
+            pip install --upgrade numpy==${{ matrix.numpy }};
+          else
+            pip uninstall --yes numpy;
+          fi
+          pip install --upgrade coveralls pytest-cov pytest
+          pip list
+
+      - name: Set environment variables
+        shell: bash
+        run: |
+          echo "LD_LIBRARY_PATH=$GEOS_INSTALL/lib" >> $GITHUB_ENV
+          echo $GEOS_INSTALL/bin >> $GITHUB_PATH
+
+      - name: Build and install Shapely
+        shell: bash
+        run: |
+          pip install -v -e .
+
+      - name: Overview of the Python environment (pip list)
+        shell: bash
+        run: |
+          pip list
+
+      - name: Run tests
+        shell: bash
+        continue-on-error: ${{ matrix.geos == 'master' }}
+        run: |
+          if [ "$SPEEDUPS" == "1" ]; then SPEEDUPS_FLAG=--with-speedups; else SPEEDUPS_FLAG=--without-speedups; fi
+          python -c "from shapely import geos; print(geos.geos_version_string)"
+          python -c "from shapely import speedups; print(speedups.enabled)"
+          python -m pytest --cov shapely --cov-report term-missing "${SPEEDUPS_FLAG}"
+
+      - name: Run doctests
+        if: ${{ matrix.python == '3.8' && matrix.numpy && matrix.speedups == '1' }}
+        shell: bash
+        run: |
+          python -m pytest shapely --doctest-modules
+
+      - name: Upload coverage
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+          COVERALLS_SERVICE_NAME: github-actions
+          COVERALLS_PARALLEL: true
+        shell: bash
+        run: |
+          coveralls || echo "!! intermittent coveralls failure"
+
+  coveralls:
+    name: Indicate completion to coveralls.io
+    needs: test
+    runs-on: ubuntu-latest
+    container: python:3-slim
+    steps:
+    - name: Finished
+      run: |
+        pip3 install --upgrade coveralls
+        coveralls --finish || echo "!! intermittent coveralls failure"
+      env:
+        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/tests/__init__.py b/tests/__init__.py
index 223f8b6..d7bcf52 100755
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -17,7 +17,7 @@ except ImportError:
     numpy = False
     numpy_version = 'not available'
 
-# Show some diagnostic information; handy for Travis CI
+# Show some diagnostic information; handy for CI
 print('Python version: ' + sys.version.replace('\n', ' '))
 print('GEOS version: ' + geos_version_string)
 print('Numpy version: ' + numpy_version)
diff --git a/tests/test_iterops.py b/tests/test_iterops.py
index 5341896..3962933 100644
--- a/tests/test_iterops.py
+++ b/tests/test_iterops.py
@@ -1,13 +1,17 @@
 """Test operator iterations
 """
-from . import unittest
+from . import unittest, shapely20_deprecated
 from shapely import iterops
+from shapely.errors import ShapelyDeprecationWarning
 from shapely.geometry import Point, Polygon
 from shapely.geos import TopologicalError
 
+import pytest
+
 
 class IterOpsTestCase(unittest.TestCase):
 
+    @shapely20_deprecated
     def test_iterops(self):
 
         coords = ((0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0), (0.0, 0.0))
@@ -43,7 +47,7 @@ class IterOpsTestCase(unittest.TestCase):
                  for p in points))),
             [[(0.5, 0.5)]])
 
-
+    @shapely20_deprecated
     def test_err(self):
         # bowtie polygon.
         coords = ((0.0, 0.0), (0.0, 1.0), (1.0, 0.0), (1.0, 1.0), (0.0, 0.0))
@@ -55,6 +59,7 @@ class IterOpsTestCase(unittest.TestCase):
             all([isinstance(x, Polygon)
                  for x in iterops.intersects(polygon, points, True)]))
 
+    @shapely20_deprecated
     def test_topological_error(self):
         p1 = [(339, 346), (459, 346), (399, 311), (340, 277), (399, 173),
               (280, 242), (339, 415), (280, 381), (460, 207), (339, 346)]
@@ -67,3 +72,12 @@ class IterOpsTestCase(unittest.TestCase):
 
         with self.assertRaises(TopologicalError):
             list(iterops.within(polygon1, [polygon2]))
+
+    def test_iterops_deprecated(self):
+
+        coords = ((0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0), (0.0, 0.0))
+        polygon = Polygon(coords)
+        points = [Point(0.5, 0.5), Point(2.0, 2.0)]
+
+        with pytest.warns(ShapelyDeprecationWarning, match="'contains' function"):
+            list(iterops.contains(polygon, points, True))