Skip to content

Commit 9e0d5c6

Browse files
committed
Add validate() to SaveResult, VectorCube, MlModel and StacResource
ref: #766
1 parent 4aba08a commit 9e0d5c6

File tree

9 files changed

+106
-5
lines changed

9 files changed

+106
-5
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1010
### Added
1111

1212
- Support `collection_property` based property filtering in `load_stac` ([#246](https://github.com/Open-EO/openeo-python-client/issues/246))
13+
- Add `validate()` method to `SaveResult`, `VectorCube`, `MlModel` and `StacResource` classes ([#766](https://github.com/Open-EO/openeo-python-client/issues/766))
1314

1415
### Changed
1516

openeo/rest/_datacube.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
)
2020
from openeo.internal.warnings import UserDeprecationWarning
2121
from openeo.rest import OpenEoClientException
22+
from openeo.rest.models.general import ValidationResponse
2223
from openeo.util import dict_no_none, str_truncate
2324

2425
if typing.TYPE_CHECKING:
@@ -104,6 +105,16 @@ def _build_pgnode(
104105

105106
# TODO #278 also move process graph "execution" methods here: `download`, `execute`, `execute_batch`, `create_job`, `save_udf`, ...
106107

108+
def validate(self) -> ValidationResponse:
109+
"""
110+
Validate a process graph without executing it.
111+
112+
:return: container of validation of errors (dictionaries with "code" and "message" fields)
113+
114+
.. versionadded:: 0.41.0
115+
"""
116+
return self._connection.validate_process_graph(self)
117+
107118
def _repr_html_(self):
108119
process = {"process_graph": self.flat_graph()}
109120
parameters = {

openeo/rest/connection.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -994,7 +994,11 @@ def validate_process_graph(
994994
a local file path or URL to a JSON representation,
995995
a :py:class:`~openeo.rest.multiresult.MultiResult` object, ...
996996
997-
:return: list of errors (dictionaries with "code" and "message" fields)
997+
:return: container of validation errors (dictionaries with "code" and "message" fields)
998+
999+
.. versionchanged:: 0.38.0
1000+
returns a :py:class:`~openeo.rest.models.general.ValidationResponse` object
1001+
instead of a simple list of error dictionaries.
9981002
"""
9991003
pg_with_metadata = self._build_request_with_process_graph(process_graph)["process"]
10001004
data = self.post(path="/validation", json=pg_with_metadata, expected_status=200).json()

openeo/rest/datacube.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474
from openeo.rest.graph_building import CollectionProperty
7575
from openeo.rest.job import BatchJob, RESTJob
7676
from openeo.rest.mlmodel import MlModel
77+
from openeo.rest.models.general import ValidationResponse
7778
from openeo.rest.result import SaveResult
7879
from openeo.rest.service import Service
7980
from openeo.rest.udp import RESTUserDefinedProcess
@@ -2499,13 +2500,20 @@ def download(
24992500
on_response_headers=on_response_headers,
25002501
)
25012502

2502-
def validate(self) -> List[dict]:
2503+
def validate(self) -> ValidationResponse:
25032504
"""
25042505
Validate a process graph without executing it.
25052506
2506-
:return: list of errors (dictionaries with "code" and "message" fields)
2507+
:return: container of validation of errors (dictionaries with "code" and "message" fields)
2508+
2509+
.. versionchanged:: 0.38.0
2510+
returns a :py:class:`~openeo.rest.models.general.ValidationResponse` object
2511+
instead of a simple list of error dictionaries.
25072512
"""
2508-
return self._connection.validate_process_graph(self.flat_graph())
2513+
# TODO this method implementation does not really override something
2514+
# it is just kept to override the doc.
2515+
# At some point this should be removed for simplicity.
2516+
return super().validate()
25092517

25102518
def tiled_viewing_service(self, type: str, **kwargs) -> Service:
25112519
return self._connection.create_service(self.flat_graph(), type=type, **kwargs)

tests/internal/test_documentation.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,16 @@ def test_extract_main_description():
6161
(DataCube.create_job, VectorCube.create_job),
6262
(DataCube.execute_batch, VectorCube.execute_batch),
6363
(DataCube.save_result, VectorCube.save_result),
64+
(DataCube.validate, VectorCube.validate),
6465
# DataCube vs MlModel
6566
(DataCube.create_job, MlModel.create_job),
6667
(DataCube.execute_batch, MlModel.execute_batch),
68+
(DataCube.validate, MlModel.validate),
6769
# DataCube vs StacResource
6870
(DataCube.download, StacResource.download),
6971
(DataCube.create_job, StacResource.create_job),
7072
(DataCube.execute_batch, StacResource.execute_batch),
73+
(DataCube.validate, StacResource.validate),
7174
],
7275
)
7376
def test_cube_processing_params_and_return(method_a, method_b):

tests/rest/datacube/test_datacube.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
from openeo.rest._testing import build_capabilities
2727
from openeo.rest.connection import Connection
2828
from openeo.rest.datacube import DataCube
29+
from openeo.rest.models.general import ValidationResponse
2930
from openeo.testing.stac import StacDummyBuilder
3031
from openeo.util import dict_no_none
3132

@@ -1595,3 +1596,21 @@ def test_execute_batch_with_title(s2cube, dummy_backend):
15951596
"description": "Lorem ipsum dolor S2 amet",
15961597
}
15971598
}
1599+
1600+
1601+
def test_cube_validate(con120, dummy_backend):
1602+
dummy_backend.next_validation_errors = [{"code": "OddSupport", "message": "Odd values are not supported."}]
1603+
cube = con120.load_collection("S2")
1604+
result = cube.validate()
1605+
1606+
assert dummy_backend.validation_requests == [
1607+
{
1608+
"loadcollection1": {
1609+
"process_id": "load_collection",
1610+
"arguments": {"id": "S2", "spatial_extent": None, "temporal_extent": None},
1611+
"result": True,
1612+
},
1613+
}
1614+
]
1615+
assert isinstance(result, ValidationResponse)
1616+
assert result == [{"code": "OddSupport", "message": "Odd values are not supported."}]

tests/rest/datacube/test_vectorcube.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from openeo.rest import OpenEoClientException
1111
from openeo.rest._testing import DummyBackend, build_capabilities
1212
from openeo.rest.connection import Connection
13+
from openeo.rest.models.general import ValidationResponse
1314
from openeo.rest.vectorcube import VectorCube
1415
from openeo.util import InvalidBBoxException, dict_no_none
1516

@@ -854,3 +855,21 @@ def test_execute_batch_with_title(vector_cube, dummy_backend):
854855
"description": "Lorem ipsum dolor S2 amet",
855856
}
856857
}
858+
859+
860+
def test_vector_cube_validate(vector_cube, dummy_backend):
861+
dummy_backend.next_validation_errors = [{"code": "OfflineRequired", "message": "Turn off your smartphone"}]
862+
863+
result = vector_cube.validate()
864+
865+
assert dummy_backend.validation_requests == [
866+
{
867+
"loadgeojson1": {
868+
"process_id": "load_geojson",
869+
"arguments": {"data": {"coordinates": [1, 2], "type": "Point"}, "properties": []},
870+
"result": True,
871+
}
872+
}
873+
]
874+
assert isinstance(result, ValidationResponse)
875+
assert result == [{"code": "OfflineRequired", "message": "Turn off your smartphone"}]

tests/rest/test_connection.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
extract_connections,
4747
paginate,
4848
)
49-
from openeo.rest.models.general import Link
49+
from openeo.rest.models.general import Link, ValidationResponse
5050
from openeo.rest.vectorcube import VectorCube
5151
from openeo.testing.stac import StacDummyBuilder
5252
from openeo.util import ContextTimer, deep_get, dict_no_none
@@ -4865,6 +4865,17 @@ def test_validate_process_graph(con120, dummy_backend):
48654865
dummy_backend.next_validation_errors = [{"code": "OddSupport", "message": "Odd values are not supported."}]
48664866
cube = con120.load_collection("S2")
48674867
res = con120.validate_process_graph(cube)
4868+
4869+
assert dummy_backend.validation_requests == [
4870+
{
4871+
"loadcollection1": {
4872+
"arguments": {"id": "S2", "spatial_extent": None, "temporal_extent": None},
4873+
"process_id": "load_collection",
4874+
"result": True,
4875+
}
4876+
}
4877+
]
4878+
assert isinstance(res, ValidationResponse)
48684879
assert res == [{"code": "OddSupport", "message": "Odd values are not supported."}]
48694880

48704881

tests/rest/test_result.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from openeo.rest.datacube import THIS
2+
from openeo.rest.models.general import ValidationResponse
23
from openeo.rest.result import SaveResult
34

45

@@ -24,3 +25,27 @@ def test_legacy_save_result_export_workspace(dummy_backend):
2425
"result": True,
2526
},
2627
}
28+
29+
30+
def test_save_result_validate(dummy_backend):
31+
dummy_backend.next_validation_errors = [{"code": "OfflineRequired", "message": "Turn off your smartphone"}]
32+
33+
s2 = dummy_backend.connection.load_collection("S2")
34+
saved = s2.save_result(format="GTiff")
35+
result = saved.validate()
36+
37+
assert dummy_backend.validation_requests == [
38+
{
39+
"loadcollection1": {
40+
"process_id": "load_collection",
41+
"arguments": {"id": "S2", "spatial_extent": None, "temporal_extent": None},
42+
},
43+
"saveresult1": {
44+
"process_id": "save_result",
45+
"arguments": {"data": {"from_node": "loadcollection1"}, "format": "GTiff", "options": {}},
46+
"result": True,
47+
},
48+
}
49+
]
50+
assert isinstance(result, ValidationResponse)
51+
assert result == [{"code": "OfflineRequired", "message": "Turn off your smartphone"}]

0 commit comments

Comments
 (0)