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 v3.0.0a release #234

Merged
merged 36 commits into from
May 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
0c4793e
update for v3.0.0
jonhealy1 Apr 27, 2024
185a512
lint
jonhealy1 Apr 27, 2024
9cd6ec8
update tests pass 1
jonhealy1 Apr 28, 2024
57c0d4a
update tests 2
jonhealy1 Apr 28, 2024
e6e3363
clean up
jonhealy1 Apr 28, 2024
19bda7d
update
jonhealy1 Apr 28, 2024
84ac529
update to stac-fastapi v3.0.0a0
jonhealy1 May 7, 2024
377118e
Merge branch 'main' into stac-fastapi-v3.0
jonhealy1 May 7, 2024
150c3f3
unskip collection extensions put test
jonhealy1 May 7, 2024
12b7243
add example with between timestamps
jonhealy1 May 7, 2024
a511bc5
update filter es logic
jonhealy1 May 7, 2024
7138336
add updated method to opensearch
jonhealy1 May 7, 2024
7f67fca
update typing extensions
jonhealy1 May 7, 2024
fa12732
update again
jonhealy1 May 7, 2024
17a0bb5
comment out elasticsearch 7 testing for now
jonhealy1 May 7, 2024
25c49c5
fix ports
jonhealy1 May 7, 2024
f42b060
install core first
jonhealy1 May 7, 2024
260e360
find errors
jonhealy1 May 7, 2024
0ed1f4c
convert enum in core
jonhealy1 May 7, 2024
eb2b2ab
clean up
jonhealy1 May 7, 2024
e67e036
clean up 2
jonhealy1 May 7, 2024
d670c5c
more cleaning
jonhealy1 May 8, 2024
f3cd61c
update changelog
jonhealy1 May 8, 2024
c5c81dc
Merge branch 'main' into stac-fastapi-v3.0
jonhealy1 May 8, 2024
93cd1b6
changelog fix
jonhealy1 May 8, 2024
f133ab1
Update stac_fastapi/tests/extensions/test_filter.py
jonhealy1 May 8, 2024
6967685
hardcode max limit for now
jonhealy1 May 9, 2024
ac28653
use fastapi-slim
jonhealy1 May 9, 2024
3ca89ff
update for python 3.12
jonhealy1 May 9, 2024
81a64c3
only run lint in 3.11
jonhealy1 May 9, 2024
037c078
use asyncbasefiltersclient from stac-fastapi
jonhealy1 May 9, 2024
0fe5599
remove pystac
jonhealy1 May 9, 2024
d4e4a43
added test_item_custom_links
pedro-cf May 9, 2024
a198efb
lint
jonhealy1 May 9, 2024
17aacb6
comment out test for now
jonhealy1 May 10, 2024
db750da
use constant for max limit
jonhealy1 May 10, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 12 additions & 8 deletions .github/workflows/cicd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ jobs:
- 9202:9202
strategy:
matrix:
python-version: [ "3.8", "3.9", "3.10", "3.11"]
python-version: [ "3.8", "3.9", "3.10", "3.11", "3.12"]

name: Python ${{ matrix.python-version }} testing

Expand All @@ -78,13 +78,21 @@ jobs:
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Lint code
uses: pre-commit/[email protected]
if: ${{ matrix.python-version == 3.11 }}
run: |
python -m pip install pre-commit
pre-commit run --all-files

- name: Install pipenv
run: |
python -m pip install --upgrade pipenv wheel

- name: Install core library stac-fastapi
run: |
pip install ./stac_fastapi/core

- name: Install elasticsearch stac-fastapi
run: |
pip install ./stac_fastapi/elasticsearch[dev,server]
Expand All @@ -93,16 +101,12 @@ jobs:
run: |
pip install ./stac_fastapi/opensearch[dev,server]

- name: Install core library stac-fastapi
run: |
pip install ./stac_fastapi/core

- name: Run test suite against Elasticsearch 7.x
run: |
pipenv run pytest -svvv
env:
ENVIRONMENT: testing
ES_PORT: 9200
ES_PORT: 9400
ES_HOST: 172.17.0.1
ES_USE_SSL: false
ES_VERIFY_CERTS: false
Expand All @@ -113,7 +117,7 @@ jobs:
pipenv run pytest -svvv
env:
ENVIRONMENT: testing
ES_PORT: 9400
ES_PORT: 9200
ES_HOST: 172.17.0.1
ES_USE_SSL: false
ES_VERIFY_CERTS: false
Expand Down
14 changes: 13 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,19 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

## [Unreleased]

### Added

- Support for Python 3.12 [#234](https://github.com/stac-utils/stac-fastapi-elasticsearch/pull/234)

### Changed

- Updated stac-fastapi parent libraries to v3.0.0a0 [#234](https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch/pull/234)
- Removed pystac dependency [#234](https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch/pull/234)

### Fixed

- Fixed issue where paginated search queries would return a `next_token` on the last page [#243](https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch/pull/243)

## [v2.4.1]

### Added
Expand All @@ -15,7 +28,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

### Fixed

- Fixed issue where paginated search queries would return a `next_token` on the last page [#243](https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch/pull/243)
- Fixed issue where searches return an empty `links` array [#241](https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch/pull/241)

## [v2.4.0]
Expand Down
2 changes: 1 addition & 1 deletion dockerfiles/Dockerfile.dev.es
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ FROM python:3.10-slim
# update apt pkgs, and install build-essential for ciso8601
RUN apt-get update && \
apt-get -y upgrade && \
apt-get install -y build-essential && \
apt-get install -y build-essential git && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*

Expand Down
18 changes: 9 additions & 9 deletions stac_fastapi/core/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,18 @@
desc = f.read()

install_requires = [
"fastapi",
"attrs",
"pydantic[dotenv]<2",
"stac_pydantic==2.0.*",
"stac-fastapi.types==2.5.5.post1",
"stac-fastapi.api==2.5.5.post1",
"stac-fastapi.extensions==2.5.5.post1",
"pystac[validation]",
"fastapi-slim",
"attrs>=23.2.0",
"pydantic[dotenv]",
"stac_pydantic>=3",
"stac-fastapi.types==3.0.0a",
"stac-fastapi.api==3.0.0a",
"stac-fastapi.extensions==3.0.0a",
"orjson",
"overrides",
"geojson-pydantic",
"pygeofilter==0.2.1",
"typing_extensions==4.4.0",
"typing_extensions==4.8.0",
]

setup(
Expand All @@ -35,6 +34,7 @@
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"License :: OSI Approved :: MIT License",
],
url="https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch",
Expand Down
67 changes: 48 additions & 19 deletions stac_fastapi/core/stac_fastapi/core/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import re
from datetime import datetime as datetime_type
from datetime import timezone
from enum import Enum
from typing import Any, Dict, List, Optional, Set, Type, Union
from urllib.parse import unquote_plus, urljoin

Expand All @@ -14,6 +15,7 @@
from pydantic import ValidationError
from pygeofilter.backends.cql2_json import to_cql2
from pygeofilter.parsers.cql2_text import parse as parse_cql2_text
from stac_pydantic import Collection, Item, ItemCollection
from stac_pydantic.links import Relations
from stac_pydantic.shared import BBox, MimeTypes
from stac_pydantic.version import STAC_VERSION
Expand All @@ -25,7 +27,6 @@
from stac_fastapi.core.session import Session
from stac_fastapi.core.types.core import (
AsyncBaseCoreClient,
AsyncBaseFiltersClient,
AsyncBaseTransactionsClient,
)
from stac_fastapi.extensions.third_party.bulk_transactions import (
Expand All @@ -36,11 +37,11 @@
from stac_fastapi.types import stac as stac_types
from stac_fastapi.types.config import Settings
from stac_fastapi.types.conformance import BASE_CONFORMANCE_CLASSES
from stac_fastapi.types.core import AsyncBaseFiltersClient
from stac_fastapi.types.extension import ApiExtension
from stac_fastapi.types.requests import get_base_url
from stac_fastapi.types.rfc3339 import DateTimeType
from stac_fastapi.types.search import BaseSearchPostRequest
from stac_fastapi.types.stac import Collection, Collections, Item, ItemCollection

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -189,7 +190,7 @@ async def landing_page(self, **kwargs) -> stac_types.LandingPage:

return landing_page

async def all_collections(self, **kwargs) -> Collections:
async def all_collections(self, **kwargs) -> stac_types.Collections:
"""Read all collections from the database.

Args:
Expand Down Expand Up @@ -221,9 +222,11 @@ async def all_collections(self, **kwargs) -> Collections:
next_link = PagingLinks(next=next_token, request=request).link_next()
links.append(next_link)

return Collections(collections=collections, links=links)
return stac_types.Collections(collections=collections, links=links)

async def get_collection(self, collection_id: str, **kwargs) -> Collection:
async def get_collection(
self, collection_id: str, **kwargs
) -> stac_types.Collection:
"""Get a collection from the database by its id.

Args:
Expand All @@ -250,7 +253,7 @@ async def item_collection(
limit: int = 10,
token: str = None,
**kwargs,
) -> ItemCollection:
) -> stac_types.ItemCollection:
"""Read items from a specific collection in the database.

Args:
Expand Down Expand Up @@ -320,14 +323,16 @@ async def item_collection(

links = await PagingLinks(request=request, next=next_token).get_links()

return ItemCollection(
return stac_types.ItemCollection(
type="FeatureCollection",
features=items,
links=links,
context=context_obj,
)

async def get_item(self, item_id: str, collection_id: str, **kwargs) -> Item:
async def get_item(
self, item_id: str, collection_id: str, **kwargs
) -> stac_types.Item:
"""Get an item from the database based on its id and collection id.

Args:
Expand Down Expand Up @@ -399,6 +404,24 @@ def _return_date(

return result

def _format_datetime_range(self, date_tuple: DateTimeType) -> str:
"""
Convert a tuple of datetime objects or None into a formatted string for API requests.

Args:
date_tuple (tuple): A tuple containing two elements, each can be a datetime object or None.

Returns:
str: A string formatted as 'YYYY-MM-DDTHH:MM:SS.sssZ/YYYY-MM-DDTHH:MM:SS.sssZ', with '..' used if any element is None.
"""

def format_datetime(dt):
"""Format a single datetime object to the ISO8601 extended format with 'Z'."""
return dt.strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3] + "Z" if dt else ".."

start, end = date_tuple
return f"{format_datetime(start)}/{format_datetime(end)}"

async def get_search(
self,
request: Request,
Expand All @@ -415,7 +438,7 @@ async def get_search(
filter: Optional[str] = None,
filter_lang: Optional[str] = None,
**kwargs,
) -> ItemCollection:
) -> stac_types.ItemCollection:
"""Get search results from the database.

Args:
Expand Down Expand Up @@ -455,7 +478,7 @@ async def get_search(
filter_lang = match.group(1)

if datetime:
base_args["datetime"] = datetime
base_args["datetime"] = self._format_datetime_range(datetime)

if intersects:
base_args["intersects"] = orjson.loads(unquote_plus(intersects))
Expand Down Expand Up @@ -502,7 +525,7 @@ async def get_search(

async def post_search(
self, search_request: BaseSearchPostRequest, request: Request
) -> ItemCollection:
) -> stac_types.ItemCollection:
"""
Perform a POST search on the catalog.

Expand Down Expand Up @@ -552,8 +575,10 @@ async def post_search(
for field_name, expr in search_request.query.items():
field = "properties__" + field_name
for op, value in expr.items():
# Convert enum to string
operator = op.value if isinstance(op, Enum) else op
search = self.database.apply_stacql_filter(
search=search, op=op, field=field, value=value
search=search, op=operator, field=field, value=value
)

# only cql2_json is supported here
Expand Down Expand Up @@ -619,7 +644,7 @@ async def post_search(

links = await PagingLinks(request=request, next=next_token).get_links()

return ItemCollection(
return stac_types.ItemCollection(
type="FeatureCollection",
features=items,
links=links,
Expand All @@ -637,7 +662,7 @@ class TransactionsClient(AsyncBaseTransactionsClient):

@overrides
async def create_item(
self, collection_id: str, item: stac_types.Item, **kwargs
self, collection_id: str, item: Union[Item, ItemCollection], **kwargs
) -> Optional[stac_types.Item]:
"""Create an item in the collection.

Expand All @@ -654,6 +679,7 @@ async def create_item(
ConflictError: If the item in the specified collection already exists.

"""
item = item.model_dump(mode="json")
base_url = str(kwargs["request"].base_url)

# If a feature collection is posted
Expand All @@ -677,7 +703,7 @@ async def create_item(

@overrides
async def update_item(
self, collection_id: str, item_id: str, item: stac_types.Item, **kwargs
self, collection_id: str, item_id: str, item: Item, **kwargs
) -> stac_types.Item:
"""Update an item in the collection.

Expand All @@ -694,13 +720,14 @@ async def update_item(
NotFound: If the specified collection is not found in the database.

"""
item = item.model_dump(mode="json")
base_url = str(kwargs["request"].base_url)
now = datetime_type.now(timezone.utc).isoformat().replace("+00:00", "Z")
item["properties"]["updated"] = now

await self.database.check_collection_exists(collection_id)
await self.delete_item(item_id=item_id, collection_id=collection_id)
await self.create_item(collection_id=collection_id, item=item, **kwargs)
await self.create_item(collection_id=collection_id, item=Item(**item), **kwargs)

return ItemSerializer.db_to_stac(item, base_url)

Expand All @@ -722,7 +749,7 @@ async def delete_item(

@overrides
async def create_collection(
self, collection: stac_types.Collection, **kwargs
self, collection: Collection, **kwargs
) -> stac_types.Collection:
"""Create a new collection in the database.

Expand All @@ -736,17 +763,17 @@ async def create_collection(
Raises:
ConflictError: If the collection already exists.
"""
collection = collection.model_dump(mode="json")
base_url = str(kwargs["request"].base_url)
collection = self.database.collection_serializer.stac_to_db(
collection, base_url
)
await self.database.create_collection(collection=collection)

return CollectionSerializer.db_to_stac(collection, base_url)

@overrides
async def update_collection(
self, collection: stac_types.Collection, **kwargs
self, collection: Collection, **kwargs
) -> stac_types.Collection:
"""
Update a collection.
Expand All @@ -766,6 +793,8 @@ async def update_collection(
A STAC collection that has been updated in the database.

"""
collection = collection.model_dump(mode="json")

base_url = str(kwargs["request"].base_url)

collection_id = kwargs["request"].query_params.get(
Expand Down
Loading