Skip to content

Commit 1af1fdf

Browse files
committed
Issue #197 add vector cube UDF test to filter out geometries
1 parent 4b9c0ef commit 1af1fdf

File tree

3 files changed

+117
-4
lines changed

3 files changed

+117
-4
lines changed

openeo_driver/testing.py

+12-4
Original file line numberDiff line numberDiff line change
@@ -533,7 +533,15 @@ def to_geojson_feature_collection(self) -> dict:
533533

534534

535535
class ApproxGeoJSONByBounds:
536-
"""pytest assert helper to build a matcher to check if a certain GeoJSON construct is within expected bounds"""
536+
"""
537+
pytest assert helper to build a matcher to check if a certain GeoJSON construct has expected bounds
538+
539+
Usage example:
540+
541+
>>> geometry = {"type": "Polygon", "coordinates": [...]}
542+
# Check that this geometry has bounds (1, 2, 6, 5) with some absolute tolerance
543+
>>> assert geometry == ApproxGeoJSONByBounds(1, 2, 6, 5, abs=0.1)
544+
"""
537545

538546
def __init__(
539547
self,
@@ -543,8 +551,9 @@ def __init__(
543551
abs: Optional[float] = None,
544552
):
545553
bounds = args[0] if len(args) == 1 else args
546-
assert isinstance(bounds, (list, tuple)) and len(bounds) == 4
547-
self.expected_bounds = [float(b) for b in bounds]
554+
bounds = [float(b) for b in bounds]
555+
assert len(bounds) == 4
556+
self.expected_bounds = bounds
548557
self.rel = rel
549558
self.abs = abs
550559
self.expected_types = set(types)
@@ -572,7 +581,6 @@ def __repr__(self):
572581
msg += "\n" + "\n".join(f" # {i}" for i in self.actual_info)
573582
return msg
574583

575-
576584
def caplog_with_custom_formatter(caplog: pytest.LogCaptureFixture, format: Union[str, logging.Formatter]):
577585
"""
578586
Context manager to set a custom formatter on the caplog fixture.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
{
2+
"type": "FeatureCollection",
3+
"features": [
4+
{
5+
"type": "Feature",
6+
"properties": {"id": "first", "pop": 123},
7+
"geometry": {
8+
"type": "Polygon",
9+
"coordinates": [[[1, 1], [3, 1], [2, 3], [1, 1]]]
10+
}
11+
},
12+
{
13+
"type": "Feature",
14+
"properties": {"id": "second", "pop": 456},
15+
"geometry": {
16+
"type": "Polygon",
17+
"coordinates": [[[4, 2], [5, 4], [3, 4], [4, 2]]]
18+
}
19+
},
20+
{
21+
"type": "Feature",
22+
"properties": {"id": "third", "pop": 789},
23+
"geometry": {
24+
"type": "Polygon",
25+
"coordinates": [[[6, 2], [10, 2], [12, 6], [8, 6], [6, 2]]]
26+
}
27+
},
28+
{
29+
"type": "Feature",
30+
"properties": {"id": "fourth", "pop": 101112},
31+
"geometry": {
32+
"type": "Polygon",
33+
"coordinates": [[[-2, 7], [5, 7], [5, 14], [-2, 14], [-2, 7]]]
34+
}
35+
}
36+
]
37+
}

tests/test_views_execute.py

+68
Original file line numberDiff line numberDiff line change
@@ -3592,3 +3592,71 @@ def process_geometries(udf_data: UdfData) -> UdfData:
35923592
],
35933593
}
35943594
)
3595+
3596+
def test_apply_dimension_run_udf_filter_geometries_dimension_properties(self, api100):
3597+
"""
3598+
Test to use `apply_dimension(dimension="properties", process=UDF)` to filter out certain
3599+
entries from geometries dimension.
3600+
3601+
Note that, strictly speaking, this approach draws outside the lines of the openEO API spec
3602+
as apply_dimension only allows changing the cardinality of the provided dimension ("properties" in this case),
3603+
not any other dimension (like "geometries" in this case).
3604+
"""
3605+
udf_code = """
3606+
from openeo.udf import UdfData, FeatureCollection
3607+
import shapely.geometry
3608+
def process_geometries(udf_data: UdfData) -> UdfData:
3609+
[feature_collection] = udf_data.get_feature_collection_list()
3610+
gdf = feature_collection.data
3611+
to_intersect = shapely.geometry.box(4, 3, 8, 4)
3612+
gdf = gdf[gdf["geometry"].intersects(to_intersect)]
3613+
udf_data.set_feature_collection_list([
3614+
FeatureCollection(id="_", data=gdf),
3615+
])
3616+
"""
3617+
udf_code = textwrap.dedent(udf_code)
3618+
process_graph = {
3619+
"get_vector_data": {
3620+
"process_id": "load_uploaded_files",
3621+
"arguments": {"paths": [str(get_path("geojson/FeatureCollection10.json"))], "format": "GeoJSON"},
3622+
},
3623+
"apply_dimension": {
3624+
"process_id": "apply_dimension",
3625+
"arguments": {
3626+
"data": {"from_node": "get_vector_data"},
3627+
"dimension": "properties",
3628+
"process": {
3629+
"process_graph": {
3630+
"runudf1": {
3631+
"process_id": "run_udf",
3632+
"arguments": {
3633+
"data": {"from_node": "get_vector_data"},
3634+
"udf": udf_code,
3635+
"runtime": "Python",
3636+
},
3637+
"result": True,
3638+
}
3639+
},
3640+
},
3641+
},
3642+
"result": True,
3643+
},
3644+
}
3645+
resp = api100.check_result(process_graph)
3646+
assert resp.json == DictSubSet(
3647+
{
3648+
"type": "FeatureCollection",
3649+
"features": [
3650+
{
3651+
"type": "Feature",
3652+
"geometry": ApproxGeoJSONByBounds(3, 2, 5, 4, types=["Polygon"], abs=0.1),
3653+
"properties": {"id": "second", "pop": 456},
3654+
},
3655+
{
3656+
"type": "Feature",
3657+
"geometry": ApproxGeoJSONByBounds(6, 2, 12, 6, types=["Polygon"], abs=0.1),
3658+
"properties": {"id": "third", "pop": 789},
3659+
},
3660+
],
3661+
}
3662+
)

0 commit comments

Comments
 (0)