Repository: ungarj/mapchete
Pull request #482 (2022-09-14 14:13:29)

make code compatible with fiona >1.9


Patch:
diff --git a/mapchete/index.py b/mapchete/index.py
index 4b25a49..60b9356 100644
--- a/mapchete/index.py
+++ b/mapchete/index.py
@@ -226,7 +226,7 @@ class VectorFileWriter:
                 self.sink = fiona.open(self.path, "a")
             else:
                 self.sink = fiona.open(
-                    self.path, "w", driver=self.driver, crs=crs, schema=schema
+                    self.path, "w", driver=self.driver, crs=crs.to_dict(), schema=schema
                 )
                 self._existing = {}
         else:  # pragma: no cover
diff --git a/mapchete/io/_geometry_operations.py b/mapchete/io/_geometry_operations.py
index 5f4a3f6..1becd64 100644
--- a/mapchete/io/_geometry_operations.py
+++ b/mapchete/io/_geometry_operations.py
@@ -78,19 +78,25 @@ def reproject_geometry(
     """
     src_crs = validate_crs(src_crs)
     dst_crs = validate_crs(dst_crs)
+    if not isinstance(geometry, base.BaseGeometry):  # pragma: no cover
+        raise TypeError(f"invalid geometry type: {type(geometry)}")
 
     def _reproject_geom(geometry, src_crs, dst_crs):
         if geometry.is_empty:
             return geometry
         else:
-            out_geom = to_shape(
-                transform_geom(
-                    src_crs.to_dict(),
-                    dst_crs.to_dict(),
-                    mapping(geometry),
-                    antimeridian_cutting=antimeridian_cutting,
-                )
+            transformed = transform_geom(
+                src_crs.to_dict(),
+                dst_crs.to_dict(),
+                mapping(geometry),
+                antimeridian_cutting=antimeridian_cutting,
             )
+            # Fiona >1.9 returns None if transformation errored
+            if transformed is None:  # pragma: no cover
+                raise ReprojectionFailed(
+                    f"fiona.transform.transform_geom could not transform geometry from {src_crs} to {dst_crs}"
+                )
+            out_geom = to_shape(transformed)
             return _repair(out_geom) if validity_check else out_geom
 
     def _segmentize_value(geometry, segmentize_fraction):
@@ -232,7 +238,7 @@ def segmentize_geometry(geometry, segmentize_value):
     )
 
 
-def to_shape(geom):
+def to_shape(geom) -> base.BaseGeometry:
     """
     Convert geometry to shapely geometry if necessary.
 
@@ -244,7 +250,7 @@ def to_shape(geom):
     -------
     shapely geometry
     """
-    return shape(geom) if isinstance(geom, dict) else geom
+    return shape(geom) if not isinstance(geom, base.BaseGeometry) else geom
 
 
 def multipart_to_singleparts(geom):
diff --git a/mapchete/validate.py b/mapchete/validate.py
index 3429539..7a8012e 100644
--- a/mapchete/validate.py
+++ b/mapchete/validate.py
@@ -203,10 +203,11 @@ def validate_crs(crs):
             return CRS().from_string(crs)
     elif isinstance(crs, int):
         return CRS().from_epsg(crs)
-    elif isinstance(crs, dict):
-        return CRS().from_dict(crs)
     else:
-        raise TypeError("invalid CRS given")
+        try:
+            return CRS.from_user_input(crs)
+        except Exception:
+            raise TypeError(f"invalid CRS given: {crs}")
 
 
 def validate_write_window_params(in_tile, out_tile, in_data, out_profile):
diff --git a/requirements.txt b/requirements.txt
index 50a7d2f..fbd9087 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -7,7 +7,7 @@ cached-property>=1.5.1
 click>=7.1.1
 click-plugins>=1.1.1
 click-spinner>=0.1.10
-fiona>=1.8.13.post1,<=1.8.21
+fiona>=1.8.13.post1
 Flask>=1.1.2
 fsspec[s3]>=0.8.4
 geobuf>=1.1.1
@@ -19,7 +19,7 @@ numpy>=1.16
 oyaml>=0.9
 pyproj
 retry>=0.9.2
-rasterio>=1.0.28,<1.3.0
+rasterio>=1.0.28
 s3fs>=0.5.2
 Shapely>=1.7.1,<1.8.1
 tilematrix>=2022.3.0


Test patch:
diff --git a/test/test_formats_flatgeobuf.py b/test/test_formats_flatgeobuf.py
index c5c7de8..ddc2a13 100644
--- a/test/test_formats_flatgeobuf.py
+++ b/test/test_formats_flatgeobuf.py
@@ -15,7 +15,8 @@ def test_input_data_read(mp_tmpdir, flatgeobuf, landpoly_3857):
             input_tile = formats.default.geojson.InputTile(tile, mp)
             assert isinstance(input_tile.read(), list)
             for feature in input_tile.read():
-                assert isinstance(feature, dict)
+                assert "geometry" in feature
+                assert "properties" in feature
 
     # reprojected FlatGeobuf
     config = flatgeobuf.dict
@@ -36,7 +37,8 @@ def test_input_data_read(mp_tmpdir, flatgeobuf, landpoly_3857):
                 any_data = True
                 assert isinstance(input_tile.read(), list)
                 for feature in input_tile.read():
-                    assert isinstance(feature, dict)
+                    assert "geometry" in feature
+                    assert "properties" in feature
         assert any_data
 
 
diff --git a/test/test_formats_geojson.py b/test/test_formats_geojson.py
index f4a227e..8e498d9 100644
--- a/test/test_formats_geojson.py
+++ b/test/test_formats_geojson.py
@@ -15,7 +15,8 @@ def test_input_data_read(mp_tmpdir, geojson, landpoly_3857):
             input_tile = formats.default.geojson.InputTile(tile, mp)
             assert isinstance(input_tile.read(), list)
             for feature in input_tile.read():
-                assert isinstance(feature, dict)
+                assert "geometry" in feature
+                assert "properties" in feature
 
     # reprojected GeoJSON
     config = geojson.dict
@@ -36,7 +37,8 @@ def test_input_data_read(mp_tmpdir, geojson, landpoly_3857):
                 any_data = True
                 assert isinstance(input_tile.read(), list)
                 for feature in input_tile.read():
-                    assert isinstance(feature, dict)
+                    assert "geometry" in feature
+                    assert "properties" in feature
         assert any_data
 
 
diff --git a/test/test_io_vector.py b/test/test_io_vector.py
index f1aa202..4a27277 100644
--- a/test/test_io_vector.py
+++ b/test/test_io_vector.py
@@ -359,7 +359,6 @@ def test_indexed_features(landpoly):
     assert features.keys()
 
     for f in features:
-        assert isinstance(f, dict)
         assert "properties" in f
         assert "geometry" in f