Repository: opendatacube/datacube-core

Issue:
ShapelyDeprecationWarning: The 'type' attribute is deprecated -> use the 'geom_type' attribute instead.
```
datacube/utils/geometry/_base.py:623: ShapelyDeprecationWarning: The 'type' attribute is deprecated, and will be removed in the future. You can use the 'geom_type' attribute instead.
    if geom.type in ['Point', 'MultiPoint']:

datacube/utils/geometry/_base.py:626: ShapelyDeprecationWarning: The 'type' attribute is deprecated, and will be removed in the future. You can use the 'geom_type' attribute instead.
    if geom.type in ['GeometryCollection', 'MultiPolygon', 'MultiLineString']:

datacube/utils/geometry/_base.py:629: ShapelyDeprecationWarning: The 'type' attribute is deprecated, and will be removed in the future. You can use the 'geom_type' attribute instead.
    if geom.type in ['LineString', 'LinearRing']:

datacube/utils/geometry/_base.py:632: ShapelyDeprecationWarning: The 'type' attribute is deprecated, and will be removed in the future. You can use the 'geom_type' attribute instead.
    if geom.type == 'Polygon':
```

Discussion:
codecov[bot]: # [Codecov](https://codecov.io/gh/opendatacube/datacube-core/pull/1402?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=opendatacube) Report
Base: **91.96**% // Head: **91.96**% // No change to project coverage :thumbsup:
> Coverage data is based on head [(`2223b97`)](https://codecov.io/gh/opendatacube/datacube-core/pull/1402?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=opendatacube) compared to base [(`8b51010`)](https://codecov.io/gh/opendatacube/datacube-core/commit/8b51010635e45ed9f0f6092fd942a5d4e572727f?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=opendatacube).
> Patch coverage: 91.66% of modified lines in pull request are covered.

> :exclamation: Current head 2223b97 differs from pull request most recent head 665ad50. Consider uploading reports for the commit 665ad50 to get more accurate results

<details><summary>Additional details and impacted files</summary>


```diff
@@           Coverage Diff            @@
##           develop    #1402   +/-   ##
========================================
  Coverage    91.96%   91.96%           
========================================
  Files          133      133           
  Lines        14450    14450           
========================================
  Hits         13289    13289           
  Misses        1161     1161           
```


| [Impacted Files](https://codecov.io/gh/opendatacube/datacube-core/pull/1402?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=opendatacube) | Coverage Δ | |
|---|---|---|
| [datacube/drivers/postgis/\_spatial.py](https://codecov.io/gh/opendatacube/datacube-core/pull/1402?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=opendatacube#diff-ZGF0YWN1YmUvZHJpdmVycy9wb3N0Z2lzL19zcGF0aWFsLnB5) | `94.06% <66.66%> (ø)` | |
| [datacube/utils/geometry/\_base.py](https://codecov.io/gh/opendatacube/datacube-core/pull/1402?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=opendatacube#diff-ZGF0YWN1YmUvdXRpbHMvZ2VvbWV0cnkvX2Jhc2UucHk=) | `99.34% <100.00%> (ø)` | |

Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=opendatacube). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=opendatacube)

</details>

[:umbrella: View full report at Codecov](https://codecov.io/gh/opendatacube/datacube-core/pull/1402?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=opendatacube).   
:loudspeaker: Do you have feedback about the report comment? [Let us know in this issue](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=opendatacube).


Patch:
diff --git a/datacube/drivers/postgis/_spatial.py b/datacube/drivers/postgis/_spatial.py
index c8222f4c..7481745a 100644
--- a/datacube/drivers/postgis/_spatial.py
+++ b/datacube/drivers/postgis/_spatial.py
@@ -147,9 +147,9 @@ def spindexes(engine: Connectable) -> Mapping[CRS, Type[SpatialIndex]]:
 
 def promote_to_multipolygon(geom: Geom) -> Geom:
     # Assumes input is a polygon or multipolygon - does not work on lines or points
-    if geom.type == "Multipolygon":
+    if geom.geom_type == "Multipolygon":
         return geom
-    elif geom.type == "Polygon":
+    elif geom.geom_type == "Polygon":
         # Promote to multipolygon (is there a more elegant way to do this??
         polycoords = [list(geom.geom.exterior.coords)]
         for interior in geom.geom.interiors:
@@ -157,7 +157,7 @@ def promote_to_multipolygon(geom: Geom) -> Geom:
         geom = multipolygon([polycoords], crs=geom.crs)
         return geom
     else:
-        raise ValueError(f"Cannot promote geometry type {geom.type} to multi-polygon")
+        raise ValueError(f"Cannot promote geometry type {geom.geom_type} to multi-polygon")
 
 
 def geom_alchemy(geom: Geom) -> str:
diff --git a/datacube/utils/geometry/_base.py b/datacube/utils/geometry/_base.py
index 1f669cb5..55bab91a 100644
--- a/datacube/utils/geometry/_base.py
+++ b/datacube/utils/geometry/_base.py
@@ -538,8 +538,8 @@ class Geometry:
         return self.geom._repr_svg_()
 
     @property
-    def type(self) -> str:
-        return self.geom.type
+    def geom_type(self) -> str:
+        return self.geom.geom_type
 
     @property
     def is_empty(self) -> bool:
@@ -623,20 +623,20 @@ class Geometry:
         """
 
         def segmentize_shapely(geom: base.BaseGeometry) -> base.BaseGeometry:
-            if geom.type in ['Point', 'MultiPoint']:
-                return type(geom)(geom)  # clone without changes
+            if geom.geom_type in ['Point', 'MultiPoint']:
+                return _clone_shapely_geom(geom)  # clone without changes
 
-            if geom.type in ['GeometryCollection', 'MultiPolygon', 'MultiLineString']:
+            if geom.geom_type in ['GeometryCollection', 'MultiPolygon', 'MultiLineString']:
                 return type(geom)([segmentize_shapely(g) for g in geom.geoms])
 
-            if geom.type in ['LineString', 'LinearRing']:
+            if geom.geom_type in ['LineString', 'LinearRing']:
                 return type(geom)(densify(list(geom.coords), resolution))
 
-            if geom.type == 'Polygon':
+            if geom.geom_type == 'Polygon':
                 return geometry.Polygon(densify(list(geom.exterior.coords), resolution),
                                         [densify(list(i.coords), resolution) for i in geom.interiors])
 
-            raise ValueError('unknown geometry type {}'.format(geom.type))  # pragma: no cover
+            raise ValueError('unknown geometry type {}'.format(geom.geom_type))  # pragma: no cover
 
         return Geometry(segmentize_shapely(self.geom), self.crs)
 
@@ -801,7 +801,7 @@ def clip_lon180(geom: Geometry, tol=1e-6) -> Geometry:
         clip = _pick_clip(xx)
         return _clip_180(xx, clip), yy
 
-    if geom.type.startswith('Multi'):
+    if geom.geom_type.startswith('Multi'):
         return multigeom(g.transform(transformer) for g in geom)
 
     return geom.transform(transformer)
@@ -942,7 +942,7 @@ def multigeom(geoms: Iterable[Geometry]) -> Geometry:
     """ Construct Multi{Polygon|LineString|Point}
     """
     geoms = [g for g in geoms]  # force into list
-    src_types = {g.type for g in geoms}
+    src_types = {g.geom_type for g in geoms}
     if len(src_types) > 1:
         raise ValueError("All Geometries must be of the same type")
 
diff --git a/docs/about/whats_new.rst b/docs/about/whats_new.rst
index a2b610d8..e9094824 100644
--- a/docs/about/whats_new.rst
+++ b/docs/about/whats_new.rst
@@ -8,6 +8,8 @@ What's New
 v1.8.next
 =========
 
+- Rename Geometry `type` attribute to `geom_type`, to align with Shapely 2.0 (:pull:`1402`)
+
 
 v1.8.11 (6 February 2023)
 =========================


Test patch:
diff --git a/tests/test_geometry.py b/tests/test_geometry.py
index 1da1dcfe..3efbe3ef 100644
--- a/tests/test_geometry.py
+++ b/tests/test_geometry.py
@@ -307,14 +307,14 @@ def test_multigeom():
     b1 = geometry.box(*p1, *p2, epsg4326)
     b2 = geometry.box(*p3, *p4, epsg4326)
     bb = multigeom([b1, b2])
-    assert bb.type == 'MultiPolygon'
+    assert bb.geom_type == 'MultiPolygon'
     assert bb.crs is b1.crs
     assert len(list(bb)) == 2
 
     g1 = geometry.line([p1, p2], None)
     g2 = geometry.line([p3, p4], None)
     gg = multigeom(iter([g1, g2, g1]))
-    assert gg.type == 'MultiLineString'
+    assert gg.geom_type == 'MultiLineString'
     assert gg.crs is g1.crs
     assert len(list(gg)) == 3
 
@@ -322,7 +322,7 @@ def test_multigeom():
     g2 = geometry.point(*p2, epsg3857)
     g3 = geometry.point(*p3, epsg3857)
     gg = multigeom(iter([g1, g2, g3]))
-    assert gg.type == 'MultiPoint'
+    assert gg.geom_type == 'MultiPoint'
     assert gg.crs is g1.crs
     assert len(list(gg)) == 3
     assert list(gg)[0] == g1
@@ -390,8 +390,8 @@ def test_to_crs():
     mpoly = (geometry.box(0, 0, 1, 3, 'EPSG:4326') |
              geometry.box(2, 4, 3, 6, 'EPSG:4326'))
 
-    assert mpoly.type == 'MultiPolygon'
-    assert mpoly.to_crs(epsg3857).type == 'MultiPolygon'
+    assert mpoly.geom_type == 'MultiPolygon'
+    assert mpoly.to_crs(epsg3857).geom_type == 'MultiPolygon'
 
     poly = geometry.polygon([(0, 0), (0, 5), (10, 5)], None)
     assert poly.crs is None
@@ -455,19 +455,19 @@ def test_unary_union():
     assert union0 == box1
 
     union1 = geometry.unary_union([box1, box4])
-    assert union1.type == 'MultiPolygon'
+    assert union1.geom_type == 'MultiPolygon'
     assert union1.area == 2.0 * box1.area
 
     union2 = geometry.unary_union([box1, box2])
-    assert union2.type == 'Polygon'
+    assert union2.geom_type == 'Polygon'
     assert union2.area == 1.5 * box1.area
 
     union3 = geometry.unary_union([box1, box2, box3, box4])
-    assert union3.type == 'Polygon'
+    assert union3.geom_type == 'Polygon'
     assert union3.area == 2.5 * box1.area
 
     union4 = geometry.unary_union([union1, box2, box3])
-    assert union4.type == 'Polygon'
+    assert union4.geom_type == 'Polygon'
     assert union4.area == 2.5 * box1.area
 
     assert geometry.unary_union([]) is None
@@ -502,7 +502,7 @@ def test_unary_intersection():
 
     inter5 = geometry.unary_intersection([box1, box2, box3, box4, box5])
     assert bool(inter5)
-    assert inter5.type == 'LineString'
+    assert inter5.geom_type == 'LineString'
     assert inter5.length == 20.0
 
     inter6 = geometry.unary_intersection([box1, box2, box3, box4, box5, box6])
@@ -788,7 +788,7 @@ def test_chop():
 
     chopped = chop_along_antimeridian(poly)
     assert chopped.crs is poly.crs
-    assert chopped.type == 'MultiPolygon'
+    assert chopped.geom_type == 'MultiPolygon'
     assert len([g for g in chopped]) == 2
 
     poly = geometry.box(0, 0, 10, 20, 'EPSG:4326')._to_crs(epsg3857)
@@ -830,10 +830,10 @@ def test_wrap_dateline():
                              (4465089.861944263, -5313778.16975072),
                              (3658653.1976781483, -4995675.379595791)], crs=albers_crs)
     wrapped = wrap.to_crs(geog_crs)
-    assert wrapped.type == 'Polygon'
+    assert wrapped.geom_type == 'Polygon'
     assert wrapped.intersects(geometry.line([(0, -90), (0, 90)], crs=geog_crs))
     wrapped = wrap.to_crs(geog_crs, wrapdateline=True)
-    assert wrapped.type == 'MultiPolygon'
+    assert wrapped.geom_type == 'MultiPolygon'
     assert not wrapped.intersects(geometry.line([(0, -90), (0, 90)], crs=geog_crs))
 
 
@@ -867,9 +867,9 @@ def test_wrap_dateline_sinusoidal(pts):
 
     wrap = geometry.polygon(pts, crs=sinus_crs)
     wrapped = wrap.to_crs(epsg4326)
-    assert wrapped.type == 'Polygon'
+    assert wrapped.geom_type == 'Polygon'
     wrapped = wrap.to_crs(epsg4326, wrapdateline=True)
-    assert wrapped.type == 'MultiPolygon'
+    assert wrapped.geom_type == 'MultiPolygon'
     assert not wrapped.intersects(geometry.line([(0, -90), (0, 90)], crs=epsg4326))
 
 
@@ -878,10 +878,10 @@ def test_wrap_dateline_utm():
                         849000, -1642500, 'EPSG:32660')
 
     wrapped = poly.to_crs(epsg4326)
-    assert wrapped.type == 'Polygon'
+    assert wrapped.geom_type == 'Polygon'
     assert wrapped.intersects(geometry.line([(0, -90), (0, 90)], crs=epsg4326))
     wrapped = poly.to_crs(epsg4326, wrapdateline=True)
-    assert wrapped.type == 'MultiPolygon'
+    assert wrapped.geom_type == 'MultiPolygon'
     assert not wrapped.intersects(geometry.line([(0, -90), (0, 90)], crs=epsg4326))