Skip to content

Commit 57f9be0

Browse files
authored
packing: treat the IDs of the outputs separately (#1501)
1 parent ffb7513 commit 57f9be0

File tree

4 files changed

+112
-20
lines changed

4 files changed

+112
-20
lines changed

cwltool/pack.py

Lines changed: 50 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -172,8 +172,15 @@ def loadref(base: Optional[str], lr_uri: str) -> ResolveType:
172172
raise Exception("loader should not be None")
173173
return lr_loadingContext.loader.resolve_ref(lr_uri, base_url=base)[0]
174174

175-
ids = set() # type: Set[str]
176-
find_ids(processobj, ids)
175+
input_ids: Set[str] = set()
176+
output_ids: Set[str] = set()
177+
178+
if isinstance(processobj, MutableSequence):
179+
mainobj = processobj[0]
180+
else:
181+
mainobj = processobj
182+
find_ids(cast(Dict[str, Any], mainobj)["inputs"], input_ids)
183+
find_ids(cast(Dict[str, Any], mainobj)["outputs"], output_ids)
177184

178185
runs = {uri}
179186
find_run(processobj, loadref, runs)
@@ -186,17 +193,19 @@ def loadref(base: Optional[str], lr_uri: str) -> ResolveType:
186193
update_to_version = ORDERED_VERSIONS[m]
187194

188195
for f in runs:
189-
find_ids(document_loader.resolve_ref(f)[0], ids)
196+
find_ids(document_loader.resolve_ref(f)[0], input_ids)
190197

191-
names = set() # type: Set[str]
192-
if rewrite_out is None:
193-
rewrite = {} # type: Dict[str, str]
194-
else:
195-
rewrite = rewrite_out
198+
input_names: Set[str] = set()
199+
output_names: Set[str] = set()
200+
201+
rewrite_inputs: Dict[str, str] = {}
202+
rewrite_outputs: Dict[str, str] = {}
196203

197204
mainpath, _ = urllib.parse.urldefrag(uri)
198205

199-
def rewrite_id(r: str, mainuri: str) -> None:
206+
def rewrite_id(
207+
r: str, mainuri: str, rewrite: Dict[str, str], names: Set[str]
208+
) -> None:
200209
if r == mainuri:
201210
rewrite[r] = "#main"
202211
elif r.startswith(mainuri) and r[len(mainuri)] in ("#", "/"):
@@ -212,17 +221,20 @@ def rewrite_id(r: str, mainuri: str) -> None:
212221
if path not in rewrite:
213222
rewrite[path] = "#" + uniquename(shortname(path), names)
214223

215-
sortedids = sorted(ids)
224+
sorted_input_ids = sorted(input_ids)
225+
sorted_output_ids = sorted(output_ids)
216226

217-
for r in sortedids:
218-
rewrite_id(r, uri)
227+
for r in sorted_input_ids:
228+
rewrite_id(r, uri, rewrite_inputs, input_names)
229+
for r in sorted_output_ids:
230+
rewrite_id(r, uri, rewrite_outputs, output_names)
219231

220232
packed = CommentedMap(
221233
(("$graph", CommentedSeq()), ("cwlVersion", update_to_version))
222234
)
223235
namespaces = metadata.get("$namespaces", None)
224236

225-
schemas = set() # type: Set[str]
237+
schemas: Set[str] = set()
226238
if "$schemas" in metadata:
227239
for each_schema in metadata["$schemas"]:
228240
schemas.add(each_schema)
@@ -259,7 +271,7 @@ def rewrite_id(r: str, mainuri: str) -> None:
259271
):
260272
continue
261273
dc = cast(Dict[str, Any], copy.deepcopy(dcr))
262-
v = rewrite[r]
274+
v = rewrite_inputs[r]
263275
dc["id"] = v
264276
for n in ("name", "cwlVersion", "$namespaces", "$schemas"):
265277
if n in dc:
@@ -271,12 +283,29 @@ def rewrite_id(r: str, mainuri: str) -> None:
271283
if namespaces:
272284
packed["$namespaces"] = namespaces
273285

274-
for r in list(rewrite.keys()):
275-
v = rewrite[r]
276-
replace_refs(packed, rewrite, r + "/" if "#" in r else r + "#", v + "/")
286+
save_outputs = packed["$graph"][0].pop("outputs")
287+
for r in list(rewrite_inputs.keys()):
288+
v = rewrite_inputs[r]
289+
replace_refs(packed, rewrite_inputs, r + "/" if "#" in r else r + "#", v + "/")
277290

278291
import_embed(packed, set())
279292

293+
packed["$graph"][0]["outputs"] = save_outputs
294+
for r in list(rewrite_outputs.keys()):
295+
v = rewrite_outputs[r]
296+
replace_refs(
297+
packed["$graph"][0]["outputs"],
298+
rewrite_outputs,
299+
r + "/" if "#" in r else r + "#",
300+
v + "/",
301+
)
302+
303+
for r in list(
304+
rewrite_inputs.keys()
305+
): # again, to process the outputSource references
306+
v = rewrite_inputs[r]
307+
replace_refs(packed, rewrite_inputs, r + "/" if "#" in r else r + "#", v + "/")
308+
280309
if len(packed["$graph"]) == 1:
281310
# duplicate 'cwlVersion', '$schemas', and '$namespaces' inside '$graph'
282311
# when there is only a single item because main.print_pack() will print
@@ -287,4 +316,8 @@ def rewrite_id(r: str, mainuri: str) -> None:
287316
if namespaces:
288317
packed["$graph"][0]["$namespaces"] = namespaces
289318

319+
if rewrite_out is not None:
320+
rewrite_out.update(rewrite_inputs)
321+
rewrite_out.update(rewrite_outputs)
322+
290323
return packed

tests/test_pack.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from functools import partial
66
from io import StringIO
77
from pathlib import Path
8-
from typing import Any, Dict, List, cast
8+
from typing import Dict
99

1010
import pytest
1111
from schema_salad.utils import yaml_no_ts
@@ -30,6 +30,10 @@
3030
"tests/wf/operation/expect_operation-single_packed.cwl",
3131
),
3232
("tests/wf/trick_revsort.cwl", "tests/wf/expect_trick_packed.cwl"),
33+
(
34+
"tests/wf/iwd-passthrough1.cwl",
35+
"tests/wf/expect_iwd-passthrough1_packed.cwl",
36+
),
3337
(
3438
"tests/wf/revsort_datetime.cwl",
3539
"tests/wf/expect_revsort_datetime_packed.cwl",
@@ -45,8 +49,6 @@ def test_packing(unpacked: str, expected: str) -> None:
4549
)
4650

4751
packed = json.loads(print_pack(loadingContext, uri))
48-
if len(cast(List[Any], packed["$graph"])) == 1:
49-
packed = cast(List[Any], packed["$graph"])[0]
5052
context_dir = os.path.abspath(os.path.dirname(get_data(unpacked)))
5153
adjustFileObjs(packed, partial(make_relative, context_dir))
5254
adjustDirObjs(packed, partial(make_relative, context_dir))
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{
2+
"class": "CommandLineTool",
3+
"doc": "YAML |- syntax does not add trailing newline so in the listing entry\nbelow there is no whitespace surrounding the value\n$(inputs.filelist), so it is evaluated as a File object. Compare to\niwd-passthrough2.cwl\n",
4+
"requirements": [
5+
{
6+
"listing": [
7+
{
8+
"entryname": "renamed-filelist.txt",
9+
"entry": "$(inputs.filelist)"
10+
}
11+
],
12+
"class": "InitialWorkDirRequirement"
13+
}
14+
],
15+
"inputs": [
16+
{
17+
"type": "File",
18+
"id": "#main/filelist"
19+
}
20+
],
21+
"baseCommand": "true",
22+
"id": "#main",
23+
"outputs": [
24+
{
25+
"type": "File",
26+
"outputBinding": {
27+
"glob": "renamed-filelist.txt"
28+
},
29+
"id": "#main/filelist"
30+
}
31+
],
32+
"cwlVersion": "v1.2"
33+
}

tests/wf/iwd-passthrough1.cwl

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#!/usr/bin/env cwl-runner
2+
class: CommandLineTool
3+
cwlVersion: v1.2
4+
doc: |
5+
YAML |- syntax does not add trailing newline so in the listing entry
6+
below there is no whitespace surrounding the value
7+
$(inputs.filelist), so it is evaluated as a File object. Compare to
8+
iwd-passthrough2.cwl
9+
10+
requirements:
11+
InitialWorkDirRequirement:
12+
listing:
13+
- entryname: "renamed-filelist.txt"
14+
entry: |-
15+
$(inputs.filelist)
16+
inputs:
17+
filelist:
18+
type: File
19+
outputs:
20+
filelist:
21+
type: File
22+
outputBinding:
23+
glob: renamed-filelist.txt
24+
baseCommand: "true"

0 commit comments

Comments
 (0)