From 0b97a51700a4005dd5a337915b0e065dbc07475c Mon Sep 17 00:00:00 2001 From: Jan Van den bosch Date: Thu, 28 Nov 2024 14:38:00 +0100 Subject: [PATCH] quick fix to omit datetime from item search request #950 --- CHANGELOG.md | 4 ++ openeogeotrellis/_version.py | 2 +- openeogeotrellis/load_stac.py | 8 ++- setup.py | 2 +- .../catalog.json | 17 +++++++ .../collection.json | 33 +++++++++++++ tests/test_api_result.py | 49 ++++++++++++++++++- 7 files changed, 110 insertions(+), 5 deletions(-) create mode 100644 tests/data/stac/issue950-api-omit-temporal-extent/catalog.json create mode 100644 tests/data/stac/issue950-api-omit-temporal-extent/collection.json diff --git a/CHANGELOG.md b/CHANGELOG.md index ddc7d8946..a0deaaf08 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,10 @@ without compromising stable operations. - Throw error when trying to use unsupported `target_dimension` in `aggregate_spatial` ([#951](https://github.com/Open-EO/openeo-geopyspark-driver/issues/951)) +## 0.51.0 + +- `load_stac`: omit `datetime` parameter from STAC API item search request if no `temporal_extent` specified ([#950](https://github.com/Open-EO/openeo-geopyspark-driver/issues/950)) + ## 0.50.1 - Fix `reduce_dimension` of bands for GeoTIFF output in batch job ([#943](https://github.com/Open-EO/openeo-geopyspark-driver/issues/943)) diff --git a/openeogeotrellis/_version.py b/openeogeotrellis/_version.py index a2f7732cf..bc1aa6fde 100644 --- a/openeogeotrellis/_version.py +++ b/openeogeotrellis/_version.py @@ -1 +1 @@ -__version__ = "0.50.1a1" +__version__ = "0.51.0a1" diff --git a/openeogeotrellis/load_stac.py b/openeogeotrellis/load_stac.py index 702a65569..139202408 100644 --- a/openeogeotrellis/load_stac.py +++ b/openeogeotrellis/load_stac.py @@ -20,6 +20,7 @@ from openeo_driver.errors import OpenEOApiException, ProcessParameterUnsupportedException, JobNotFoundException, \ ProcessParameterInvalidException from openeo_driver.jobregistry import PARTIAL_JOB_STATUS +from openeo_driver.ProcessGraphDeserializer import DEFAULT_TEMPORAL_EXTENT from openeo_driver.users import User from openeo_driver.util.geometry import BoundingBox, GeometryBufferer from openeo_driver.util.utm import utm_zone_from_epsg @@ -249,8 +250,11 @@ def operator_value(criterion: Dict[str, object]) -> (str, object): collections=collection_id, bbox=requested_bbox.reproject("EPSG:4326").as_wsen_tuple() if requested_bbox else None, limit=20, - datetime=f"{from_date.isoformat().replace('+00:00', 'Z')}/" - f"{to_date.isoformat().replace('+00:00', 'Z')}", # end is inclusive + datetime=( + None if temporal_extent is DEFAULT_TEMPORAL_EXTENT + else f"{from_date.isoformat().replace('+00:00', 'Z')}/" + f"{to_date.isoformat().replace('+00:00', 'Z')}" # end is inclusive + ), fields=fields, ) diff --git a/setup.py b/setup.py index 0551e6722..8c254defa 100644 --- a/setup.py +++ b/setup.py @@ -54,7 +54,7 @@ tests_require=tests_require, install_requires=[ "openeo>=0.33.0", - "openeo_driver>=0.118.0.dev", + "openeo_driver>=0.119.0.dev", 'pyspark==3.4.2; python_version>="3.8"', 'pyspark>=2.3.1,<2.4.0; python_version<"3.8"', 'geopyspark==0.4.7+openeo', diff --git a/tests/data/stac/issue950-api-omit-temporal-extent/catalog.json b/tests/data/stac/issue950-api-omit-temporal-extent/catalog.json new file mode 100644 index 000000000..be1367dca --- /dev/null +++ b/tests/data/stac/issue950-api-omit-temporal-extent/catalog.json @@ -0,0 +1,17 @@ +{ + "id": "catalog", + "type": "Catalog", + "description": "description", + "conformsTo": ["https://api.stacspec.org/v1.0.0-rc.1/item-search"], + "stac_version": "1.0.0", + "links": [ + { + "rel": "child", + "href": "https://stac.test/collections/collection" + }, + { + "rel": "search", + "href": "search" + } + ] +} diff --git a/tests/data/stac/issue950-api-omit-temporal-extent/collection.json b/tests/data/stac/issue950-api-omit-temporal-extent/collection.json new file mode 100644 index 000000000..9ddfa36bd --- /dev/null +++ b/tests/data/stac/issue950-api-omit-temporal-extent/collection.json @@ -0,0 +1,33 @@ +{ + "id": "collection", + "type": "Collection", + "description": "description", + "license": "proprietary", + "stac_version": "1.0.0", + "extent": { + "spatial": { + "bbox": [ + [ + -180, + -90, + 180, + 90 + ] + ] + }, + "temporal": { + "interval": [ + [ + null, + null + ] + ] + } + }, + "links": [ + { + "rel": "root", + "href": "https://stac.test" + } + ] +} diff --git a/tests/test_api_result.py b/tests/test_api_result.py index 40602ccfc..6e651d706 100644 --- a/tests/test_api_result.py +++ b/tests/test_api_result.py @@ -4376,7 +4376,10 @@ def item(path) -> dict: process_graph = { "loadstac1": { "process_id": "load_stac", - "arguments": {"url": "https://stac.test/collections/collection"}, + "arguments": { + "url": "https://stac.test/collections/collection", + "temporal_extent": ["2021-02-01", "2021-03-01"], + }, }, "saveresult1": { "process_id": "save_result", @@ -4397,6 +4400,50 @@ def item(path) -> dict: assert (ds["band3"] == 3).all() assert (ds["band4"] == 4).all() + def test_load_stac_omits_default_temporal_extent(self, api110, urllib_mock, requests_mock, tmp_path): + """load_stac from a STAC API without specifying a temporal_extent""" + + def feature_collection(request, _) -> dict: + assert request.qs["collections"][0] == "collection" # sanity check + assert "datetime" not in request.qs + + return { + "type": "FeatureCollection", + "features": [], + } + + urllib_mock.get( + "https://stac.test/collections/collection", + data=get_test_data_file("stac/issue950-api-omit-temporal-extent/collection.json").read_text(), + ) + urllib_mock.get( + "https://stac.test", # for pystac + data=get_test_data_file("stac/issue950-api-omit-temporal-extent/catalog.json").read_text(), + ) + requests_mock.get( + "https://stac.test", # for pystac_client + text=get_test_data_file("stac/issue950-api-omit-temporal-extent/catalog.json").read_text(), + ) + requests_mock.get("https://stac.test/search", json=feature_collection) + + process_graph = { + "loadstac1": { + "process_id": "load_stac", + "arguments": { + "url": "https://stac.test/collections/collection", + # no temporal_extent + }, + }, + "saveresult1": { + "process_id": "save_result", + "arguments": {"data": {"from_node": "loadstac1"}, "format": "NetCDF"}, + "result": True, + }, + } + + res = api110.result(process_graph).assert_status_code(400) + assert "NoDataAvailable" in res.text + class TestEtlApiReporting: @pytest.fixture(autouse=True)