Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update for stac-fastapi v2.5.x #101

Merged
merged 16 commits into from
Apr 25, 2024
4 changes: 4 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## [Unreleased]

### Changed

- Updated stac-fastapi libraries to v2.5.4 ([#101](https://github.com/stac-utils/stac-fastapi-pgstac/pull/101))
-
### Added

- Ability to configure the database runtime parameters ([#92](https://github.com/stac-utils/stac-fastapi-pgstac/pull/92))
Expand Down
2 changes: 1 addition & 1 deletion scripts/ingest_joplin.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def post_or_put(url: str, data: dict):
"""Post or put data to url."""
r = requests.post(url, json=data)
if r.status_code == 409:
new_url = url if data["type"] == "Collection" else url + f"/{data['id']}"
new_url = url + f"/{data['id']}"
# Exists, so update
r = requests.put(new_url, json=data)
# Unchanged may throw a 404
Expand Down
6 changes: 3 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@
"orjson",
"pydantic[dotenv]>=1.10.8", # https://github.com/pydantic/pydantic/issues/5821
"stac_pydantic==2.0.*",
"stac-fastapi.types~=2.4.9",
"stac-fastapi.api~=2.4.9",
"stac-fastapi.extensions~=2.4.9",
"stac-fastapi.types~=2.5.5",
"stac-fastapi.api~=2.5.5",
"stac-fastapi.extensions~=2.5.5",
"asyncpg",
"buildpg",
"brotli_asgi",
Expand Down
18 changes: 11 additions & 7 deletions stac_fastapi/pgstac/core.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
"""Item crud client."""
import re
from datetime import datetime
from typing import Any, Dict, List, Optional, Union
from urllib.parse import unquote_plus, urljoin

Expand All @@ -16,9 +15,10 @@
from stac_fastapi.types.core import AsyncBaseCoreClient
from stac_fastapi.types.errors import InvalidQueryParameter, NotFoundError
from stac_fastapi.types.requests import get_base_url
from stac_fastapi.types.rfc3339 import DateTimeType
from stac_fastapi.types.stac import Collection, Collections, Item, ItemCollection
from stac_pydantic.links import Relations
from stac_pydantic.shared import MimeTypes
from stac_pydantic.shared import BBox, MimeTypes

from stac_fastapi.pgstac.config import Settings
from stac_fastapi.pgstac.models.links import (
Expand All @@ -28,7 +28,7 @@
PagingLinks,
)
from stac_fastapi.pgstac.types.search import PgstacSearch
from stac_fastapi.pgstac.utils import filter_fields
from stac_fastapi.pgstac.utils import filter_fields, format_datetime_range

NumType = Union[float, int]

Expand Down Expand Up @@ -155,8 +155,12 @@ async def _search_base(

settings: Settings = request.app.state.settings

if search_request.datetime:
search_request.datetime = format_datetime_range(search_request.datetime)

search_request.conf = search_request.conf or {}
search_request.conf["nohydrate"] = settings.use_api_hydrate

search_request_json = search_request.json(exclude_none=True, by_alias=True)

try:
Expand Down Expand Up @@ -248,8 +252,8 @@ async def item_collection(
self,
collection_id: str,
request: Request,
bbox: Optional[List[NumType]] = None,
datetime: Optional[Union[str, datetime]] = None,
bbox: Optional[BBox] = None,
datetime: Optional[DateTimeType] = None,
limit: Optional[int] = None,
token: str = None,
**kwargs,
Expand Down Expand Up @@ -341,8 +345,8 @@ async def get_search(
request: Request,
collections: Optional[List[str]] = None,
ids: Optional[List[str]] = None,
bbox: Optional[List[NumType]] = None,
datetime: Optional[Union[str, datetime]] = None,
bbox: Optional[BBox] = None,
datetime: Optional[DateTimeType] = None,
limit: Optional[int] = None,
query: Optional[str] = None,
token: Optional[str] = None,
Expand Down
33 changes: 33 additions & 0 deletions stac_fastapi/pgstac/utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
"""stac-fastapi utility methods."""
from datetime import datetime
from typing import Any, Dict, Optional, Set, Union

from stac_fastapi.types.rfc3339 import DateTimeType
from stac_fastapi.types.stac import Item


Expand Down Expand Up @@ -113,3 +115,34 @@ def dict_deep_update(merge_to: Dict[str, Any], merge_from: Dict[str, Any]) -> No
dict_deep_update(merge_to[k], merge_from[k])
else:
merge_to[k] = v


def format_datetime_range(dt_range: DateTimeType) -> Union[str, Any]:
"""
Convert a datetime object or a tuple of datetime objects to a formatted string for datetime ranges.

Args:
dt_range (DateTimeType): The date interval,
which might be a single datetime or a tuple with one or two datetimes.

Returns:
str: A formatted string like 'YYYY-MM-DDTHH:MM:SSZ/..', 'YYYY-MM-DDTHH:MM:SSZ', or the original string input.
"""
# Handle a single datetime object
if isinstance(dt_range, datetime):
return dt_range.isoformat().replace("+00:00", "Z")

# Handle a tuple containing datetime objects or None
if isinstance(dt_range, tuple):
start, end = dt_range

# Convert start datetime to string if not None, otherwise use ".."
start_str = start.isoformat().replace("+00:00", "Z") if start else ".."

# Convert end datetime to string if not None, otherwise use ".."
end_str = end.isoformat().replace("+00:00", "Z") if end else ".."

return f"{start_str}/{end_str}"

# Return input as-is if it's not any expected type (fallback)
return dt_range
2 changes: 1 addition & 1 deletion tests/api/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"DELETE /collections/{collection_id}/items/{item_id}",
"POST /collections",
"POST /collections/{collection_id}/items",
"PUT /collections",
"PUT /collections/{collection_id}",
"PUT /collections/{collection_id}/items/{item_id}",
]

Expand Down
2 changes: 1 addition & 1 deletion tests/clients/test_postgres.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ async def test_update_collection(app_client, load_test_collection):
in_coll = load_test_collection
in_coll.keywords.append("newkeyword")

resp = await app_client.put("/collections", json=in_coll.dict())
resp = await app_client.put(f"/collections/{in_coll.id}", json=in_coll.dict())
assert resp.status_code == 200

resp = await app_client.get(f"/collections/{in_coll.id}")
Expand Down
4 changes: 2 additions & 2 deletions tests/resources/test_collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ async def test_update_collection(app_client, load_test_data, load_test_collectio
in_coll = load_test_collection
in_coll.keywords.append("newkeyword")

resp = await app_client.put("/collections", json=in_coll.dict())
resp = await app_client.put(f"/collections/{in_coll.id}", json=in_coll.dict())
assert resp.status_code == 200
put_coll = Collection.parse_obj(resp.json())

Expand Down Expand Up @@ -88,7 +88,7 @@ async def test_update_new_collection(app_client, load_test_collection):
in_coll = load_test_collection
in_coll.id = "test-updatenew"

resp = await app_client.put("/collections", json=in_coll.dict())
resp = await app_client.put(f"/collections/{in_coll.id}", json=in_coll.dict())
assert resp.status_code == 404


Expand Down
6 changes: 6 additions & 0 deletions tests/resources/test_conformance.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ async def test_landing_page_links(
assert link.get("type") == expected_media_type

link_path = urllib.parse.urlsplit(link.get("href")).path

# this feels hacky
# assert link_path == (
# app.state.router_prefix + app.state.router_prefix + expected_path
# ) or (app.state.router_prefix + expected_path)

assert link_path == app.state.router_prefix + expected_path

resp = await app_client.get(link_path.rsplit("/", 1)[-1])
vincentsarago marked this conversation as resolved.
Show resolved Hide resolved
Expand Down
2 changes: 1 addition & 1 deletion tests/resources/test_item.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ async def test_update_collection(app_client, load_test_data, load_test_collectio
in_coll = load_test_collection
in_coll.keywords.append("newkeyword")

resp = await app_client.put("/collections", json=in_coll.dict())
resp = await app_client.put(f"/collections/{in_coll.id}", json=in_coll.dict())
assert resp.status_code == 200

resp = await app_client.get(f"/collections/{in_coll.id}")
Expand Down
Loading