Skip to content

Commit f1be9c3

Browse files
Merge branch 'main' into dependabot/github_actions/all-4c0b306cda
2 parents 6a52f8c + ffcc60b commit f1be9c3

File tree

5 files changed

+59
-7
lines changed

5 files changed

+59
-7
lines changed

CHANGES.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## [Unreleased]
44

5+
### Fixed
6+
7+
- avoid pydantic validation for `/collections` response when using `fields` extension ([#326](https://github.com/stac-utils/stac-fastapi-pgstac/pull/326))
8+
59
## [6.1.2] - 2025-11-24
610

711
### Changed

Dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ RUN python -m pip install -U pip
1919
WORKDIR /app
2020

2121
COPY stac_fastapi/ stac_fastapi/
22+
COPY scripts/wait-for-it.sh scripts/wait-for-it.sh
2223
COPY pyproject.toml pyproject.toml
2324
COPY README.md README.md
2425

docker-compose.yml

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,9 @@ services:
2222
- ENABLE_TRANSACTIONS_EXTENSIONS=TRUE
2323
ports:
2424
- "8082:8082"
25-
volumes:
26-
- ./scripts:/tmp/scripts
2725
depends_on:
2826
- database
29-
command: bash -c "/tmp/scripts/wait-for-it.sh database:5432 && python -m stac_fastapi.pgstac.app"
27+
command: bash -c "scripts/wait-for-it.sh database:5432 && python -m stac_fastapi.pgstac.app"
3028
develop:
3129
watch:
3230
- action: rebuild
@@ -67,7 +65,7 @@ services:
6765
- ./scripts:/tmp/scripts
6866
command: >
6967
/bin/sh -c "
70-
/tmp/scripts/wait-for-it.sh -t 60 app:8082 &&
68+
scripts/wait-for-it.sh -t 60 app:8082 &&
7169
python -m pip install pip -U &&
7270
python -m pip install requests &&
7371
python /tmp/scripts/ingest_joplin.py http://app:8082
@@ -91,7 +89,7 @@ services:
9189
service: app
9290
command: >
9391
bash -c "
94-
/tmp/scripts/wait-for-it.sh database:5432 &&
92+
scripts/wait-for-it.sh database:5432 &&
9593
uvicorn stac_fastapi.pgstac.app:app --host 0.0.0.0 --port 8082 --proxy-headers --forwarded-allow-ips=* --root-path=/api/v1/pgstac
9694
"
9795

stac_fastapi/pgstac/core.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ async def all_collections( # noqa: C901
150150
prev=prev_link,
151151
).get_links()
152152

153-
return Collections(
153+
collections = Collections(
154154
collections=linked_collections or [],
155155
links=links,
156156
numberMatched=collections_result.get(
@@ -161,6 +161,14 @@ async def all_collections( # noqa: C901
161161
),
162162
)
163163

164+
# If we have the `fields` extension enabled
165+
# we need to avoid Pydantic validation because the
166+
# Items might not be a valid STAC Item objects
167+
if fields:
168+
return JSONResponse(collections) # type: ignore
169+
170+
return collections
171+
164172
async def get_collection(
165173
self,
166174
collection_id: str,
@@ -617,7 +625,7 @@ def _clean_search_args( # noqa: C901
617625
else:
618626
includes.add(field)
619627

620-
base_args["fields"] = {"include": includes, "exclude": excludes}
628+
base_args["fields"] = {"include": list(includes), "exclude": list(excludes)}
621629

622630
if q:
623631
base_args["q"] = q

tests/api/test_api.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,47 @@ async def test_app_query_extension_gte(load_test_data, app_client, load_test_col
271271
assert len(resp_json["features"]) == 1
272272

273273

274+
async def test_app_collection_fields_extension(
275+
load_test_data, app_client, load_test_collection, app
276+
):
277+
fields = ["title"]
278+
resp = await app_client.get("/collections", params={"fields": ",".join(fields)})
279+
280+
assert resp.status_code == 200
281+
282+
resp_json = resp.json()
283+
resp_collections = resp_json["collections"]
284+
285+
assert len(resp_collections) > 0
286+
# NOTE: It's a bug that 'collection' is always included; see #327
287+
constant_fields = ["id", "links", "collection"]
288+
for collection in resp_collections:
289+
assert set(collection.keys()) == set(fields + constant_fields)
290+
291+
292+
async def test_app_item_fields_extension(
293+
load_test_data, app_client, load_test_collection, load_test_item, app
294+
):
295+
coll = load_test_collection
296+
fields = ["id", "geometry"]
297+
resp = await app_client.get(
298+
f"/collections/{coll['id']}/items", params={"fields": ",".join(fields)}
299+
)
300+
301+
assert resp.status_code == 200
302+
303+
resp_json = resp.json()
304+
features = resp_json["features"]
305+
306+
assert len(features) > 0
307+
# These fields are always included in items
308+
constant_fields = ["id", "links"]
309+
if not app.state.settings.use_api_hydrate:
310+
constant_fields.append("collection")
311+
for item in features:
312+
assert set(item.keys()) == set(fields + constant_fields)
313+
314+
274315
async def test_app_sort_extension(load_test_data, app_client, load_test_collection):
275316
coll = load_test_collection
276317
first_item = load_test_data("test_item.json")

0 commit comments

Comments
 (0)