Skip to content

Commit 762fe7b

Browse files
committed
Fix item assets
1 parent 3d75620 commit 762fe7b

18 files changed

+227
-55
lines changed

pystac/extensions/base.py

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1+
from __future__ import annotations
2+
13
import re
24
import warnings
35
from abc import ABC, abstractmethod
46
from typing import (
7+
TYPE_CHECKING,
58
Any,
69
Dict,
710
Generic,
@@ -16,6 +19,9 @@
1619

1720
import pystac
1821

22+
if TYPE_CHECKING:
23+
from pystac.extensions.item_assets import AssetDefinition
24+
1925
VERSION_REGEX = re.compile("/v[0-9].[0-9].*/")
2026

2127

@@ -157,7 +163,39 @@ def has_extension(cls, obj: S) -> bool:
157163
@classmethod
158164
def validate_owner_has_extension(
159165
cls,
160-
asset: pystac.Asset,
166+
asset: Union[pystac.Asset, AssetDefinition],
167+
add_if_missing: bool = False,
168+
) -> None:
169+
"""
170+
DEPRECATED
171+
172+
.. deprecated:: 1.9
173+
Use :meth:`ensure_owner_has_extension` instead.
174+
175+
Given an :class:`~pystac.Asset`, checks if the asset's owner has this
176+
extension's schema URI in its :attr:`~pystac.STACObject.stac_extensions` list.
177+
If ``add_if_missing`` is ``True``, the schema URI will be added to the owner.
178+
179+
Args:
180+
asset : The asset whose owner should be validated.
181+
add_if_missing : Whether to add the schema URI to the owner if it is
182+
not already present. Defaults to False.
183+
184+
Raises:
185+
STACError : If ``add_if_missing`` is ``True`` and ``asset.owner`` is
186+
``None``.
187+
"""
188+
warnings.warn(
189+
"ensure_owner_has_extension is deprecated and will be removed in v1.9. "
190+
"Use ensure_owner_has_extension instead",
191+
DeprecationWarning,
192+
)
193+
return cls.ensure_owner_has_extension(asset, add_if_missing)
194+
195+
@classmethod
196+
def ensure_owner_has_extension(
197+
cls,
198+
asset: Union[pystac.Asset, AssetDefinition],
161199
add_if_missing: bool = False,
162200
) -> None:
163201
"""Given an :class:`~pystac.Asset`, checks if the asset's owner has this
@@ -176,8 +214,8 @@ def validate_owner_has_extension(
176214
if asset.owner is None:
177215
if add_if_missing:
178216
raise pystac.STACError(
179-
"Attempted to use add_if_missing=True for an Asset with no owner. "
180-
"Use Asset.set_owner or set add_if_missing=False."
217+
"Attempted to use add_if_missing=True for an Asset or ItemAsset "
218+
"with no owner. Use .set_owner or set add_if_missing=False."
181219
)
182220
else:
183221
return

pystac/extensions/classification.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
)
2020

2121
import pystac
22-
import pystac.extensions.item_assets as item_assets
22+
from pystac.extensions import item_assets
2323
from pystac.extensions.base import (
2424
ExtensionManagementMixin,
2525
PropertiesExtension,
@@ -536,12 +536,10 @@ def ext(cls, obj: T, add_if_missing: bool = False) -> ClassificationExtension[T]
536536
cls.ensure_has_extension(obj, add_if_missing)
537537
return cast(ClassificationExtension[T], ItemClassificationExtension(obj))
538538
elif isinstance(obj, pystac.Asset):
539-
cls.validate_owner_has_extension(obj, add_if_missing)
539+
cls.ensure_owner_has_extension(obj, add_if_missing)
540540
return cast(ClassificationExtension[T], AssetClassificationExtension(obj))
541541
elif isinstance(obj, item_assets.AssetDefinition):
542-
cls.ensure_has_extension(
543-
cast(Union[pystac.Item, pystac.Collection], obj.owner), add_if_missing
544-
)
542+
cls.ensure_owner_has_extension(obj, add_if_missing)
545543
return cast(
546544
ClassificationExtension[T], ItemAssetsClassificationExtension(obj)
547545
)

pystac/extensions/datacube.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,14 @@
66
from typing import Any, Dict, Generic, List, Literal, Optional, TypeVar, Union, cast
77

88
import pystac
9+
from pystac.extensions import item_assets
910
from pystac.extensions.base import ExtensionManagementMixin, PropertiesExtension
1011
from pystac.extensions.hooks import ExtensionHooks
1112
from pystac.utils import StringEnum, get_required, map_opt
1213

13-
T = TypeVar("T", pystac.Collection, pystac.Item, pystac.Asset)
14+
T = TypeVar(
15+
"T", pystac.Collection, pystac.Item, pystac.Asset, item_assets.AssetDefinition
16+
)
1417

1518
SCHEMA_URI = "https://stac-extensions.github.io/datacube/v2.0.0/schema.json"
1619

@@ -545,8 +548,11 @@ def ext(cls, obj: T, add_if_missing: bool = False) -> DatacubeExtension[T]:
545548
cls.ensure_has_extension(obj, add_if_missing)
546549
return cast(DatacubeExtension[T], ItemDatacubeExtension(obj))
547550
elif isinstance(obj, pystac.Asset):
548-
cls.validate_owner_has_extension(obj, add_if_missing)
551+
cls.ensure_owner_has_extension(obj, add_if_missing)
549552
return cast(DatacubeExtension[T], AssetDatacubeExtension(obj))
553+
elif isinstance(obj, item_assets.AssetDefinition):
554+
cls.ensure_owner_has_extension(obj, add_if_missing)
555+
return cast(DatacubeExtension[T], ItemAssetsDatacubeExtension(obj))
550556
else:
551557
raise pystac.ExtensionTypeError(cls._ext_error_message(obj))
552558

@@ -616,6 +622,15 @@ def __repr__(self) -> str:
616622
return "<AssetDatacubeExtension Item id={}>".format(self.asset_href)
617623

618624

625+
class ItemAssetsDatacubeExtension(DatacubeExtension[item_assets.AssetDefinition]):
626+
properties: Dict[str, Any]
627+
asset_defn: item_assets.AssetDefinition
628+
629+
def __init__(self, item_asset: item_assets.AssetDefinition):
630+
self.asset_defn = item_asset
631+
self.properties = item_asset.properties
632+
633+
619634
class DatacubeExtensionHooks(ExtensionHooks):
620635
schema_uri: str = SCHEMA_URI
621636
prev_extension_ids = {"datacube"}

pystac/extensions/eo.py

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
)
1919

2020
import pystac
21-
from pystac.extensions import projection, view
21+
from pystac.extensions import item_assets, projection, view
2222
from pystac.extensions.base import (
2323
ExtensionManagementMixin,
2424
PropertiesExtension,
@@ -29,7 +29,7 @@
2929
from pystac.summaries import RangeSummary
3030
from pystac.utils import get_required, map_opt
3131

32-
T = TypeVar("T", pystac.Item, pystac.Asset)
32+
T = TypeVar("T", pystac.Item, pystac.Asset, item_assets.AssetDefinition)
3333

3434
SCHEMA_URI: str = "https://stac-extensions.github.io/eo/v1.1.0/schema.json"
3535
SCHEMA_URIS: List[str] = [
@@ -411,8 +411,11 @@ def ext(cls, obj: T, add_if_missing: bool = False) -> EOExtension[T]:
411411
cls.ensure_has_extension(obj, add_if_missing)
412412
return cast(EOExtension[T], ItemEOExtension(obj))
413413
elif isinstance(obj, pystac.Asset):
414-
cls.validate_owner_has_extension(obj, add_if_missing)
414+
cls.ensure_owner_has_extension(obj, add_if_missing)
415415
return cast(EOExtension[T], AssetEOExtension(obj))
416+
elif isinstance(obj, item_assets.AssetDefinition):
417+
cls.ensure_owner_has_extension(obj, add_if_missing)
418+
return cast(EOExtension[T], ItemAssetsEOExtension(obj))
416419
else:
417420
raise pystac.ExtensionTypeError(cls._ext_error_message(obj))
418421

@@ -537,6 +540,25 @@ def __repr__(self) -> str:
537540
return "<AssetEOExtension Asset href={}>".format(self.asset_href)
538541

539542

543+
class ItemAssetsEOExtension(EOExtension[item_assets.AssetDefinition]):
544+
properties: Dict[str, Any]
545+
asset_defn: item_assets.AssetDefinition
546+
547+
def _get_bands(self) -> Optional[List[Band]]:
548+
if BANDS_PROP not in self.properties:
549+
return None
550+
return list(
551+
map(
552+
lambda band: Band(band),
553+
cast(List[Dict[str, Any]], self.properties.get(BANDS_PROP)),
554+
)
555+
)
556+
557+
def __init__(self, item_asset: item_assets.AssetDefinition):
558+
self.asset_defn = item_asset
559+
self.properties = item_asset.properties
560+
561+
540562
class SummariesEOExtension(SummariesExtension):
541563
"""A concrete implementation of :class:`~SummariesExtension` that extends
542564
the ``summaries`` field of a :class:`~pystac.Collection` to include properties

pystac/extensions/ext.py

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from dataclasses import dataclass
2-
from typing import TYPE_CHECKING, Any, Dict, Generic, Literal, TypeVar, cast
2+
from typing import Any, Dict, Generic, Literal, TypeVar, cast
33

44
import pystac
55
from pystac.extensions.classification import ClassificationExtension
@@ -22,8 +22,7 @@
2222
from pystac.extensions.view import ViewExtension
2323
from pystac.extensions.xarray_assets import XarrayAssetsExtension
2424

25-
if TYPE_CHECKING:
26-
T = TypeVar("T", pystac.Asset, AssetDefinition)
25+
T = TypeVar("T", pystac.Asset, AssetDefinition)
2726

2827
EXTENSION_NAMES = Literal[
2928
"classification",
@@ -192,9 +191,8 @@ def xarray(self) -> XarrayAssetsExtension[pystac.Item]:
192191
return XarrayAssetsExtension.ext(self.stac_object)
193192

194193

195-
@dataclass
196-
class AssetExt(Generic[T]):
197-
stac_object: pystac.Asset
194+
class _AssetExt(Generic[T]):
195+
stac_object: T
198196

199197
def has(self, name: EXTENSION_NAMES) -> bool:
200198
if self.stac_object.owner is None:
@@ -237,10 +235,6 @@ def cube(self) -> DatacubeExtension[T]:
237235
def eo(self) -> EOExtension[T]:
238236
return EOExtension.ext(self.stac_object)
239237

240-
@property
241-
def file(self) -> FileExtension:
242-
return FileExtension.ext(self.stac_object)
243-
244238
@property
245239
def pc(self) -> PointcloudExtension[T]:
246240
return PointcloudExtension.ext(self.stac_object)
@@ -269,14 +263,28 @@ def storage(self) -> StorageExtension[T]:
269263
def table(self) -> TableExtension[T]:
270264
return TableExtension.ext(self.stac_object)
271265

272-
@property
273-
def timestamps(self) -> TimestampsExtension[T]:
274-
return TimestampsExtension.ext(self.stac_object)
275-
276266
@property
277267
def view(self) -> ViewExtension[T]:
278268
return ViewExtension.ext(self.stac_object)
279269

270+
271+
@dataclass
272+
class AssetExt(_AssetExt[pystac.Asset]):
273+
stac_object: pystac.Asset
274+
275+
@property
276+
def file(self) -> FileExtension:
277+
return FileExtension.ext(self.stac_object)
278+
280279
@property
281-
def xarray(self) -> XarrayAssetsExtension[T]:
280+
def timestamps(self) -> TimestampsExtension[pystac.Asset]:
281+
return TimestampsExtension.ext(self.stac_object)
282+
283+
@property
284+
def xarray(self) -> XarrayAssetsExtension[pystac.Asset]:
282285
return XarrayAssetsExtension.ext(self.stac_object)
286+
287+
288+
@dataclass
289+
class ItemAssetExt(_AssetExt[AssetDefinition]):
290+
stac_object: AssetDefinition

pystac/extensions/file.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ def ext(cls, obj: pystac.Asset, add_if_missing: bool = False) -> FileExtension:
226226
This extension can be applied to instances of :class:`~pystac.Asset`.
227227
"""
228228
if isinstance(obj, pystac.Asset):
229-
cls.validate_owner_has_extension(obj, add_if_missing)
229+
cls.ensure_owner_has_extension(obj, add_if_missing)
230230
return cls(obj)
231231
else:
232232
raise pystac.ExtensionTypeError(cls._ext_error_message(obj))

pystac/extensions/item_assets.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from pystac.utils import get_required
1313

1414
if TYPE_CHECKING:
15-
from pystac.extensions.ext import AssetExt
15+
from pystac.extensions.ext import ItemAssetExt
1616

1717
SCHEMA_URI = "https://stac-extensions.github.io/item-assets/v1.0.0/schema.json"
1818

@@ -208,10 +208,10 @@ def create_asset(self, href: str) -> pystac.Asset:
208208
)
209209

210210
@property
211-
def ext(self) -> AssetExt:
212-
from pystac.extensions.ext import AssetExt
211+
def ext(self) -> ItemAssetExt:
212+
from pystac.extensions.ext import ItemAssetExt
213213

214-
return AssetExt(stac_object=self)
214+
return ItemAssetExt(stac_object=self)
215215

216216

217217
class ItemAssetsExtension(ExtensionManagementMixin[pystac.Collection]):

pystac/extensions/pointcloud.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
)
1717

1818
import pystac
19+
from pystac.extensions import item_assets
1920
from pystac.extensions.base import (
2021
ExtensionManagementMixin,
2122
PropertiesExtension,
@@ -25,7 +26,7 @@
2526
from pystac.summaries import RangeSummary
2627
from pystac.utils import StringEnum, get_required, map_opt
2728

28-
T = TypeVar("T", pystac.Item, pystac.Asset)
29+
T = TypeVar("T", pystac.Item, pystac.Asset, item_assets.AssetDefinition)
2930

3031
SCHEMA_URI: str = "https://stac-extensions.github.io/pointcloud/v1.0.0/schema.json"
3132
PREFIX: str = "pc:"
@@ -468,8 +469,11 @@ def ext(cls, obj: T, add_if_missing: bool = False) -> PointcloudExtension[T]:
468469
raise pystac.ExtensionTypeError(
469470
"Pointcloud extension does not apply to Collection Assets."
470471
)
471-
cls.validate_owner_has_extension(obj, add_if_missing)
472+
cls.ensure_owner_has_extension(obj, add_if_missing)
472473
return cast(PointcloudExtension[T], AssetPointcloudExtension(obj))
474+
elif isinstance(obj, item_assets.AssetDefinition):
475+
cls.ensure_owner_has_extension(obj, add_if_missing)
476+
return cast(PointcloudExtension[T], ItemAssetsPointcloudExtension(obj))
473477
else:
474478
raise pystac.ExtensionTypeError(cls._ext_error_message(obj))
475479

@@ -533,6 +537,15 @@ def __repr__(self) -> str:
533537
return f"<AssetPointcloudExtension Asset {self.repr_id}>"
534538

535539

540+
class ItemAssetsPointcloudExtension(PointcloudExtension[item_assets.AssetDefinition]):
541+
properties: Dict[str, Any]
542+
asset_defn: item_assets.AssetDefinition
543+
544+
def __init__(self, item_asset: item_assets.AssetDefinition):
545+
self.asset_defn = item_asset
546+
self.properties = item_asset.properties
547+
548+
536549
class SummariesPointcloudExtension(SummariesExtension):
537550
"""A concrete implementation of :class:`~SummariesExtension` that extends
538551
the ``summaries`` field of a :class:`~pystac.Collection` to include properties

pystac/extensions/projection.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,15 @@
1818
)
1919

2020
import pystac
21+
from pystac.extensions import item_assets
2122
from pystac.extensions.base import (
2223
ExtensionManagementMixin,
2324
PropertiesExtension,
2425
SummariesExtension,
2526
)
2627
from pystac.extensions.hooks import ExtensionHooks
2728

28-
T = TypeVar("T", pystac.Item, pystac.Asset)
29+
T = TypeVar("T", pystac.Item, pystac.Asset, item_assets.AssetDefinition)
2930

3031
SCHEMA_URI: str = "https://stac-extensions.github.io/projection/v1.1.0/schema.json"
3132
SCHEMA_URIS: List[str] = [
@@ -301,8 +302,11 @@ def ext(cls, obj: T, add_if_missing: bool = False) -> ProjectionExtension[T]:
301302
cls.ensure_has_extension(obj, add_if_missing)
302303
return cast(ProjectionExtension[T], ItemProjectionExtension(obj))
303304
elif isinstance(obj, pystac.Asset):
304-
cls.validate_owner_has_extension(obj, add_if_missing)
305+
cls.ensure_owner_has_extension(obj, add_if_missing)
305306
return cast(ProjectionExtension[T], AssetProjectionExtension(obj))
307+
elif isinstance(obj, item_assets.AssetDefinition):
308+
cls.ensure_owner_has_extension(obj, add_if_missing)
309+
return cast(ProjectionExtension[T], ItemAssetsProjectionExtension(obj))
306310
else:
307311
raise pystac.ExtensionTypeError(cls._ext_error_message(obj))
308312

@@ -367,6 +371,15 @@ def __repr__(self) -> str:
367371
return "<AssetProjectionExtension Asset href={}>".format(self.asset_href)
368372

369373

374+
class ItemAssetsProjectionExtension(ProjectionExtension[item_assets.AssetDefinition]):
375+
properties: Dict[str, Any]
376+
asset_defn: item_assets.AssetDefinition
377+
378+
def __init__(self, item_asset: item_assets.AssetDefinition):
379+
self.asset_defn = item_asset
380+
self.properties = item_asset.properties
381+
382+
370383
class SummariesProjectionExtension(SummariesExtension):
371384
"""A concrete implementation of :class:`~SummariesExtension` that extends
372385
the ``summaries`` field of a :class:`~pystac.Collection` to include properties

0 commit comments

Comments
 (0)