4
4
"""
5
5
6
6
import enum
7
- from typing import Generic , Optional , Set , TypeVar , cast
7
+ from datetime import datetime as Datetime
8
+ from pystac .summaries import RangeSummary
9
+ from typing import Dict , Any , List , Generic , Iterable , Optional , Set , TypeVar , cast
8
10
9
11
import pystac
10
12
from pystac .extensions .base import (
11
13
ExtensionManagementMixin ,
12
14
PropertiesExtension ,
15
+ SummariesExtension ,
13
16
)
14
17
from pystac .extensions .hooks import ExtensionHooks
15
- from pystac .utils import map_opt
18
+ from pystac .utils import str_to_datetime , datetime_to_str , map_opt
16
19
17
20
T = TypeVar ("T" , pystac .Item , pystac .Asset )
18
21
19
22
SCHEMA_URI = "https://stac-extensions.github.io/sat/v1.0.0/schema.json"
20
23
21
- ORBIT_STATE : str = "sat:orbit_state"
22
- RELATIVE_ORBIT : str = "sat:relative_orbit"
24
+ PREFIX : str = "sat:"
25
+ PLATFORM_INTERNATIONAL_DESIGNATOR_PROP : str = (
26
+ PREFIX + "platform_international_designator"
27
+ )
28
+ ABSOLUTE_ORBIT_PROP : str = PREFIX + "absolute_orbit"
29
+ ORBIT_STATE_PROP : str = PREFIX + "orbit_state"
30
+ RELATIVE_ORBIT_PROP : str = PREFIX + "relative_orbit"
31
+ ANX_DATETIME_PROP : str = PREFIX + "anx_datetime"
23
32
24
33
25
- class OrbitState (enum .Enum ):
34
+ class OrbitState (str , enum .Enum ):
26
35
ASCENDING = "ascending"
27
36
DESCENDING = "descending"
28
37
GEOSTATIONARY = "geostationary"
@@ -31,25 +40,31 @@ class OrbitState(enum.Enum):
31
40
class SatExtension (
32
41
Generic [T ], PropertiesExtension , ExtensionManagementMixin [pystac .Item ]
33
42
):
34
- """SatItemExt extends Item to add sat properties to a STAC Item.
43
+ """An abstract class that can be used to extend the properties of an
44
+ :class:`~pystac.Item` or :class:`~pystac.Asset` with properties from the
45
+ :stac-ext:`Satellite Extension <sat>`. This class is generic over the type of
46
+ STAC Object to be extended (e.g. :class:`~pystac.Item`,
47
+ :class:`~pystac.Collection`).
35
48
36
- Args:
37
- item : The item to be extended.
49
+ To create a concrete instance of :class:`SatExtension`, use the
50
+ :meth:`SatExtension.ext` method. For example:
38
51
39
- Attributes:
40
- item : The item that is being extended.
52
+ .. code-block:: python
41
53
42
- Note:
43
- Using SatItemExt to directly wrap an item will add the 'sat'
44
- extension ID to the item's stac_extensions.
54
+ >>> item: pystac.Item = ...
55
+ >>> sat_ext = SatExtension.ext(item)
45
56
"""
46
57
47
58
def apply (
48
59
self ,
49
60
orbit_state : Optional [OrbitState ] = None ,
50
61
relative_orbit : Optional [int ] = None ,
62
+ absolute_orbit : Optional [int ] = None ,
63
+ platform_international_designator : Optional [str ] = None ,
64
+ anx_datetime : Optional [Datetime ] = None ,
51
65
) -> None :
52
- """Applies ext extension properties to the extended Item.
66
+ """Applies ext extension properties to the extended :class:`~pystac.Item` or
67
+ class:`~pystac.Asset`.
53
68
54
69
Must specify at least one of orbit_state or relative_orbit in order
55
70
for the sat extension to properties to be valid.
@@ -62,41 +77,75 @@ def apply(
62
77
the time of acquisition.
63
78
"""
64
79
80
+ self .platform_international_designator = platform_international_designator
65
81
self .orbit_state = orbit_state
82
+ self .absolute_orbit = absolute_orbit
66
83
self .relative_orbit = relative_orbit
84
+ self .anx_datetime = anx_datetime
67
85
68
86
@property
69
- def orbit_state (self ) -> Optional [OrbitState ]:
70
- """Get or sets an orbit state of the item.
87
+ def platform_international_designator (self ) -> Optional [str ]:
88
+ """Gets or sets the International Designator, also known as COSPAR ID, and
89
+ NSSDCA ID."""
90
+ return self ._get_property (PLATFORM_INTERNATIONAL_DESIGNATOR_PROP , str )
71
91
72
- Returns:
73
- OrbitState or None
74
- """
75
- return map_opt (lambda x : OrbitState (x ), self ._get_property (ORBIT_STATE , str ))
92
+ @platform_international_designator .setter
93
+ def platform_international_designator (self , v : Optional [str ]) -> None :
94
+ self ._set_property (PLATFORM_INTERNATIONAL_DESIGNATOR_PROP , v )
95
+
96
+ @property
97
+ def orbit_state (self ) -> Optional [OrbitState ]:
98
+ """Get or sets an orbit state of the object."""
99
+ return map_opt (
100
+ lambda x : OrbitState (x ), self ._get_property (ORBIT_STATE_PROP , str )
101
+ )
76
102
77
103
@orbit_state .setter
78
104
def orbit_state (self , v : Optional [OrbitState ]) -> None :
79
- self ._set_property (ORBIT_STATE , map_opt (lambda x : x .value , v ))
105
+ self ._set_property (ORBIT_STATE_PROP , map_opt (lambda x : x .value , v ))
80
106
81
107
@property
82
- def relative_orbit (self ) -> Optional [int ]:
83
- """Get or sets a relative orbit number of the item.
108
+ def absolute_orbit (self ) -> Optional [int ]:
109
+ """Get or sets a absolute orbit number of the item."""
110
+ return self ._get_property (ABSOLUTE_ORBIT_PROP , int )
84
111
85
- Returns:
86
- int or None
87
- """
88
- return self ._get_property (RELATIVE_ORBIT , int )
112
+ @absolute_orbit .setter
113
+ def absolute_orbit (self , v : Optional [int ]) -> None :
114
+ self ._set_property (ABSOLUTE_ORBIT_PROP , v )
115
+
116
+ @property
117
+ def relative_orbit (self ) -> Optional [int ]:
118
+ """Get or sets a relative orbit number of the item."""
119
+ return self ._get_property (RELATIVE_ORBIT_PROP , int )
89
120
90
121
@relative_orbit .setter
91
122
def relative_orbit (self , v : Optional [int ]) -> None :
92
- self ._set_property (RELATIVE_ORBIT , v )
123
+ self ._set_property (RELATIVE_ORBIT_PROP , v )
124
+
125
+ @property
126
+ def anx_datetime (self ) -> Optional [Datetime ]:
127
+ return map_opt (str_to_datetime , self ._get_property (ANX_DATETIME_PROP , str ))
128
+
129
+ @anx_datetime .setter
130
+ def anx_datetime (self , v : Optional [Datetime ]) -> None :
131
+ self ._set_property (ANX_DATETIME_PROP , map_opt (datetime_to_str , v ))
93
132
94
133
@classmethod
95
134
def get_schema_uri (cls ) -> str :
96
135
return SCHEMA_URI
97
136
98
137
@classmethod
99
138
def ext (cls , obj : T , add_if_missing : bool = False ) -> "SatExtension[T]" :
139
+ """Extends the given STAC Object with properties from the :stac-ext:`Satellite
140
+ Extension <sat>`.
141
+
142
+ This extension can be applied to instances of :class:`~pystac.Item` or
143
+ :class:`~pystac.Asset`.
144
+
145
+ Raises:
146
+
147
+ pystac.ExtensionTypeError : If an invalid object type is passed.
148
+ """
100
149
if isinstance (obj , pystac .Item ):
101
150
if add_if_missing :
102
151
cls .add_to (obj )
@@ -112,8 +161,28 @@ def ext(cls, obj: T, add_if_missing: bool = False) -> "SatExtension[T]":
112
161
f"Satellite extension does not apply to type '{ type (obj ).__name__ } '"
113
162
)
114
163
164
+ @staticmethod
165
+ def summaries (obj : pystac .Collection ) -> "SummariesSatExtension" :
166
+ """Returns the extended summaries object for the given collection."""
167
+ return SummariesSatExtension (obj )
168
+
115
169
116
170
class ItemSatExtension (SatExtension [pystac .Item ]):
171
+ """A concrete implementation of :class:`SatExtension` on an :class:`~pystac.Item`
172
+ that extends the properties of the Item to include properties defined in the
173
+ :stac-ext:`Satellite Extension <sat>`.
174
+
175
+ This class should generally not be instantiated directly. Instead, call
176
+ :meth:`SatExtension.ext` on an :class:`~pystac.Item` to
177
+ extend it.
178
+ """
179
+
180
+ item : pystac .Item
181
+ """The :class:`~pystac.Item` being extended."""
182
+
183
+ properties : Dict [str , Any ]
184
+ """The :class:`~pystac.Item` properties, including extension properties."""
185
+
117
186
def __init__ (self , item : pystac .Item ):
118
187
self .item = item
119
188
self .properties = item .properties
@@ -123,6 +192,25 @@ def __repr__(self) -> str:
123
192
124
193
125
194
class AssetSatExtension (SatExtension [pystac .Asset ]):
195
+ """A concrete implementation of :class:`SatExtension` on an :class:`~pystac.Asset`
196
+ that extends the properties of the Asset to include properties defined in the
197
+ :stac-ext:`Satellite Extension <sat>`.
198
+
199
+ This class should generally not be instantiated directly. Instead, call
200
+ :meth:`SatExtension.ext` on an :class:`~pystac.Asset` to
201
+ extend it.
202
+ """
203
+
204
+ asset_href : str
205
+ """The ``href`` value of the :class:`~pystac.Asset` being extended."""
206
+
207
+ properties : Dict [str , Any ]
208
+ """The :class:`~pystac.Asset` fields, including extension properties."""
209
+
210
+ additional_read_properties : Optional [Iterable [Dict [str , Any ]]] = None
211
+ """If present, this will be a list containing 1 dictionary representing the
212
+ properties of the owning :class:`~pystac.Item`."""
213
+
126
214
def __init__ (self , asset : pystac .Asset ):
127
215
self .asset_href = asset .href
128
216
self .properties = asset .extra_fields
@@ -133,6 +221,75 @@ def __repr__(self) -> str:
133
221
return "<AssetSatExtension Asset href={}>" .format (self .asset_href )
134
222
135
223
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
+
136
293
class SatExtensionHooks (ExtensionHooks ):
137
294
schema_uri : str = SCHEMA_URI
138
295
prev_extension_ids : Set [str ] = set (["sat" ])
0 commit comments