Skip to content

Commit fc3be80

Browse files
committed
Add Sat Extension summaries
1 parent cfb7a2a commit fc3be80

File tree

2 files changed

+185
-3
lines changed

2 files changed

+185
-3
lines changed

pystac/extensions/sat.py

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,14 @@
55

66
import enum
77
from datetime import datetime as Datetime
8-
from typing import Dict, Any, Generic, Iterable, Optional, Set, TypeVar, cast
8+
from pystac.summaries import RangeSummary
9+
from typing import Dict, Any, List, Generic, Iterable, Optional, Set, TypeVar, cast
910

1011
import pystac
1112
from pystac.extensions.base import (
1213
ExtensionManagementMixin,
1314
PropertiesExtension,
15+
SummariesExtension,
1416
)
1517
from pystac.extensions.hooks import ExtensionHooks
1618
from pystac.utils import str_to_datetime, datetime_to_str, map_opt
@@ -159,6 +161,11 @@ def ext(cls, obj: T, add_if_missing: bool = False) -> "SatExtension[T]":
159161
f"Satellite extension does not apply to type '{type(obj).__name__}'"
160162
)
161163

164+
@staticmethod
165+
def summaries(obj: pystac.Collection) -> "SummariesSatExtension":
166+
"""Returns the extended summaries object for the given collection."""
167+
return SummariesSatExtension(obj)
168+
162169

163170
class ItemSatExtension(SatExtension[pystac.Item]):
164171
"""A concrete implementation of :class:`SatExtension` on an :class:`~pystac.Item`
@@ -214,6 +221,75 @@ def __repr__(self) -> str:
214221
return "<AssetSatExtension Asset href={}>".format(self.asset_href)
215222

216223

224+
class SummariesSatExtension(SummariesExtension):
225+
"""A concrete implementation of :class:`~SummariesExtension` that extends
226+
the ``summaries`` field of a :class:`~pystac.Collection` to include properties
227+
defined in the :stac-ext:`Satellite Extension <sat>`.
228+
"""
229+
230+
@property
231+
def platform_international_designator(self) -> Optional[List[str]]:
232+
"""Get or sets the summary of
233+
:attr:`SatExtension.platform_international_designator` values for this
234+
Collection.
235+
"""
236+
237+
return self.summaries.get_list(PLATFORM_INTERNATIONAL_DESIGNATOR_PROP)
238+
239+
@platform_international_designator.setter
240+
def platform_international_designator(self, v: Optional[List[str]]) -> None:
241+
self._set_summary(PLATFORM_INTERNATIONAL_DESIGNATOR_PROP, v)
242+
243+
@property
244+
def orbit_state(self) -> Optional[List[OrbitState]]:
245+
"""Get or sets the summary of :attr:`SatExtension.orbit_state` values
246+
for this Collection.
247+
"""
248+
249+
return self.summaries.get_list(ORBIT_STATE_PROP)
250+
251+
@orbit_state.setter
252+
def orbit_state(self, v: Optional[List[OrbitState]]) -> None:
253+
self._set_summary(ORBIT_STATE_PROP, v)
254+
255+
@property
256+
def absolute_orbit(self) -> Optional[RangeSummary[int]]:
257+
return self.summaries.get_range(ABSOLUTE_ORBIT_PROP)
258+
259+
@absolute_orbit.setter
260+
def absolute_orbit(self, v: Optional[RangeSummary[int]]) -> None:
261+
self._set_summary(ABSOLUTE_ORBIT_PROP, v)
262+
263+
@property
264+
def relative_orbit(self) -> Optional[RangeSummary[int]]:
265+
return self.summaries.get_range(RELATIVE_ORBIT_PROP)
266+
267+
@relative_orbit.setter
268+
def relative_orbit(self, v: Optional[RangeSummary[int]]) -> None:
269+
self._set_summary(RELATIVE_ORBIT_PROP, v)
270+
271+
@property
272+
def anx_datetime(self) -> Optional[RangeSummary[Datetime]]:
273+
return map_opt(
274+
lambda s: RangeSummary(
275+
str_to_datetime(s.minimum), str_to_datetime(s.maximum)
276+
),
277+
self.summaries.get_range(ANX_DATETIME_PROP),
278+
)
279+
280+
@anx_datetime.setter
281+
def anx_datetime(self, v: Optional[RangeSummary[Datetime]]) -> None:
282+
self._set_summary(
283+
ANX_DATETIME_PROP,
284+
map_opt(
285+
lambda s: RangeSummary(
286+
datetime_to_str(s.minimum), datetime_to_str(s.maximum)
287+
),
288+
v,
289+
),
290+
)
291+
292+
217293
class SatExtensionHooks(ExtensionHooks):
218294
schema_uri: str = SCHEMA_URI
219295
prev_extension_ids: Set[str] = set(["sat"])

tests/extensions/test_sat.py

Lines changed: 108 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
"""Tests for pystac.extensions.sat."""
22

33
import datetime
4+
from pystac.summaries import RangeSummary
45
from typing import Any, Dict
56
import unittest
67

78
import pystac
8-
from pystac.utils import str_to_datetime
9+
from pystac.utils import str_to_datetime, datetime_to_str
910
from pystac import ExtensionTypeError
1011
from pystac.extensions import sat
11-
from pystac.extensions.sat import SatExtension
12+
from pystac.extensions.sat import OrbitState, SatExtension
1213
from tests.utils import TestCases
1314

1415

@@ -216,3 +217,108 @@ def test_should_raise_exception_when_passing_invalid_extension_object(
216217
SatExtension.ext,
217218
object(),
218219
)
220+
221+
222+
class SatSummariesTest(unittest.TestCase):
223+
def setUp(self) -> None:
224+
self.maxDiff = None
225+
226+
self.collection = pystac.Collection.from_file(
227+
TestCases.get_path("data-files/collections/multi-extent.json")
228+
)
229+
230+
def test_platform_international_designation(self) -> None:
231+
summaries_ext = SatExtension.summaries(self.collection)
232+
platform_international_designator_list = ["2018-080A"]
233+
234+
summaries_ext.platform_international_designator = ["2018-080A"]
235+
236+
self.assertEqual(
237+
summaries_ext.platform_international_designator,
238+
platform_international_designator_list,
239+
)
240+
241+
summaries_dict = self.collection.to_dict()["summaries"]
242+
243+
self.assertEqual(
244+
summaries_dict["sat:platform_international_designator"],
245+
platform_international_designator_list,
246+
)
247+
248+
def test_orbit_state(self) -> None:
249+
summaries_ext = SatExtension.summaries(self.collection)
250+
orbit_state_list = [OrbitState.ASCENDING]
251+
252+
summaries_ext.orbit_state = orbit_state_list
253+
254+
self.assertEqual(
255+
summaries_ext.orbit_state,
256+
orbit_state_list,
257+
)
258+
259+
summaries_dict = self.collection.to_dict()["summaries"]
260+
261+
self.assertEqual(
262+
summaries_dict["sat:orbit_state"],
263+
orbit_state_list,
264+
)
265+
266+
def test_absolute_orbit(self) -> None:
267+
summaries_ext = SatExtension.summaries(self.collection)
268+
absolute_orbit_range = RangeSummary(2000, 3000)
269+
270+
summaries_ext.absolute_orbit = absolute_orbit_range
271+
272+
self.assertEqual(
273+
summaries_ext.absolute_orbit,
274+
absolute_orbit_range,
275+
)
276+
277+
summaries_dict = self.collection.to_dict()["summaries"]
278+
279+
self.assertEqual(
280+
summaries_dict["sat:absolute_orbit"],
281+
absolute_orbit_range.to_dict(),
282+
)
283+
284+
def test_relative_orbit(self) -> None:
285+
summaries_ext = SatExtension.summaries(self.collection)
286+
relative_orbit_range = RangeSummary(50, 100)
287+
288+
summaries_ext.relative_orbit = relative_orbit_range
289+
290+
self.assertEqual(
291+
summaries_ext.relative_orbit,
292+
relative_orbit_range,
293+
)
294+
295+
summaries_dict = self.collection.to_dict()["summaries"]
296+
297+
self.assertEqual(
298+
summaries_dict["sat:relative_orbit"],
299+
relative_orbit_range.to_dict(),
300+
)
301+
302+
def test_anx_datetime(self) -> None:
303+
summaries_ext = SatExtension.summaries(self.collection)
304+
anx_datetime_range = RangeSummary(
305+
str_to_datetime("2020-01-01T00:00:00.000Z"),
306+
str_to_datetime("2020-01-02T00:00:00.000Z"),
307+
)
308+
309+
summaries_ext.anx_datetime = anx_datetime_range
310+
311+
self.assertEqual(
312+
summaries_ext.anx_datetime,
313+
anx_datetime_range,
314+
)
315+
316+
summaries_dict = self.collection.to_dict()["summaries"]
317+
318+
self.assertDictEqual(
319+
summaries_dict["sat:anx_datetime"],
320+
{
321+
"minimum": datetime_to_str(anx_datetime_range.minimum),
322+
"maximum": datetime_to_str(anx_datetime_range.maximum),
323+
},
324+
)

0 commit comments

Comments
 (0)