From 6fa0b54f80f44791d02deb45c8a2195dbbb9c344 Mon Sep 17 00:00:00 2001 From: Thomas Li Fredriksen Date: Wed, 27 Oct 2021 15:39:14 +0200 Subject: [PATCH 1/4] Extension/datacube - added variable property --- pystac/extensions/datacube.py | 107 +++++++++++++++++++++++++++++++++- 1 file changed, 105 insertions(+), 2 deletions(-) diff --git a/pystac/extensions/datacube.py b/pystac/extensions/datacube.py index fa51f61b1..67986d1e6 100644 --- a/pystac/extensions/datacube.py +++ b/pystac/extensions/datacube.py @@ -21,6 +21,7 @@ PREFIX: str = "cube:" DIMENSIONS_PROP = PREFIX + "dimensions" +VARIABLES_PROP = PREFIX + "variables" # Dimension properties DIM_TYPE_PROP = "type" @@ -28,6 +29,7 @@ DIM_AXIS_PROP = "axis" DIM_EXTENT_PROP = "extent" DIM_VALUES_PROP = "values" +DIM_DIMENSIONS_PROP = "dimensions" DIM_STEP_PROP = "step" DIM_REF_SYS_PROP = "reference_system" DIM_UNIT_PROP = "unit" @@ -398,6 +400,100 @@ def reference_system(self, v: Optional[Union[str, float, Dict[str, Any]]]) -> No self.properties[DIM_REF_SYS_PROP] = v +class VariableType(str, Enum): + """Variable object types""" + + DATA = "data" + AUXILIARY = "auxiliary" + + +class Variable: + properties: Dict[str, Any] + + def __init__(self, properties: Dict[str, Any]) -> None: + self.properties = properties + + @property + def dimensions(self) -> List[str]: + """The dimensions of hte variable. Should refer to keys in the `cube:dimensions` object + or be an empty list if the variable has no dimensions""" + return get_required( + self.properties.get(DIM_DIMENSIONS_PROP), "cube:variable", DIM_DIMENSIONS_PROP + ) + + @dimensions.setter + def dimensions(self, v: List[str]) -> None: + self.properties[DIM_DIMENSIONS_PROP] = v + + @property + def var_type(self) -> Union[VariableType, str]: + """Type of the variable, either `data` or `auxiliary`""" + return get_required( + self.properties.get(DIM_TYPE_PROP), "cube:variable", DIM_TYPE_PROP + ) + + @var_type.setter + def var_type(self, v: Union[VariableType, str]) -> None: + self.properties[DIM_TYPE_PROP] = v + + @property + def description(self) -> Optional[str]: + """Detailed multi-line description to explain the variable. `CommonMark 0.29 + `__ syntax MAY be used for rich text representation.""" + return self.properties.get(DIM_DESC_PROP) + + @description.setter + def description(self, v: Optional[str]): + if v is None: + self.properties.pop(DIM_DESC_PROP, None) + else: + self.properties[DIM_DESC_PROP] = v + + @property + def extent(self) -> List[Union[float, str, None]]: + """If the variable consists of `ordinal values + `, the extent (lower and upper bounds) of the + values as two-dimensional array. Use `None` for open intervals""" + return self.properties.get(DIM_EXTENT_PROP) + + @extent.setter + def extent(self, v: Optional[List[Union[float, str, None]]]): + if v is None: + self.properties.pop(DIM_EXTENT_PROP) + else: + self.properties[DIM_EXTENT_PROP] = v + + @property + def values(self) -> Optional[List[Union[float, str]]]: + """A set of all potential values, especially useful for `nominal values + `.""" + return self.properties.get(DIM_VALUES_PROP) + + @values.setter + def values(self, v: Optional[List[Union[float, str]]]): + if v is None: + self.properties.pop(DIM_VALUES_PROP) + else: + self.properties[DIM_VALUES_PROP] = v + + @property + def unit(self) -> Optional[str]: + """The unit of measurement for the data, preferably compliant to `UDUNITS-2 + ` units (singular)""" + return self.properties.get(DIM_UNIT_PROP) + + @unit.setter + def unit(self, v: Optional[str]): + if v is None: + self.properties.pop(DIM_UNIT_PROP) + else: + self.properties[DIM_UNIT_PROP] = v + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "Variable": + return Variable(d) + + class DatacubeExtension( Generic[T], PropertiesExtension, @@ -423,8 +519,6 @@ def apply(self, dimensions: Dict[str, Dimension]) -> None: :class:`~pystac.Collection`, :class:`~pystac.Item` or :class:`~pystac.Asset`. Args: - bands : A list of available bands where each item is a :class:`~Band` - object. If given, requires at least one band. dimensions : Dictionary mapping dimension name to a :class:`Dimension` object. """ @@ -442,6 +536,15 @@ def dimensions(self) -> Dict[str, Dimension]: def dimensions(self, v: Dict[str, Dimension]) -> None: self._set_property(DIMENSIONS_PROP, {k: dim.to_dict() for k, dim in v.items()}) + @property + def variables(self) -> Optional[Dict[str, Variable]]: + """Dictionary mapping variable name to a :class:`Variable` object.""" + result = self._get_property(VARIABLES_PROP, Dict[str, Any]) + + if result is None: + return None + return {k: Variable.from_dict(v) for k, v in result.items()} + @classmethod def get_schema_uri(cls) -> str: return SCHEMA_URI From f4f5d83b1601b4f4e10d122344d90f12472bdc8f Mon Sep 17 00:00:00 2001 From: Thomas Li Fredriksen Date: Wed, 27 Oct 2021 19:38:52 +0200 Subject: [PATCH 2/4] Extension/datacube - complied with pre-commit hooks --- pystac/extensions/datacube.py | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/pystac/extensions/datacube.py b/pystac/extensions/datacube.py index 67986d1e6..4e347d129 100644 --- a/pystac/extensions/datacube.py +++ b/pystac/extensions/datacube.py @@ -415,10 +415,12 @@ def __init__(self, properties: Dict[str, Any]) -> None: @property def dimensions(self) -> List[str]: - """The dimensions of hte variable. Should refer to keys in the `cube:dimensions` object + """The dimensions of the variable. Should refer to keys in the `cube:dimensions` object or be an empty list if the variable has no dimensions""" return get_required( - self.properties.get(DIM_DIMENSIONS_PROP), "cube:variable", DIM_DIMENSIONS_PROP + self.properties.get(DIM_DIMENSIONS_PROP), + "cube:variable", + DIM_DIMENSIONS_PROP, ) @dimensions.setter @@ -443,7 +445,7 @@ def description(self) -> Optional[str]: return self.properties.get(DIM_DESC_PROP) @description.setter - def description(self, v: Optional[str]): + def description(self, v: Optional[str]) -> None: if v is None: self.properties.pop(DIM_DESC_PROP, None) else: @@ -452,16 +454,16 @@ def description(self, v: Optional[str]): @property def extent(self) -> List[Union[float, str, None]]: """If the variable consists of `ordinal values - `, the extent (lower and upper bounds) of the - values as two-dimensional array. Use `None` for open intervals""" - return self.properties.get(DIM_EXTENT_PROP) + `, the extent + (lower and upper bounds) of the values as two-dimensional array. Use `None` for + open intervals""" + return get_required( + self.properties.get(DIM_EXTENT_PROP), "cube:variable", DIM_EXTENT_PROP + ) @extent.setter - def extent(self, v: Optional[List[Union[float, str, None]]]): - if v is None: - self.properties.pop(DIM_EXTENT_PROP) - else: - self.properties[DIM_EXTENT_PROP] = v + def extent(self, v: List[Union[float, str, None]]) -> None: + self.properties[DIM_EXTENT_PROP] = v @property def values(self) -> Optional[List[Union[float, str]]]: @@ -470,7 +472,7 @@ def values(self) -> Optional[List[Union[float, str]]]: return self.properties.get(DIM_VALUES_PROP) @values.setter - def values(self, v: Optional[List[Union[float, str]]]): + def values(self, v: Optional[List[Union[float, str]]]) -> None: if v is None: self.properties.pop(DIM_VALUES_PROP) else: @@ -483,7 +485,7 @@ def unit(self) -> Optional[str]: return self.properties.get(DIM_UNIT_PROP) @unit.setter - def unit(self, v: Optional[str]): + def unit(self, v: Optional[str]) -> None: if v is None: self.properties.pop(DIM_UNIT_PROP) else: From a8ed46760e56660bb64190abcb1d2d0b23279e19 Mon Sep 17 00:00:00 2001 From: Thomas Li Fredriksen Date: Thu, 28 Oct 2021 11:25:32 +0200 Subject: [PATCH 3/4] Extension/datacube - applied suggest changes from pr #645 --- CHANGELOG.md | 1 + docs/api.rst | 8 +++++ pystac/extensions/datacube.py | 52 +++++++++++++++++------------ tests/data-files/datacube/item.json | 2 +- 4 files changed, 40 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d1279eb8..8d128267e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ ([#590](https://github.com/stac-utils/pystac/pull/590)) - Links will get their `title` from their target if no `title` is provided ([#607](https://github.com/stac-utils/pystac/pull/607)) - Relax typing on `LabelClasses` from `List` to `Sequence` ([#627](https://github.com/stac-utils/pystac/pull/627)) +- Upgraded datacube-extension to version 2.0.0 ([#645](https://github.com/stac-utils/pystac/pull/645)) ### Fixed diff --git a/docs/api.rst b/docs/api.rst index dc91592e5..9b90dc27b 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -362,6 +362,14 @@ AdditionalDimension :show-inheritance: :inherited-members: +Variable +~~~~~~~~ + +.. autoclass:: pystac.extensions.datacube.Variable + :members: + :show-inheritance: + :inherited-members: + DatacubeExtension ~~~~~~~~~~~~~~~~~ diff --git a/pystac/extensions/datacube.py b/pystac/extensions/datacube.py index 4e347d129..aaa1044bb 100644 --- a/pystac/extensions/datacube.py +++ b/pystac/extensions/datacube.py @@ -17,7 +17,7 @@ T = TypeVar("T", pystac.Collection, pystac.Item, pystac.Asset) -SCHEMA_URI = "https://stac-extensions.github.io/datacube/v1.0.0/schema.json" +SCHEMA_URI = "https://stac-extensions.github.io/datacube/v2.0.0/schema.json" PREFIX: str = "cube:" DIMENSIONS_PROP = PREFIX + "dimensions" @@ -34,6 +34,14 @@ DIM_REF_SYS_PROP = "reference_system" DIM_UNIT_PROP = "unit" +# Variable properties +VAR_TYPE_PROP = "type" +VAR_DESC_PROP = "description" +VAR_EXTENT_PROP = "extent" +VAR_VALUES_PROP = "values" +VAR_DIMENSIONS_PROP = "dimensions" +VAR_UNIT_PROP = "unit" + class DimensionType(str, Enum): """Dimension object types for spatial and temporal Dimension Objects.""" @@ -415,81 +423,81 @@ def __init__(self, properties: Dict[str, Any]) -> None: @property def dimensions(self) -> List[str]: - """The dimensions of the variable. Should refer to keys in the `cube:dimensions` object - or be an empty list if the variable has no dimensions""" + """The dimensions of the variable. Should refer to keys in the ``cube:dimensions`` + object or be an empty list if the variable has no dimensions""" return get_required( - self.properties.get(DIM_DIMENSIONS_PROP), + self.properties.get(VAR_DIMENSIONS_PROP), "cube:variable", - DIM_DIMENSIONS_PROP, + VAR_DIMENSIONS_PROP, ) @dimensions.setter def dimensions(self, v: List[str]) -> None: - self.properties[DIM_DIMENSIONS_PROP] = v + self.properties[VAR_DIMENSIONS_PROP] = v @property def var_type(self) -> Union[VariableType, str]: - """Type of the variable, either `data` or `auxiliary`""" + """Type of the variable, either ``data`` or ``auxiliary``""" return get_required( - self.properties.get(DIM_TYPE_PROP), "cube:variable", DIM_TYPE_PROP + self.properties.get(VAR_TYPE_PROP), "cube:variable", VAR_TYPE_PROP ) @var_type.setter def var_type(self, v: Union[VariableType, str]) -> None: - self.properties[DIM_TYPE_PROP] = v + self.properties[VAR_TYPE_PROP] = v @property def description(self) -> Optional[str]: """Detailed multi-line description to explain the variable. `CommonMark 0.29 `__ syntax MAY be used for rich text representation.""" - return self.properties.get(DIM_DESC_PROP) + return self.properties.get(VAR_DESC_PROP) @description.setter def description(self, v: Optional[str]) -> None: if v is None: - self.properties.pop(DIM_DESC_PROP, None) + self.properties.pop(VAR_DESC_PROP, None) else: - self.properties[DIM_DESC_PROP] = v + self.properties[VAR_DESC_PROP] = v @property def extent(self) -> List[Union[float, str, None]]: """If the variable consists of `ordinal values `, the extent - (lower and upper bounds) of the values as two-dimensional array. Use `None` for - open intervals""" + (lower and upper bounds) of the values as two-dimensional array. Use ``None`` + for open intervals""" return get_required( - self.properties.get(DIM_EXTENT_PROP), "cube:variable", DIM_EXTENT_PROP + self.properties.get(VAR_EXTENT_PROP), "cube:variable", VAR_EXTENT_PROP ) @extent.setter def extent(self, v: List[Union[float, str, None]]) -> None: - self.properties[DIM_EXTENT_PROP] = v + self.properties[VAR_EXTENT_PROP] = v @property def values(self) -> Optional[List[Union[float, str]]]: """A set of all potential values, especially useful for `nominal values `.""" - return self.properties.get(DIM_VALUES_PROP) + return self.properties.get(VAR_VALUES_PROP) @values.setter def values(self, v: Optional[List[Union[float, str]]]) -> None: if v is None: - self.properties.pop(DIM_VALUES_PROP) + self.properties.pop(VAR_VALUES_PROP) else: - self.properties[DIM_VALUES_PROP] = v + self.properties[VAR_VALUES_PROP] = v @property def unit(self) -> Optional[str]: """The unit of measurement for the data, preferably compliant to `UDUNITS-2 ` units (singular)""" - return self.properties.get(DIM_UNIT_PROP) + return self.properties.get(VAR_UNIT_PROP) @unit.setter def unit(self, v: Optional[str]) -> None: if v is None: - self.properties.pop(DIM_UNIT_PROP) + self.properties.pop(VAR_UNIT_PROP) else: - self.properties[DIM_UNIT_PROP] = v + self.properties[VAR_UNIT_PROP] = v @staticmethod def from_dict(d: Dict[str, Any]) -> "Variable": diff --git a/tests/data-files/datacube/item.json b/tests/data-files/datacube/item.json index ddcd32e04..c33b13d52 100644 --- a/tests/data-files/datacube/item.json +++ b/tests/data-files/datacube/item.json @@ -1,7 +1,7 @@ { "stac_version": "1.0.0-rc.1", "stac_extensions": [ - "https://stac-extensions.github.io/datacube/v1.0.0/schema.json" + "https://stac-extensions.github.io/datacube/v2.0.0/schema.json" ], "id": "datacube-123", "type": "Feature", From 761f652a26d8123045ee66ac8af53317ffcbecb5 Mon Sep 17 00:00:00 2001 From: Thomas Li Fredriksen Date: Thu, 28 Oct 2021 20:30:47 +0200 Subject: [PATCH 4/4] Extension/datacube - applied suggest changes from pr #645 --- docs/api.rst | 8 ++++++++ pystac/extensions/datacube.py | 1 - 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/docs/api.rst b/docs/api.rst index 9b90dc27b..639c3350d 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -362,6 +362,14 @@ AdditionalDimension :show-inheritance: :inherited-members: +VariableType +~~~~~~~~~~~~ + +.. autoclass:: pystac.extensions.datacube.VariableType + :members: + :show-inheritance: + :inherited-members: + Variable ~~~~~~~~ diff --git a/pystac/extensions/datacube.py b/pystac/extensions/datacube.py index aaa1044bb..0a374fcab 100644 --- a/pystac/extensions/datacube.py +++ b/pystac/extensions/datacube.py @@ -29,7 +29,6 @@ DIM_AXIS_PROP = "axis" DIM_EXTENT_PROP = "extent" DIM_VALUES_PROP = "values" -DIM_DIMENSIONS_PROP = "dimensions" DIM_STEP_PROP = "step" DIM_REF_SYS_PROP = "reference_system" DIM_UNIT_PROP = "unit"