Skip to content

Commit ccf3de5

Browse files
authored
Merge pull request #1072 from common-workflow-language/inputBinding.position-expr
Input binding.position expr
2 parents bffea7f + 3838819 commit ccf3de5

15 files changed

+384
-146
lines changed

cwltool/builder.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,13 @@ def bind_input(self,
211211

212212
bp = list(aslist(lead_pos))
213213
if "position" in binding:
214-
bp.extend(aslist(binding["position"]))
214+
position = binding["position"]
215+
if isinstance(position, str): # no need to test the CWL Version
216+
# the schema for v1.0 only allow ints
217+
binding['position'] = self.do_eval(position, context=datum)
218+
bp.append(binding['position'])
219+
else:
220+
bp.extend(aslist(binding['position']))
215221
else:
216222
bp.append(0)
217223
bp.extend(aslist(tail_pos))

cwltool/command_line_tool.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -592,12 +592,17 @@ def collect_output_ports(self,
592592
ports, # type: Set[Dict[Text, Any]]
593593
builder, # type: Builder
594594
outdir, # type: Text
595+
rcode, # type: int
595596
compute_checksum=True, # type: bool
596597
jobname="", # type: Text
597598
readers=None # type: Dict[Text, Any]
598599
): # type: (...) -> OutputPorts
599600
ret = {} # type: OutputPorts
600601
debug = _logger.isEnabledFor(logging.DEBUG)
602+
cwl_version = self.metadata.get(
603+
"http://commonwl.org/cwltool#original_cwlVersion", None)
604+
if cwl_version != "v1.0":
605+
builder.resources["exitCode"] = rcode
601606
try:
602607
fs_access = builder.make_fs_access(outdir)
603608
custom_output = fs_access.join(outdir, "cwl.output.json")

cwltool/job.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -187,8 +187,8 @@ def __init__(self,
187187
self.generatemapper = None # type: Optional[PathMapper]
188188

189189
# set in CommandLineTool.job(i)
190-
self.collect_outputs = cast(Callable[[Any], Any],
191-
None) # type: Union[Callable[[Any], Any], functools.partial[Any]]
190+
self.collect_outputs = cast(Callable[[Text, int], MutableMapping[Text, Any]],
191+
None) # type: Union[Callable[[Text, int], MutableMapping[Text, Any]], functools.partial[MutableMapping[Text, Any]]]
192192
self.output_callback = cast(Callable[[Any, Any], Any], None)
193193
self.outdir = u""
194194
self.tmpdir = u""
@@ -261,7 +261,7 @@ def _execute(self,
261261
assert runtimeContext.prov_obj is not None
262262
runtimeContext.prov_obj.used_artefacts(
263263
job_order, runtimeContext.process_run_id, str(self.name))
264-
outputs = {} # type: Dict[Text,Text]
264+
outputs = {} # type: MutableMapping[Text,Any]
265265
try:
266266
stdin_path = None
267267
if self.stdin is not None:
@@ -328,7 +328,7 @@ def _execute(self,
328328
self.generatemapper, self.outdir, self.builder.outdir,
329329
inplace_update=self.inplace_update)
330330

331-
outputs = self.collect_outputs(self.outdir)
331+
outputs = self.collect_outputs(self.outdir, rcode)
332332
outputs = bytes2str_in_dicts(outputs) # type: ignore
333333
except OSError as e:
334334
if e.errno == 2:
@@ -689,7 +689,7 @@ def docker_monitor(self, cidfile, tmpdir_prefix, cleanup_cidfile, process):
689689
try:
690690
with open(cidfile) as cidhandle:
691691
cid = cidhandle.readline().strip()
692-
except OSError:
692+
except (OSError, IOError):
693693
cid = None
694694
max_mem = self.docker_get_memory(cid)
695695
tmp_dir, tmp_prefix = os.path.split(tmpdir_prefix)

cwltool/process.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
import tempfile
1414
import textwrap
1515
import uuid
16-
from collections import Iterable # pylint: disable=unused-import
16+
1717
from io import open
1818
from typing import (Any, Callable, Dict, Generator, Iterator, List,
1919
Mapping, MutableMapping, MutableSequence, Optional, Set, Tuple,
@@ -53,6 +53,10 @@
5353
if TYPE_CHECKING:
5454
from .provenance import ProvenanceProfile # pylint: disable=unused-import
5555

56+
if PY3:
57+
from collections.abc import Iterable # only works on python 3.3+
58+
else:
59+
from collections import Iterable # pylint: disable=unused-import
5660

5761
class LogAsDebugFilter(logging.Filter):
5862
def __init__(self, name, parent): # type: (Text, logging.Logger) -> None
@@ -722,7 +726,14 @@ def inc(d): # type: (List[int]) -> None
722726
if isinstance(arg, MutableMapping):
723727
arg = copy.deepcopy(arg)
724728
if arg.get("position"):
725-
arg["position"] = [arg["position"], i]
729+
position = arg.get("position")
730+
if isinstance(position, str): # no need to test the
731+
# CWLVersion as the v1.0
732+
# schema only allows ints
733+
position = builder.do_eval(position)
734+
if position is None:
735+
position = 0
736+
arg["position"] = [position, i]
726737
else:
727738
arg["position"] = [0, i]
728739
bindings.append(arg)

cwltool/schemas/v1.1.0-dev1/CommandLineTool.yml

Lines changed: 55 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
saladVersion: v1.1
12
$base: "https://w3id.org/cwl/cwl#"
23

34
$namespaces:
@@ -56,8 +57,8 @@ $graph:
5657
* When defining record types with `CommandInputRecordSchema`, fields of
5758
type `File` may now include `format`, `loadContents`,
5859
`secondaryFiles` and `streamable`.
59-
* `CommandInputRecordSchema`, `CommandOutputRecordSchema`,
60-
`CommandInputEnumSchema and `CommandInputArraySchema` now have an optional
60+
* `CommandInputRecordSchema`, `CommandOutputRecordSchema`,
61+
`CommandInputEnumSchema and `CommandInputArraySchema` now have an optional
6162
`doc` field.
6263
* `inputBinding` has been added as an optional field for
6364
`CommandInputRecordSchema` (was previously in CWL `draft-3` but
@@ -88,8 +89,8 @@ $graph:
8889
* Added `InputParameter.loadContents` field. Use of `loadContents` in
8990
`InputBinding` is deprecated; it is preserved for v1.0 backwards
9091
compatability and will be removed in CWL v2.0.
91-
* [Added](#ToolTimeLimit) `ToolTimeLimit` feature, allowing to set an upper limit on the
92-
execution time of a CommandLineTool.
92+
* [Added](#ToolTimeLimit) `ToolTimeLimit` feature, allows setting
93+
an upper limit on the execution time of a CommandLineTool.
9394
* [Added](#WorkReuse) `WorkReuse` feature, allowing to enable or disable the reuse
9495
behavior for a particular tool or step for implementations that
9596
support reusing output from past work.
@@ -100,6 +101,15 @@ $graph:
100101
* [Added](#LoadListingRequirement) `LoadListingRequirement`
101102
and [loadListing](#LoadContents) to control whether and how
102103
`Directory` listings should be loaded for use in expressions.
104+
* The position field of the [CommandLineBinding](#CommandLineBinding) can
105+
now be calculated from a CWL Expression.
106+
* The exit code of a CommandLineTool invocation is now
107+
available to expressions in `outputEval` as `runtime.exitCode`
108+
* [Better explain](#map) the `map<…>` notation that has existed since v1.0.
109+
* Fixed schema error where the `type` field inside the `inputs` and
110+
`outputs` field was incorrectly listed as optional.
111+
* For multi-Process CWL documents, if no particular process is named then
112+
the process with the `id` of `#main` is chosen.
103113
104114
See also the [CWL Workflow Description, v1.1.0-dev1 changelog](Workflow.html#Changelog).
105115
@@ -197,8 +207,14 @@ $graph:
197207
198208
fields:
199209
- name: position
200-
type: int?
201-
doc: "The sorting key. Default position is 0."
210+
type: [ int, Expression, string, "null" ]
211+
doc: |
212+
The sorting key. Default position is 0. If the inputBinding is
213+
associated with an input parameter, then the value of `self` in the
214+
expression will be the value of the input parameter. Input parameter
215+
defaults (as specified by the `InputParameter.default` field) must be
216+
applied before evaluating the expression. Expressions must return a
217+
single value of type int or a null.
202218
- name: prefix
203219
type: string?
204220
doc: "Command line prefix to add before the value."
@@ -316,13 +332,15 @@ $graph:
316332
- string
317333
- Expression
318334
doc: |
319-
Evaluate an expression to generate the output value. If `glob` was
320-
specified, the value of `self` must be an array containing file objects
321-
that were matched. If no files were matched, `self` must be a zero
322-
length array; if a single file was matched, the value of `self` is an
323-
array of a single element. Additionally, if `loadContents` is `true`,
324-
the File objects must include up to the first 64 KiB of file contents
325-
in the `contents` field.
335+
Evaluate an expression to generate the output value. If
336+
`glob` was specified, the value of `self` must be an array
337+
containing file objects that were matched. If no files were
338+
matched, `self` must be a zero length array; if a single file
339+
was matched, the value of `self` is an array of a single
340+
element. Additionally, if `loadContents` is `true`, the File
341+
objects must include up to the first 64 KiB of file contents
342+
in the `contents` field. The exit code of the process is
343+
available in the expression as `runtime.exitCode`.
326344
327345
- name: CommandLineBindable
328346
type: record
@@ -436,7 +454,6 @@ $graph:
436454
fields:
437455
- name: type
438456
type:
439-
- "null"
440457
- CWLType
441458
- stdin
442459
- CommandInputRecordSchema
@@ -471,7 +488,6 @@ $graph:
471488
fields:
472489
- name: type
473490
type:
474-
- "null"
475491
- CWLType
476492
- stdout
477493
- stderr
@@ -1097,36 +1113,6 @@ $graph:
10971113
doc: Maximum reserved filesystem based storage for the designated output directory, in mebibytes (2**20)
10981114

10991115

1100-
- type: record
1101-
name: ToolTimeLimit
1102-
extends: ProcessRequirement
1103-
doc: |
1104-
Set an upper limit on the execution time of a CommandLineTool.
1105-
A tool execution which exceeds the time limit may
1106-
be preemptively terminated and considered failed. May also be
1107-
used by batch systems to make scheduling decisions.
1108-
1109-
Limit applies only to the command execution time. Time for
1110-
additional steps, such as file download/upload, docker pull or
1111-
expression evaluation is not considered for exceeding time limit.
1112-
1113-
If ToolTimeLimit is set on a workflow level, it propagates down to
1114-
individual processes, in line with requirement inheritance rules.
1115-
ToolTimeLimit is not used to limit the execution time of a Workflow.
1116-
fields:
1117-
- name: class
1118-
type: string
1119-
doc: "Always 'ToolTimeLimit'"
1120-
jsonldPredicate:
1121-
"_id": "@type"
1122-
"_type": "@vocab"
1123-
- name: timelimit
1124-
type: [long, string, Expression]
1125-
doc: |
1126-
The time limit, in seconds. A time limit of zero means no
1127-
time limit. Negative time limits are an error.
1128-
1129-
11301116
- type: record
11311117
name: WorkReuse
11321118
extends: ProcessRequirement
@@ -1226,3 +1212,27 @@ $graph:
12261212
"_type": "@vocab"
12271213
inplaceUpdate:
12281214
type: boolean
1215+
1216+
- type: record
1217+
name: ToolTimeLimit
1218+
extends: ProcessRequirement
1219+
doc: |
1220+
Set an upper limit on the execution time of a CommandLineTool.
1221+
A CommandLineTool whose execution duration exceeds the time
1222+
limit may be preemptively terminated and considered failed.
1223+
May also be used by batch systems to make scheduling decisions.
1224+
The execution duration excludes external operations, such as
1225+
staging of files, pulling a docker image etc, and only counts
1226+
wall-time for the execution of the command line itself.
1227+
fields:
1228+
- name: class
1229+
type: string
1230+
doc: "Always 'ToolTimeLimit'"
1231+
jsonldPredicate:
1232+
"_id": "@type"
1233+
"_type": "@vocab"
1234+
- name: timelimit
1235+
type: [long, string, Expression]
1236+
doc: |
1237+
The time limit, in seconds. A time limit of zero means no
1238+
time limit. Negative time limits are an error.

cwltool/schemas/v1.1.0-dev1/CommonWorkflowLanguage.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
saladVersion: v1.1
12
$base: "https://w3id.org/cwl/cwl#"
23

34
$namespaces:

cwltool/schemas/v1.1.0-dev1/Process.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
saladVersion: v1.1
12
$base: "https://w3id.org/cwl/cwl#"
23

34
$namespaces:

cwltool/schemas/v1.1.0-dev1/README.md

Lines changed: 5 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,9 @@
1-
# Common Workflow Language Specifications, v1.1.0-dev1
1+
Hello!
22

3-
<!-- remove this before v1.1 is final! -->
4-
WARNING, this is a draft and in progress! Development of CWL v1.1 is coordinated at https://github.com/common-workflow-language/common-workflow-language/milestone/6
3+
This repo represent the current working proposal for v1.1 of the Common Workflow Language standard.
54

6-
The CWL specifications are divided up into several documents.
5+
Proposed changes that aren't yet implemented are tracked at https://github.com/common-workflow-language/common-workflow-language/milestone/6
76

8-
The [User Guide](http://www.commonwl.org/user_guide/) provides a gentle
9-
introduction to writing CWL command line tools and workflows.
7+
You can render this using https://github.com/common-workflow-language/cwl-website/blob/master/website.sh
108

11-
The [Command Line Tool Description Specification](CommandLineTool.html)
12-
specifies the document schema and execution semantics for wrapping and
13-
executing command line tools.
14-
15-
The [Workflow Description Specification](Workflow.html) specifies the document
16-
schema and execution semantics for composing workflows from components such as
17-
command line tools and other workflows.
18-
19-
The
20-
[Semantic Annotations for Linked Avro Data (SALAD) Specification](SchemaSalad.html)
21-
specifies the preprocessing steps that must be applied when loading CWL
22-
documents and the schema language used to write the above specifications.
23-
24-
Also available are inheritance graphs (as SVG images) for the [Schema Salad object model](salad.svg) and the [CWL object model](cwl.svg).
25-
26-
# Running the CWL conformance tests
27-
28-
1. Install a CWL runner of your choice. The reference runner can be installed as
29-
the default runner by doing:
30-
```
31-
pip install cwlref-runner
32-
```
33-
34-
2. Install the CWL test parser:
35-
36-
```
37-
pip install cwltest
38-
```
39-
You may need to activate a virtualenv first, or do a local install by adding `--user` after `install` above.
40-
41-
3. From within a copy of [this repository](https://github.com/common-workflow-language/cwl-v1.1) (e.g. cwl-v1.1) execute the main test script
42-
```
43-
./run_test.sh
44-
```
45-
46-
If the CWL runner isn't installed as `cwl-runner` then you can specify the name:
47-
48-
```
49-
./run_test.sh RUNNER=cwltool
50-
```
51-
52-
You can also specify additional options that are specific for the particular CWL runner you are using.
53-
For example, with CWL reference runner you can turn on parallel execution mode:
54-
55-
```
56-
./run_test.sh RUNNER=cwltool EXTRA=--parallel
57-
```
58-
59-
This can be combined with launching more than one CWL conformance test at once with `-j`:
60-
61-
```
62-
./run_test.sh -j4 RUNNER=cwltool EXTRA=--parallel
63-
```
64-
65-
66-
For details of options you can pass to the test script, do:
67-
```
68-
./run_test.sh --help
69-
```
70-
71-
The full test suite takes about 10 minutes to run
9+
The current rendering is at https://www.commonwl.org/v1.1.0-dev1/

0 commit comments

Comments
 (0)