Skip to content

Commit a729cd2

Browse files
author
Jon Duckworth
authored
Merge pull request #450 from duckontheweb/change/gh-370-ext-exception
Raise exception when extending object that does not have schema URI
2 parents 7f8e7aa + 5f2296f commit a729cd2

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+1316
-76
lines changed

.coveragerc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[report]
2-
fail_under = 90
2+
fail_under = 91
33

44
[run]
55
source = pystac

CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
STAC Items ([#430](https://github.com/stac-utils/pystac/pull/430))
1313
- Support for Python 3.9 ([#420](https://github.com/stac-utils/pystac/pull/420))
1414
- Migration for pre-1.0.0-rc.1 Stats Objects (renamed to Range Objects in 1.0.0-rc.3) ([#447](https://github.com/stac-utils/pystac/pull/447))
15+
- Attempting to extend a `STACObject` that does not contain the extension's schema URI in
16+
`stac_extensions` raises new `ExtensionNotImplementedError` ([#450](https://github.com/stac-utils/pystac/pull/450))
1517

1618
### Changed
1719

@@ -20,6 +22,9 @@
2022
`StacIO.read_text` ([#433](https://github.com/stac-utils/pystac/pull/433))
2123
- `FileExtension` updated to work with File Info Extension v2.0.0 ([#442](https://github.com/stac-utils/pystac/pull/442))
2224
- `FileExtension` only operates on `pystac.Asset` instances ([#442](https://github.com/stac-utils/pystac/pull/442))
25+
- `*Extension.ext` methods now have an optional `add_if_missing` argument, which will
26+
add the extension schema URI to the object's `stac_extensions` list if it is not
27+
present ([#450](https://github.com/stac-utils/pystac/pull/450))
2328

2429
### Fixed
2530

@@ -377,4 +382,3 @@ Initial release.
377382
[v0.3.2]: <https://github.com/stac-utils/pystac/compare/v0.3.1..v0.3.2>
378383
[v0.3.1]: <https://github.com/stac-utils/pystac/compare/v0.3.0..v0.3.1>
379384
[v0.3.0]: <https://github.com/stac-utils/pystac/tree/v0.3.0>
380-

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

docs/contributing.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ example, to format all the Python code, run ``pre-commit run --all-files black``
6262

6363
You can also install a Git pre-commit hook which will run the relevant linters and
6464
formatters on any staged code when committing. This will be much faster than running on
65-
all files, which is usually[#]_ only required when changing the pre-commit version or
65+
all files, which is usually [#]_ only required when changing the pre-commit version or
6666
configuration. Once installed you can bypass this check by adding the ``--no-verify``
6767
flag to Git commit commands, as in ``git commit --no-verify``.
6868

pystac/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
STACError,
88
STACTypeError,
99
ExtensionAlreadyExistsError,
10+
ExtensionNotImplemented,
1011
ExtensionTypeError,
1112
RequiredPropertyMissing,
1213
STACValidationError,

pystac/errors.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ class ExtensionAlreadyExistsError(Exception):
3535
pass
3636

3737

38+
class ExtensionNotImplemented(Exception):
39+
"""Attempted to extend a STAC object that does not implement the given
40+
extension."""
41+
42+
3843
class RequiredPropertyMissing(Exception):
3944
"""This error is raised when a required value was expected
4045
to be there but was missing or None. This will happen, for example,

pystac/extensions/base.py

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from abc import ABC, abstractmethod
22
from typing import Generic, Iterable, List, Optional, Dict, Any, Type, TypeVar, Union
33

4-
from pystac import Collection, RangeSummary, STACObject, Summaries
4+
import pystac
55

66

77
class SummariesExtension:
@@ -12,16 +12,16 @@ class SummariesExtension:
1212
extension-specific class that inherits from this class and instantiate that. See
1313
:class:`~pystac.extensions.eo.SummariesEOExtension` for an example."""
1414

15-
summaries: Summaries
15+
summaries: pystac.Summaries
1616
"""The summaries for the :class:`~pystac.Collection` being extended."""
1717

18-
def __init__(self, collection: Collection) -> None:
18+
def __init__(self, collection: pystac.Collection) -> None:
1919
self.summaries = collection.summaries
2020

2121
def _set_summary(
2222
self,
2323
prop_key: str,
24-
v: Optional[Union[List[Any], RangeSummary[Any], Dict[str, Any]]],
24+
v: Optional[Union[List[Any], pystac.RangeSummary[Any], Dict[str, Any]]],
2525
) -> None:
2626
if v is None:
2727
self.summaries.remove(prop_key)
@@ -77,7 +77,7 @@ def _set_property(
7777
self.properties[prop_name] = v
7878

7979

80-
S = TypeVar("S", bound=STACObject)
80+
S = TypeVar("S", bound=pystac.STACObject)
8181

8282

8383
class ExtensionManagementMixin(Generic[S], ABC):
@@ -124,3 +124,17 @@ def has_extension(cls, obj: S) -> bool:
124124
obj.stac_extensions is not None
125125
and cls.get_schema_uri() in obj.stac_extensions
126126
)
127+
128+
@classmethod
129+
def validate_has_extension(cls, obj: Union[S, pystac.Asset]) -> None:
130+
"""Given a :class:`~pystac.STACObject` or :class:`pystac.Asset` instance, checks
131+
if the object (or its owner in the case of an Asset) has this extension's schema
132+
URI in it's :attr:`~pystac.STACObject.stac_extensions` list."""
133+
extensible = obj.owner if isinstance(obj, pystac.Asset) else obj
134+
if (
135+
extensible is not None
136+
and cls.get_schema_uri() not in extensible.stac_extensions
137+
):
138+
raise pystac.ExtensionNotImplemented(
139+
f"Could not find extension schema URI {cls.get_schema_uri()} in object."
140+
)

pystac/extensions/datacube.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -337,13 +337,22 @@ def dimensions(self, v: Dict[str, Dimension]) -> None:
337337
def get_schema_uri(cls) -> str:
338338
return SCHEMA_URI
339339

340-
@staticmethod
341-
def ext(obj: T) -> "DatacubeExtension[T]":
340+
@classmethod
341+
def ext(cls, obj: T, add_if_missing: bool = False) -> "DatacubeExtension[T]":
342342
if isinstance(obj, pystac.Collection):
343+
if add_if_missing:
344+
cls.add_to(obj)
345+
cls.validate_has_extension(obj)
343346
return cast(DatacubeExtension[T], CollectionDatacubeExtension(obj))
344347
if isinstance(obj, pystac.Item):
348+
if add_if_missing:
349+
cls.add_to(obj)
350+
cls.validate_has_extension(obj)
345351
return cast(DatacubeExtension[T], ItemDatacubeExtension(obj))
346352
elif isinstance(obj, pystac.Asset):
353+
if add_if_missing and obj.owner is not None:
354+
cls.add_to(obj.owner)
355+
cls.validate_has_extension(obj)
347356
return cast(DatacubeExtension[T], AssetDatacubeExtension(obj))
348357
else:
349358
raise pystac.ExtensionTypeError(

pystac/extensions/eo.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -346,8 +346,8 @@ def cloud_cover(self, v: Optional[float]) -> None:
346346
def get_schema_uri(cls) -> str:
347347
return SCHEMA_URI
348348

349-
@staticmethod
350-
def ext(obj: T) -> "EOExtension[T]":
349+
@classmethod
350+
def ext(cls, obj: T, add_if_missing: bool = False) -> "EOExtension[T]":
351351
"""Extends the given STAC Object with properties from the :stac-ext:`Electro-Optical
352352
Extension <eo>`.
353353
@@ -359,8 +359,14 @@ def ext(obj: T) -> "EOExtension[T]":
359359
pystac.ExtensionTypeError : If an invalid object type is passed.
360360
"""
361361
if isinstance(obj, pystac.Item):
362+
if add_if_missing:
363+
cls.add_to(obj)
364+
cls.validate_has_extension(obj)
362365
return cast(EOExtension[T], ItemEOExtension(obj))
363366
elif isinstance(obj, pystac.Asset):
367+
if add_if_missing and isinstance(obj.owner, pystac.Item):
368+
cls.add_to(obj.owner)
369+
cls.validate_has_extension(obj)
364370
return cast(EOExtension[T], AssetEOExtension(obj))
365371
else:
366372
raise pystac.ExtensionTypeError(

pystac/extensions/file.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,13 +193,21 @@ def get_schema_uri(cls) -> str:
193193
return SCHEMA_URI
194194

195195
@classmethod
196-
def ext(cls, obj: pystac.Asset) -> "FileExtension":
196+
def ext(cls, obj: pystac.Asset, add_if_missing: bool = False) -> "FileExtension":
197197
"""Extends the given STAC Object with properties from the :stac-ext:`File Info
198198
Extension <file>`.
199199
200200
This extension can be applied to instances of :class:`~pystac.Asset`.
201201
"""
202-
return cls(obj)
202+
if isinstance(obj, pystac.Asset):
203+
if add_if_missing and isinstance(obj.owner, pystac.Item):
204+
cls.add_to(obj.owner)
205+
cls.validate_has_extension(obj)
206+
return cls(obj)
207+
else:
208+
raise pystac.ExtensionTypeError(
209+
f"File Info extension does not apply to type {type(obj)}"
210+
)
203211

204212

205213
class FileExtensionHooks(ExtensionHooks):

0 commit comments

Comments
 (0)