From d2fd4a6ab3a9869d2c2b622fb84c9e9304c9aab1 Mon Sep 17 00:00:00 2001 From: Arjan Date: Wed, 22 May 2024 09:25:12 +0200 Subject: [PATCH] Make `str_to_interval` not return a tuple for single-value input (#692) * Do not return tuple for single-value input * Add PR reference to changelog * update from main --------- Co-authored-by: vincentsarago --- CHANGES.md | 5 ++- .../types/stac_fastapi/types/rfc3339.py | 15 +++---- stac_fastapi/types/tests/test_rfc3339.py | 42 +++++++++++++------ 3 files changed, 42 insertions(+), 20 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index abff6ce4..d26773a5 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -7,12 +7,15 @@ * Switch from `fastapi` to `fastapi-slim` to avoid installing unwanted dependencies. ([#687](https://github.com/stac-utils/stac-fastapi/pull/687)) * Replace Enum with `Literal` for `FilterLang`. ([#686](https://github.com/stac-utils/stac-fastapi/pull/686)) * Update stac-pydantic requirement to `~3.1` ([#697](https://github.com/stac-utils/stac-fastapi/pull/697)) -* Fix datetime interval for GET Search when passing a single value ([#697](https://github.com/stac-utils/stac-fastapi/pull/697)) ### Removed * Pystac as it was just used for a datetime to string function. ([#690](https://github.com/stac-utils/stac-fastapi/pull/690)) +### Fixed + +* Make `str_to_interval` not return a tuple for single-value input (fixing `datetime` argument as passed to `get_search`). ([#692](https://github.com/stac-utils/stac-fastapi/pull/692)) + ## [3.0.0a0] - 2024-05-06 ### Added diff --git a/stac_fastapi/types/stac_fastapi/types/rfc3339.py b/stac_fastapi/types/stac_fastapi/types/rfc3339.py index 5ba0630a..77ec993d 100644 --- a/stac_fastapi/types/stac_fastapi/types/rfc3339.py +++ b/stac_fastapi/types/stac_fastapi/types/rfc3339.py @@ -94,16 +94,17 @@ def parse_single_date(date_str: str) -> datetime: def str_to_interval(interval: Optional[str]) -> Optional[DateTimeType]: """ - Extract a tuple of datetime objects from an interval string defined by the OGC API. - The interval can either be a single datetime or a range with start and end datetime. + Extract a single datetime object or a tuple of datetime objects from an + interval string defined by the OGC API. The interval can either be a + single datetime or a range with start and end datetime. Args: interval (Optional[str]): The interval string to convert to datetime objects, or None if no datetime is specified. Returns: - Optional[DateTimeType]: A tuple of datetime.datetime objects or - None if input is None. + Optional[DateTimeType]: A single datetime.datetime object, a tuple of + datetime.datetime objects, or None if input is None. Raises: HTTPException: If the string is not valid for various reasons such as being empty, @@ -122,11 +123,11 @@ def str_to_interval(interval: Optional[str]) -> Optional[DateTimeType]: detail="Interval string contains more than one forward slash.", ) - if len(values) == 1: - values = [values[0], values[0]] - try: start = parse_single_date(values[0]) if values[0] not in ["..", ""] else None + if len(values) == 1: + return start + end = ( parse_single_date(values[1]) if len(values) > 1 and values[1] not in ["..", ""] diff --git a/stac_fastapi/types/tests/test_rfc3339.py b/stac_fastapi/types/tests/test_rfc3339.py index 8d83dbb9..dc4c897d 100644 --- a/stac_fastapi/types/tests/test_rfc3339.py +++ b/stac_fastapi/types/tests/test_rfc3339.py @@ -1,4 +1,4 @@ -from datetime import timezone +from datetime import datetime, timezone import pytest from fastapi import HTTPException @@ -86,27 +86,35 @@ def test_parse_valid_str_to_datetime(test_input): @pytest.mark.parametrize("test_input", invalid_intervals) -def test_parse_invalid_interval_to_datetime(test_input): +def test_str_to_interval_with_invalid_interval(test_input): with pytest.raises(HTTPException) as exc_info: str_to_interval(test_input) assert ( exc_info.value.status_code == 400 - ), "Should return a 400 status code for invalid intervals" + ), "str_to_interval should return a 400 status code for invalid interval" -@pytest.mark.parametrize("test_input", valid_intervals) -def test_parse_valid_interval_to_datetime(test_input): - assert str_to_interval(test_input) +@pytest.mark.parametrize("test_input", invalid_datetimes) +def test_str_to_interval_with_invalid_datetime(test_input): + with pytest.raises(HTTPException) as exc_info: + str_to_interval(test_input) + assert ( + exc_info.value.status_code == 400 + ), "str_to_interval should return a 400 status code for invalid datetime" -def test_now_functions() -> None: - now1 = now_in_utc() - now2 = now_in_utc() +@pytest.mark.parametrize("test_input", valid_intervals) +def test_str_to_interval_with_valid_interval(test_input): + assert isinstance( + str_to_interval(test_input), tuple + ), "str_to_interval should return tuple for multi-value input" - assert now1 < now2 - assert now1.tzinfo == timezone.utc - rfc3339_str_to_datetime(now_to_rfc3339_str()) +@pytest.mark.parametrize("test_input", valid_datetimes) +def test_str_to_interval_with_valid_datetime(test_input): + assert isinstance( + str_to_interval(test_input), datetime + ), "str_to_interval should return single datetime for single-value input" def test_str_to_interval_with_none(): @@ -114,3 +122,13 @@ def test_str_to_interval_with_none(): assert ( str_to_interval(None) is None ), "str_to_interval should return None when input is None" + + +def test_now_functions() -> None: + now1 = now_in_utc() + now2 = now_in_utc() + + assert now1 < now2 + assert now1.tzinfo == timezone.utc + + rfc3339_str_to_datetime(now_to_rfc3339_str())