diff --git a/openeo_driver/ProcessGraphDeserializer.py b/openeo_driver/ProcessGraphDeserializer.py index 9ff795d8..479c495d 100644 --- a/openeo_driver/ProcessGraphDeserializer.py +++ b/openeo_driver/ProcessGraphDeserializer.py @@ -2145,6 +2145,20 @@ def text_merge( data: List[Union[str, int, float, bool, None]], separator: Union[str, int, float, bool, None] = "" ) -> str: + # TODO #196 text_merge is deprecated if favor of test_concat + return str(separator).join(str(d) for d in data) + + +# TODO #195 #196 use official spec instead of custom openeo-processes/experimental/text_concat.json +@process_registry_100.add_function(spec=read_spec("openeo-processes/experimental/text_concat.json")) +def text_concat( + args: Dict, + env: EvalEnv + # data: List[Union[str, int, float, bool, None]], + # separator: Union[str, int, float, bool, None] = "" +) -> str: + data = extract_arg(args, "data") + separator = args.get("separator", "") return str(separator).join(str(d) for d in data) diff --git a/openeo_driver/processes.py b/openeo_driver/processes.py index dfac4658..d6081fc7 100644 --- a/openeo_driver/processes.py +++ b/openeo_driver/processes.py @@ -140,10 +140,10 @@ def add_process(self, name: str, function: Callable = None, spec: dict = None, n if function and self._argument_names: sig = inspect.signature(function) arg_names = [n for n, p in sig.parameters.items() if p.kind == inspect.Parameter.POSITIONAL_OR_KEYWORD] - if arg_names[:len(self._argument_names)] != self._argument_names: - raise ProcessRegistryException("Process {p!r} has invalid argument names: {a}".format( - p=name, a=arg_names - )) + if arg_names[: len(self._argument_names)] != self._argument_names: + raise ProcessRegistryException( + f"Process {name!r} has invalid argument names: {arg_names}. Expected {self._argument_names}" + ) self._processes[self._key(name=name, namespace=namespace)] = ProcessData(function=function, spec=spec) diff --git a/openeo_driver/specs/openeo-processes/experimental/text_concat.json b/openeo_driver/specs/openeo-processes/experimental/text_concat.json new file mode 100644 index 00000000..698c1cbc --- /dev/null +++ b/openeo_driver/specs/openeo-processes/experimental/text_concat.json @@ -0,0 +1,104 @@ +{ + "id": "text_concat", + "summary": "Concatenate elements to a single text", + "description": "Merges text representations (also known as *string*) of a set of elements to a single text, having the separator between each element.", + "categories": [ + "texts" + ], + "parameters": [ + { + "name": "data", + "description": "A set of elements. Numbers, boolean values and null values get converted to their (lower case) string representation. For example: `1` (integer), `-1.5` (number), `true` / `false` (boolean values)", + "schema": { + "type": "array", + "items": { + "type": [ + "string", + "number", + "boolean", + "null" + ] + } + } + }, + { + "name": "separator", + "description": "A separator to put between each of the individual texts. Defaults to an empty string.", + "schema": { + "type": [ + "string", + "number", + "boolean", + "null" + ] + }, + "default": "", + "optional": true + } + ], + "returns": { + "description": "A string containing a string representation of all the array elements in the same order, with the separator between each element.", + "schema": { + "type": "string" + } + }, + "examples": [ + { + "arguments": { + "data": [ + "Hello", + "World" + ], + "separator": " " + }, + "returns": "Hello World" + }, + { + "arguments": { + "data": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 0 + ] + }, + "returns": "1234567890" + }, + { + "arguments": { + "data": [ + null, + true, + false, + 1, + -1.5, + "ß" + ], + "separator": "\n" + }, + "returns": "null\ntrue\nfalse\n1\n-1.5\nß" + }, + { + "arguments": { + "data": [ + 2, + 0 + ], + "separator": 1 + }, + "returns": "210" + }, + { + "arguments": { + "data": [] + }, + "returns": "" + } + ] +} diff --git a/tests/test_views_execute.py b/tests/test_views_execute.py index b79ad974..583306b9 100644 --- a/tests/test_views_execute.py +++ b/tests/test_views_execute.py @@ -2134,23 +2134,30 @@ def test_execute_no_cube_logic(api100, process_graph, expected): assert api100.result(process_graph).assert_status_code(200).json == expected -@pytest.mark.parametrize(["process_id", "arguments", "expected"], [ - ("text_begins", {"data": "FooBar", "pattern": "Foo"}, True), - ("text_begins", {"data": "FooBar", "pattern": "Bar"}, False), - ("text_begins", {"data": "FooBar", "pattern": "fOo"}, False), - ("text_begins", {"data": "FooBar", "pattern": "fOo", "case_sensitive": False}, True), - ("text_contains", {"data": "FooBar", "pattern": "oB"}, True), - ("text_contains", {"data": "FooBar", "pattern": "ob"}, False), - ("text_contains", {"data": "FooBar", "pattern": "ob", "case_sensitive": False}, True), - ("text_ends", {"data": "FooBar", "pattern": "Bar"}, True), - ("text_ends", {"data": "FooBar", "pattern": "Foo"}, False), - ("text_ends", {"data": "FooBar", "pattern": "bar"}, False), - ("text_ends", {"data": "FooBar", "pattern": "bar", "case_sensitive": False}, True), - ("text_merge", {"data": ["foo", "bar"]}, "foobar"), - ("text_merge", {"data": ["foo", "bar"], "separator": "--"}, "foo--bar"), - ("text_merge", {"data": [1, 2, 3], "separator": "/"}, "1/2/3"), - ("text_merge", {"data": [1, "b"], "separator": 0}, "10b"), -]) +@pytest.mark.parametrize( + ["process_id", "arguments", "expected"], + [ + ("text_begins", {"data": "FooBar", "pattern": "Foo"}, True), + ("text_begins", {"data": "FooBar", "pattern": "Bar"}, False), + ("text_begins", {"data": "FooBar", "pattern": "fOo"}, False), + ("text_begins", {"data": "FooBar", "pattern": "fOo", "case_sensitive": False}, True), + ("text_contains", {"data": "FooBar", "pattern": "oB"}, True), + ("text_contains", {"data": "FooBar", "pattern": "ob"}, False), + ("text_contains", {"data": "FooBar", "pattern": "ob", "case_sensitive": False}, True), + ("text_ends", {"data": "FooBar", "pattern": "Bar"}, True), + ("text_ends", {"data": "FooBar", "pattern": "Foo"}, False), + ("text_ends", {"data": "FooBar", "pattern": "bar"}, False), + ("text_ends", {"data": "FooBar", "pattern": "bar", "case_sensitive": False}, True), + ("text_merge", {"data": ["foo", "bar"]}, "foobar"), + ("text_merge", {"data": ["foo", "bar"], "separator": "--"}, "foo--bar"), + ("text_merge", {"data": [1, 2, 3], "separator": "/"}, "1/2/3"), + ("text_merge", {"data": [1, "b"], "separator": 0}, "10b"), + ("text_concat", {"data": ["foo", "bar"]}, "foobar"), + ("text_concat", {"data": ["foo", "bar"], "separator": "--"}, "foo--bar"), + ("text_concat", {"data": [1, 2, 3], "separator": "/"}, "1/2/3"), + ("text_concat", {"data": [1, "b"], "separator": 0}, "10b"), + ], +) def test_text_processes(api100, process_id, arguments, expected): # TODO: null propagation (`text_begins(data=null,...) -> null`) can not be tested at the moment pg = {"t": {"process_id": process_id, "arguments": arguments, "result":True}}