Skip to content

Commit

Permalink
fixup! Eliminate _check_dimension and _get_time_dim_or_default
Browse files Browse the repository at this point in the history
  • Loading branch information
soxofaan committed Aug 3, 2023
1 parent f01cd01 commit a25f3ab
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 26 deletions.
8 changes: 4 additions & 4 deletions openeo_driver/ProcessGraphDeserializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -680,7 +680,7 @@ def apply_dimension(args: ProcessArgs, env: EvalEnv) -> DriverDataCube:
data_cube = args.get_required("data", expected_type=DriverDataCube)
process = args.get_deep("process", "process_graph", expected_type=dict)
dimension = args.get_required(
"dimension", expected_type=str, validator=lambda d: d in data_cube.metadata.dimension_names()
"dimension", expected_type=str, validator=ProcessArgs.validator_one_of(data_cube.metadata.dimension_names())
)
target_dimension = args.get_optional("target_dimension", default=None, expected_type=str)
context = args.get_optional("context", default=None)
Expand Down Expand Up @@ -748,7 +748,7 @@ def reduce_dimension(args: ProcessArgs, env: EvalEnv) -> DriverDataCube:
data_cube: DriverDataCube = args.get_required("data", expected_type=DriverDataCube)
reduce_pg = args.get_deep("reducer", "process_graph", expected_type=dict)
dimension = args.get_required(
"dimension", expected_type=str, validator=lambda d: d in data_cube.metadata.dimension_names()
"dimension", expected_type=str, validator=ProcessArgs.validator_one_of(data_cube.metadata.dimension_names())
)
context = args.get_optional("context", default=None)
return data_cube.reduce_dimension(reducer=reduce_pg, dimension=dimension, context=context, env=env)
Expand Down Expand Up @@ -924,7 +924,7 @@ def aggregate_temporal(args: ProcessArgs, env: EvalEnv) -> DriverDataCube:
dimension = args.get_optional(
"dimension",
default=lambda: data_cube.metadata.temporal_dimension.name,
validator=lambda d: d in data_cube.metadata.dimension_names(),
validator=ProcessArgs.validator_one_of(data_cube.metadata.dimension_names()),
)
context = args.get_optional("context", default=None)

Expand All @@ -941,7 +941,7 @@ def aggregate_temporal_period(args: ProcessArgs, env: EvalEnv) -> DriverDataCube
dimension = args.get_optional(
"dimension",
default=lambda: data_cube.metadata.temporal_dimension.name,
validator=lambda d: d in data_cube.metadata.dimension_names(),
validator=ProcessArgs.validator_one_of(data_cube.metadata.dimension_names()),
)
context = args.get_optional("context", default=None)

Expand Down
26 changes: 24 additions & 2 deletions openeo_driver/processes.py
Original file line number Diff line number Diff line change
Expand Up @@ -321,8 +321,15 @@ def _check_value(
raise ProcessParameterInvalidException(
parameter=name, process=self.process_id, reason=f"Expected {expected_type} but got {type(value)}."
)
if validator and not validator(value):
raise ProcessParameterInvalidException(parameter=name, process=self.process_id, reason="Failed validation.")
if validator:
try:
valid = validator(value)
reason = "Failed validation."
except Exception as e:
valid = False
reason = str(e)
if not valid:
raise ProcessParameterInvalidException(parameter=name, process=self.process_id, reason=reason)

def get_optional(
self,
Expand Down Expand Up @@ -418,3 +425,18 @@ def get_enum(self, name: str, options: typing.Container[ArgumentValue]) -> Argum
reason=f"Invalid enum value {value!r}. Expected one of {options}.",
)
return value

@staticmethod
def validator_one_of(options: list, show_value: bool = True):
"""Build a validator function that check that the value is in given list"""

def validator(value):
if value not in options:
if show_value:
message = f"Must be one of {options!r} but got {value!r}."
else:
message = f"Must be one of {options!r}."
raise ValueError(message)
return True

return validator
23 changes: 23 additions & 0 deletions tests/test_processes.py
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,12 @@ def test_get_required_with_type(self):
def test_get_required_with_validator(self):
args = ProcessArgs({"color": "red", "size": 5}, process_id="wibble")
assert args.get_required("color", expected_type=str, validator=lambda v: len(v) == 3) == "red"
assert (
args.get_required(
"color", expected_type=str, validator=ProcessArgs.validator_one_of(["red", "green", "blue"])
)
== "red"
)
assert args.get_required("size", expected_type=int, validator=lambda v: v % 3 == 2) == 5
with pytest.raises(
ProcessParameterInvalidException,
Expand All @@ -477,6 +483,15 @@ def test_get_required_with_validator(self):
match=re.escape("The value passed for parameter 'size' in process 'wibble' is invalid: Failed validation."),
):
_ = args.get_required("size", expected_type=int, validator=lambda v: v % 3 == 1)
with pytest.raises(
ProcessParameterInvalidException,
match=re.escape(
"The value passed for parameter 'color' in process 'wibble' is invalid: Must be one of ['yellow', 'violet'] but got 'red'."
),
):
_ = args.get_required(
"color", expected_type=str, validator=ProcessArgs.validator_one_of(["yellow", "violet"])
)

def test_get_optional(self):
args = ProcessArgs({"foo": "bar"}, process_id="wibble")
Expand Down Expand Up @@ -512,11 +527,19 @@ def test_get_optional_with_type(self):
def test_get_optional_with_validator(self):
args = ProcessArgs({"foo": "bar"}, process_id="wibble")
assert args.get_optional("foo", validator=lambda s: all(c.lower() for c in s)) == "bar"
assert args.get_optional("foo", validator=ProcessArgs.validator_one_of(["bar", "meh"])) == "bar"
with pytest.raises(
ProcessParameterInvalidException,
match=re.escape("The value passed for parameter 'foo' in process 'wibble' is invalid: Failed validation."),
):
_ = args.get_optional("foo", validator=lambda s: all(c.isupper() for c in s))
with pytest.raises(
ProcessParameterInvalidException,
match=re.escape(
"The value passed for parameter 'foo' in process 'wibble' is invalid: Must be one of ['nope', 'meh'] but got 'bar'."
),
):
_ = args.get_optional("foo", validator=ProcessArgs.validator_one_of(["nope", "meh"]))

def test_get_deep(self):
args = ProcessArgs({"foo": {"bar": {"color": "red", "size": {"x": 5, "y": 8}}}}, process_id="wibble")
Expand Down
38 changes: 18 additions & 20 deletions tests/test_views_execute.py
Original file line number Diff line number Diff line change
Expand Up @@ -402,10 +402,9 @@ def test_reduce_temporal_run_udf_invalid_dimension(api):
preprocess=preprocess_check_and_replace('"dimension": "t"', '"dimension": "tempo"')
)
resp.assert_error(
400, "ProcessParameterInvalid",
message="The value passed for parameter 'dimension' in process '{p}' is invalid: got 'tempo', but should be one of ['x', 'y', 't']".format(
p="reduce_dimension" if api.api_version_compare.at_least("1.0.0") else "reduce"
)
400,
"ProcessParameterInvalid",
message="The value passed for parameter 'dimension' in process 'reduce_dimension' is invalid: Must be one of ['x', 'y', 't'] but got 'tempo'.",
)


Expand All @@ -423,10 +422,9 @@ def test_reduce_bands_run_udf_invalid_dimension(api):
preprocess=preprocess_check_and_replace('"dimension": "bands"', '"dimension": "layers"')
)
resp.assert_error(
400, 'ProcessParameterInvalid',
message="The value passed for parameter 'dimension' in process '{p}' is invalid: got 'layers', but should be one of ['x', 'y', 't', 'bands']".format(
p="reduce_dimension" if api.api_version_compare.at_least("1.0.0") else "reduce"
)
400,
"ProcessParameterInvalid",
message="The value passed for parameter 'dimension' in process 'reduce_dimension' is invalid: Must be one of ['x', 'y', 't', 'bands'] but got 'layers'.",
)


Expand All @@ -448,8 +446,9 @@ def test_apply_dimension_temporal_run_udf_invalid_temporal_dimension(api):
preprocess=preprocess_check_and_replace('"dimension": "t"', '"dimension": "letemps"')
)
resp.assert_error(
400, 'ProcessParameterInvalid',
message="The value passed for parameter 'dimension' in process 'apply_dimension' is invalid: got 'letemps', but should be one of ['x', 'y', 't']"
400,
"ProcessParameterInvalid",
message="The value passed for parameter 'dimension' in process 'apply_dimension' is invalid: Must be one of ['x', 'y', 't'] but got 'letemps'.",
)


Expand Down Expand Up @@ -480,10 +479,9 @@ def test_reduce_max_bands(api):
def test_reduce_max_invalid_dimension(api):
res = api.result("reduce_max.json", preprocess=preprocess_check_and_replace("PLACEHOLDER", "orbit"))
res.assert_error(
400, 'ProcessParameterInvalid',
message="The value passed for parameter 'dimension' in process '{p}' is invalid: got 'orbit', but should be one of ['x', 'y', 't', 'bands']".format(
p="reduce_dimension" if api.api_version_compare.at_least("1.0.0") else "reduce"
)
400,
"ProcessParameterInvalid",
message="The value passed for parameter 'dimension' in process 'reduce_dimension' is invalid: Must be one of ['x', 'y', 't', 'bands'] but got 'orbit'.",
)


Expand Down Expand Up @@ -534,10 +532,9 @@ def test_reduce_bands_invalid_dimension(api):
res = api.result("reduce_bands.json",
preprocess=preprocess_check_and_replace('"dimension": "bands"', '"dimension": "layor"'))
res.assert_error(
400, "ProcessParameterInvalid",
message="The value passed for parameter 'dimension' in process '{p}' is invalid: got 'layor', but should be one of ['x', 'y', 't', 'bands']".format(
p="reduce_dimension" if api.api_version_compare.at_least("1.0.0") else "reduce"
)
400,
"ProcessParameterInvalid",
message="The value passed for parameter 'dimension' in process 'reduce_dimension' is invalid: Must be one of ['x', 'y', 't', 'bands'] but got 'layor'.",
)


Expand Down Expand Up @@ -951,8 +948,9 @@ def test_aggregate_temporal_max_invalid_temporal_dimension(api):
preprocess=preprocess_check_and_replace('"dimension": "t"', '"dimension": "detijd"')
)
resp.assert_error(
400, 'ProcessParameterInvalid',
message="The value passed for parameter 'dimension' in process 'aggregate_temporal' is invalid: got 'detijd', but should be one of ['x', 'y', 't']"
400,
"ProcessParameterInvalid",
message="The value passed for parameter 'dimension' in process 'aggregate_temporal' is invalid: Must be one of ['x', 'y', 't'] but got 'detijd'.",
)


Expand Down

0 comments on commit a25f3ab

Please sign in to comment.