diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c73abaed..c72ac303c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added `show_error_logs` argument to `cube.execute_batch()`/`job.start_and_wait()`/... to toggle the automatic printing of error logs on failure ([#505](https://github.com/Open-EO/openeo-python-client/issues/505)) - Added `Connection.web_editor()` to build link to the openEO backend in the openEO Web Editor - Add support for `log_level` in `create_job()` and `execute_job()` ([#704](https://github.com/Open-EO/openeo-python-client/issues/704)) +- Add initial support for "geometry" dimension type in `CubeMetadata` ([#705](https://github.com/Open-EO/openeo-python-client/issues/705)) ### Changed diff --git a/openeo/metadata.py b/openeo/metadata.py index 8b7701579..0ded32e84 100644 --- a/openeo/metadata.py +++ b/openeo/metadata.py @@ -213,6 +213,19 @@ def rename_labels(self, target, source) -> Dimension: def rename(self, name) -> Dimension: return BandDimension(name=name, bands=self.bands) + +class GeometryDimension(Dimension): + # TODO: how to model/store labels of geometry dimension? + def __init__(self, name: str): + super().__init__(name=name, type="geometry") + + def rename(self, name) -> Dimension: + return GeometryDimension(name=name) + + def rename_labels(self, target, source) -> Dimension: + return GeometryDimension(name=self.name) + + class CubeMetadata: """ Interface for metadata of a data cube. @@ -229,7 +242,7 @@ def __init__(self, dimensions: Optional[List[Dimension]] = None): if dimensions is not None: for dim in self._dimensions: # TODO: here we blindly pick last bands or temporal dimension if multiple. Let user choose? - # TODO: add spacial dimension handling? + # TODO: add spatial dimension handling? if dim.type == "bands": if isinstance(dim, BandDimension): self._band_dimension = dim @@ -284,6 +297,16 @@ def temporal_dimension(self) -> TemporalDimension: def spatial_dimensions(self) -> List[SpatialDimension]: return [d for d in self._dimensions if isinstance(d, SpatialDimension)] + def has_geometry_dimension(self): + return any(isinstance(d, GeometryDimension) for d in self._dimensions) + + @property + def geometry_dimension(self) -> GeometryDimension: + for d in self._dimensions: + if isinstance(d, GeometryDimension): + return d + raise MetadataException("No geometry dimension") + @property def bands(self) -> List[Band]: """Get band metadata as list of Band metadata tuples""" @@ -365,7 +388,7 @@ def reduce_spatial(self) -> CubeMetadata: dimensions = [d for d in self._dimensions if not isinstance(d, SpatialDimension)] return self._clone_and_update(dimensions=dimensions) - def add_dimension(self, name: str, label: Union[str, float], type: str = None) -> CubeMetadata: + def add_dimension(self, name: str, label: Union[str, float], type: Optional[str] = None) -> CubeMetadata: """Create new CubeMetadata object with added dimension""" if any(d.name == name for d in self._dimensions): raise DimensionAlreadyExistsException(f"Dimension with name {name!r} already exists") @@ -375,6 +398,8 @@ def add_dimension(self, name: str, label: Union[str, float], type: str = None) - dim = SpatialDimension(name=name, extent=[label, label]) elif type == "temporal": dim = TemporalDimension(name=name, extent=[label, label]) + elif type == "geometry": + dim = GeometryDimension(name=name) else: dim = Dimension(type=type or "other", name=name) return self._clone_and_update(dimensions=self._dimensions + [dim]) diff --git a/tests/test_metadata.py b/tests/test_metadata.py index a11bc6aaa..da9280ed6 100644 --- a/tests/test_metadata.py +++ b/tests/test_metadata.py @@ -632,7 +632,7 @@ def test_collectionmetadata_add_band_dimension_duplicate(): _ = metadata.add_dimension("layer", "red", "bands") -def test_cubemetadata_add_band_dimension_dublicate(): +def test_cubemetadata_add_band_dimension_duplicate(): metadata = CubeMetadata(dimensions=[TemporalDimension(name="t", extent=None)]) metadata = metadata.add_dimension("layer", "red", "bands") with pytest.raises(DimensionAlreadyExistsException, match="Dimension with name 'layer' already exists"): @@ -679,6 +679,20 @@ def test_cubemetadata_add_temporal_dimension_duplicate(): _ = metadata.add_dimension("date", "2020-05-15", "temporal") +def test_cube_metadata_add_dimension_geometry(): + orig = CubeMetadata(dimensions=[TemporalDimension(name="t", extent=None)]) + new = orig.add_dimension(name="fields", label="Mol", type="geometry") + + assert orig.dimension_names() == ["t"] + assert not orig.has_geometry_dimension() + with pytest.raises(MetadataException): + orig.geometry_dimension() + + assert new.dimension_names() == ["t", "fields"] + assert new.has_geometry_dimension() + assert new.geometry_dimension.name == "fields" + assert new.geometry_dimension.type == "geometry" + def test_collectionmetadata_drop_dimension(): metadata = CollectionMetadata( {