Repository: Toblerity/Shapely
Pull request #926 (2020-06-06 11:22:34)

Deprecate asShape (CachingGeometryProxy adapter classes)
Deprecating the adapter classes that create geometry-like proxy objects with coordinates stored in external objects (xref https://github.com/shapely/shapely-rfc/pull/1/).

I again started with the Point geometry to check if the workflow looks good. 

There are however multiple ways to create those objects. For points, you have the general `asShape` and `asPoint`, but in principle also the `PointAdapter` class constructor (but I don't know whether those are regarded as public API?). 

The way I did it now is to add a deprecation warning to both `asShape` and `asPoint`, so the message can be specific. Bu there are certainly other ways to do it as well.


coveralls: 
[![Coverage Status](https://coveralls.io/builds/31281129/badge)](https://coveralls.io/builds/31281129)

Coverage increased (+0.03%) to 81.837% when pulling **8b2714573bceced863dcd9f8c967cc92dba93b27 on jorisvandenbossche:deprecate-poxies** into **ea25f8cbaa177213aabfda55a8ab2f272f263b2b on Toblerity:master**.

sgillies: Excellent, @jorisvandenbossche . I can't think of a reason not to eliminate the adapter classes in 2.0. There's a lot of code there that we won't want to maintain anymore and it only exists to support a kind of mutability.

How about warning from the adapter constructors, mentioning deprecation of the class *and* the factory functions (asShape, asPoint, &c)?
jorisvandenbossche: > How about warning from the adapter constructors, mentioning deprecation of the class and the factory functions (asShape, asPoint, &c)?

OK, doing a warning only in the class + a general message so it is valid for all possible ways to construct it sounds good.
jorisvandenbossche: Updated the warning message and location. If that looks good, then will do the same for the other geometry types.

Patch:
diff --git a/shapely/ctypes_declarations.py b/shapely/ctypes_declarations.py
index f9d199a..adcd90d 100644
--- a/shapely/ctypes_declarations.py
+++ b/shapely/ctypes_declarations.py
@@ -288,6 +288,9 @@ def prototype(lgeos, geos_version):
     lgeos.GEOSCovers.restype = c_byte
     lgeos.GEOSCovers.argtypes = [c_void_p, c_void_p]
 
+    lgeos.GEOSCoveredBy.restype = c_byte
+    lgeos.GEOSCoveredBy.argtypes = [c_void_p, c_void_p]
+
     lgeos.GEOSEquals.restype = c_byte
     lgeos.GEOSEquals.argtypes = [c_void_p, c_void_p]
 
@@ -546,7 +549,7 @@ def prototype(lgeos, geos_version):
         lgeos.GEOSMinimumClearance.argtypes = [c_void_p]
         lgeos.GEOSMinimumClearance.restype = c_double
 
-    if geos_version > (3, 8, 0):
+    if geos_version >= (3, 8, 0):
         lgeos.GEOSMakeValid.restype = c_void_p
         lgeos.GEOSMakeValid.argtypes = [c_void_p]
 
diff --git a/shapely/geometry/base.py b/shapely/geometry/base.py
index a4e0d6a..a5c85d7 100644
--- a/shapely/geometry/base.py
+++ b/shapely/geometry/base.py
@@ -732,6 +732,10 @@ class BaseGeometry(object):
         """Returns True if the geometry covers the other, else False"""
         return bool(self.impl['covers'](self, other))
 
+    def covered_by(self, other):
+        """Returns True if the geometry is covered by the other, else False"""
+        return bool(self.impl['covered_by'](self, other))
+
     def contains(self, other):
         """Returns True if the geometry contains the other, else False"""
         return bool(self.impl['contains'](self, other))
diff --git a/shapely/geometry/geo.py b/shapely/geometry/geo.py
index 11969b7..c34d022 100644
--- a/shapely/geometry/geo.py
+++ b/shapely/geometry/geo.py
@@ -1,6 +1,10 @@
 """
 Geometry factories based on the geo interface
 """
+import warnings
+
+from shapely.errors import ShapelyDeprecationWarning
+
 from .point import Point, asPoint
 from .linestring import LineString, asLineString
 from .polygon import Polygon, asPolygon
@@ -122,6 +126,12 @@ def asShape(context):
     stored in the context, and changes to them will be reflected in the
     returned geometry object.
 
+    .. deprecated:: 1.8
+       The proxy geometries (adapter classes) created by this function are
+       deprecated, and this function will be removed in Shapely 2.0.
+       Use the `shape` function instead to convert a GeoJSON-like dict
+       to a Shapely geometry.
+
     Parameters
     ----------
     context :
@@ -177,6 +187,13 @@ def asShape(context):
         return MultiPolygonAdapter(ob["coordinates"], context_type='geojson')
     elif geom_type == "geometrycollection":
         geoms = [asShape(g) for g in ob.get("geometries", [])]
+        if len(geoms) == 0:
+            # in this case no asShape call already raised the warning
+            warnings.warn(
+                "The proxy geometries (through the 'asShape()' constructor) "
+                "are deprecated and will be removed in Shapely 2.0. Use the "
+                "'shape()' function instead.",
+                ShapelyDeprecationWarning, stacklevel=2)
         return GeometryCollection(geoms)
     else:
         raise ValueError("Unknown geometry type: %s" % geom_type)
diff --git a/shapely/geometry/linestring.py b/shapely/geometry/linestring.py
index c25cc7a..47b7f71 100644
--- a/shapely/geometry/linestring.py
+++ b/shapely/geometry/linestring.py
@@ -154,6 +154,12 @@ class LineString(BaseGeometry):
 class LineStringAdapter(CachingGeometryProxy, LineString):
 
     def __init__(self, context):
+        warnings.warn(
+            "The proxy geometries (through the 'asShape()', 'asLineString()' or "
+            "'LineStringAdapter()' constructors) are deprecated and will be "
+            "removed in Shapely 2.0. Use the 'shape()' function or the "
+            "standard 'LineString()' constructor instead.",
+            ShapelyDeprecationWarning, stacklevel=4)
         self.context = context
         self.factory = geos_linestring_from_py
 
diff --git a/shapely/geometry/multilinestring.py b/shapely/geometry/multilinestring.py
index 4821d44..3b7baf2 100644
--- a/shapely/geometry/multilinestring.py
+++ b/shapely/geometry/multilinestring.py
@@ -2,7 +2,9 @@
 """
 
 from ctypes import c_void_p, cast
+import warnings
 
+from shapely.errors import ShapelyDeprecationWarning
 from shapely.geos import lgeos
 from shapely.geometry.base import BaseMultipartGeometry, geos_geom_from_py
 from shapely.geometry import linestring
@@ -82,6 +84,12 @@ class MultiLineStringAdapter(CachingGeometryProxy, MultiLineString):
     _other_owned = False
 
     def __init__(self, context):
+        warnings.warn(
+            "The proxy geometries (through the 'asShape()', 'asMultiLineString()' "
+            "or 'MultiLineStringAdapter()' constructors) are deprecated and will be "
+            "removed in Shapely 2.0. Use the 'shape()' function or the "
+            "standard 'MultiLineString()' constructor instead.",
+            ShapelyDeprecationWarning, stacklevel=4)
         self.context = context
         self.factory = geos_multilinestring_from_py
 
diff --git a/shapely/geometry/multipoint.py b/shapely/geometry/multipoint.py
index ca25cfe..f57c73e 100644
--- a/shapely/geometry/multipoint.py
+++ b/shapely/geometry/multipoint.py
@@ -2,7 +2,9 @@
 """
 
 from ctypes import byref, c_double, c_void_p, cast
+import warnings
 
+from shapely.errors import ShapelyDeprecationWarning
 from shapely.geos import lgeos
 from shapely.geometry.base import (
     BaseMultipartGeometry, exceptNull, geos_geom_from_py)
@@ -117,6 +119,12 @@ class MultiPointAdapter(CachingGeometryProxy, MultiPoint):
     _other_owned = False
 
     def __init__(self, context):
+        warnings.warn(
+            "The proxy geometries (through the 'asShape()', 'asMultiPoint()' "
+            "or 'MultiPointAdapter()' constructors) are deprecated and will be "
+            "removed in Shapely 2.0. Use the 'shape()' function or the "
+            "standard 'MultiPoint()' constructor instead.",
+            ShapelyDeprecationWarning, stacklevel=4)
         self.context = context
         self.factory = geos_multipoint_from_py
 
diff --git a/shapely/geometry/multipolygon.py b/shapely/geometry/multipolygon.py
index 8188ff4..2434c73 100644
--- a/shapely/geometry/multipolygon.py
+++ b/shapely/geometry/multipolygon.py
@@ -2,7 +2,9 @@
 """
 
 from ctypes import c_void_p, cast
+import warnings
 
+from shapely.errors import ShapelyDeprecationWarning
 from shapely.geos import lgeos
 from shapely.geometry.base import BaseMultipartGeometry, geos_geom_from_py
 from shapely.geometry import polygon
@@ -101,6 +103,12 @@ class MultiPolygonAdapter(CachingGeometryProxy, MultiPolygon):
     _other_owned = False
 
     def __init__(self, context, context_type='polygons'):
+        warnings.warn(
+            "The proxy geometries (through the 'asShape()', 'asMultiPolygon()' "
+            "or 'MultiPolygonAdapter()' constructors) are deprecated and will be "
+            "removed in Shapely 2.0. Use the 'shape()' function or the "
+            "standard 'MultiPolygon()' constructor instead.",
+            ShapelyDeprecationWarning, stacklevel=3)
         self.context = context
         if context_type == 'geojson':
             self.factory = geos_multipolygon_from_py
diff --git a/shapely/geometry/point.py b/shapely/geometry/point.py
index 8deddee..fef3cc7 100644
--- a/shapely/geometry/point.py
+++ b/shapely/geometry/point.py
@@ -169,6 +169,12 @@ class PointAdapter(CachingGeometryProxy, Point):
     _other_owned = False
 
     def __init__(self, context):
+        warnings.warn(
+            "The proxy geometries (through the 'asShape()', 'asPoint()' or "
+            "'PointAdapter()' constructors) are deprecated and will be "
+            "removed in Shapely 2.0. Use the 'shape()' function or the "
+            "standard 'Point()' constructor instead.",
+            ShapelyDeprecationWarning, stacklevel=4)
         self.context = context
         self.factory = geos_point_from_py
 
diff --git a/shapely/geometry/polygon.py b/shapely/geometry/polygon.py
index 731267c..66edb16 100644
--- a/shapely/geometry/polygon.py
+++ b/shapely/geometry/polygon.py
@@ -103,6 +103,12 @@ class LinearRingAdapter(LineStringAdapter):
     __p__ = None
 
     def __init__(self, context):
+        warnings.warn(
+            "The proxy geometries (through the 'asShape()', 'asLinearRing()' or "
+            "'LinearRingAdapter()' constructors) are deprecated and will be "
+            "removed in Shapely 2.0. Use the 'shape()' function or the "
+            "standard 'LinearRing()' constructor instead.",
+            ShapelyDeprecationWarning, stacklevel=3)
         self.context = context
         self.factory = geos_linearring_from_py
 
@@ -367,6 +373,12 @@ class Polygon(BaseGeometry):
 class PolygonAdapter(PolygonProxy, Polygon):
 
     def __init__(self, shell, holes=None):
+        warnings.warn(
+            "The proxy geometries (through the 'asShape()', 'asPolygon()' or "
+            "'PolygonAdapter()' constructors) are deprecated and will be "
+            "removed in Shapely 2.0. Use the 'shape()' function or the "
+            "standard 'Polygon()' constructor instead.",
+            ShapelyDeprecationWarning, stacklevel=4)
         self.shell = shell
         self.holes = holes
         self.context = (shell, holes)
diff --git a/shapely/geos.py b/shapely/geos.py
index 791fda8..936c2fa 100644
--- a/shapely/geos.py
+++ b/shapely/geos.py
@@ -817,7 +817,7 @@ class LGEOS330(LGEOS320):
         attr.__name__ = func.__name__
         setattr(self, key, attr)
 
-        for pred in (self.GEOSisClosed,):
+        for pred in (self.GEOSisClosed, self.GEOSCoveredBy):
             pred.func.errcheck = errcheck_predicate
 
         def parallel_offset(geom, distance, resolution=16, join_style=1,
@@ -834,6 +834,7 @@ class LGEOS330(LGEOS320):
         self.methods['snap'] = self.GEOSSnap
         self.methods['shared_paths'] = self.GEOSSharedPaths
         self.methods['buffer_with_params'] = self.GEOSBufferWithParams
+        self.methods['covered_by'] = self.GEOSCoveredBy
 
 
 class LGEOS340(LGEOS330):
diff --git a/shapely/impl.py b/shapely/impl.py
index dbc9bc4..1a7481b 100644
--- a/shapely/impl.py
+++ b/shapely/impl.py
@@ -146,6 +146,7 @@ IMPL320 = {
 IMPL330 = {
     'is_closed': (UnaryPredicate, 'is_closed'),
     'buffer_with_params': (UnaryTopologicalOp, 'buffer_with_params'),
+    'covered_by': (BinaryPredicate, 'covered_by')
 }
 
 IMPL360 = {
diff --git a/shapely/ops.py b/shapely/ops.py
index 8571404..7c6d15d 100644
--- a/shapely/ops.py
+++ b/shapely/ops.py
@@ -6,8 +6,8 @@ from ctypes import byref, c_void_p, c_double
 from shapely.prepared import prep
 from shapely.geos import lgeos
 from shapely.geometry.base import geom_factory, BaseGeometry, BaseMultipartGeometry
-from shapely.geometry import asShape, asLineString, asMultiLineString, Point, MultiPoint,\
-                             LineString, MultiLineString, Polygon, GeometryCollection
+from shapely.geometry import (
+    shape, Point, MultiPoint, LineString, MultiLineString, Polygon, GeometryCollection)
 from shapely.geometry.polygon import orient as orient_
 from shapely.algorithms.polylabel import polylabel
 
@@ -25,9 +25,9 @@ class CollectionOperator(object):
             return ob
         else:
             try:
-                return asShape(ob)
-            except ValueError:
-                return asLineString(ob)
+                return shape(ob)
+            except (ValueError, AttributeError):
+                return LineString(ob)
 
     def polygonize(self, lines):
         """Creates polygons from a source of lines
@@ -105,9 +105,9 @@ class CollectionOperator(object):
             source = lines
         elif hasattr(lines, '__iter__'):
             try:
-                source = asMultiLineString([ls.coords for ls in lines])
+                source = MultiLineString([ls.coords for ls in lines])
             except AttributeError:
-                source = asMultiLineString(lines)
+                source = MultiLineString(lines)
         if source is None:
             raise ValueError("Cannot linemerge %s" % lines)
         result = lgeos.GEOSLineMerge(source._geom)


Test patch:
diff --git a/tests/test_collection.py b/tests/test_collection.py
index c87fd7a..60c48cd 100644
--- a/tests/test_collection.py
+++ b/tests/test_collection.py
@@ -1,9 +1,13 @@
-from . import unittest
+from . import unittest, shapely20_deprecated
+
+from shapely.errors import ShapelyDeprecationWarning
 from shapely.geometry import LineString
 from shapely.geometry.collection import GeometryCollection
 from shapely.geometry import shape
 from shapely.geometry import asShape
 
+import pytest
+
 
 class CollectionTestCase(unittest.TestCase):
 
@@ -26,7 +30,8 @@ class CollectionTestCase(unittest.TestCase):
         # access geometry, this should not seg fault as 1.2.15 did
         self.assertIsNotNone(child.wkt)
 
-    def test_geointerface(self):
+    @shapely20_deprecated
+    def test_geointerface_adapter(self):
         d = {"type": "GeometryCollection","geometries": [
                 {"type": "Point", "coordinates": (0, 3)},
                 {"type": "LineString", "coordinates": ((2, 0), (1, 0))}
@@ -40,6 +45,12 @@ class CollectionTestCase(unittest.TestCase):
         self.assertIn("Point", geom_types)
         self.assertIn("LineString", geom_types)
 
+    def test_geointerface(self):
+        d = {"type": "GeometryCollection","geometries": [
+                {"type": "Point", "coordinates": (0, 3)},
+                {"type": "LineString", "coordinates": ((2, 0), (1, 0))}
+            ]}
+
         # shape
         m = shape(d)
         self.assertEqual(m.geom_type, "GeometryCollection")
@@ -48,7 +59,8 @@ class CollectionTestCase(unittest.TestCase):
         self.assertIn("Point", geom_types)
         self.assertIn("LineString", geom_types)
 
-    def test_empty_geointerface(self):
+    @shapely20_deprecated
+    def test_empty_geointerface_adapter(self):
         d = {"type": "GeometryCollection", "geometries": []}
 
         # asShape
@@ -57,6 +69,9 @@ class CollectionTestCase(unittest.TestCase):
         self.assertEqual(len(m), 0)
         self.assertEqual(m.geoms, [])
 
+    def test_empty_geointerface(self):
+        d = {"type": "GeometryCollection", "geometries": []}
+
         # shape
         m = shape(d)
         self.assertEqual(m.geom_type, "GeometryCollection")
@@ -77,5 +92,18 @@ class CollectionTestCase(unittest.TestCase):
         self.assertEqual(m.geoms, [])
 
 
+def test_geometrycollection_adapter_deprecated():
+    d = {"type": "GeometryCollection","geometries": [
+            {"type": "Point", "coordinates": (0, 3)},
+            {"type": "LineString", "coordinates": ((2, 0), (1, 0))}
+    ]}
+    with pytest.warns(ShapelyDeprecationWarning):
+        asShape(d)
+
+    d = {"type": "GeometryCollection", "geometries": []}
+    with pytest.warns(ShapelyDeprecationWarning):
+        asShape(d)
+
+
 def test_suite():
     return unittest.TestLoader().loadTestsFromTestCase(CollectionTestCase)
diff --git a/tests/test_create_inconsistent_dimensionality.py b/tests/test_create_inconsistent_dimensionality.py
index 14b31cc..90ad40c 100644
--- a/tests/test_create_inconsistent_dimensionality.py
+++ b/tests/test_create_inconsistent_dimensionality.py
@@ -10,7 +10,7 @@ any dimension which is not present in every coordinate.
 import pytest
 
 from shapely import wkt
-from shapely.geometry import asShape, LineString, Polygon
+from shapely.geometry import shape, LineString, Polygon
 
 
 geojson_cases = [
@@ -37,7 +37,7 @@ wkt_cases = [
 @pytest.mark.parametrize('geojson', geojson_cases)
 def test_create_from_geojson(geojson):
     with pytest.raises(ValueError) as exc:
-        wkt = asShape(geojson).wkt
+        wkt = shape(geojson).wkt
     assert exc.match("Inconsistent coordinate dimensionality")
 
 
diff --git a/tests/test_emptiness.py b/tests/test_emptiness.py
index 91b6a01..cd63c81 100644
--- a/tests/test_emptiness.py
+++ b/tests/test_emptiness.py
@@ -1,10 +1,14 @@
 from . import unittest
+
+from shapely.errors import ShapelyDeprecationWarning
 from shapely.geometry.base import BaseGeometry, EmptyGeometry
 import shapely.geometry as sgeom
 from shapely.geometry.polygon import LinearRing
 
 from shapely.geometry import MultiPolygon, mapping, shape, asShape
 
+import pytest
+
 
 empty_generator = lambda: iter([])
 
@@ -63,13 +67,22 @@ class EmptinessTestCase(unittest.TestCase):
         self.assertTrue(LinearRing(empty_generator()).is_empty)
 
 
+def test_shape_empty():
+    empty_mp = MultiPolygon()
+    empty_json = mapping(empty_mp)
+    empty_shape = shape(empty_json)
+    assert empty_shape.is_empty
+
+
 def test_asshape_empty():
     empty_mp = MultiPolygon()
     empty_json = mapping(empty_mp)
-    empty_asShape = asShape(empty_json)
+    with pytest.warns(ShapelyDeprecationWarning, match="proxy geometries"):
+        empty_asShape = asShape(empty_json)
     assert empty_asShape.is_empty
 
 
+
 def test_suite():
     return unittest.TestLoader().loadTestsFromTestCase(EmptinessTestCase)
 
diff --git a/tests/test_geointerface.py b/tests/test_geointerface.py
index b9514b9..0816b48 100644
--- a/tests/test_geointerface.py
+++ b/tests/test_geointerface.py
@@ -1,11 +1,13 @@
-from . import unittest
+from . import unittest, shapely20_deprecated
 
-from shapely.geometry import asShape
-from shapely.geometry.multipoint import MultiPointAdapter
-from shapely.geometry.linestring import LineStringAdapter
-from shapely.geometry.multilinestring import MultiLineStringAdapter
+import pytest
+
+from shapely.geometry import asShape, shape
+from shapely.geometry.multipoint import MultiPoint, MultiPointAdapter
+from shapely.geometry.linestring import LineString, LineStringAdapter
+from shapely.geometry.multilinestring import MultiLineString, MultiLineStringAdapter
 from shapely.geometry.polygon import Polygon, PolygonAdapter
-from shapely.geometry.multipolygon import MultiPolygonAdapter
+from shapely.geometry.multipolygon import MultiPolygon, MultiPolygonAdapter
 from shapely import wkt
 
 
@@ -16,7 +18,8 @@ class GeoThing(object):
 
 class GeoInterfaceTestCase(unittest.TestCase):
 
-    def test_geointerface(self):
+    @shapely20_deprecated
+    def test_geointerface_adapter(self):
         # Adapt a dictionary
         d = {"type": "Point", "coordinates": (0.0, 0.0)}
         shape = asShape(d)
@@ -71,6 +74,61 @@ class GeoInterfaceTestCase(unittest.TestCase):
         self.assertIsInstance(shape, MultiPolygonAdapter)
         self.assertEqual(len(shape.geoms), 1)
 
+    def test_geointerface(self):
+        # Convert a dictionary
+        d = {"type": "Point", "coordinates": (0.0, 0.0)}
+        geom = shape(d)
+        self.assertEqual(geom.geom_type, 'Point')
+        self.assertEqual(tuple(geom.coords), ((0.0, 0.0),))
+
+        # Convert an object that implements the geo protocol
+        geom = None
+        thing = GeoThing({"type": "Point", "coordinates": (0.0, 0.0)})
+        geom = shape(thing)
+        self.assertEqual(geom.geom_type, 'Point')
+        self.assertEqual(tuple(geom.coords), ((0.0, 0.0),))
+
+        # Check line string
+        geom = shape(
+            {'type': 'LineString', 'coordinates': ((-1.0, -1.0), (1.0, 1.0))})
+        self.assertIsInstance(geom, LineString)
+        self.assertEqual(tuple(geom.coords), ((-1.0, -1.0), (1.0, 1.0)))
+
+        # polygon
+        geom = shape(
+            {'type': 'Polygon',
+             'coordinates':
+                (((0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (2.0, -1.0), (0.0, 0.0)),
+                 ((0.1, 0.1), (0.1, 0.2), (0.2, 0.2), (0.2, 0.1), (0.1, 0.1)))}
+        )
+        self.assertIsInstance(geom, Polygon)
+        self.assertEqual(
+            tuple(geom.exterior.coords),
+            ((0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (2.0, -1.0), (0.0, 0.0)))
+        self.assertEqual(len(geom.interiors), 1)
+
+        # multi point
+        geom = shape({'type': 'MultiPoint',
+                       'coordinates': ((1.0, 2.0), (3.0, 4.0))})
+        self.assertIsInstance(geom, MultiPoint)
+        self.assertEqual(len(geom.geoms), 2)
+
+        # multi line string
+        geom = shape({'type': 'MultiLineString',
+                       'coordinates': (((0.0, 0.0), (1.0, 2.0)),)})
+        self.assertIsInstance(geom, MultiLineString)
+        self.assertEqual(len(geom.geoms), 1)
+
+        # multi polygon
+        geom = shape(
+            {'type': 'MultiPolygon',
+             'coordinates':
+                [(((0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0), (0.0, 0.0)),
+                  ((0.1, 0.1), (0.1, 0.2), (0.2, 0.2), (0.2, 0.1), (0.1, 0.1))
+                  )]})
+        self.assertIsInstance(geom, MultiPolygon)
+        self.assertEqual(len(geom.geoms), 1)
+
 
 def test_empty_wkt_polygon():
     """Confirm fix for issue #450"""
diff --git a/tests/test_linestring.py b/tests/test_linestring.py
index 51bd7c7..98bc51e 100644
--- a/tests/test_linestring.py
+++ b/tests/test_linestring.py
@@ -50,6 +50,7 @@ class LineStringTestCase(unittest.TestCase):
                          {'type': 'LineString',
                           'coordinates': ((-1.0, -1.0), (1.0, 1.0))})
 
+    @shapely20_deprecated
     def test_linestring_adapter(self):
         # Adapt a coordinate list to a line string
         coords = [[5.0, 6.0], [7.0, 8.0]]
@@ -148,6 +149,12 @@ class LineStringTestCase(unittest.TestCase):
         la = asarray(line.coords)
         assert_array_equal(la, expected)
 
+    @shapely20_deprecated
+    @unittest.skipIf(not numpy, 'Numpy required')
+    def test_numpy_adapter(self):
+        from numpy import array, asarray
+        from numpy.testing import assert_array_equal
+
         # Adapt a Numpy array to a line string
         a = array([[1.0, 2.0], [3.0, 4.0]])
         la = asLineString(a)
@@ -161,6 +168,11 @@ class LineStringTestCase(unittest.TestCase):
         pas = asarray(la)
         assert_array_equal(pas, array([[1.0, 2.0], [3.0, 4.0]]))
 
+    @unittest.skipIf(not numpy, 'Numpy required')
+    def test_numpy_asarray(self):
+        from numpy import array, asarray
+        from numpy.testing import assert_array_equal
+
         # From Array.txt
         a = asarray([[0.0, 0.0], [2.0, 2.0], [1.0, 1.0]])
         line = LineString(a)
@@ -173,6 +185,11 @@ class LineStringTestCase(unittest.TestCase):
         b = asarray(line)
         assert_array_equal(b, array([[0., 0.], [2., 2.], [1., 1.]]))
 
+    @unittest.skipIf(not numpy, 'Numpy required')
+    def test_numpy_empty(self):
+        from numpy import array, asarray
+        from numpy.testing import assert_array_equal
+
         # Test array interface of empty linestring
         le = LineString()
         a = asarray(le)
@@ -185,6 +202,11 @@ def test_linestring_mutability_deprecated():
         line.coords = ((-1.0, -1.0), (1.0, 1.0))
 
 
+def test_linestring_adapter_deprecated():
+    coords = [[5.0, 6.0], [7.0, 8.0]]
+    with pytest.warns(ShapelyDeprecationWarning, match="proxy geometries"):
+        asLineString(coords)
+
 
 def test_suite():
     return unittest.TestLoader().loadTestsFromTestCase(LineStringTestCase)
diff --git a/tests/test_multilinestring.py b/tests/test_multilinestring.py
index be3f4ab..e69cd4f 100644
--- a/tests/test_multilinestring.py
+++ b/tests/test_multilinestring.py
@@ -1,5 +1,9 @@
-from . import unittest, numpy, test_int_types
+from . import unittest, numpy, shapely20_deprecated
 from .test_multi import MultiGeometryTestCase
+
+import pytest
+
+from shapely.errors import ShapelyDeprecationWarning
 from shapely.geos import lgeos
 from shapely.geometry import LineString, MultiLineString, asMultiLineString
 from shapely.geometry.base import dump_coords
@@ -66,6 +70,13 @@ class MultiLineStringTestCase(MultiGeometryTestCase):
         self.assertEqual(len(geom.geoms), 1)
         self.assertEqual(dump_coords(geom), [[(0.0, 0.0), (1.0, 2.0)]])
 
+
+    @shapely20_deprecated
+    @unittest.skipIf(not numpy, 'Numpy required')
+    def test_numpy_adapter(self):
+        from numpy import array
+        from numpy.testing import assert_array_equal
+
         # Adapt a sequence of Numpy arrays to a multilinestring
         a = [array(((1.0, 2.0), (3.0, 4.0)))]
         geoma = asMultiLineString(a)
@@ -80,5 +91,11 @@ class MultiLineStringTestCase(MultiGeometryTestCase):
         self.subgeom_access_test(MultiLineString, [line0, line1])
 
 
+def test_multilinestring_adapter_deprecated():
+    coords = [[[5.0, 6.0], [7.0, 8.0]]]
+    with pytest.warns(ShapelyDeprecationWarning, match="proxy geometries"):
+        asMultiLineString(coords)
+
+
 def test_suite():
     return unittest.TestLoader().loadTestsFromTestCase(MultiLineStringTestCase)
diff --git a/tests/test_multipoint.py b/tests/test_multipoint.py
index c84443c..4728fab 100644
--- a/tests/test_multipoint.py
+++ b/tests/test_multipoint.py
@@ -1,5 +1,9 @@
-from . import unittest, numpy, test_int_types
+from . import unittest, numpy, shapely20_deprecated
 from .test_multi import MultiGeometryTestCase
+
+import pytest
+
+from shapely.errors import ShapelyDeprecationWarning
 from shapely.geometry import Point, MultiPoint, asMultiPoint
 from shapely.geometry.base import dump_coords
 
@@ -35,6 +39,8 @@ class MultiPointTestCase(MultiGeometryTestCase):
                          {'type': 'MultiPoint',
                           'coordinates': ((1.0, 2.0), (3.0, 4.0))})
 
+    @shapely20_deprecated
+    def test_multipoint_adapter(self):
         # Adapt a coordinate list to a line string
         coords = [[5.0, 6.0], [7.0, 8.0]]
         geoma = asMultiPoint(coords)
@@ -56,6 +62,13 @@ class MultiPointTestCase(MultiGeometryTestCase):
         geom = MultiPoint((Point(1.0, 2.0), Point(3.0, 4.0)))
         assert_array_equal(array(geom), array([[1., 2.], [3., 4.]]))
 
+    @shapely20_deprecated
+    @unittest.skipIf(not numpy, 'Numpy required')
+    def test_numpy_adapter(self):
+
+        from numpy import array, asarray
+        from numpy.testing import assert_array_equal
+
         # Adapt a Numpy array to a multipoint
         a = array([[1.0, 2.0], [3.0, 4.0]])
         geoma = asMultiPoint(a)
@@ -74,5 +87,12 @@ class MultiPointTestCase(MultiGeometryTestCase):
         p1 = Point(3.0, 4.0)
         self.subgeom_access_test(MultiPoint, [p0, p1])
 
+
+def test_multipoint_adapter_deprecated():
+    coords = [[5.0, 6.0], [7.0, 8.0]]
+    with pytest.warns(ShapelyDeprecationWarning, match="proxy geometries"):
+        asMultiPoint(coords)
+
+
 def test_suite():
     return unittest.TestLoader().loadTestsFromTestCase(MultiPointTestCase)
diff --git a/tests/test_multipolygon.py b/tests/test_multipolygon.py
index 6039a97..d1c58dc 100644
--- a/tests/test_multipolygon.py
+++ b/tests/test_multipolygon.py
@@ -1,8 +1,10 @@
 import pytest
 
+from shapely.errors import ShapelyDeprecationWarning
 from shapely.geometry import Polygon, MultiPolygon, asMultiPolygon
 from shapely.geometry.base import dump_coords
-from . import unittest, numpy, test_int_types
+
+from . import unittest, numpy, test_int_types, shapely20_deprecated
 from .test_multi import MultiGeometryTestCase
 
 
@@ -61,6 +63,8 @@ class MultiPolygonTestCase(MultiGeometryTestCase):
                               ((0.25, 0.25), (0.25, 0.5), (0.5, 0.5),
                                (0.5, 0.25), (0.25, 0.25)))]})
 
+    @shapely20_deprecated
+    def test_multipolygon_adapter(self):
         # Adapter
         coords = ((0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0))
         holes_coords = [((0.25, 0.25), (0.25, 0.5), (0.5, 0.5), (0.5, 0.25))]
@@ -87,3 +91,8 @@ def test_fail_list_of_multipolygons():
         MultiPolygon([multi])
 
 
+def test_multipolygon_adapter_deprecated():
+    coords = ((0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0))
+    holes_coords = [((0.25, 0.25), (0.25, 0.5), (0.5, 0.5), (0.5, 0.25))]
+    with pytest.warns(ShapelyDeprecationWarning, match="proxy geometries"):
+        asMultiPolygon([(coords, holes_coords)])
diff --git a/tests/test_ndarrays.py b/tests/test_ndarrays.py
index 26e1843..4dc6fae 100644
--- a/tests/test_ndarrays.py
+++ b/tests/test_ndarrays.py
@@ -4,7 +4,7 @@
 
 from functools import reduce
 
-from . import unittest
+from . import unittest, shapely20_deprecated
 from shapely import geometry
 
 try:
@@ -15,8 +15,9 @@ except ImportError:
 
 class TransposeTestCase(unittest.TestCase):
 
+    @shapely20_deprecated
     @unittest.skipIf(not numpy, 'numpy not installed')
-    def test_multipoint(self):
+    def test_multipoint_adapter(self):
         arr = numpy.array([[1.0, 1.0, 2.0, 2.0, 1.0], [3.0, 4.0, 4.0, 3.0, 3.0]])
         tarr = arr.T
         shape = geometry.asMultiPoint(tarr)
@@ -26,8 +27,9 @@ class TransposeTestCase(unittest.TestCase):
             [(1.0, 3.0), (1.0, 4.0), (2.0, 4.0), (2.0, 3.0), (1.0, 3.0)]
         )
 
+    @shapely20_deprecated
     @unittest.skipIf(not numpy, 'numpy not installed')
-    def test_linestring(self):
+    def test_linestring_adapter(self):
         a = numpy.array([[1.0, 1.0, 2.0, 2.0, 1.0], [3.0, 4.0, 4.0, 3.0, 3.0]])
         t = a.T
         s = geometry.asLineString(t)
@@ -36,8 +38,9 @@ class TransposeTestCase(unittest.TestCase):
             [(1.0, 3.0), (1.0, 4.0), (2.0, 4.0), (2.0, 3.0), (1.0, 3.0)]
         )
 
+    @shapely20_deprecated
     @unittest.skipIf(not numpy, 'numpy not installed')
-    def test_polygon(self):
+    def test_polygon_adapter(self):
         a = numpy.array([[1.0, 1.0, 2.0, 2.0, 1.0], [3.0, 4.0, 4.0, 3.0, 3.0]])
         t = a.T
         s = geometry.asPolygon(t)
@@ -46,6 +49,36 @@ class TransposeTestCase(unittest.TestCase):
             [(1.0, 3.0), (1.0, 4.0), (2.0, 4.0), (2.0, 3.0), (1.0, 3.0)]
         )
 
+    @unittest.skipIf(not numpy, 'numpy not installed')
+    def test_multipoint(self):
+        arr = numpy.array([[1.0, 1.0, 2.0, 2.0, 1.0], [3.0, 4.0, 4.0, 3.0, 3.0]])
+        tarr = arr.T
+        shape = geometry.MultiPoint(tarr)
+        coords = reduce(lambda x, y: x + y, [list(g.coords) for g in shape])
+        self.assertEqual(
+            coords,
+            [(1.0, 3.0), (1.0, 4.0), (2.0, 4.0), (2.0, 3.0), (1.0, 3.0)]
+        )
+
+    @unittest.skipIf(not numpy, 'numpy not installed')
+    def test_linestring(self):
+        a = numpy.array([[1.0, 1.0, 2.0, 2.0, 1.0], [3.0, 4.0, 4.0, 3.0, 3.0]])
+        t = a.T
+        s = geometry.LineString(t)
+        self.assertEqual(
+            list(s.coords),
+            [(1.0, 3.0), (1.0, 4.0), (2.0, 4.0), (2.0, 3.0), (1.0, 3.0)]
+        )
+
+    @unittest.skipIf(not numpy, 'numpy not installed')
+    def test_polygon(self):
+        a = numpy.array([[1.0, 1.0, 2.0, 2.0, 1.0], [3.0, 4.0, 4.0, 3.0, 3.0]])
+        t = a.T
+        s = geometry.Polygon(t)
+        self.assertEqual(
+            list(s.exterior.coords),
+            [(1.0, 3.0), (1.0, 4.0), (2.0, 4.0), (2.0, 3.0), (1.0, 3.0)]
+        )
 
 def test_suite():
     return unittest.TestLoader().loadTestsFromTestCase(TransposeTestCase)
diff --git a/tests/test_point.py b/tests/test_point.py
index 599a78f..b147e24 100644
--- a/tests/test_point.py
+++ b/tests/test_point.py
@@ -62,6 +62,7 @@ class LineStringTestCase(unittest.TestCase):
         self.assertEqual(p.__geo_interface__,
                          {'type': 'Point', 'coordinates': (0.0, 0.0)})
 
+    @shapely20_deprecated
     def test_point_adapter(self):
         p = Point(0.0, 0.0)
         # Adapt a coordinate list to a point
@@ -103,6 +104,12 @@ class LineStringTestCase(unittest.TestCase):
         p = Point(array([1.0, 2.0]))
         self.assertEqual(p.coords[:], [(1.0, 2.0)])
 
+    @shapely20_deprecated
+    @unittest.skipIf(not numpy, 'Numpy required')
+    def test_numpy_adapter(self):
+        from numpy import array, asarray
+        from numpy.testing import assert_array_equal
+
         # Adapt a Numpy array to a point
         a = array([1.0, 2.0])
         pa = asPoint(a)
@@ -126,6 +133,11 @@ class LineStringTestCase(unittest.TestCase):
         pas = asarray(pa)
         assert_array_equal(pas, array([1.0, 4.0]))
 
+    @unittest.skipIf(not numpy, 'Numpy required')
+    def test_numpy_asarray(self):
+        from numpy import array, asarray
+        from numpy.testing import assert_array_equal
+
         # From Array.txt
         p = Point(0.0, 0.0, 1.0)
         coords = p.coords[0]
@@ -167,5 +179,11 @@ def test_point_mutability_deprecated():
         p.coords = (2.0, 1.0)
 
 
+def test_point_adapter_deprecated():
+    coords = [3.0, 4.0]
+    with pytest.warns(ShapelyDeprecationWarning, match="proxy geometries"):
+        asPoint(coords)
+
+
 def test_suite():
     return unittest.TestLoader().loadTestsFromTestCase(LineStringTestCase)
diff --git a/tests/test_polygon.py b/tests/test_polygon.py
index e11fdee..ebae799 100644
--- a/tests/test_polygon.py
+++ b/tests/test_polygon.py
@@ -2,8 +2,11 @@
 """
 
 from . import unittest, numpy, shapely20_deprecated
+
+import pytest
+
 from shapely.wkb import loads as load_wkb
-from shapely.errors import TopologicalError
+from shapely.errors import TopologicalError, ShapelyDeprecationWarning
 from shapely.geos import lgeos
 from shapely.geometry import Point, Polygon, asPolygon
 from shapely.geometry.polygon import LinearRing, LineString, asLinearRing
@@ -39,6 +42,7 @@ class PolygonTestCase(unittest.TestCase):
              'coordinates': ((0.0, 0.0), (0.0, 2.0), (2.0, 2.0), (2.0, 0.0),
                              (0.0, 0.0))})
 
+    @shapely20_deprecated
     def test_linearring_adapter(self):
         # Test ring adapter
         coords = [[0.0, 0.0], [0.0, 1.0], [1.0, 1.0], [1.0, 0.0]]
@@ -108,18 +112,21 @@ class PolygonTestCase(unittest.TestCase):
                              (0.0, 0.0)), ((0.25, 0.25), (0.25, 0.5),
                              (0.5, 0.5), (0.5, 0.25), (0.25, 0.25)))})
 
+        # Error handling
+        with self.assertRaises(ValueError):
+            # A LinearRing must have at least 3 coordinate tuples
+            Polygon([[1, 2], [2, 3]])
+
+    @shapely20_deprecated
+    def test_polygon_adapter(self):
         # Adapter
+        coords = ((0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0))
         hole_coords = [((0.25, 0.25), (0.25, 0.5), (0.5, 0.5), (0.5, 0.25))]
         pa = asPolygon(coords, hole_coords)
         self.assertEqual(len(pa.exterior.coords), 5)
         self.assertEqual(len(pa.interiors), 1)
         self.assertEqual(len(pa.interiors[0].coords), 5)
 
-        # Error handling
-        with self.assertRaises(ValueError):
-            # A LinearRing must have at least 3 coordinate tuples
-            Polygon([[1, 2], [2, 3]])
-
     def test_linearring_empty(self):
         # Test Non-operability of Null rings
         r_null = LinearRing()
@@ -273,5 +280,18 @@ class PolygonTestCase(unittest.TestCase):
         assert p.exterior == LinearRing()
 
 
+def test_linearring_adapter_deprecated():
+    coords = [[0.0, 0.0], [0.0, 1.0], [1.0, 1.0], [1.0, 0.0]]
+    with pytest.warns(ShapelyDeprecationWarning, match="proxy geometries"):
+        asLinearRing(coords)
+
+
+def test_polygon_adapter_deprecated():
+    coords = ((0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0))
+    hole_coords = [((0.25, 0.25), (0.25, 0.5), (0.5, 0.5), (0.5, 0.25))]
+    with pytest.warns(ShapelyDeprecationWarning, match="proxy geometries"):
+        asPolygon(coords, hole_coords)
+
+
 def test_suite():
     return unittest.TestLoader().loadTestsFromTestCase(PolygonTestCase)
diff --git a/tests/test_predicates.py b/tests/test_predicates.py
index c3c1cb4..62c4793 100644
--- a/tests/test_predicates.py
+++ b/tests/test_predicates.py
@@ -10,6 +10,7 @@ class PredicatesTestCase(unittest.TestCase):
     def test_binary_predicates(self):
 
         point = Point(0.0, 0.0)
+        point2 = Point(2.0, 2.0)
 
         self.assertTrue(point.disjoint(Point(-1.0, -1.0)))
         self.assertFalse(point.touches(Point(-1.0, -1.0)))
@@ -20,6 +21,9 @@ class PredicatesTestCase(unittest.TestCase):
         self.assertFalse(point.touches(Point(-1.0, -1.0)))
         self.assertTrue(point.equals(Point(0.0, 0.0)))
         self.assertTrue(point.covers(Point(0.0, 0.0)))
+        self.assertTrue(point.covered_by(Point(0.0, 0.0)))
+        self.assertFalse(point.covered_by(point2))
+        self.assertFalse(point2.covered_by(point))
         self.assertFalse(point.covers(Point(-1.0, -1.0)))
 
     def test_unary_predicates(self):