Skip to content

Commit

Permalink
Fix PUT collections (#666)
Browse files Browse the repository at this point in the history
Co-authored-by: Arjan van Bentem <[email protected]>
Co-authored-by: Jonathan Healy <[email protected]>
  • Loading branch information
3 people authored Apr 24, 2024
1 parent 0bd592e commit 108fc2c
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 22 deletions.
3 changes: 2 additions & 1 deletion CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@

### Fixed

* Fix missing payload for the PUT `collection/{collection_id}` endpoint ([#665](https://github.com/stac-utils/stac-fastapi/issues/665))
* Return 400 for datetime errors ([#670](https://github.com/stac-utils/stac-fastapi/pull/670))

## [2.5.3] - 2024-04-23

### Fixed
### Fixed

* Remove the str2list converter from intersection queries via BaseSearchGetRequest ([#668](https://github.com/stac-utils/stac-fastapi/pull/668))
* Apply datetime converter in ItemCollection endpoint model ([#667](https://github.com/stac-utils/stac-fastapi/pull/667))
Expand Down
4 changes: 2 additions & 2 deletions stac_fastapi/api/stac_fastapi/api/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,14 +103,14 @@ def create_post_request_model(

@attr.s # type:ignore
class CollectionUri(APIRequest):
"""Delete collection."""
"""Get or delete collection."""

collection_id: str = attr.ib(default=Path(..., description="Collection ID"))


@attr.s
class ItemUri(CollectionUri):
"""Delete item."""
"""Get or delete item."""

item_id: str = attr.ib(default=Path(..., description="Item ID"))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ class PutItem(ItemUri):
item: stac_types.Item = attr.ib(default=Body(None))


@attr.s
class PutCollection(CollectionUri):
"""Update Collection."""

collection: stac_types.Collection = attr.ib(default=Body(None))


@attr.s
class TransactionExtension(ApiExtension):
"""Transaction Extension.
Expand Down Expand Up @@ -128,7 +135,7 @@ def register_update_collection(self):
response_model_exclude_none=True,
methods=["PUT"],
endpoint=create_async_endpoint(
self.client.update_collection, stac_types.Collection
self.client.update_collection, PutCollection
),
)

Expand Down
87 changes: 73 additions & 14 deletions stac_fastapi/extensions/tests/test_transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from stac_fastapi.extensions.core import TransactionExtension
from stac_fastapi.types.config import ApiSettings
from stac_fastapi.types.core import BaseCoreClient, BaseTransactionsClient
from stac_fastapi.types.stac import Item, ItemCollection
from stac_fastapi.types.stac import Collection, Item, ItemCollection


class DummyCoreClient(BaseCoreClient):
Expand All @@ -32,25 +32,32 @@ def item_collection(self, *args, **kwargs):


class DummyTransactionsClient(BaseTransactionsClient):
"""Defines a pattern for implementing the STAC transaction extension."""
"""Dummy client returning parts of the request, rather than proper STAC items."""

def create_item(self, item: Union[Item, ItemCollection], *args, **kwargs):
return {"created": True, "type": item["type"]}
def create_item(self, item: Union[Item, ItemCollection], **kwargs):
return {"type": item["type"]}

def update_item(self, *args, **kwargs):
raise NotImplementedError
def update_item(self, collection_id: str, item_id: str, item: Item, **kwargs):
return {
"path_collection_id": collection_id,
"path_item_id": item_id,
"type": item["type"],
}

def delete_item(self, *args, **kwargs):
raise NotImplementedError
def delete_item(self, item_id: str, collection_id: str, **kwargs):
return {
"path_collection_id": collection_id,
"path_item_id": item_id,
}

def create_collection(self, *args, **kwargs):
raise NotImplementedError
def create_collection(self, collection: Collection, **kwargs):
return {"type": collection["type"]}

def update_collection(self, *args, **kwargs):
raise NotImplementedError
def update_collection(self, collection_id: str, collection: Collection, **kwargs):
return {"path_collection_id": collection_id, "type": collection["type"]}

def delete_collection(self, *args, **kwargs):
raise NotImplementedError
def delete_collection(self, collection_id: str, **kwargs):
return {"path_collection_id": collection_id}


def test_create_item(client: TestClient, item: Item) -> None:
Expand All @@ -69,6 +76,42 @@ def test_create_item_collection(
assert response.json()["type"] == "FeatureCollection"


def test_update_item(client: TestClient, item: Item) -> None:
response = client.put(
"/collections/a-collection/items/an-item", content=json.dumps(item)
)
assert response.is_success, response.text
assert response.json()["path_collection_id"] == "a-collection"
assert response.json()["path_item_id"] == "an-item"
assert response.json()["type"] == "Feature"


def test_delete_item(client: TestClient) -> None:
response = client.delete("/collections/a-collection/items/an-item")
assert response.is_success, response.text
assert response.json()["path_collection_id"] == "a-collection"
assert response.json()["path_item_id"] == "an-item"


def test_create_collection(client: TestClient, collection: Collection) -> None:
response = client.post("/collections", content=json.dumps(collection))
assert response.is_success, response.text
assert response.json()["type"] == "Collection"


def test_update_collection(client: TestClient, collection: Collection) -> None:
response = client.put("/collections/a-collection", content=json.dumps(collection))
assert response.is_success, response.text
assert response.json()["path_collection_id"] == "a-collection"
assert response.json()["type"] == "Collection"


def test_delete_collection(client: TestClient, collection: Collection) -> None:
response = client.delete("/collections/a-collection")
assert response.is_success, response.text
assert response.json()["path_collection_id"] == "a-collection"


@pytest.fixture
def client(
core_client: DummyCoreClient, transactions_client: DummyTransactionsClient
Expand Down Expand Up @@ -119,3 +162,19 @@ def item() -> Item:
"assets": {},
"collection": "test_collection",
}


@pytest.fixture
def collection() -> Collection:
return {
"type": "Collection",
"stac_version": "1.0.0",
"stac_extensions": [],
"id": "test_collection",
"extent": {
"spatial": {"bbox": [[-180, -90, 180, 90]]},
"temporal": {
"interval": [["2000-01-01T00:00:00Z", "2024-01-01T00:00:00Z"]]
},
},
}
8 changes: 4 additions & 4 deletions stac_fastapi/types/stac_fastapi/types/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,10 @@ def update_collection(
) -> Optional[Union[stac_types.Collection, Response]]:
"""Perform a complete update on an existing collection.
Called with `PUT /collections/{collection_id}`. It is expected that this item
already exists. The update should do a diff against the saved collection and
perform any necessary updates. Partial updates are not supported by the
transactions extension.
Called with `PUT /collections/{collection_id}`. It is expected that this
collection already exists. The update should do a diff against the saved
collection and perform any necessary updates. Partial updates are not
supported by the transactions extension.
Args:
collection_id: id of the existing collection to be updated
Expand Down

0 comments on commit 108fc2c

Please sign in to comment.