Skip to content

Commit 0432554

Browse files
author
Jon Duckworth
authored
Merge pull request #513 from duckontheweb/update/timestamps-extension
Update Timestamps Extension
2 parents 5fa819f + 4870116 commit 0432554

File tree

7 files changed

+324
-50
lines changed

7 files changed

+324
-50
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
- `LabelMethod` enum in `pystac.extensions.label` with recommended values for
1111
`"label:methods"` field ([#484](https://github.com/stac-utils/pystac/pull/484))
1212
- Label Extension summaries ([#484](https://github.com/stac-utils/pystac/pull/484))
13+
- Timestamps Extension summaries ([#513](https://github.com/stac-utils/pystac/pull/513))
14+
- Define equality and `__repr__` of `RangeSummary` instances based on `to_dict`
15+
representation ([#513](https://github.com/stac-utils/pystac/pull/513))
1316

1417
### Changed
1518

docs/api.rst

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -536,17 +536,29 @@ ItemScientificExtension
536536
Timestamps Extension
537537
--------------------
538538

539-
Implements the :stac-ext:`Timestamps Extension <timestamps>`.
539+
These classes are representations of the :stac-ext:`Timestamps Extension Spec
540+
<timestamps>`.
540541

541-
TimestampsItemExt
542-
~~~~~~~~~~~~~~~~~
542+
TimestampsExtension
543+
~~~~~~~~~~~~~~~~~~~
543544

544-
**TEMPORARILY REMOVED**
545+
.. autoclass:: pystac.extensions.timestamps.TimestampsExtension
546+
:members:
547+
:show-inheritance:
545548

546-
.. .. autoclass:: pystac.extensions.timestamps.TimestampsItemExt
547-
.. :members:
548-
.. :undoc-members:
549-
.. :show-inheritance:
549+
ItemTimestampsExtension
550+
~~~~~~~~~~~~~~~~~~~~~~~
551+
552+
.. autoclass:: pystac.extensions.timestamps.ItemTimestampsExtension
553+
:members:
554+
:show-inheritance:
555+
556+
AssetTimestampsExtension
557+
~~~~~~~~~~~~~~~~~~~~~~~~
558+
559+
.. autoclass:: pystac.extensions.timestamps.AssetTimestampsExtension
560+
:members:
561+
:show-inheritance:
550562

551563
SAR Extension
552564
-------------

pystac/extensions/eo.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -278,10 +278,11 @@ class EOExtension(
278278
Generic[T], PropertiesExtension, ExtensionManagementMixin[pystac.Item]
279279
):
280280
"""An abstract class that can be used to extend the properties of an
281-
:class:`~pystac.Item` or :class:`~pystac.Collection` with properties from the
281+
:class:`~pystac.Item` or :class:`~pystac.Asset` with properties from the
282282
:stac-ext:`Electro-Optical Extension <eo>`. This class is generic over the type of
283283
STAC Object to be extended (e.g. :class:`~pystac.Item`,
284-
:class:`~pystac.Collection`).
284+
:class:`~pystac.
285+
Asset`).
285286
286287
To create a concrete instance of :class:`EOExtension`, use the
287288
:meth:`EOExtension.ext` method. For example:

pystac/extensions/timestamps.py

Lines changed: 166 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@
44
"""
55

66
from datetime import datetime as Datetime
7-
from typing import Generic, Optional, Set, TypeVar, cast
7+
from pystac.summaries import RangeSummary
8+
from typing import Dict, Any, Generic, Iterable, Optional, Set, TypeVar, cast
89

910
import pystac
1011
from pystac.extensions.base import (
1112
ExtensionManagementMixin,
1213
PropertiesExtension,
14+
SummariesExtension,
1315
)
1416
from pystac.extensions.hooks import ExtensionHooks
1517
from pystac.utils import datetime_to_str, map_opt, str_to_datetime
@@ -26,8 +28,18 @@
2628
class TimestampsExtension(
2729
Generic[T], PropertiesExtension, ExtensionManagementMixin[pystac.Item]
2830
):
29-
"""TimestampsItemExt is the extension of an Item in that
30-
allows to specify additional timestamps for assets and metadata.
31+
"""An abstract class that can be used to extend the properties of an
32+
:class:`~pystac.Item` or :class:`~pystac.Asset` with properties from the
33+
:stac-ext:`Timestamps Extension <timestamps>`. This class is generic over the type
34+
of STAC Object to be extended (e.g. :class:`~pystac.Item`, :class:`~pystac.Asset`).
35+
36+
To create a concrete instance of :class:`TimestampsExtension`, use the
37+
:meth:`TimestampsExtension.ext` method. For example:
38+
39+
.. code-block:: python
40+
41+
>>> item: pystac.Item = ...
42+
>>> ts_ext = TimestampsExtension.ext(item)
3143
"""
3244

3345
def apply(
@@ -52,18 +64,13 @@ def apply(
5264

5365
@property
5466
def published(self) -> Optional[Datetime]:
55-
"""Get or sets a datetime objects that represent
56-
the date and time that the corresponding data
57-
was published the first time.
58-
59-
'Published'
60-
has a different meaning depending on where it is used. If available in
61-
the asset properties, it refers to the timestamps valid for the actual data
62-
linked to the Asset Object. If it comes from the Item properties, it's
63-
referencing to the timestamp valid for the metadata.
64-
65-
Returns:
66-
datetime
67+
"""Gets or sets a datetime object that represents the date and time that the
68+
corresponding data was published the first time.
69+
70+
'Published' has a different meaning depending on where it is used. If available
71+
in the asset properties, it refers to the timestamps valid for the actual data
72+
linked to the Asset Object. If it comes from the Item properties, it refers to
73+
timestamp valid for the metadata.
6774
"""
6875
return map_opt(str_to_datetime, self._get_property(PUBLISHED_PROP, str))
6976

@@ -73,18 +80,13 @@ def published(self, v: Optional[Datetime]) -> None:
7380

7481
@property
7582
def expires(self) -> Optional[Datetime]:
76-
"""Get or sets a datetime objects that represent
77-
the date and time the corresponding data
78-
expires (is not valid any longer).
79-
80-
'Unpublished'
81-
has a different meaning depending on where it is used. If available in
82-
the asset properties, it refers to the timestamps valid for the actual data
83-
linked to the Asset Object. If it comes from the Item properties, it's
84-
referencing to the timestamp valid for the metadata.
85-
86-
Returns:
87-
datetime
83+
"""Gets or sets a datetime object that represents the date and time the
84+
corresponding data expires (is not valid any longer).
85+
86+
'Unpublished' has a different meaning depending on where it is used. If
87+
available in the asset properties, it refers to the timestamps valid for the
88+
actual data linked to the Asset Object. If it comes from the Item properties,
89+
it refers to to the timestamp valid for the metadata.
8890
"""
8991
return map_opt(str_to_datetime, self._get_property(EXPIRES_PROP, str))
9092

@@ -94,17 +96,13 @@ def expires(self, v: Optional[Datetime]) -> None:
9496

9597
@property
9698
def unpublished(self) -> Optional[Datetime]:
97-
"""Get or sets a datetime objects that represent
98-
the Date and time the corresponding data was unpublished.
99-
100-
'Unpublished'
101-
has a different meaning depending on where it is used. If available in
102-
the asset properties, it refers to the timestamps valid for the actual data
103-
linked to the Asset Object. If it comes from the Item properties, it's
104-
referencing to the timestamp valid for the metadata.
99+
"""Gets or sets a datetime object that represents the date and time the
100+
corresponding data was unpublished.
105101
106-
Returns:
107-
datetime
102+
'Unpublished' has a different meaning depending on where it is used. If
103+
available in the asset properties, it refers to the timestamps valid for the
104+
actual data linked to the Asset Object. If it comes from the Item properties,
105+
it's referencing to the timestamp valid for the metadata.
108106
"""
109107
return map_opt(str_to_datetime, self._get_property(UNPUBLISHED_PROP, str))
110108

@@ -118,6 +116,16 @@ def get_schema_uri(cls) -> str:
118116

119117
@classmethod
120118
def ext(cls, obj: T, add_if_missing: bool = False) -> "TimestampsExtension[T]":
119+
"""Extends the given STAC Object with properties from the :stac-ext:`Timestamps
120+
Extension <timestamps>`.
121+
122+
This extension can be applied to instances of :class:`~pystac.Item` or
123+
:class:`~pystac.Asset`.
124+
125+
Raises:
126+
127+
pystac.ExtensionTypeError : If an invalid object type is passed.
128+
"""
121129
if isinstance(obj, pystac.Item):
122130
if add_if_missing:
123131
cls.add_to(obj)
@@ -133,25 +141,144 @@ def ext(cls, obj: T, add_if_missing: bool = False) -> "TimestampsExtension[T]":
133141
f"Timestamps extension does not apply to type '{type(obj).__name__}'"
134142
)
135143

144+
@staticmethod
145+
def summaries(obj: pystac.Collection) -> "SummariesTimestampsExtension":
146+
"""Returns the extended summaries object for the given collection."""
147+
return SummariesTimestampsExtension(obj)
148+
136149

137150
class ItemTimestampsExtension(TimestampsExtension[pystac.Item]):
151+
"""A concrete implementation of :class:`TimestampsExtension` on an
152+
:class:`~pystac.Item` that extends the properties of the Item to include properties
153+
defined in the :stac-ext:`Timestamps Extension <timestamps>`.
154+
155+
This class should generally not be instantiated directly. Instead, call
156+
:meth:`TimestampsExtension.ext` on an :class:`~pystac.Item` to extend it.
157+
"""
158+
159+
item: pystac.Item
160+
"""The :class:`~pystac.Item` being extended."""
161+
162+
properties: Dict[str, Any]
163+
"""The :class:`~pystac.Item` properties, including extension properties."""
164+
138165
def __init__(self, item: pystac.Item):
139166
self.item = item
140167
self.properties = item.properties
141168

142169
def __repr__(self) -> str:
143-
return "<ItemtimestampsExtension Item id={}>".format(self.item.id)
170+
return "<ItemTimestampsExtension Item id={}>".format(self.item.id)
144171

145172

146173
class AssetTimestampsExtension(TimestampsExtension[pystac.Asset]):
174+
"""A concrete implementation of :class:`TimestampsExtension` on an
175+
:class:`~pystac.Asset` that extends the Asset fields to include properties
176+
defined in the :stac-ext:`Timestamps Extension <timestamps>`.
177+
178+
This class should generally not be instantiated directly. Instead, call
179+
:meth:`TimestampsExtension.ext` on an :class:`~pystac.Asset` to extend it.
180+
"""
181+
182+
asset_href: str
183+
"""The ``href`` value of the :class:`~pystac.Asset` being extended."""
184+
185+
properties: Dict[str, Any]
186+
"""The :class:`~pystac.Asset` fields, including extension properties."""
187+
188+
additional_read_properties: Optional[Iterable[Dict[str, Any]]] = None
189+
"""If present, this will be a list containing 1 dictionary representing the
190+
properties of the owning :class:`~pystac.Item`."""
191+
147192
def __init__(self, asset: pystac.Asset):
148193
self.asset_href = asset.href
149194
self.properties = asset.properties
150195
if asset.owner and isinstance(asset.owner, pystac.Item):
151196
self.additional_read_properties = [asset.owner.properties]
152197

153198
def __repr__(self) -> str:
154-
return "<AssettimestampsExtension Asset href={}>".format(self.asset_href)
199+
return "<AssetTimestampsExtension Asset href={}>".format(self.asset_href)
200+
201+
202+
class SummariesTimestampsExtension(SummariesExtension):
203+
"""A concrete implementation of :class:`~SummariesExtension` that extends
204+
the ``summaries`` field of a :class:`~pystac.Collection` to include properties
205+
defined in the :stac-ext:`Timestamps Extension <timestamps>`.
206+
"""
207+
208+
@property
209+
def published(self) -> Optional[RangeSummary[Datetime]]:
210+
"""Get or sets the summary of :attr:`TimestampsExtension.published` values
211+
for this Collection.
212+
"""
213+
214+
return map_opt(
215+
lambda s: RangeSummary(
216+
str_to_datetime(s.minimum), str_to_datetime(s.maximum)
217+
),
218+
self.summaries.get_range(PUBLISHED_PROP),
219+
)
220+
221+
@published.setter
222+
def published(self, v: Optional[RangeSummary[Datetime]]) -> None:
223+
self._set_summary(
224+
PUBLISHED_PROP,
225+
map_opt(
226+
lambda s: RangeSummary(
227+
datetime_to_str(s.minimum), datetime_to_str(s.maximum)
228+
),
229+
v,
230+
),
231+
)
232+
233+
@property
234+
def expires(self) -> Optional[RangeSummary[Datetime]]:
235+
"""Get or sets the summary of :attr:`TimestampsExtension.expires` values
236+
for this Collection.
237+
"""
238+
239+
return map_opt(
240+
lambda s: RangeSummary(
241+
str_to_datetime(s.minimum), str_to_datetime(s.maximum)
242+
),
243+
self.summaries.get_range(EXPIRES_PROP),
244+
)
245+
246+
@expires.setter
247+
def expires(self, v: Optional[RangeSummary[Datetime]]) -> None:
248+
self._set_summary(
249+
EXPIRES_PROP,
250+
map_opt(
251+
lambda s: RangeSummary(
252+
datetime_to_str(s.minimum), datetime_to_str(s.maximum)
253+
),
254+
v,
255+
),
256+
)
257+
258+
@property
259+
def unpublished(self) -> Optional[RangeSummary[Datetime]]:
260+
"""Get or sets the summary of :attr:`TimestampsExtension.unpublished` values
261+
for this Collection.
262+
"""
263+
264+
return map_opt(
265+
lambda s: RangeSummary(
266+
str_to_datetime(s.minimum), str_to_datetime(s.maximum)
267+
),
268+
self.summaries.get_range(UNPUBLISHED_PROP),
269+
)
270+
271+
@unpublished.setter
272+
def unpublished(self, v: Optional[RangeSummary[Datetime]]) -> None:
273+
self._set_summary(
274+
UNPUBLISHED_PROP,
275+
map_opt(
276+
lambda s: RangeSummary(
277+
datetime_to_str(s.minimum), datetime_to_str(s.maximum)
278+
),
279+
v,
280+
),
281+
)
155282

156283

157284
class TimestampsExtensionHooks(ExtensionHooks):

pystac/summaries.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,15 @@ def from_dict(cls, d: Dict[str, Any]) -> "RangeSummary[T]":
5959
maximum: T = get_required(d.get("maximum"), "RangeSummary", "maximum")
6060
return cls(minimum=minimum, maximum=maximum)
6161

62+
def __eq__(self, o: object) -> bool:
63+
if not isinstance(o, RangeSummary):
64+
return NotImplemented
65+
66+
return self.to_dict() == o.to_dict()
67+
68+
def __repr__(self) -> str:
69+
return self.to_dict().__repr__()
70+
6271

6372
FIELDS_JSON_URL = (
6473
"https://cdn.jsdelivr.net/npm/@radiantearth/stac-fields/fields-normalized.json"

0 commit comments

Comments
 (0)