From c3fb492309b7a52c1a725af36a39df21b244b4ba Mon Sep 17 00:00:00 2001 From: Zoe Statman-Weil Date: Tue, 6 Aug 2024 14:31:52 -0700 Subject: [PATCH 1/8] expand pagination to work with pgstac 0.9.X --- stac_fastapi/pgstac/core.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/stac_fastapi/pgstac/core.py b/stac_fastapi/pgstac/core.py index 648d42a1..e9bdda62 100644 --- a/stac_fastapi/pgstac/core.py +++ b/stac_fastapi/pgstac/core.py @@ -1,4 +1,5 @@ """Item crud client.""" +import logging import re from typing import Any, Dict, List, Optional, Set, Union @@ -204,8 +205,17 @@ async def _search_base( # noqa: C901 f"Datetime parameter {search_request.datetime} is invalid." ) from e - next: Optional[str] = items.pop("next", None) - prev: Optional[str] = items.pop("prev", None) + # Starting in pgstac 0.9.0, the `next` and `prev` tokens are returned in spec-compliant links with method GET + next_from_link: Optional[str] = None + prev_from_link: Optional[str] = None + for link in items.get("links", []): + if link.get("rel") == "next": + next_from_link = link.get("href").split("token=next:")[1] + if link.get("rel") == "prev": + prev_from_link = link.get("href").split("token=prev:")[1] + + next: Optional[str] = items.pop("next", next_from_link) + prev: Optional[str] = items.pop("prev", prev_from_link) collection = ItemCollection(**items) fields = getattr(search_request, "fields", None) From 8c7a710b4853f928b535d6cd280a5132f19ef516 Mon Sep 17 00:00:00 2001 From: Zoe Statman-Weil Date: Tue, 6 Aug 2024 14:35:32 -0700 Subject: [PATCH 2/8] pre-commit fixes --- stac_fastapi/pgstac/core.py | 1 - 1 file changed, 1 deletion(-) diff --git a/stac_fastapi/pgstac/core.py b/stac_fastapi/pgstac/core.py index e9bdda62..9a41f4f7 100644 --- a/stac_fastapi/pgstac/core.py +++ b/stac_fastapi/pgstac/core.py @@ -1,5 +1,4 @@ """Item crud client.""" -import logging import re from typing import Any, Dict, List, Optional, Set, Union From d7cc21986426ea093a8bb704ac3bb9ed69f17d83 Mon Sep 17 00:00:00 2001 From: Zoe Statman-Weil Date: Tue, 6 Aug 2024 14:56:57 -0700 Subject: [PATCH 3/8] add changes to log --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index 1995e07a..5cd0f341 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -4,6 +4,7 @@ - Enable filter extension for `GET /items` requests and add `Queryables` links in `/collections` and `/collections/{collection_id}` responses ([#89](https://github.com/stac-utils/stac-fastapi-pgstac/pull/89)) - Allow to omit `collection` in bulk item insertions. Same identifier checks as with single insertions ([#113](https://github.com/stac-utils/stac-fastapi-pgstac/pull/113)) +- Handle `next` and `dev` tokens now returned as links from pgstac>=0.9.0 ## [3.0.0a4] - 2024-07-10 From b1e6a91b01b8b27dea9f2c5a83d02fc8593744c1 Mon Sep 17 00:00:00 2001 From: vincentsarago Date: Thu, 26 Sep 2024 11:09:14 +0200 Subject: [PATCH 4/8] update pypgstac version in test dependencies --- CHANGES.md | 3 +-- setup.py | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 6b960355..26a91524 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -3,8 +3,7 @@ ## [Unreleased] - Fix Docker compose file, so example data can be loaded into database (author @zstatmanweil, https://github.com/stac-utils/stac-fastapi-pgstac/pull/142) -- Handle `next` and `dev` tokens now returned as links from pgstac>=0.9.0 - +- Handle `next` and `dev` tokens now returned as links from pgstac>=0.9.0 (author @zstatmanweil, https://github.com/stac-utils/stac-fastapi-pgstac/pull/140) - Fix `filter` extension implementation in `CoreCrudClient` ## [3.0.0] - 2024-08-02 diff --git a/setup.py b/setup.py index 76b52893..3736af05 100644 --- a/setup.py +++ b/setup.py @@ -23,7 +23,7 @@ extra_reqs = { "dev": [ "pystac[validation]", - "pypgstac[psycopg]==0.8.*", + "pypgstac[psycopg]==0.9.*", "pytest-postgresql", "pytest", "pytest-cov", From 965e5a814f4035d7ca6ba59948ce266e0b3b1de9 Mon Sep 17 00:00:00 2001 From: vincentsarago Date: Thu, 26 Sep 2024 11:11:46 +0200 Subject: [PATCH 5/8] update pypgstac version --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 3736af05..c7ec8ba1 100644 --- a/setup.py +++ b/setup.py @@ -17,7 +17,7 @@ "buildpg", "brotli_asgi", "pygeofilter>=0.2", - "pypgstac==0.8.*", + "pypgstac>=0.8,<0.10", ] extra_reqs = { From d91d155c877a52c2f850747288aefaa09933b712 Mon Sep 17 00:00:00 2001 From: vincentsarago Date: Mon, 7 Oct 2024 21:43:12 +0200 Subject: [PATCH 6/8] update from main (collection-search) --- .dockerignore | 4 +- .github/workflows/cicd.yaml | 2 +- CHANGES.md | 3 + docker-compose.yml | 2 +- setup.py | 6 +- stac_fastapi/pgstac/app.py | 39 ++++-- stac_fastapi/pgstac/core.py | 207 +++++++++++++++++++---------- tests/api/test_api.py | 64 ++++++++- tests/conftest.py | 8 +- tests/resources/test_collection.py | 27 ++++ 10 files changed, 271 insertions(+), 91 deletions(-) diff --git a/.dockerignore b/.dockerignore index e187e45a..ddfce7a0 100644 --- a/.dockerignore +++ b/.dockerignore @@ -9,5 +9,7 @@ coverage.xml *.log .git .envrc +*egg-info -venv \ No newline at end of file +venv +env diff --git a/.github/workflows/cicd.yaml b/.github/workflows/cicd.yaml index 2618036c..d4a03663 100644 --- a/.github/workflows/cicd.yaml +++ b/.github/workflows/cicd.yaml @@ -47,7 +47,7 @@ jobs: runs-on: ubuntu-latest services: pgstac: - image: ghcr.io/stac-utils/pgstac:v0.7.10 + image: ghcr.io/stac-utils/pgstac:v0.8.6 env: POSTGRES_USER: username POSTGRES_PASSWORD: password diff --git a/CHANGES.md b/CHANGES.md index 26a91524..7fdd6a50 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -4,7 +4,10 @@ - Fix Docker compose file, so example data can be loaded into database (author @zstatmanweil, https://github.com/stac-utils/stac-fastapi-pgstac/pull/142) - Handle `next` and `dev` tokens now returned as links from pgstac>=0.9.0 (author @zstatmanweil, https://github.com/stac-utils/stac-fastapi-pgstac/pull/140) +- Add collection search extension ([#139](https://github.com/stac-utils/stac-fastapi-pgstac/pull/139)) - Fix `filter` extension implementation in `CoreCrudClient` +- update `pypgstac` requirement to `>=0.8,<0.10` +- set `pypgstac==0.9.*` for test requirements ## [3.0.0] - 2024-08-02 diff --git a/docker-compose.yml b/docker-compose.yml index ec1080aa..02158a68 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -44,7 +44,7 @@ services: database: container_name: stac-db - image: ghcr.io/stac-utils/pgstac:v0.8.5 + image: ghcr.io/stac-utils/pgstac:v0.9.1 environment: - POSTGRES_USER=username - POSTGRES_PASSWORD=password diff --git a/setup.py b/setup.py index c7ec8ba1..e9abcae2 100644 --- a/setup.py +++ b/setup.py @@ -10,9 +10,9 @@ "orjson", "pydantic", "stac_pydantic==3.1.*", - "stac-fastapi.api~=3.0", - "stac-fastapi.extensions~=3.0", - "stac-fastapi.types~=3.0", + "stac-fastapi.api~=3.0.2", + "stac-fastapi.extensions~=3.0.2", + "stac-fastapi.types~=3.0.2", "asyncpg", "buildpg", "brotli_asgi", diff --git a/stac_fastapi/pgstac/app.py b/stac_fastapi/pgstac/app.py index 924ea01f..5e28cd09 100644 --- a/stac_fastapi/pgstac/app.py +++ b/stac_fastapi/pgstac/app.py @@ -10,6 +10,7 @@ from fastapi.responses import ORJSONResponse from stac_fastapi.api.app import StacApi from stac_fastapi.api.models import ( + EmptyRequest, ItemCollectionUri, create_get_request_model, create_post_request_model, @@ -22,6 +23,7 @@ TokenPaginationExtension, TransactionExtension, ) +from stac_fastapi.extensions.core.collection_search import CollectionSearchExtension from stac_fastapi.extensions.third_party import BulkTransactionExtension from stac_fastapi.pgstac.config import Settings @@ -47,34 +49,49 @@ "bulk_transactions": BulkTransactionExtension(client=BulkTransactionsClient()), } -if enabled_extensions := os.getenv("ENABLED_EXTENSIONS"): - extensions = [ - extensions_map[extension_name] for extension_name in enabled_extensions.split(",") - ] -else: - extensions = list(extensions_map.values()) +enabled_extensions = ( + os.environ["ENABLED_EXTENSIONS"].split(",") + if "ENABLED_EXTENSIONS" in os.environ + else list(extensions_map.keys()) + ["collection_search"] +) +extensions = [ + extension for key, extension in extensions_map.items() if key in enabled_extensions +] -if any(isinstance(ext, TokenPaginationExtension) for ext in extensions): - items_get_request_model = create_request_model( +items_get_request_model = ( + create_request_model( model_name="ItemCollectionUri", base_model=ItemCollectionUri, mixins=[TokenPaginationExtension().GET], request_type="GET", ) -else: - items_get_request_model = ItemCollectionUri + if any(isinstance(ext, TokenPaginationExtension) for ext in extensions) + else ItemCollectionUri +) + +collection_search_extension = ( + CollectionSearchExtension.from_extensions(extensions) + if "collection_search" in enabled_extensions + else None +) +collections_get_request_model = ( + collection_search_extension.GET if collection_search_extension else EmptyRequest +) post_request_model = create_post_request_model(extensions, base_model=PgstacSearch) get_request_model = create_get_request_model(extensions) api = StacApi( settings=settings, - extensions=extensions, + extensions=extensions + [collection_search_extension] + if collection_search_extension + else extensions, client=CoreCrudClient(post_request_model=post_request_model), # type: ignore response_class=ORJSONResponse, items_get_request_model=items_get_request_model, search_get_request_model=get_request_model, search_post_request_model=post_request_model, + collections_get_request_model=collections_get_request_model, ) app = api.app diff --git a/stac_fastapi/pgstac/core.py b/stac_fastapi/pgstac/core.py index 00778c4e..0917ab16 100644 --- a/stac_fastapi/pgstac/core.py +++ b/stac_fastapi/pgstac/core.py @@ -1,5 +1,6 @@ """Item crud client.""" +import json import re from typing import Any, Dict, List, Optional, Set, Union from urllib.parse import unquote_plus, urljoin @@ -14,12 +15,11 @@ from pygeofilter.parsers.cql2_text import parse as parse_cql2_text from pypgstac.hydration import hydrate from stac_fastapi.api.models import JSONResponse -from stac_fastapi.types.core import AsyncBaseCoreClient +from stac_fastapi.types.core import AsyncBaseCoreClient, Relations 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 BBox, MimeTypes from stac_fastapi.pgstac.config import Settings @@ -39,17 +39,66 @@ class CoreCrudClient(AsyncBaseCoreClient): """Client for core endpoints defined by stac.""" - async def all_collections(self, request: Request, **kwargs) -> Collections: - """Read all collections from the database.""" + async def all_collections( # noqa: C901 + self, + request: Request, + # Extensions + bbox: Optional[BBox] = None, + datetime: Optional[DateTimeType] = None, + limit: Optional[int] = None, + query: Optional[str] = None, + token: Optional[str] = None, + fields: Optional[List[str]] = None, + sortby: Optional[str] = None, + filter: Optional[str] = None, + filter_lang: Optional[str] = None, + **kwargs, + ) -> Collections: + """Cross catalog search (GET). + + Called with `GET /collections`. + + Returns: + Collections which match the search criteria, returns all + collections by default. + """ base_url = get_base_url(request) + # Parse request parameters + base_args = { + "bbox": bbox, + "limit": limit, + "token": token, + "query": orjson.loads(unquote_plus(query)) if query else query, + } + + clean_args = clean_search_args( + base_args=base_args, + datetime=datetime, + fields=fields, + sortby=sortby, + filter_query=filter, + filter_lang=filter_lang, + ) + async with request.app.state.get_connection(request, "r") as conn: - collections = await conn.fetchval( - """ - SELECT * FROM all_collections(); + q, p = render( """ + SELECT * FROM collection_search(:req::text::jsonb); + """, + req=json.dumps(clean_args), ) + collections_result: Collections = await conn.fetchval(q, *p) + + next: Optional[str] = None + prev: Optional[str] = None + + if links := collections_result.get("links"): + next = collections_result["links"].pop("next") + prev = collections_result["links"].pop("prev") + linked_collections: List[Collection] = [] + collections = collections_result["collections"] if collections is not None and len(collections) > 0: for c in collections: coll = Collection(**c) @@ -71,25 +120,16 @@ async def all_collections(self, request: Request, **kwargs) -> Collections: linked_collections.append(coll) - links = [ - { - "rel": Relations.root.value, - "type": MimeTypes.json, - "href": base_url, - }, - { - "rel": Relations.parent.value, - "type": MimeTypes.json, - "href": base_url, - }, - { - "rel": Relations.self.value, - "type": MimeTypes.json, - "href": urljoin(base_url, "collections"), - }, - ] - collection_list = Collections(collections=linked_collections or [], links=links) - return collection_list + links = await PagingLinks( + request=request, + next=next, + prev=prev, + ).get_links() + + return Collections( + collections=linked_collections or [], + links=links, + ) async def get_collection( self, collection_id: str, request: Request, **kwargs @@ -395,7 +435,7 @@ async def post_search( return ItemCollection(**item_collection) - async def get_search( # noqa: C901 + async def get_search( self, request: Request, collections: Optional[List[str]] = None, @@ -430,51 +470,15 @@ async def get_search( # noqa: C901 "query": orjson.loads(unquote_plus(query)) if query else query, } - if filter: - if filter_lang == "cql2-text": - filter = to_cql2(parse_cql2_text(filter)) - filter_lang = "cql2-json" - - base_args["filter"] = orjson.loads(filter) - base_args["filter-lang"] = filter_lang - - if datetime: - base_args["datetime"] = format_datetime_range(datetime) - - if intersects: - base_args["intersects"] = orjson.loads(unquote_plus(intersects)) - - if sortby: - # https://github.com/radiantearth/stac-spec/tree/master/api-spec/extensions/sort#http-get-or-post-form - sort_param = [] - for sort in sortby: - sortparts = re.match(r"^([+-]?)(.*)$", sort) - if sortparts: - sort_param.append( - { - "field": sortparts.group(2).strip(), - "direction": "desc" if sortparts.group(1) == "-" else "asc", - } - ) - base_args["sortby"] = sort_param - - if fields: - includes = set() - excludes = set() - for field in fields: - if field[0] == "-": - excludes.add(field[1:]) - elif field[0] == "+": - includes.add(field[1:]) - else: - includes.add(field) - base_args["fields"] = {"include": includes, "exclude": excludes} - - # Remove None values from dict - clean = {} - for k, v in base_args.items(): - if v is not None and v != []: - clean[k] = v + clean = clean_search_args( + base_args=base_args, + intersects=intersects, + datetime=datetime, + fields=fields, + sortby=sortby, + filter_query=filter, + filter_lang=filter_lang, + ) # Do the request try: @@ -485,3 +489,62 @@ async def get_search( # noqa: C901 ) from e return await self.post_search(search_request, request=request) + + +def clean_search_args( # noqa: C901 + base_args: Dict[str, Any], + intersects: Optional[str] = None, + datetime: Optional[DateTimeType] = None, + fields: Optional[List[str]] = None, + sortby: Optional[str] = None, + filter_query: Optional[str] = None, + filter_lang: Optional[str] = None, +) -> Dict[str, Any]: + """Clean up search arguments to match format expected by pgstac""" + if filter_query: + if filter_lang == "cql2-text": + filter_query = to_cql2(parse_cql2_text(filter_query)) + filter_lang = "cql2-json" + + base_args["filter"] = orjson.loads(filter_query) + base_args["filter_lang"] = filter_lang + + if datetime: + base_args["datetime"] = format_datetime_range(datetime) + + if intersects: + base_args["intersects"] = orjson.loads(unquote_plus(intersects)) + + if sortby: + # https://github.com/radiantearth/stac-spec/tree/master/api-spec/extensions/sort#http-get-or-post-form + sort_param = [] + for sort in sortby: + sortparts = re.match(r"^([+-]?)(.*)$", sort) + if sortparts: + sort_param.append( + { + "field": sortparts.group(2).strip(), + "direction": "desc" if sortparts.group(1) == "-" else "asc", + } + ) + base_args["sortby"] = sort_param + + if fields: + includes = set() + excludes = set() + for field in fields: + if field[0] == "-": + excludes.add(field[1:]) + elif field[0] == "+": + includes.add(field[1:]) + else: + includes.add(field) + base_args["fields"] = {"include": includes, "exclude": excludes} + + # Remove None values from dict + clean = {} + for k, v in base_args.items(): + if v is not None and v != []: + clean[k] = v + + return clean diff --git a/tests/api/test_api.py b/tests/api/test_api.py index 2077c352..b135dce5 100644 --- a/tests/api/test_api.py +++ b/tests/api/test_api.py @@ -12,7 +12,11 @@ from pystac import Collection, Extent, Item, SpatialExtent, TemporalExtent from stac_fastapi.api.app import StacApi from stac_fastapi.api.models import create_get_request_model, create_post_request_model -from stac_fastapi.extensions.core import FieldsExtension, TransactionExtension +from stac_fastapi.extensions.core import ( + CollectionSearchExtension, + FieldsExtension, + TransactionExtension, +) from stac_fastapi.types import stac as stac_types from stac_fastapi.pgstac.core import CoreCrudClient, Settings @@ -502,6 +506,49 @@ async def test_collection_queryables(load_test_data, app_client, load_test_colle assert "id" in q["properties"] +@pytest.mark.asyncio +async def test_get_collections_search( + app_client, load_test_collection, load_test2_collection +): + # this search should only return a single collection + resp = await app_client.get( + "/collections", + params={"datetime": "2010-01-01T00:00:00Z/2010-01-02T00:00:00Z"}, + ) + assert len(resp.json()["collections"]) == 1 + assert resp.json()["collections"][0]["id"] == load_test2_collection.id + + # same with this one + resp = await app_client.get( + "/collections", + params={"datetime": "2020-01-01T00:00:00Z/.."}, + ) + assert len(resp.json()["collections"]) == 1 + assert resp.json()["collections"][0]["id"] == load_test_collection["id"] + + # no params should return both collections + resp = await app_client.get( + "/collections", + ) + assert len(resp.json()["collections"]) == 2 + + # this search should return test collection 1 first + resp = await app_client.get( + "/collections", + params={"sortby": "title"}, + ) + assert resp.json()["collections"][0]["id"] == load_test_collection["id"] + assert resp.json()["collections"][1]["id"] == load_test2_collection.id + + # this search should return test collection 2 first + resp = await app_client.get( + "/collections", + params={"sortby": "-title"}, + ) + assert resp.json()["collections"][1]["id"] == load_test_collection["id"] + assert resp.json()["collections"][0]["id"] == load_test2_collection.id + + @pytest.mark.asyncio async def test_item_collection_filter_bbox( load_test_data, app_client, load_test_collection @@ -683,12 +730,18 @@ async def get_collection( ] post_request_model = create_post_request_model(extensions, base_model=PgstacSearch) get_request_model = create_get_request_model(extensions) + + collection_search_extension = CollectionSearchExtension.from_extensions( + extensions=extensions + ) + api = StacApi( client=Client(post_request_model=post_request_model), settings=settings, extensions=extensions, search_post_request_model=post_request_model, search_get_request_model=get_request_model, + collections_get_request_model=collection_search_extension.GET, ) app = api.app await connect_to_db(app) @@ -760,6 +813,15 @@ async def test_no_extension( collections = await client.get("http://test/collections") assert collections.status_code == 200, collections.text + # datetime should be ignored + collection_datetime = await client.get( + "http://test/collections/test-collection", + params={ + "datetime": "2000-01-01T00:00:00Z/2000-12-31T00:00:00Z", + }, + ) + assert collection_datetime.text == collection.text + item = await client.get( "http://test/collections/test-collection/items/test-item" ) diff --git a/tests/conftest.py b/tests/conftest.py index e5955b75..fc63514f 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -23,6 +23,7 @@ create_request_model, ) from stac_fastapi.extensions.core import ( + CollectionSearchExtension, FieldsExtension, FilterExtension, SortExtension, @@ -133,6 +134,7 @@ def api_client(request, database): FilterExtension(client=FiltersClient()), BulkTransactionExtension(client=BulkTransactionsClient()), ] + collection_search_extension = CollectionSearchExtension.from_extensions(extensions) items_get_request_model = create_request_model( model_name="ItemCollectionUri", @@ -147,13 +149,17 @@ def api_client(request, database): search_post_request_model = create_post_request_model( extensions, base_model=PgstacSearch ) + + collections_get_request_model = collection_search_extension.GET + api = StacApi( settings=api_settings, - extensions=extensions, + extensions=extensions + [collection_search_extension], client=CoreCrudClient(post_request_model=search_post_request_model), items_get_request_model=items_get_request_model, search_get_request_model=search_get_request_model, search_post_request_model=search_post_request_model, + collections_get_request_model=collections_get_request_model, response_class=ORJSONResponse, router=APIRouter(prefix=prefix), ) diff --git a/tests/resources/test_collection.py b/tests/resources/test_collection.py index 3a2183b1..634747bc 100644 --- a/tests/resources/test_collection.py +++ b/tests/resources/test_collection.py @@ -276,3 +276,30 @@ async def test_get_collections_queryables_links(app_client, load_test_collection f"/collections/{collection_id}", ) assert "Queryables" in [link.get("title") for link in resp.json()["links"]] + + +@pytest.mark.asyncio +async def test_get_collections_search( + app_client, load_test_collection, load_test2_collection +): + # this search should only return a single collection + resp = await app_client.get( + "/collections", + params={"datetime": "2010-01-01T00:00:00Z/2010-01-02T00:00:00Z"}, + ) + assert len(resp.json()["collections"]) == 1 + assert resp.json()["collections"][0]["id"] == load_test2_collection.id + + # same with this one + resp = await app_client.get( + "/collections", + params={"datetime": "2020-01-01T00:00:00Z/.."}, + ) + assert len(resp.json()["collections"]) == 1 + assert resp.json()["collections"][0]["id"] == load_test_collection["id"] + + # no params should return both collections + resp = await app_client.get( + "/collections", + ) + assert len(resp.json()["collections"]) == 2 From fc9abcb7025e7bd6b30d5c624811214874b9701a Mon Sep 17 00:00:00 2001 From: vincentsarago Date: Mon, 14 Oct 2024 17:32:43 +0200 Subject: [PATCH 7/8] fix --- tests/conftest.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/conftest.py b/tests/conftest.py index 2bdcc0be..e571cae6 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -134,7 +134,6 @@ def api_client(request, database): FilterExtension(client=FiltersClient()), BulkTransactionExtension(client=BulkTransactionsClient()), ] - collection_search_extension = CollectionSearchExtension.from_extensions(extensions) collection_extensions = [ QueryExtension(), From 1b3e871a4aa80a47fe115b3e6969bc902a68f6a6 Mon Sep 17 00:00:00 2001 From: vincentsarago Date: Mon, 14 Oct 2024 17:41:49 +0200 Subject: [PATCH 8/8] update ci to test pgstac 0.8 and 0.9 --- .github/workflows/cicd.yaml | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/.github/workflows/cicd.yaml b/.github/workflows/cicd.yaml index d4a03663..0ae6f963 100644 --- a/.github/workflows/cicd.yaml +++ b/.github/workflows/cicd.yaml @@ -11,7 +11,13 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] + include: + - {python: '3.12', pypgstac: '0.9.*'} + - {python: '3.12', pypgstac: '0.8.*'} + - {python: '3.11', pypgstac: '0.8.*'} + - {python: '3.9', pypgstac: '0.8.*'} + - {python: '3.8', pypgstac: '0.8.*'} + timeout-minutes: 20 steps: @@ -22,12 +28,12 @@ jobs: - name: Setup Python uses: actions/setup-python@v5 with: - python-version: ${{ matrix.python-version }} + python-version: ${{ matrix.python }} cache: pip cache-dependency-path: setup.py - name: Lint code - if: ${{ matrix.python-version == 3.11 }} + if: ${{ matrix.python == 3.11 }} run: | python -m pip install pre-commit pre-commit run --all-files @@ -39,6 +45,7 @@ jobs: run: | python -m pip install --upgrade pip python -m pip install .[dev,server] + python -m pip install "pypgstac==${{ matrix.pypgstac }}" - name: Run test suite run: python -m pytest --cov stac_fastapi.pgstac --cov-report xml --cov-report term-missing