Skip to content

Commit

Permalink
Update version extension (#1262)
Browse files Browse the repository at this point in the history
* refactor: normalize import style

#1259

* refactor(tests): modernize version extension tests

- #993
- #948

* feat: add experimental to version ext

* feat: version is optional in version extension

* refactor: test import naming, ext

* feat: catalog extensions

* refactor: import style

* feat: add history media type

* feat: separate BaseVersionExtension

* feat: impl migration

* doc: fixups

* chore: update changelog

* fix(tests): mark some extra vcrs

* fix: pop_if_none on deprecated
  • Loading branch information
gadomski authored Oct 16, 2023
1 parent 59d1868 commit 7bf4f6e
Show file tree
Hide file tree
Showing 40 changed files with 2,302 additions and 2,994 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

- `validate_all` now accepts a `STACObject` (in addition to accepting a dict, which is now deprecated), but prohibits supplying a value for `href`, which must be supplied _only_ when supplying an object as a dict. Once `validate_all` removes support for an object as a dict, the `href` parameter will also be removed. ([#1246](https://github.com/stac-utils/pystac/pull/1246))
- Report `href` when schema url resolution fails ([#1263](https://github.com/stac-utils/pystac/pull/1263))
- Version extension updated to v1.2.0 ([#1262](https://github.com/stac-utils/pystac/pull/1262))

### Fixed

Expand Down
13 changes: 13 additions & 0 deletions pystac/catalog.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
if TYPE_CHECKING:
from pystac.asset import Asset
from pystac.collection import Collection
from pystac.extensions.ext import CatalogExt
from pystac.item import Item

C = TypeVar("C", bound="Catalog")
Expand Down Expand Up @@ -1245,3 +1246,15 @@ def from_file(cls: type[C], href: HREF, stac_io: pystac.StacIO | None = None) ->
@classmethod
def matches_object_type(cls, d: dict[str, Any]) -> bool:
return identify_stac_object_type(d) == STACObjectType.CATALOG

@property
def ext(self) -> CatalogExt:
"""Accessor for extension classes on this catalog
Example::
print(collection.ext.version)
"""
from pystac.extensions.ext import CatalogExt

return CatalogExt(stac_object=self)
77 changes: 43 additions & 34 deletions pystac/extensions/ext.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from dataclasses import dataclass
from typing import Any, Generic, Literal, TypeVar, cast

import pystac
from pystac import Asset, Catalog, Collection, Item, STACError
from pystac.extensions.classification import ClassificationExtension
from pystac.extensions.datacube import DatacubeExtension
from pystac.extensions.eo import EOExtension
Expand All @@ -18,11 +18,11 @@
from pystac.extensions.storage import StorageExtension
from pystac.extensions.table import TableExtension
from pystac.extensions.timestamps import TimestampsExtension
from pystac.extensions.version import VersionExtension
from pystac.extensions.version import BaseVersionExtension, VersionExtension
from pystac.extensions.view import ViewExtension
from pystac.extensions.xarray_assets import XarrayAssetsExtension

T = TypeVar("T", pystac.Asset, AssetDefinition)
T = TypeVar("T", Asset, AssetDefinition)

EXTENSION_NAMES = Literal[
"classification",
Expand Down Expand Up @@ -80,8 +80,8 @@ def _get_class_by_name(name: str) -> Any:


@dataclass
class CollectionExt:
stac_object: pystac.Collection
class CatalogExt:
stac_object: Catalog

def has(self, name: EXTENSION_NAMES) -> bool:
return cast(bool, _get_class_by_name(name).has_extension(self.stac_object))
Expand All @@ -93,33 +93,38 @@ def remove(self, name: EXTENSION_NAMES) -> None:
_get_class_by_name(name).remove_from(self.stac_object)

@property
def cube(self) -> DatacubeExtension[pystac.Collection]:
def version(self) -> VersionExtension[Catalog]:
return VersionExtension.ext(self.stac_object)


@dataclass
class CollectionExt(CatalogExt):
stac_object: Collection

@property
def cube(self) -> DatacubeExtension[Collection]:
return DatacubeExtension.ext(self.stac_object)

@property
def item_assets(self) -> dict[str, AssetDefinition]:
return ItemAssetsExtension.ext(self.stac_object).item_assets

@property
def sci(self) -> ScientificExtension[pystac.Collection]:
def sci(self) -> ScientificExtension[Collection]:
return ScientificExtension.ext(self.stac_object)

@property
def table(self) -> TableExtension[pystac.Collection]:
def table(self) -> TableExtension[Collection]:
return TableExtension.ext(self.stac_object)

@property
def version(self) -> VersionExtension[pystac.Collection]:
return VersionExtension.ext(self.stac_object)

@property
def xarray(self) -> XarrayAssetsExtension[pystac.Collection]:
def xarray(self) -> XarrayAssetsExtension[Collection]:
return XarrayAssetsExtension.ext(self.stac_object)


@dataclass
class ItemExt:
stac_object: pystac.Item
stac_object: Item

def has(self, name: EXTENSION_NAMES) -> bool:
return cast(bool, _get_class_by_name(name).has_extension(self.stac_object))
Expand All @@ -131,15 +136,15 @@ def remove(self, name: EXTENSION_NAMES) -> None:
_get_class_by_name(name).remove_from(self.stac_object)

@property
def classification(self) -> ClassificationExtension[pystac.Item]:
def classification(self) -> ClassificationExtension[Item]:
return ClassificationExtension.ext(self.stac_object)

@property
def cube(self) -> DatacubeExtension[pystac.Item]:
def cube(self) -> DatacubeExtension[Item]:
return DatacubeExtension.ext(self.stac_object)

@property
def eo(self) -> EOExtension[pystac.Item]:
def eo(self) -> EOExtension[Item]:
return EOExtension.ext(self.stac_object)

@property
Expand All @@ -151,43 +156,43 @@ def mgrs(self) -> MgrsExtension:
return MgrsExtension.ext(self.stac_object)

@property
def pc(self) -> PointcloudExtension[pystac.Item]:
def pc(self) -> PointcloudExtension[Item]:
return PointcloudExtension.ext(self.stac_object)

@property
def proj(self) -> ProjectionExtension[pystac.Item]:
def proj(self) -> ProjectionExtension[Item]:
return ProjectionExtension.ext(self.stac_object)

@property
def sar(self) -> SarExtension[pystac.Item]:
def sar(self) -> SarExtension[Item]:
return SarExtension.ext(self.stac_object)

@property
def sat(self) -> SatExtension[pystac.Item]:
def sat(self) -> SatExtension[Item]:
return SatExtension.ext(self.stac_object)

@property
def storage(self) -> StorageExtension[pystac.Item]:
def storage(self) -> StorageExtension[Item]:
return StorageExtension.ext(self.stac_object)

@property
def table(self) -> TableExtension[pystac.Item]:
def table(self) -> TableExtension[Item]:
return TableExtension.ext(self.stac_object)

@property
def timestamps(self) -> TimestampsExtension[pystac.Item]:
def timestamps(self) -> TimestampsExtension[Item]:
return TimestampsExtension.ext(self.stac_object)

@property
def version(self) -> VersionExtension[pystac.Item]:
def version(self) -> VersionExtension[Item]:
return VersionExtension.ext(self.stac_object)

@property
def view(self) -> ViewExtension[pystac.Item]:
def view(self) -> ViewExtension[Item]:
return ViewExtension.ext(self.stac_object)

@property
def xarray(self) -> XarrayAssetsExtension[pystac.Item]:
def xarray(self) -> XarrayAssetsExtension[Item]:
return XarrayAssetsExtension.ext(self.stac_object)


Expand All @@ -196,7 +201,7 @@ class _AssetExt(Generic[T]):

def has(self, name: EXTENSION_NAMES) -> bool:
if self.stac_object.owner is None:
raise pystac.STACError(
raise STACError(
f"Attempted to add extension='{name}' for an Asset with no owner. "
"Use Asset.set_owner and then try to add the extension again."
)
Expand All @@ -207,7 +212,7 @@ def has(self, name: EXTENSION_NAMES) -> bool:

def add(self, name: EXTENSION_NAMES) -> None:
if self.stac_object.owner is None:
raise pystac.STACError(
raise STACError(
f"Attempted to add extension='{name}' for an Asset with no owner. "
"Use Asset.set_owner and then try to add the extension again."
)
Expand All @@ -216,7 +221,7 @@ def add(self, name: EXTENSION_NAMES) -> None:

def remove(self, name: EXTENSION_NAMES) -> None:
if self.stac_object.owner is None:
raise pystac.STACError(
raise STACError(
f"Attempted to remove extension='{name}' for an Asset with no owner. "
"Use Asset.set_owner and then try to remove the extension again."
)
Expand Down Expand Up @@ -263,25 +268,29 @@ def storage(self) -> StorageExtension[T]:
def table(self) -> TableExtension[T]:
return TableExtension.ext(self.stac_object)

@property
def version(self) -> BaseVersionExtension[T]:
return BaseVersionExtension.ext(self.stac_object)

@property
def view(self) -> ViewExtension[T]:
return ViewExtension.ext(self.stac_object)


@dataclass
class AssetExt(_AssetExt[pystac.Asset]):
stac_object: pystac.Asset
class AssetExt(_AssetExt[Asset]):
stac_object: Asset

@property
def file(self) -> FileExtension:
return FileExtension.ext(self.stac_object)

@property
def timestamps(self) -> TimestampsExtension[pystac.Asset]:
def timestamps(self) -> TimestampsExtension[Asset]:
return TimestampsExtension.ext(self.stac_object)

@property
def xarray(self) -> XarrayAssetsExtension[pystac.Asset]:
def xarray(self) -> XarrayAssetsExtension[Asset]:
return XarrayAssetsExtension.ext(self.stac_object)


Expand Down
Loading

0 comments on commit 7bf4f6e

Please sign in to comment.