Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
34 changes: 33 additions & 1 deletion planet/clients/features.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,11 @@ async def list_items(
self,
collection_id: str,
limit: int = 10,
bbox: Optional[list[float]] = None,
datetime: Optional[str] = None,
id: Optional[str] = None,
hashid: Optional[str] = None,
sort: Optional[str] = None,
) -> AsyncIterator[Feature]:
"""
List features in `collection_id`.
Expand All @@ -124,6 +129,19 @@ async def list_items(
APIs. Within the Python SDK, the entire Feature can generally be
passed to functions that accept a geometry.

Parameters:
collection_id: ID of the collection to list features from.
limit: Maximum number of features to return. 0 means no limit.
bbox: Only return features intersecting this bounding box, given
as [xmin, ymin, xmax, ymax].
datetime: Only return features matching this datetime. Accepts a
single RFC 3339 datetime or an interval, e.g.
"2024-01-01T00:00:00Z/2024-12-31T23:59:59Z".
id: Only return features whose id matches this value. Prefix the
value with "~" for substring (fuzzy) matching.
hashid: Only return the feature with this hashid.
sort: Sort order for the returned features, e.g. "id" or "-id".

example:

```
Expand Down Expand Up @@ -154,7 +172,21 @@ def _next_link(self, page):

url = f'{self._base_url}/collections/{collection_id}/items'

resp = await self._session.request(method='GET', url=url)
params: dict[str, Any] = {}
if bbox is not None:
params['bbox'] = ','.join(str(coord) for coord in bbox)
if datetime is not None:
params['datetime'] = datetime
if id is not None:
params['id'] = id
if hashid is not None:
params['hashid'] = hashid
if sort is not None:
params['sort'] = sort

resp = await self._session.request(method='GET',
url=url,
params=params)
async for feat in _FeaturesPager(resp,
self._session.request,
limit=limit):
Expand Down
15 changes: 13 additions & 2 deletions planet/sync/features.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,12 @@ def delete_collection(self, collection_id: str) -> None:

def list_items(self,
collection_id: str,
limit: int = 0) -> Iterator[Feature]:
limit: int = 0,
bbox: Optional[list[float]] = None,
datetime: Optional[str] = None,
id: Optional[str] = None,
hashid: Optional[str] = None,
sort: Optional[str] = None) -> Iterator[Feature]:
"""
List features in `collection_id`.

Expand All @@ -122,7 +127,13 @@ def list_items(self,
```
"""
return self._client._aiter_to_iter(
self._client.list_items(collection_id, limit=limit))
self._client.list_items(collection_id,
limit=limit,
bbox=bbox,
datetime=datetime,
id=id,
hashid=hashid,
sort=sort))

def get_item(self, collection_id: str, feature_id: str) -> Feature:
"""
Expand Down
32 changes: 32 additions & 0 deletions tests/integration/test_features_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,38 @@ def assertf(resp):
assertf(list(cl_sync.list_items(collection_id)))


@respx.mock
async def test_list_items_with_filters():
collection_id = "test"
items_url = f"{TEST_URL}/collections/{collection_id}/items"

mock_response(items_url,
list_features_response(collection_id, num_features=1))

filters = dict(
bbox=[1.0, 2.0, 3.0, 4.0],
datetime="2024-01-01T00:00:00Z/2024-12-31T23:59:59Z",
id="~abc",
hashid="deadbeef",
sort="-id",
)

# async client forwards every filter as a query parameter
[feat async for feat in cl_async.list_items(collection_id, **filters)]
sent = respx.calls[-1].request.url.params
assert sent["bbox"] == "1.0,2.0,3.0,4.0"
assert sent["datetime"] == filters["datetime"]
assert sent["id"] == "~abc"
assert sent["hashid"] == "deadbeef"
assert sent["sort"] == "-id"

# sync wrapper forwards them too
list(cl_sync.list_items(collection_id, **filters))
sent_sync = respx.calls[-1].request.url.params
assert sent_sync["bbox"] == "1.0,2.0,3.0,4.0"
assert sent_sync["sort"] == "-id"


@respx.mock
@pytest.mark.parametrize(
"feature, expected_body",
Expand Down