diff --git a/cwltool/update.py b/cwltool/update.py index b7f54a700..e8824e61b 100644 --- a/cwltool/update.py +++ b/cwltool/update.py @@ -55,28 +55,26 @@ def v1_0to1_1( def rewrite_requirements(t: CWLObjectType) -> None: if "requirements" in t: for r in cast(MutableSequence[CWLObjectType], t["requirements"]): - if isinstance(r, MutableMapping): - cls = cast(str, r["class"]) - if cls in rewrite: - r["class"] = rewrite[cls] - else: - raise ValidationException( - "requirements entries must be dictionaries: {} {}.".format(type(r), r) - ) + cls = cast(str, r["class"]) + if cls in rewrite: + r["class"] = rewrite[cls] if "hints" in t: - for r in cast(MutableSequence[CWLObjectType], t["hints"]): + for index, r in enumerate(cast(MutableSequence[CWLObjectType], t["hints"])): if isinstance(r, MutableMapping): + if "class" not in r: + raise SourceLine(r, None, ValidationException).makeError( + "'hints' entry missing required key 'class'." + ) cls = cast(str, r["class"]) if cls in rewrite: r["class"] = rewrite[cls] else: - raise ValidationException(f"hints entries must be dictionaries: {type(r)} {r}.") + raise SourceLine(t["hints"], index, ValidationException).makeError( + f"'hints' entries must be dictionaries: {type(r)} {r}." + ) if "steps" in t: for s in cast(MutableSequence[CWLObjectType], t["steps"]): - if isinstance(s, MutableMapping): - rewrite_requirements(s) - else: - raise ValidationException(f"steps entries must be dictionaries: {type(s)} {s}.") + rewrite_requirements(s) def update_secondaryFiles( t: CWLOutputType, top: bool = False diff --git a/tests/test_load_tool.py b/tests/test_load_tool.py index 9727d772b..3d0cba161 100644 --- a/tests/test_load_tool.py +++ b/tests/test_load_tool.py @@ -3,6 +3,7 @@ from pathlib import Path import pytest +from schema_salad.exceptions import ValidationException from cwltool.context import LoadingContext, RuntimeContext from cwltool.errors import WorkflowException @@ -143,3 +144,25 @@ def test_import_tracked() -> None: assert tool.doc_loader is not None assert path in tool.doc_loader.idx + + +def test_load_badhints() -> None: + """Check for expected error while update a bads hints list.""" + loadingContext = LoadingContext() + uri = Path(get_data("tests/wf/hello-workflow-badhints.cwl")).as_uri() + with pytest.raises( + ValidationException, + match=r".*tests\/wf\/hello-workflow-badhints\.cwl\:18:4:\s*'hints'\s*entry\s*missing\s*required\s*key\s*'class'\.", + ): + load_tool(uri, loadingContext) + + +def test_load_badhints_nodict() -> None: + """Check for expected error while update a hints list with a numerical entry.""" + loadingContext = LoadingContext() + uri = Path(get_data("tests/wf/hello-workflow-badhints2.cwl")).as_uri() + with pytest.raises( + ValidationException, + match=r".*tests\/wf\/hello-workflow-badhints2\.cwl:41:5:\s*'hints'\s*entries\s*must\s*be\s*dictionaries:\s*\s*42\.", + ): + load_tool(uri, loadingContext) diff --git a/tests/wf/hello-workflow-badhints.cwl b/tests/wf/hello-workflow-badhints.cwl new file mode 100755 index 000000000..e4bc659f1 --- /dev/null +++ b/tests/wf/hello-workflow-badhints.cwl @@ -0,0 +1,41 @@ +#!/usr/bin/env cwl-runner + +cwlVersion: v1.0 +class: Workflow + +label: "Hello World" +doc: "Outputs a message using echo" + +inputs: + usermessage: string + +outputs: + response: + outputSource: step0/response + type: File + +hints: + - {} + +steps: + step0: + run: + class: CommandLineTool + inputs: + message: + type: string + doc: "The message to print" + default: "Hello World" + inputBinding: + position: 1 + baseCommand: echo + arguments: + - "-n" + - "-e" + stdout: response.txt + outputs: + response: + type: stdout + in: + message: usermessage + out: [response] diff --git a/tests/wf/hello-workflow-badhints2.cwl b/tests/wf/hello-workflow-badhints2.cwl new file mode 100755 index 000000000..1cc17229e --- /dev/null +++ b/tests/wf/hello-workflow-badhints2.cwl @@ -0,0 +1,41 @@ +#!/usr/bin/env cwl-runner + +cwlVersion: v1.0 +class: Workflow + +label: "Hello World" +doc: "Outputs a message using echo" + +inputs: + usermessage: string + +outputs: + response: + outputSource: step0/response + type: File + +steps: + step0: + run: + class: CommandLineTool + inputs: + message: + type: string + doc: "The message to print" + default: "Hello World" + inputBinding: + position: 1 + baseCommand: echo + arguments: + - "-n" + - "-e" + stdout: response.txt + outputs: + response: + type: stdout + in: + message: usermessage + out: [response] + +hints: + - 42