Skip to content

Commit 92ddf38

Browse files
authored
Fix intervals (#363)
* fix: typing of _to_isoformat_range * fix: reject double open-ended intervals * fix: allow empty strings in intervals * chore: update changelog
1 parent e45c68d commit 92ddf38

File tree

3 files changed

+19
-1
lines changed

3 files changed

+19
-1
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
1515

1616
### Fixed
1717

18+
- Some mishandled cases for datetime intervals [#363](https://github.com/stac-utils/pystac-client/pull/363)
19+
1820
### Removed
1921

2022
- Python 3.7 support [#347](https://github.com/stac-utils/pystac-client/pull/347)

pystac_client/item_search.py

+7-1
Original file line numberDiff line numberDiff line change
@@ -439,7 +439,7 @@ def _to_utc_isoformat(dt: datetime_) -> str:
439439
def _to_isoformat_range(
440440
self,
441441
component: DatetimeOrTimestamp,
442-
) -> Tuple[Optional[str], Optional[str]]:
442+
) -> Tuple[str, Optional[str]]:
443443
"""Converts a single DatetimeOrTimestamp into one or two Datetimes.
444444
445445
This is required to expand a single value like "2017" out to the whole
@@ -456,6 +456,8 @@ def _to_isoformat_range(
456456
elif isinstance(component, str):
457457
if component == "..":
458458
return component, None
459+
elif component == "":
460+
return "..", None
459461

460462
match = DATETIME_REGEX.match(component)
461463
if not match:
@@ -504,12 +506,16 @@ def _format_datetime(self, value: Optional[DatetimeLike]) -> Optional[Datetime]:
504506
if not components:
505507
return None
506508
elif len(components) == 1:
509+
if components[0] is None:
510+
raise Exception("cannot create a datetime query with None")
507511
start, end = self._to_isoformat_range(components[0])
508512
if end is not None:
509513
return f"{start}/{end}"
510514
else:
511515
return start
512516
elif len(components) == 2:
517+
if all(c is None for c in components):
518+
raise Exception("cannot create a double open-ended interval")
513519
start, _ = self._to_isoformat_range(components[0])
514520
backup_end, end = self._to_isoformat_range(components[1])
515521
return f"{start}/{end or backup_end}"

tests/test_item_search.py

+10
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,8 @@ def test_many_datetimes(self) -> None:
254254
"2020-07-23T00:00:00+03:00",
255255
"2020-07-23T00:00:00.000+03:00",
256256
"2020-07-23T00:00:00.000z",
257+
"/2023-01-01T00:00:00Z",
258+
"2023-01-01T00:00:00Z/",
257259
]
258260
for date_time in datetimes:
259261
ItemSearch(url=SEARCH_URL, datetime=date_time)
@@ -266,6 +268,14 @@ def test_three_datetimes(self) -> None:
266268
with pytest.raises(Exception):
267269
ItemSearch(url=SEARCH_URL, datetime=[start, middle, end])
268270

271+
def test_double_open_ended_interval(self) -> None:
272+
with pytest.raises(Exception):
273+
ItemSearch(url=SEARCH_URL, datetime=[None, None])
274+
275+
def test_datetime_list_of_one_none(self) -> None:
276+
with pytest.raises(Exception):
277+
ItemSearch(url=SEARCH_URL, datetime=[None])
278+
269279
def test_single_collection_string(self) -> None:
270280
# Single ID string
271281
search = ItemSearch(url=SEARCH_URL, collections="naip")

0 commit comments

Comments
 (0)