Skip to content

Commit 1c77bda

Browse files
committed
initial schema for a loop construct prototype
Based upon @GlassOfWhiskey 's work in common-workflow-language/common-workflow-language#495 (comment) With comments from @tetron @mr-c
1 parent 84a297f commit 1c77bda

File tree

4 files changed

+324
-1
lines changed

4 files changed

+324
-1
lines changed

MANIFEST.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ include cwltool/cwlNodeEngineJSConsole.js
5757
include cwltool/cwlNodeEngineWithContext.js
5858
include cwltool/extensions.yml
5959
include cwltool/extensions-v1.1.yml
60+
include cwltool/extensions-v1.2.yml
6061
include cwltool/jshint/jshint_wrapper.js
6162
include cwltool/jshint/jshint.js
6263
include cwltool/hello.simg

cwltool/extensions-v1.2.yml

Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
$base: http://commonwl.org/cwltool#
2+
$namespaces:
3+
cwl: "https://w3id.org/cwl/cwl#"
4+
$graph:
5+
- $import: https://w3id.org/cwl/CommonWorkflowLanguage.yml
6+
7+
- name: Secrets
8+
type: record
9+
inVocab: false
10+
extends: cwl:ProcessRequirement
11+
fields:
12+
class:
13+
type: string
14+
doc: "Always 'Secrets'"
15+
jsonldPredicate:
16+
"_id": "@type"
17+
"_type": "@vocab"
18+
secrets:
19+
type: string[]
20+
doc: |
21+
List one or more input parameters that are sensitive (such as passwords)
22+
which will be deliberately obscured from logging.
23+
jsonldPredicate:
24+
"_type": "@id"
25+
refScope: 0
26+
27+
28+
- name: ProcessGenerator
29+
type: record
30+
inVocab: true
31+
extends: cwl:Process
32+
documentRoot: true
33+
fields:
34+
- name: class
35+
jsonldPredicate:
36+
"_id": "@type"
37+
"_type": "@vocab"
38+
type: string
39+
- name: run
40+
type: [string, cwl:Process]
41+
jsonldPredicate:
42+
_id: "cwl:run"
43+
_type: "@id"
44+
subscope: run
45+
doc: |
46+
Specifies the process to run.
47+
48+
- name: MPIRequirement
49+
type: record
50+
inVocab: false
51+
extends: cwl:ProcessRequirement
52+
doc: |
53+
Indicates that a process requires an MPI runtime.
54+
fields:
55+
- name: class
56+
type: string
57+
doc: "Always 'MPIRequirement'"
58+
jsonldPredicate:
59+
"_id": "@type"
60+
"_type": "@vocab"
61+
- name: processes
62+
type: [int, cwl:Expression]
63+
doc: |
64+
The number of MPI processes to start. If you give a string,
65+
this will be evaluated as a CWL Expression and it must
66+
evaluate to an integer.
67+
68+
- name: CUDARequirement
69+
type: record
70+
extends: cwl:ProcessRequirement
71+
inVocab: false
72+
doc: |
73+
Require support for NVIDA CUDA (GPU hardware acceleration).
74+
fields:
75+
class:
76+
type: string
77+
doc: 'cwltool:CUDARequirement'
78+
jsonldPredicate:
79+
_id: "@type"
80+
_type: "@vocab"
81+
cudaVersionMin:
82+
type: string
83+
doc: |
84+
Minimum CUDA version to run the software, in X.Y format. This
85+
corresponds to a CUDA SDK release. When running directly on
86+
the host (not in a container) the host must have a compatible
87+
CUDA SDK (matching the exact version, or, starting with CUDA
88+
11.3, matching major version). When run in a container, the
89+
container image should provide the CUDA runtime, and the host
90+
driver is injected into the container. In this case, because
91+
CUDA drivers are backwards compatible, it is possible to
92+
use an older SDK with a newer driver across major versions.
93+
94+
See https://docs.nvidia.com/deploy/cuda-compatibility/ for
95+
details.
96+
cudaComputeCapability:
97+
type:
98+
- 'string'
99+
- 'string[]'
100+
doc: |
101+
CUDA hardware capability required to run the software, in X.Y
102+
format.
103+
104+
* If this is a single value, it defines only the minimum
105+
compute capability. GPUs with higher capability are also
106+
accepted.
107+
108+
* If it is an array value, then only select GPUs with compute
109+
capabilities that explicitly appear in the array.
110+
cudaDeviceCountMin:
111+
type: ['null', int, cwl:Expression]
112+
default: 1
113+
doc: |
114+
Minimum number of GPU devices to request. If not specified,
115+
same as `cudaDeviceCountMax`. If neither are specified,
116+
default 1.
117+
cudaDeviceCountMax:
118+
type: ['null', int, cwl:Expression]
119+
doc: |
120+
Maximum number of GPU devices to request. If not specified,
121+
same as `cudaDeviceCountMin`.
122+
123+
- name: LoopInput
124+
type: record
125+
fields:
126+
id:
127+
type: string?
128+
jsonldPredicate: "@id"
129+
doc: "It must reference the `id` of one of the elements in the `in` field of the step."
130+
source:
131+
doc: |
132+
Specifies one or more of the step output parameters that will
133+
provide input to the loop iterations after the first one (inputs
134+
of the first iteration are the step input parameters).
135+
jsonldPredicate:
136+
"_id": "cwl:source"
137+
"_type": "@id"
138+
refScope: 2
139+
type:
140+
- string?
141+
- string[]?
142+
linkMerge:
143+
type: cwl:LinkMergeMethod?
144+
jsonldPredicate: "cwl:linkMerge"
145+
default: merge_nested
146+
doc: |
147+
The method to use to merge multiple inbound links into a single array.
148+
If not specified, the default method is "merge_nested".
149+
pickValue:
150+
type: ["null", cwl:PickValueMethod]
151+
jsonldPredicate: "cwl:pickValue"
152+
doc: |
153+
The method to use to choose non-null elements among multiple sources.
154+
default:
155+
type: ["null", Any]
156+
doc: |
157+
The default value for this parameter to use if either there is no
158+
`source` field, or the value produced by the `source` is `null`. The
159+
default must be applied prior to scattering or evaluating `valueFrom`.
160+
jsonldPredicate:
161+
_id: "sld:default"
162+
noLinkCheck: true
163+
valueFrom:
164+
type:
165+
- "null"
166+
- string
167+
- cwl:Expression
168+
jsonldPredicate: "cwl:valueFrom"
169+
doc: |
170+
To use valueFrom, [StepInputExpressionRequirement](#StepInputExpressionRequirement) must
171+
be specified in the workflow or workflow step requirements.
172+
173+
If `valueFrom` is a constant string value, use this as the value for
174+
this input parameter.
175+
176+
If `valueFrom` is a parameter reference or expression, it must be
177+
evaluated to yield the actual value to be assiged to the input field.
178+
179+
The `self` value in the parameter reference or expression must be
180+
`null` if there is no `source` field, or the value of the
181+
parameter(s) specified in the `source` field.
182+
183+
The value of `inputs` in the parameter reference or expression must be
184+
the input object to the last iteration of the workflow step after
185+
assigning the `source` values and then applying `default`.
186+
187+
The value of `outputs` in the parameter reference or expression
188+
must be the output object of the last step execution.
189+
190+
- name: Loop
191+
type: record
192+
extends: cwl:ProcessRequirement
193+
inVocab: false
194+
doc: |
195+
Prototype to enable workflow-level looping of a step.
196+
197+
Valid only under `requirements` of a https://www.commonwl.org/v1.2/Workflow.html#WorkflowStep.
198+
199+
`loop_when` is an expansion of the CWL v1.2 `when` construct which controls
200+
conditional execution and thus when using `Loop` do not also specify a `when` as
201+
the `loop_when` expanded definition is intended to replace `when` in a
202+
future version of the CWL standards.
203+
204+
Loops are evaluated after any specified `scatter`ing; the implicit gathering
205+
is done with the results of the scatter-jobs (after the `loop`s have finished).
206+
fields:
207+
class:
208+
type: string
209+
doc: 'cwltool:Loop'
210+
jsonldPredicate:
211+
_id: "@type"
212+
_type: "@vocab"
213+
loop_when:
214+
type: cwl:Expression
215+
doc: |
216+
Only run the step while the expression evaluates to `true`.
217+
If `false` and no iteration has been performed, the step is skipped.
218+
219+
A skipped step produces a `null` on each output.
220+
221+
The `inputs` value in the expression must be the step input object.
222+
223+
The `outputs` value in the expression must be the step output object
224+
produced by the execution of the last iteration of this step, except
225+
for the first execution when the `outputs` object is populated with
226+
`null`s for each output declared in this step's `out` section.
227+
228+
It is an error if this expression returns a value other than `true` or `false`.
229+
loop:
230+
type: LoopInput[]?
231+
jsonldPredicate:
232+
_id: "cwltool:loop"
233+
mapSubject: id
234+
mapPredicate: source
235+
doc: |
236+
Defines the input parameters of the loop iterations after the first one
237+
(inputs of the first iteration are the step input parameters). If no
238+
`loop` rule is specified for a given step `in` field, the initial value
239+
is kept constant among all iterations.
240+
outputMethod:
241+
type:
242+
type: enum
243+
name: LoopOutputModes
244+
symbols: [ last, all ]
245+
doc:
246+
- Specify the desired method of dealing with loop outputs
247+
- Default. Propagates only the last computed element to the subsequent steps when the loop terminates.
248+
- Propagates a single array with all output values to the subsequent steps when the loop terminates.
249+

cwltool/main.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -661,9 +661,11 @@ def setup_schema(
661661
ext10 = res.read().decode("utf-8")
662662
with pkg_resources.resource_stream(__name__, "extensions-v1.1.yml") as res:
663663
ext11 = res.read().decode("utf-8")
664+
with pkg_resources.resource_stream(__name__, "extensions-v1.2.yml") as res:
665+
ext12 = res.read().decode("utf-8")
664666
use_custom_schema("v1.0", "http://commonwl.org/cwltool", ext10)
665667
use_custom_schema("v1.1", "http://commonwl.org/cwltool", ext11)
666-
use_custom_schema("v1.2", "http://commonwl.org/cwltool", ext11)
668+
use_custom_schema("v1.2", "http://commonwl.org/cwltool", ext12)
667669
use_custom_schema("v1.2.0-dev1", "http://commonwl.org/cwltool", ext11)
668670
use_custom_schema("v1.2.0-dev2", "http://commonwl.org/cwltool", ext11)
669671
use_custom_schema("v1.2.0-dev3", "http://commonwl.org/cwltool", ext11)

tests/loop.cwl

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
cwlVersion: v1.2
2+
class: Workflow
3+
4+
$namespaces:
5+
cwltool: "http://commonwl.org/cwltool#"
6+
7+
inputs:
8+
i1: Any
9+
outputs:
10+
o1:
11+
type: Any
12+
outputSource: subworkflow/o1
13+
steps:
14+
A:
15+
run: A.cwl
16+
in:
17+
in1: in1
18+
out: [p1, p2]
19+
B:
20+
run: B.cwl
21+
in:
22+
p1: A/p1
23+
out: [p3]
24+
C:
25+
run: C.cwl
26+
in:
27+
p2: A/p2
28+
out: [p4]
29+
subworkflow:
30+
run:
31+
class: Workflow
32+
inputs:
33+
p3: Any
34+
p4: Any
35+
outputs:
36+
o1:
37+
type: Any
38+
outputSource: E/o1
39+
p3:
40+
type: Any
41+
outputSource: F/p3
42+
steps:
43+
D:
44+
run: D.cwl
45+
in:
46+
p3: p3
47+
out: [p4]
48+
E:
49+
run: E.cwl
50+
in:
51+
p4:
52+
source:
53+
- p4
54+
- D/p4
55+
pickValue: the_only_non_null
56+
out: [o1, p5]
57+
F:
58+
run: F.cwl
59+
in:
60+
p5: E/p5
61+
out: [p3]
62+
in:
63+
p3: B/p3
64+
p4: C/p4
65+
out: [o1, p3]
66+
requirements:
67+
cwltool:Loop:
68+
loop_when: $(outputs.o1 !== null)
69+
loop:
70+
p3: p3
71+
outputMethod: last

0 commit comments

Comments
 (0)