Repository: common-workflow-language/cwltool

Issue:
`--single-process` does not correctly apply step-level `ResourceRequirement` overrides
This bug occurs when executing the conformance test https://github.com/common-workflow-language/cwl-v1.2/blob/1.2.1_proposed/tests/steplevel-resreq.cwl.

When I execute the entire workflow, it provides the correct result (runtime.cores=1), but when I execute just `step1` using `--single-process` then it gives the wrong result (runtime.cores=4).

The documentation for `--single-process` says "However, requirements/hints from the step or parent workflow(s) will be inherited as usual" so I would expect it to work.


Discussion:

Resolving patch:
diff --git a/cwltool/workflow.py b/cwltool/workflow.py
--- a/cwltool/workflow.py
+++ b/cwltool/workflow.py
@@ -207,11 +207,19 @@ def __init__(
 
         loadingContext = loadingContext.copy()
 
+        parent_requirements = copy.deepcopy(getdefault(loadingContext.requirements, []))
         loadingContext.requirements = copy.deepcopy(
-            getdefault(loadingContext.requirements, [])
+            toolpath_object.get("requirements", [])
         )
         assert loadingContext.requirements is not None  # nosec
-        loadingContext.requirements.extend(toolpath_object.get("requirements", []))
+        for parent_req in parent_requirements:
+            found_in_step = False
+            for step_req in loadingContext.requirements:
+                if parent_req["class"] == step_req["class"]:
+                    found_in_step = True
+                    break
+            if not found_in_step:
+                loadingContext.requirements.append(parent_req)
         loadingContext.requirements.extend(
             cast(
                 List[CWLObjectType],


Test patch:
diff --git a/tests/subgraph/steplevel-resreq.cwl b/tests/subgraph/steplevel-resreq.cwl
new file mode 100644
--- /dev/null
+++ b/tests/subgraph/steplevel-resreq.cwl
@@ -0,0 +1,33 @@
+#!/usr/bin/env cwl-runner
+class: Workflow
+cwlVersion: v1.2
+
+requirements:
+  ResourceRequirement:
+      coresMin: 4
+      coresMax: 4
+
+inputs: []
+
+steps:
+  step1:
+    requirements:
+      ResourceRequirement:
+          coresMin: 1
+          coresMax: 1
+    run:
+      class: CommandLineTool
+      inputs: []
+      outputs:
+        output:
+          type: stdout
+      baseCommand: echo
+      stdout: cores.txt
+      arguments: [ $(runtime.cores) ]
+    in: []
+    out: [output]
+
+outputs:
+  out:
+    type: File
+    outputSource: step1/output
diff --git a/tests/test_subgraph.py b/tests/test_subgraph.py
--- a/tests/test_subgraph.py
+++ b/tests/test_subgraph.py
@@ -140,6 +140,22 @@ def test_single_process_inherit_reqs_collision() -> None:
     )
 
 
+def test_single_process_inherit_reqs_step_collision() -> None:
+    """Inherit reqs and hints --single-process reqs collision."""
+    err_code, stdout, stderr = get_main_output(
+        [
+            "--single-process",
+            "step1",
+            get_data("tests/subgraph/steplevel-resreq.cwl"),
+        ]
+    )
+    assert err_code == 0
+    assert (
+        json.loads(stdout)["output"]["checksum"]
+        == "sha1$e5fa44f2b31c1fb553b6021e7360d07d5d91ff5e"
+    )
+
+
 def test_single_process_inherit_reqs_hints_collision() -> None:
     """Inherit reqs and hints --single-process reqs + hints collision."""
     err_code, stdout, stderr = get_main_output(