Skip to content

Commit aeaa6d9

Browse files
committed
Raster Extension: simplify typing, implement #370, add to API docs
1 parent 304552d commit aeaa6d9

File tree

3 files changed

+86
-38
lines changed

3 files changed

+86
-38
lines changed

docs/api.rst

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,43 @@ AssetProjectionExtension
414414
:members:
415415
:show-inheritance:
416416

417+
Raster Extension
418+
----------------
419+
420+
DataType
421+
~~~~~~~~
422+
423+
.. autoclass:: pystac.extensions.raster.DataType
424+
:members:
425+
:undoc-members:
426+
:show-inheritance:
427+
428+
Statistics
429+
~~~~~~~~~~
430+
431+
.. autoclass:: pystac.extensions.raster.Statistics
432+
:members:
433+
434+
Histogram
435+
~~~~~~~~~
436+
437+
.. autoclass:: pystac.extensions.raster.Histogram
438+
:members:
439+
440+
RasterBand
441+
~~~~~~~~~~
442+
443+
.. autoclass:: pystac.extensions.raster.RasterBand
444+
:members:
445+
446+
RasterExtension
447+
~~~~~~~~~~~~~~~
448+
449+
.. autoclass:: pystac.extensions.raster.RasterExtension
450+
:members:
451+
:show-inheritance:
452+
:inherited-members:
453+
417454
Scientific Extension
418455
--------------------
419456

pystac/extensions/raster.py

Lines changed: 34 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"""
55

66
import enum
7-
from typing import Any, Dict, Generic, Iterable, List, Optional, TypeVar, cast
7+
from typing import Any, Dict, Iterable, List, Optional
88

99
import pystac
1010
from pystac.extensions.base import (
@@ -14,8 +14,6 @@
1414
)
1515
from pystac.utils import get_opt, get_required, map_opt
1616

17-
T = TypeVar("T", pystac.Item, pystac.Asset)
18-
1917
SCHEMA_URI = "https://stac-extensions.github.io/raster/v1.0.0/schema.json"
2018

2119
BANDS_PROP = "raster:bands"
@@ -625,9 +623,7 @@ def to_dict(self) -> Dict[str, Any]:
625623
return self.properties
626624

627625

628-
class RasterExtension(
629-
Generic[T], PropertiesExtension, ExtensionManagementMixin[pystac.Item]
630-
):
626+
class RasterExtension(PropertiesExtension, ExtensionManagementMixin[pystac.Item]):
631627
"""An abstract class that can be used to extend the properties of an
632628
:class:`~pystac.Item` or :class:`~pystac.Asset` with properties from
633629
the :stac-ext:`Raster Extension <raster>`. This class is generic over
@@ -639,6 +635,25 @@ class RasterExtension(
639635
:class:`~ItemRasterExtension` to extend an :class:`~pystac.Item`).
640636
"""
641637

638+
asset_href: str
639+
"""The ``href`` value of the :class:`~pystac.Asset` being extended."""
640+
641+
properties: Dict[str, Any]
642+
"""The :class:`~pystac.Asset` fields, including extension properties."""
643+
644+
additional_read_properties: Optional[Iterable[Dict[str, Any]]] = None
645+
"""If present, this will be a list containing 1 dictionary representing the
646+
properties of the owning :class:`~pystac.Item`."""
647+
648+
def __init__(self, asset: pystac.Asset):
649+
self.asset_href = asset.href
650+
self.properties = asset.properties
651+
if asset.owner and isinstance(asset.owner, pystac.Item):
652+
self.additional_read_properties = [asset.owner.properties]
653+
654+
def __repr__(self) -> str:
655+
return "<AssetRasterExtension Asset href={}>".format(self.asset_href)
656+
642657
def apply(self, bands: List[RasterBand]) -> None:
643658
"""Applies raster extension properties to the extended :class:`pystac.Item` or
644659
:class:`pystac.Asset`.
@@ -673,10 +688,20 @@ def _get_bands(self) -> Optional[List[RasterBand]]:
673688
def get_schema_uri(cls) -> str:
674689
return SCHEMA_URI
675690

676-
@staticmethod
677-
def ext(obj: T) -> "RasterExtension[T]":
691+
@classmethod
692+
def ext(cls, obj: pystac.Asset) -> "RasterExtension":
693+
"""Extends the given STAC Object with properties from the :stac-ext:`Raster
694+
Extension <raster>`.
695+
696+
This extension can be applied to instances of :class:`~pystac.Asset`.
697+
698+
Raises:
699+
700+
pystac.ExtensionTypeError : If an invalid object type is passed.
701+
"""
678702
if isinstance(obj, pystac.Asset):
679-
return cast(RasterExtension[T], AssetRasterExtension(obj))
703+
cls.validate_has_extension(obj)
704+
return cls(obj)
680705
else:
681706
raise pystac.ExtensionTypeError(
682707
f"Raster extension does not apply to type {type(obj)}"
@@ -687,35 +712,6 @@ def summaries(obj: pystac.Collection) -> "SummariesRasterExtension":
687712
return SummariesRasterExtension(obj)
688713

689714

690-
class AssetRasterExtension(RasterExtension[pystac.Asset]):
691-
"""A concrete implementation of :class:`RasterExtension` on an :class:`~pystac.Asset`
692-
that extends the Asset fields to include properties defined in the
693-
:stac-ext:`Raster Extension <raster>`.
694-
695-
This class should generally not be instantiated directly. Instead, call
696-
:meth:`RasterExtension.ext` on an :class:`~pystac.Asset` to extend it.
697-
"""
698-
699-
asset_href: str
700-
"""The ``href`` value of the :class:`~pystac.Asset` being extended."""
701-
702-
properties: Dict[str, Any]
703-
"""The :class:`~pystac.Asset` fields, including extension properties."""
704-
705-
additional_read_properties: Optional[Iterable[Dict[str, Any]]] = None
706-
"""If present, this will be a list containing 1 dictionary representing the
707-
properties of the owning :class:`~pystac.Item`."""
708-
709-
def __init__(self, asset: pystac.Asset):
710-
self.asset_href = asset.href
711-
self.properties = asset.properties
712-
if asset.owner and isinstance(asset.owner, pystac.Item):
713-
self.additional_read_properties = [asset.owner.properties]
714-
715-
def __repr__(self) -> str:
716-
return "<AssetRasterExtension Asset href={}>".format(self.asset_href)
717-
718-
719715
class SummariesRasterExtension(SummariesExtension):
720716
"""A concrete implementation of :class:`~SummariesExtension` that extends
721717
the ``summaries`` field of a :class:`~pystac.Collection` to include properties

tests/extensions/test_raster.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,3 +198,18 @@ def test_asset_bands(self) -> None:
198198
item.assets["test"].properties["raster:bands"][0]["statistics"]["minimum"],
199199
1,
200200
)
201+
202+
def test_extension_not_implemented(self) -> None:
203+
# Should raise exception if Item does not include extension URI
204+
item = pystac.Item.from_file(self.PLANET_EXAMPLE_URI)
205+
item.stac_extensions.remove(RasterExtension.get_schema_uri())
206+
207+
# Should raise exception if owning Item does not include extension URI
208+
asset = item.assets["data"]
209+
210+
with self.assertRaises(pystac.ExtensionNotImplemented):
211+
_ = RasterExtension.ext(asset)
212+
213+
# Should succeed if Asset has no owner
214+
ownerless_asset = pystac.Asset.from_dict(asset.to_dict())
215+
_ = RasterExtension.ext(ownerless_asset)

0 commit comments

Comments
 (0)