Skip to content
Merged
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
9 changes: 8 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [0.61.0] - 2026-09-04

### Added

- `tilebox-grpc`: Add runtime and execution environment metadata to all API requests using the `Tilebox-Client` header.
- `tilebox-datasets`: Add explicit `filter_contains_geometry` and `geometry_contains_filter` spatial query modes,
deprecated the legacy `contains` mode which is an alias for `filter_contains_geometry`.
- `tilebox-workflows`: Add task ID filters to job log and span queries and severity filters to job log queries.
- `tilebox-workflows`: Allow querying jobs without specifying a temporal extent.

### Fixed

Expand Down Expand Up @@ -489,7 +495,8 @@ the first client that does not cache data (since it's already on the local file
- Released under the [MIT](https://opensource.org/license/mit) license.
- Released packages: `tilebox-datasets`, `tilebox-workflows`, `tilebox-storage`, `tilebox-grpc`

[Unreleased]: https://github.com/tilebox/tilebox-python/compare/v0.60.0...HEAD
[Unreleased]: https://github.com/tilebox/tilebox-python/compare/v0.61.0...HEAD
[0.61.0]: https://github.com/tilebox/tilebox-python/compare/v0.60.0...v0.61.0
[0.60.0]: https://github.com/tilebox/tilebox-python/compare/v0.59.0...v0.60.0
[0.59.0]: https://github.com/tilebox/tilebox-python/compare/v0.58.0...v0.59.0
[0.58.0]: https://github.com/tilebox/tilebox-python/compare/v0.57.0...v0.58.0
Expand Down
7 changes: 5 additions & 2 deletions tilebox-datasets/tests/data/data_access.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,11 @@ def spatial_filter_likes(draw: DrawFn) -> Geometry | SpatialFilterDict:
return geometry

# return a dict
mode: SpatialFilterMode | Literal["intersects", "contains"] | None = draw(
sampled_from(["intersects", "contains"]), sampled_from(SpatialFilterMode) | none()
mode: SpatialFilterMode | Literal["intersects", "filter_contains_geometry", "geometry_contains_filter"] | None = (
draw(
sampled_from(["intersects", "filter_contains_geometry", "geometry_contains_filter"]),
sampled_from(SpatialFilterMode) | none(),
)
)
coordinate_system: SpatialCoordinateSystem | Literal["cartesian", "spherical"] | None = draw(
sampled_from(["cartesian", "spherical"]), sampled_from(SpatialCoordinateSystem) | none()
Expand Down
23 changes: 21 additions & 2 deletions tilebox-datasets/tests/data/test_data_access.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@

import pytest
from hypothesis import given
from shapely import Geometry
from shapely import Geometry, box

from tests.data.data_access import query_filters, spatial_filter_likes, spatial_filters
from tilebox.datasets.data.data_access import QueryFilters, SpatialFilter, SpatialFilterDict
from tilebox.datasets.data.data_access import QueryFilters, SpatialFilter, SpatialFilterDict, SpatialFilterMode
from tilebox.datasets.datasets.v1 import data_access_pb2
from tilebox.datasets.query import TimeInterval, field
from tilebox.datasets.query.id_interval import IDInterval
Expand Down Expand Up @@ -37,6 +37,25 @@ def test_parse_spatial_filter_like(spatial_filter_like: Geometry | SpatialFilter
assert spatial_filter.coordinate_system is not None


def test_contains_spatial_filter_mode_is_deprecated() -> None:
with pytest.warns(DeprecationWarning, match='Use "filter_contains_geometry" instead'):
spatial_filter = SpatialFilter.parse({"geometry": box(0, 0, 1, 1), "mode": "contains"})

assert spatial_filter.mode is SpatialFilterMode.FILTER_CONTAINS_GEOMETRY


@pytest.mark.parametrize(
("mode", "wire_mode"),
[
(SpatialFilterMode.FILTER_CONTAINS_GEOMETRY, data_access_pb2.SPATIAL_FILTER_MODE_FILTER_CONTAINS_GEOMETRY),
(SpatialFilterMode.GEOMETRY_CONTAINS_FILTER, data_access_pb2.SPATIAL_FILTER_MODE_GEOMETRY_CONTAINS_FILTER),
],
)
def test_directional_spatial_filter_modes(mode: SpatialFilterMode, wire_mode: int) -> None:
message = SpatialFilter(box(0, 0, 1, 1), mode).to_message()
assert message.mode == wire_mode


@given(query_filters())
def test_query_filters_to_message_and_back(q: QueryFilters) -> None:
assert QueryFilters.from_message(q.to_message()) == q
Expand Down
6 changes: 3 additions & 3 deletions tilebox-datasets/tilebox/datasets/aio/dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -464,12 +464,12 @@ async def query(
spatial_extent: The spatial extent to query data in. (Optional)
Expected to be either a shapely geometry, or a dict with the following keys:
- geometry: The geometry to query by. Must be a shapely.Polygon, shapely.MultiPolygon or shapely.Point.
- mode: The spatial filter mode to use. Can be one of "intersects" or "contains".
Defaults to "intersects".
- mode: The spatial filter mode to use. Can be one of "intersects", "filter_contains_geometry", or
"geometry_contains_filter". Defaults to "intersects".
- coordinate_system: The coordinate system to use for performing geometry calculations. Can be one
of "cartesian" or "spherical".
Only supported for spatiotemporal datasets. Will raise an error if used for other dataset types.
All datapoints whose geometry intersects the given spatial extent will be returned.
Datapoints matching the selected spatial filter mode will be returned.
skip_data: Whether to skip the actual data of the datapoint. If True, only datapoint metadata is returned.
show_progress: Whether to show a progress bar while loading the data.
If a callable is specified it is used as callback to report progress percentages.
Expand Down
20 changes: 16 additions & 4 deletions tilebox-datasets/tilebox/datasets/data/data_access.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from dataclasses import dataclass
from enum import Enum
from typing import Literal, TypeAlias, TypedDict
from warnings import warn

from shapely import Geometry, from_wkb, to_wkb

Expand All @@ -15,7 +16,8 @@

class SpatialFilterMode(Enum):
INTERSECTS = data_access_pb2.SPATIAL_FILTER_MODE_INTERSECTS
CONTAINS = data_access_pb2.SPATIAL_FILTER_MODE_CONTAINS
FILTER_CONTAINS_GEOMETRY = data_access_pb2.SPATIAL_FILTER_MODE_FILTER_CONTAINS_GEOMETRY
GEOMETRY_CONTAINS_FILTER = data_access_pb2.SPATIAL_FILTER_MODE_GEOMETRY_CONTAINS_FILTER


_filter_modes_from_string = {mode.name.lower(): mode for mode in SpatialFilterMode}
Expand All @@ -33,7 +35,10 @@ class SpatialCoordinateSystem(Enum):

class SpatialFilterDict(TypedDict):
geometry: Geometry
mode: NotRequired[SpatialFilterMode | Literal["intersects", "contains"]]
# "contains" is deprecated and retained only for backwards compatibility.
mode: NotRequired[
SpatialFilterMode | Literal["intersects", "filter_contains_geometry", "geometry_contains_filter", "contains"]
]
coordinate_system: NotRequired[SpatialCoordinateSystem | Literal["cartesian", "spherical"]]


Expand All @@ -49,8 +54,8 @@ class SpatialFilter:

Args:
geometry: The spatial geometry to filter by (e.g. a polygon)
mode: The spatial filter mode to use. Can be one of "intersects" or "contains".
Defaults to "intersects".
mode: The spatial filter mode to use. Can be one of "intersects", "filter_contains_geometry", or
"geometry_contains_filter". Defaults to "intersects".
crs: The coordinate system to use for performing geometry calculations. Can be one
of "cartesian" or "spherical".
"""
Expand Down Expand Up @@ -92,6 +97,13 @@ def parse(cls, spatial_filter_like: SpatialFilterLike) -> "SpatialFilter":
if isinstance(spatial_filter_like, dict):
mode = spatial_filter_like.get("mode", None)
if isinstance(mode, str):
if mode.lower() == "contains":
warn(
'The spatial filter mode "contains" is deprecated. Use "filter_contains_geometry" instead.',
DeprecationWarning,
stacklevel=2,
)
mode = "filter_contains_geometry"
mode = _filter_modes_from_string.get(mode.lower())
coordinate_system = spatial_filter_like.get("coordinate_system", None)
if isinstance(coordinate_system, str):
Expand Down
14 changes: 7 additions & 7 deletions tilebox-datasets/tilebox/datasets/datasets/v1/data_access_pb2.py

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading