Skip to content

Commit cfb7a2a

Browse files
committed
Add missing Sat Extension fields
1 parent 3fead31 commit cfb7a2a

File tree

2 files changed

+99
-13
lines changed

2 files changed

+99
-13
lines changed

pystac/extensions/sat.py

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

66
import enum
7+
from datetime import datetime as Datetime
78
from typing import Dict, Any, Generic, Iterable, Optional, Set, TypeVar, cast
89

910
import pystac
@@ -12,15 +13,20 @@
1213
PropertiesExtension,
1314
)
1415
from pystac.extensions.hooks import ExtensionHooks
15-
from pystac.utils import map_opt
16+
from pystac.utils import str_to_datetime, datetime_to_str, map_opt
1617

1718
T = TypeVar("T", pystac.Item, pystac.Asset)
1819

1920
SCHEMA_URI = "https://stac-extensions.github.io/sat/v1.0.0/schema.json"
2021

2122
PREFIX: str = "sat:"
22-
ORBIT_STATE: str = PREFIX + "orbit_state"
23-
RELATIVE_ORBIT: str = PREFIX + "relative_orbit"
23+
PLATFORM_INTERNATIONAL_DESIGNATOR_PROP: str = (
24+
PREFIX + "platform_international_designator"
25+
)
26+
ABSOLUTE_ORBIT_PROP: str = PREFIX + "absolute_orbit"
27+
ORBIT_STATE_PROP: str = PREFIX + "orbit_state"
28+
RELATIVE_ORBIT_PROP: str = PREFIX + "relative_orbit"
29+
ANX_DATETIME_PROP: str = PREFIX + "anx_datetime"
2430

2531

2632
class OrbitState(str, enum.Enum):
@@ -51,6 +57,9 @@ def apply(
5157
self,
5258
orbit_state: Optional[OrbitState] = None,
5359
relative_orbit: Optional[int] = None,
60+
absolute_orbit: Optional[int] = None,
61+
platform_international_designator: Optional[str] = None,
62+
anx_datetime: Optional[Datetime] = None,
5463
) -> None:
5564
"""Applies ext extension properties to the extended :class:`~pystac.Item` or
5665
class:`~pystac.Asset`.
@@ -66,26 +75,58 @@ def apply(
6675
the time of acquisition.
6776
"""
6877

78+
self.platform_international_designator = platform_international_designator
6979
self.orbit_state = orbit_state
80+
self.absolute_orbit = absolute_orbit
7081
self.relative_orbit = relative_orbit
82+
self.anx_datetime = anx_datetime
83+
84+
@property
85+
def platform_international_designator(self) -> Optional[str]:
86+
"""Gets or sets the International Designator, also known as COSPAR ID, and
87+
NSSDCA ID."""
88+
return self._get_property(PLATFORM_INTERNATIONAL_DESIGNATOR_PROP, str)
89+
90+
@platform_international_designator.setter
91+
def platform_international_designator(self, v: Optional[str]) -> None:
92+
self._set_property(PLATFORM_INTERNATIONAL_DESIGNATOR_PROP, v)
7193

7294
@property
7395
def orbit_state(self) -> Optional[OrbitState]:
7496
"""Get or sets an orbit state of the object."""
75-
return map_opt(lambda x: OrbitState(x), self._get_property(ORBIT_STATE, str))
97+
return map_opt(
98+
lambda x: OrbitState(x), self._get_property(ORBIT_STATE_PROP, str)
99+
)
76100

77101
@orbit_state.setter
78102
def orbit_state(self, v: Optional[OrbitState]) -> None:
79-
self._set_property(ORBIT_STATE, map_opt(lambda x: x.value, v))
103+
self._set_property(ORBIT_STATE_PROP, map_opt(lambda x: x.value, v))
104+
105+
@property
106+
def absolute_orbit(self) -> Optional[int]:
107+
"""Get or sets a absolute orbit number of the item."""
108+
return self._get_property(ABSOLUTE_ORBIT_PROP, int)
109+
110+
@absolute_orbit.setter
111+
def absolute_orbit(self, v: Optional[int]) -> None:
112+
self._set_property(ABSOLUTE_ORBIT_PROP, v)
80113

81114
@property
82115
def relative_orbit(self) -> Optional[int]:
83116
"""Get or sets a relative orbit number of the item."""
84-
return self._get_property(RELATIVE_ORBIT, int)
117+
return self._get_property(RELATIVE_ORBIT_PROP, int)
85118

86119
@relative_orbit.setter
87120
def relative_orbit(self, v: Optional[int]) -> None:
88-
self._set_property(RELATIVE_ORBIT, v)
121+
self._set_property(RELATIVE_ORBIT_PROP, v)
122+
123+
@property
124+
def anx_datetime(self) -> Optional[Datetime]:
125+
return map_opt(str_to_datetime, self._get_property(ANX_DATETIME_PROP, str))
126+
127+
@anx_datetime.setter
128+
def anx_datetime(self, v: Optional[Datetime]) -> None:
129+
self._set_property(ANX_DATETIME_PROP, map_opt(datetime_to_str, v))
89130

90131
@classmethod
91132
def get_schema_uri(cls) -> str:

tests/extensions/test_sat.py

Lines changed: 51 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import unittest
66

77
import pystac
8+
from pystac.utils import str_to_datetime
89
from pystac import ExtensionTypeError
910
from pystac.extensions import sat
1011
from pystac.extensions.sat import SatExtension
@@ -32,6 +33,21 @@ def setUp(self) -> None:
3233
def test_stac_extensions(self) -> None:
3334
self.assertTrue(SatExtension.has_extension(self.item))
3435

36+
def test_item_repr(self) -> None:
37+
sat_item_ext = SatExtension.ext(self.item)
38+
self.assertEqual(
39+
f"<ItemSatExtension Item id={self.item.id}>", sat_item_ext.__repr__()
40+
)
41+
42+
def test_asset_repr(self) -> None:
43+
item = pystac.Item.from_file(self.sentinel_example_uri)
44+
asset = item.assets["measurement_iw1_vh"]
45+
sat_asset_ext = SatExtension.ext(asset)
46+
47+
self.assertEqual(
48+
f"<AssetSatExtension Asset href={asset.href}>", sat_asset_ext.__repr__()
49+
)
50+
3551
def test_no_args_fails(self) -> None:
3652
SatExtension.ext(self.item).apply()
3753
with self.assertRaises(pystac.STACValidationError):
@@ -41,16 +57,45 @@ def test_orbit_state(self) -> None:
4157
orbit_state = sat.OrbitState.ASCENDING
4258
SatExtension.ext(self.item).apply(orbit_state)
4359
self.assertEqual(orbit_state, SatExtension.ext(self.item).orbit_state)
44-
self.assertNotIn(sat.RELATIVE_ORBIT, self.item.properties)
45-
self.assertFalse(SatExtension.ext(self.item).relative_orbit)
60+
self.assertNotIn(sat.RELATIVE_ORBIT_PROP, self.item.properties)
61+
self.assertIsNone(SatExtension.ext(self.item).relative_orbit)
4662
self.item.validate()
4763

4864
def test_relative_orbit(self) -> None:
4965
relative_orbit = 1234
5066
SatExtension.ext(self.item).apply(None, relative_orbit)
5167
self.assertEqual(relative_orbit, SatExtension.ext(self.item).relative_orbit)
52-
self.assertNotIn(sat.ORBIT_STATE, self.item.properties)
53-
self.assertFalse(SatExtension.ext(self.item).orbit_state)
68+
self.assertNotIn(sat.ORBIT_STATE_PROP, self.item.properties)
69+
self.assertIsNone(SatExtension.ext(self.item).orbit_state)
70+
self.item.validate()
71+
72+
def test_absolute_orbit(self) -> None:
73+
absolute_orbit = 1234
74+
SatExtension.ext(self.item).apply(absolute_orbit=absolute_orbit)
75+
self.assertEqual(absolute_orbit, SatExtension.ext(self.item).absolute_orbit)
76+
self.assertNotIn(sat.RELATIVE_ORBIT_PROP, self.item.properties)
77+
self.assertIsNone(SatExtension.ext(self.item).relative_orbit)
78+
self.item.validate()
79+
80+
def test_anx_datetime(self) -> None:
81+
anx_datetime = str_to_datetime("2020-01-01T00:00:00Z")
82+
SatExtension.ext(self.item).apply(anx_datetime=anx_datetime)
83+
self.assertEqual(anx_datetime, SatExtension.ext(self.item).anx_datetime)
84+
self.assertNotIn(sat.RELATIVE_ORBIT_PROP, self.item.properties)
85+
self.assertIsNone(SatExtension.ext(self.item).relative_orbit)
86+
self.item.validate()
87+
88+
def test_platform_international_designator(self) -> None:
89+
platform_international_designator = "2018-080A"
90+
SatExtension.ext(self.item).apply(
91+
platform_international_designator=platform_international_designator
92+
)
93+
self.assertEqual(
94+
platform_international_designator,
95+
SatExtension.ext(self.item).platform_international_designator,
96+
)
97+
self.assertNotIn(sat.ORBIT_STATE_PROP, self.item.properties)
98+
self.assertIsNone(SatExtension.ext(self.item).orbit_state)
5499
self.item.validate()
55100

56101
def test_relative_orbit_no_negative(self) -> None:
@@ -104,8 +149,8 @@ def test_to_from_dict(self) -> None:
104149
relative_orbit = 1002
105150
SatExtension.ext(self.item).apply(orbit_state, relative_orbit)
106151
d = self.item.to_dict()
107-
self.assertEqual(orbit_state.value, d["properties"][sat.ORBIT_STATE])
108-
self.assertEqual(relative_orbit, d["properties"][sat.RELATIVE_ORBIT])
152+
self.assertEqual(orbit_state.value, d["properties"][sat.ORBIT_STATE_PROP])
153+
self.assertEqual(relative_orbit, d["properties"][sat.RELATIVE_ORBIT_PROP])
109154

110155
item = pystac.Item.from_dict(d)
111156
self.assertEqual(orbit_state, SatExtension.ext(item).orbit_state)

0 commit comments

Comments
 (0)