Skip to content

Commit

Permalink
return HTTPException
Browse files Browse the repository at this point in the history
  • Loading branch information
jonhealy1 committed Apr 23, 2024
1 parent cae2278 commit 499aa50
Showing 1 changed file with 62 additions and 29 deletions.
91 changes: 62 additions & 29 deletions stac_fastapi/types/stac_fastapi/types/rfc3339.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from typing import Optional, Tuple, Union

import iso8601
from fastapi import HTTPException
from pystac.utils import datetime_to_str

RFC33339_PATTERN = (
Expand Down Expand Up @@ -45,53 +46,85 @@ def rfc3339_str_to_datetime(s: str) -> datetime:
return iso8601.parse_date(s)


def str_to_interval(interval: Optional[str]) -> Optional[DateTimeType]:
"""Extract a tuple of datetimes from an interval string.
def parse_single_date(date_str: str) -> datetime:
"""
Parse a single RFC3339 date string into a datetime object.
Args:
date_str (str): A string representing the date in RFC3339 format.
Returns:
datetime: A datetime object parsed from the date_str.
Raises:
ValueError: If the date_str is empty or contains the placeholder '..'.
"""
if ".." in date_str or not date_str:
raise ValueError("Invalid date format.")
return rfc3339_str_to_datetime(date_str)


def validate_interval_format(values: list) -> None:
"""
Validate the format of the interval string to ensure it contains at most
one forward slash.
Interval strings are defined by
OGC API - Features Part 1 for the datetime query parameter value. These follow the
form '1985-04-12T23:20:50.52Z/1986-04-12T23:20:50.52Z', and allow either the start
or end (but not both) to be open-ended with '..' or ''.
Args:
values (list): A list of strings split by '/' from the interval string.
Raises:
ValueError: If the interval string contains more than one forward slash.
"""
if len(values) > 2:
raise ValueError("Interval string contains more than one forward slash.")


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.
Args:
interval (str or None): The interval string to convert to a tuple of
datetime.datetime objects, or None if no datetime is specified.
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 tuple of datetime.datetime objects or
None if input is None.
Raises:
ValueError: If the string is not a valid interval string and not None.
HTTPException: If the string is not valid for various reasons such as being empty,
having more than one slash, or if date formats are invalid.
"""
if interval is None:
return None

if not interval:
raise ValueError("Empty interval string is invalid.")
raise HTTPException(status_code=400, detail="Empty interval string is invalid.")

values = interval.split("/")
if len(values) == 1:
# Single date for == date case
return rfc3339_str_to_datetime(values[0])
elif len(values) > 2:
raise ValueError(
f"Interval string '{interval}' contains more than one forward slash."
validate_interval_format(values)

try:
start = parse_single_date(values[0]) if values[0] not in ["..", ""] else None
end = (
parse_single_date(values[1])
if len(values) > 1 and values[1] not in ["..", ""]
else None
)

start = None
end = None
if values[0] not in ["..", ""]:
start = rfc3339_str_to_datetime(values[0])
if values[1] not in ["..", ""]:
end = rfc3339_str_to_datetime(values[1])
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))

if start is None and end is None:
raise ValueError("Double open-ended intervals are not allowed.")
raise HTTPException(
status_code=400, detail="Double open-ended intervals are not allowed."
)
if start is not None and end is not None and start > end:
raise ValueError("Start datetime cannot be before end datetime.")
else:
return start, end
raise HTTPException(
status_code=400, detail="Start datetime cannot be before end datetime."
)

return start, end


def now_in_utc() -> datetime:
Expand Down

0 comments on commit 499aa50

Please sign in to comment.