Skip to content

Commit 0f7367b

Browse files
authored
required outputs with secondaryFiles fix for containers (#1870)
* required outputs with secondaryFiles fix for containers * improve error message * leave no files behind
1 parent 263a554 commit 0f7367b

File tree

4 files changed

+178
-3
lines changed

4 files changed

+178
-3
lines changed

cwltool/command_line_tool.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1454,10 +1454,18 @@ def collect_output(
14541454
continue
14551455
if isinstance(sfitem, str):
14561456
sfitem = {"path": pathprefix + sfitem}
1457-
if not fs_access.exists(sfitem["path"]) and sf_required:
1457+
original_sfitem = copy.deepcopy(sfitem)
1458+
if (
1459+
not fs_access.exists(
1460+
cast(
1461+
str, cast(CWLObjectType, revmap(sfitem))["location"]
1462+
)
1463+
)
1464+
and sf_required
1465+
):
14581466
raise WorkflowException(
14591467
"Missing required secondary file '%s'"
1460-
% (sfitem["path"])
1468+
% (original_sfitem["path"])
14611469
)
14621470
if "path" in sfitem and "location" not in sfitem:
14631471
revmap(sfitem)
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#!/usr/bin/env cwl-runner
2+
cwlVersion: v1.2
3+
class: CommandLineTool
4+
5+
hints:
6+
DockerRequirement:
7+
dockerPull: docker.io/alpine:latest
8+
9+
inputs: []
10+
11+
baseCommand: [ touch, file.ext1, file.ext2 ]
12+
13+
outputs:
14+
output:
15+
type: File
16+
secondaryFiles:
17+
- pattern: ^.ext2
18+
required: true
19+
outputBinding:
20+
glob: file.ext1
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#!/usr/bin/env cwl-runner
2+
cwlVersion: v1.2
3+
class: CommandLineTool
4+
5+
hints:
6+
DockerRequirement:
7+
dockerPull: docker.io/alpine:latest
8+
9+
inputs: []
10+
11+
baseCommand: [ touch, file.ext1, file.ext2 ]
12+
13+
outputs:
14+
output:
15+
type: File
16+
secondaryFiles:
17+
- pattern: ^.ext3
18+
required: true
19+
outputBinding:
20+
glob: file.ext1

tests/test_docker.py

Lines changed: 128 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,20 @@
11
"""Tests for docker engine."""
2+
import json
23
import re
34
from pathlib import Path
45
from shutil import which
56

7+
import pytest
8+
69
from cwltool.main import main
710

8-
from .util import get_data, get_main_output, needs_docker
11+
from .util import (
12+
get_data,
13+
get_main_output,
14+
needs_docker,
15+
needs_podman,
16+
needs_singularity,
17+
)
918

1019

1120
@needs_docker
@@ -136,3 +145,121 @@ def test_docker_strict_memory_limit_warning(tmp_path: Path) -> None:
136145
stderr = re.sub(r"\s\s+", " ", stderr)
137146
assert result_code == 0
138147
assert "Skipping Docker software container '--memory' limit" in stderr
148+
149+
150+
@needs_docker
151+
def test_docker_required_secfile(tmp_path: Path) -> None:
152+
result_code, stdout, stderr = get_main_output(
153+
[
154+
"--outdir",
155+
str(tmp_path),
156+
get_data("tests/secondary-files-required-container.cwl"),
157+
]
158+
)
159+
assert result_code == 0, stderr
160+
assert (
161+
json.loads(stdout)["output"]["secondaryFiles"][0]["checksum"]
162+
== "sha1$da39a3ee5e6b4b0d3255bfef95601890afd80709"
163+
)
164+
165+
166+
@needs_podman
167+
def test_podman_required_secfile(tmp_path: Path) -> None:
168+
result_code, stdout, stderr = get_main_output(
169+
[
170+
"--podman",
171+
"--outdir",
172+
str(tmp_path),
173+
get_data("tests/secondary-files-required-container.cwl"),
174+
]
175+
)
176+
assert result_code == 0, stderr
177+
assert (
178+
json.loads(stdout)["output"]["secondaryFiles"][0]["checksum"]
179+
== "sha1$da39a3ee5e6b4b0d3255bfef95601890afd80709"
180+
)
181+
182+
183+
@needs_singularity
184+
def test_singularity_required_secfile(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
185+
singularity_dir = tmp_path / "singularity"
186+
singularity_dir.mkdir()
187+
monkeypatch.setenv("CWL_SINGULARITY_CACHE", str(singularity_dir))
188+
189+
result_code, stdout, stderr = get_main_output(
190+
[
191+
"--singularity",
192+
"--outdir",
193+
str(tmp_path / "out"),
194+
get_data("tests/secondary-files-required-container.cwl"),
195+
]
196+
)
197+
assert result_code == 0, stderr
198+
assert (
199+
json.loads(stdout)["output"]["secondaryFiles"][0]["checksum"]
200+
== "sha1$da39a3ee5e6b4b0d3255bfef95601890afd80709"
201+
)
202+
203+
204+
@needs_docker
205+
def test_docker_required_missing_secfile(tmp_path: Path) -> None:
206+
result_code, stdout, stderr = get_main_output(
207+
[
208+
"--outdir",
209+
str(tmp_path),
210+
get_data("tests/secondary-files-required-missing-container.cwl"),
211+
]
212+
)
213+
assert result_code == 1, stderr
214+
stderr = re.sub(r"\s\s+", " ", stderr)
215+
assert "Job error:" in stderr
216+
assert "Error collecting output for parameter 'output'" in stderr
217+
assert (
218+
"tests/secondary-files-required-missing-container.cwl:16:5: Missing required secondary file"
219+
)
220+
assert "file.ext3" in stderr
221+
222+
223+
@needs_podman
224+
def test_podman_required_missing_secfile(tmp_path: Path) -> None:
225+
result_code, stdout, stderr = get_main_output(
226+
[
227+
"--podman",
228+
"--outdir",
229+
str(tmp_path),
230+
get_data("tests/secondary-files-required-missing-container.cwl"),
231+
]
232+
)
233+
assert result_code == 1, stderr
234+
stderr = re.sub(r"\s\s+", " ", stderr)
235+
assert "Job error:" in stderr
236+
assert "Error collecting output for parameter 'output'" in stderr
237+
assert (
238+
"tests/secondary-files-required-missing-container.cwl:16:5: Missing required secondary file"
239+
)
240+
assert "file.ext3" in stderr
241+
242+
243+
@needs_singularity
244+
def test_singularity_required_missing_secfile(
245+
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
246+
) -> None:
247+
singularity_dir = tmp_path / "singularity"
248+
singularity_dir.mkdir()
249+
monkeypatch.setenv("CWL_SINGULARITY_CACHE", str(singularity_dir))
250+
result_code, stdout, stderr = get_main_output(
251+
[
252+
"--singularity",
253+
"--outdir",
254+
str(tmp_path),
255+
get_data("tests/secondary-files-required-missing-container.cwl"),
256+
]
257+
)
258+
assert result_code == 1, stderr
259+
stderr = re.sub(r"\s\s+", " ", stderr)
260+
assert "Job error:" in stderr
261+
assert "Error collecting output for parameter 'output'" in stderr
262+
assert (
263+
"tests/secondary-files-required-missing-container.cwl:16:5: Missing required secondary file"
264+
)
265+
assert "file.ext3" in stderr

0 commit comments

Comments
 (0)