diff --git a/mapchete/config/parse.py b/mapchete/config/parse.py index 0562d19b..5f5dbacb 100644 --- a/mapchete/config/parse.py +++ b/mapchete/config/parse.py @@ -5,13 +5,13 @@ from shapely import wkt from shapely.geometry import Point, shape from shapely.geometry.base import BaseGeometry -from shapely.ops import unary_union from mapchete.bounds import Bounds from mapchete.config.models import ProcessConfig, ZoomParameters from mapchete.errors import GeometryTypeError from mapchete.geometry import is_type, reproject_geometry -from mapchete.io.vector import fiona_open +from mapchete.geometry.types import Polygon, MultiPolygon +from mapchete.io.vector.indexed_features import IndexedFeatures from mapchete.path import MPath from mapchete.tile import BufferedTilePyramid from mapchete.types import BoundsLike, MPathLike, ZoomLevelsLike @@ -148,8 +148,8 @@ def bounds_from_opts( reproj = reproject_geometry( Point(x, y), src_crs=point_crs, dst_crs=tp.crs ) - x = reproj.x - y = reproj.y + x = reproj.x # type: ignore + y = reproj.y # type: ignore zoom_levels = get_zoom_levels( process_zoom_levels=raw_conf["zoom_levels"], init_zoom_levels=zoom ) @@ -205,14 +205,28 @@ def guess_geometry( crs = None # WKT or path: if isinstance(some_input, (str, MPath)): - if str(some_input).upper().startswith(("POLYGON ", "MULTIPOLYGON ")): - geom = wkt.loads(some_input) + if ( + str(some_input) + .upper() + .startswith( + ( + "POINT ", + "MULTIPOINT ", + "LINESTRING ", + "MULTILINESTRING ", + "POLYGON ", + "MULTIPOLYGON ", + "GEOMETRYCOLLECTION ", + ) + ) + ): + geom = wkt.loads(str(some_input)) else: - path = MPath.from_inp(some_input) - with path.fio_env(): - with fiona_open(str(path.absolute_path(base_dir))) as src: - geom = unary_union([shape(f["geometry"]) for f in src]) - crs = src.crs + features = IndexedFeatures.from_file( + MPath.from_inp(some_input).absolute_path(base_dir) + ) + geom = features.read_union_geometry() + crs = features.crs # GeoJSON mapping elif isinstance(some_input, dict): geom = shape(some_input) @@ -226,7 +240,7 @@ def guess_geometry( ) if not geom.is_valid: # pragma: no cover raise TypeError("area is not a valid geometry") - if not is_type(geom, "Polygon", singlepart_equivalent_matches=True): + if not is_type(geom, target_type=(Polygon, MultiPolygon)): raise GeometryTypeError( f"area must either be a Polygon or a MultiPolygon, not {geom.geom_type}" ) diff --git a/mapchete/geometry/filter.py b/mapchete/geometry/filter.py index c8b036e2..d8495a75 100644 --- a/mapchete/geometry/filter.py +++ b/mapchete/geometry/filter.py @@ -35,7 +35,7 @@ def omit_empty_geometries(geometry: Geometry) -> Generator[Geometry, None, None] def is_type( geometry: Geometry, - target_type: Union[GeometryTypeLike, Tuple[GeometryTypeLike]], + target_type: Union[GeometryTypeLike, Tuple[GeometryTypeLike, ...]], singlepart_equivalent_matches: bool = True, multipart_equivalent_matches: bool = True, ) -> bool: diff --git a/test/test_config.py b/test/test_config.py index cf80a22d..dfc688a4 100644 --- a/test/test_config.py +++ b/test/test_config.py @@ -16,7 +16,7 @@ from mapchete.config.models import DaskAdaptOptions, DaskSpecs from mapchete.config.parse import bounds_from_opts, guess_geometry from mapchete.config.process_func import ProcessFunc -from mapchete.errors import MapcheteConfigError +from mapchete.errors import GeometryTypeError, MapcheteConfigError from mapchete.io import fiona_open, rasterio_open from mapchete.path import MPath from mapchete.bounds import Bounds @@ -412,6 +412,32 @@ def test_guess_geometry(aoi_br_geojson): guess_geometry(area.centroid) +@pytest.mark.parametrize( + "geometry", + [ + lazy_fixture("polygon"), + lazy_fixture("multipolygon"), + ], +) +def test_guess_geometry_types(geometry): + assert guess_geometry(geometry.wkt)[0].is_valid + + +@pytest.mark.parametrize( + "geometry", + [ + lazy_fixture("point"), + lazy_fixture("multipoint"), + lazy_fixture("linestring"), + lazy_fixture("multilinestring"), + lazy_fixture("geometrycollection"), + ], +) +def test_guess_geometry_types_errors(geometry): + with pytest.raises(GeometryTypeError): + guess_geometry(geometry.wkt) + + def test_bounds_from_opts_wkt(wkt_geom): # WKT assert isinstance(bounds_from_opts(wkt_geometry=wkt_geom), Bounds)