From 7543db043defe937cc125f9a029d7b46c842529c Mon Sep 17 00:00:00 2001 From: Emile Sonneveld Date: Mon, 29 Jun 2026 16:22:34 +0200 Subject: [PATCH 1/4] Fix for DelayedVector that are not geojson format. --- openeo_driver/delayed_vector.py | 2 +- openeo_driver/save_result.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openeo_driver/delayed_vector.py b/openeo_driver/delayed_vector.py index f4a4abe5..4524768f 100644 --- a/openeo_driver/delayed_vector.py +++ b/openeo_driver/delayed_vector.py @@ -321,6 +321,6 @@ def _read_geojson_crs(geojson: Dict) -> pyproj.CRS: crs = geojson.get("crs", {}).get("properties", {}).get("name") return pyproj.CRS("epsg:4326") if crs is None else pyproj.CRS(crs) - def to_driver_vector_cube(self): + def to_driver_vector_cube(self) -> DriverVectorCube: gdf = self.as_geodataframe() return DriverVectorCube.from_geodataframe(gdf, dimension_name="bands") diff --git a/openeo_driver/save_result.py b/openeo_driver/save_result.py index cfab273b..fe95ab1d 100644 --- a/openeo_driver/save_result.py +++ b/openeo_driver/save_result.py @@ -1010,7 +1010,7 @@ def to_save_result(data: Any, format: Optional[str] = None, options: Optional[di return JSONResult(data.geojson, format="geojson", options=options) else: data = data.to_driver_vector_cube() - elif isinstance(data, DriverDataCube): + if isinstance(data, DriverDataCube): return ImageCollectionResult(data, format=format, options=options) elif isinstance(data, DriverVectorCube): return VectorCubeResult(cube=data, format=format, options=options) From 3c00d61fc0b6a0a401d4b2310814f087e4b83d1d Mon Sep 17 00:00:00 2001 From: Emile Sonneveld Date: Mon, 29 Jun 2026 16:50:59 +0200 Subject: [PATCH 2/4] Add test_write_delayed_vector_cube_to_parquet() --- tests/test_save_result_parquet.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/tests/test_save_result_parquet.py b/tests/test_save_result_parquet.py index ae1a1d48..a2ff1da9 100644 --- a/tests/test_save_result_parquet.py +++ b/tests/test_save_result_parquet.py @@ -1,7 +1,8 @@ import pytest from openeo_driver.datacube import DriverVectorCube -from openeo_driver.save_result import AggregatePolygonSpatialResult +from openeo_driver.delayed_vector import DelayedVector +from openeo_driver.save_result import AggregatePolygonSpatialResult, to_save_result, VectorCubeResult from .data import get_path import geopandas as gpd @@ -48,3 +49,12 @@ def test_write_driver_vector_cube_to_parquet(tmp_path): vector_cube.write_assets(tmp_path / "dummy", format="Parquet") assert gpd.read_parquet(tmp_path / "vectorcube.parquet").shape == (2, 3) + + +def test_write_delayed_vector_cube_to_parquet(tmp_path): + dv = DelayedVector(str(get_path("geojson/FeatureCollection02.json"))) + vector_cube = to_save_result(dv, format="parquet") + assert isinstance(vector_cube, VectorCubeResult) + vector_cube.write_assets(tmp_path / "dummy") + # TODO: Why are id and pop columns missing here? + assert gpd.read_parquet(tmp_path / "vectorcube.parquet").shape == (2, 1) From 9b769cba892111f0e14d6e8cd77d20279ba76e4d Mon Sep 17 00:00:00 2001 From: Emile Sonneveld Date: Tue, 30 Jun 2026 11:01:58 +0200 Subject: [PATCH 3/4] typeguard.check_argument_types() in AggregatePolygonResult. --- openeo_driver/save_result.py | 7 +++++-- setup.py | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/openeo_driver/save_result.py b/openeo_driver/save_result.py index fe95ab1d..05e991fb 100644 --- a/openeo_driver/save_result.py +++ b/openeo_driver/save_result.py @@ -26,6 +26,8 @@ import xarray from openeo.metadata import CollectionMetadata +from typeguard import check_argument_types + from openeo_driver.datacube import DriverDataCube, DriverVectorCube, DriverMlModel from openeo_driver.datastructs import StacAsset from openeo_driver.delayed_vector import DelayedVector @@ -302,9 +304,9 @@ class AggregatePolygonResult(JSONResult): # TODO: if it supports NetCDF and CSV def __init__( self, - timeseries: Dict[int, List[List[Any]]], + timeseries: Optional[Dict[str, List[List[Any]]]], regions: Union[GeometryCollection, DriverVectorCube], - metadata: CollectionMetadata = None, + metadata: Optional[CollectionMetadata] = None, ): """ :param timeseries: {timestamp: [geometries, bands]} @@ -312,6 +314,7 @@ def __init__( :param regions: GeometryCollection or DriverVectorCube :param metadata: CollectionMetadata """ + check_argument_types() super().__init__(data=timeseries) if not isinstance(regions, (GeometryCollection, DriverVectorCube)): # TODO: raise exception instead of warning? diff --git a/setup.py b/setup.py index a6ef418f..b4f4897d 100644 --- a/setup.py +++ b/setup.py @@ -30,6 +30,7 @@ "pyarrow>=10.0.0", "jsonschema", "dirty-equals>=0.6", + "typeguard", ] typing_require = [ From 982e73fcfbaf1f80e580a0c6f4ffbfc02fd645c0 Mon Sep 17 00:00:00 2001 From: Emile Sonneveld Date: Tue, 30 Jun 2026 11:16:03 +0200 Subject: [PATCH 4/4] typechecked decorator. --- openeo_driver/save_result.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/openeo_driver/save_result.py b/openeo_driver/save_result.py index 05e991fb..e92b56a6 100644 --- a/openeo_driver/save_result.py +++ b/openeo_driver/save_result.py @@ -26,7 +26,7 @@ import xarray from openeo.metadata import CollectionMetadata -from typeguard import check_argument_types +from typeguard import typechecked from openeo_driver.datacube import DriverDataCube, DriverVectorCube, DriverMlModel from openeo_driver.datastructs import StacAsset @@ -301,7 +301,7 @@ class AggregatePolygonResult(JSONResult): # TODO: if it supports NetCDF and CSV """ # TODO #71 #114 EP-3981 port this to proper vector cube support - + @typechecked def __init__( self, timeseries: Optional[Dict[str, List[List[Any]]]], @@ -314,7 +314,6 @@ def __init__( :param regions: GeometryCollection or DriverVectorCube :param metadata: CollectionMetadata """ - check_argument_types() super().__init__(data=timeseries) if not isinstance(regions, (GeometryCollection, DriverVectorCube)): # TODO: raise exception instead of warning?