Skip to content

Commit 743ac15

Browse files
authored
Merge pull request #2045 from common-workflow-language/main
Sync Updates to prov_data_input_output branch
2 parents 52b256b + 55ccde7 commit 743ac15

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+260
-107
lines changed

.github/workflows/ci-tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ jobs:
3232
strategy:
3333
matrix:
3434
py-ver-major: [3]
35-
py-ver-minor: [8, 9, 10, 11, 12]
35+
py-ver-minor: [8, 9, 10, 11, 12, 13]
3636
step: [lint, unit, bandit, mypy]
3737

3838
env:

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# Generated during tests
22
pytestdebug.log
33
tmp/
4+
*.sif
5+
involucro
46

57
# Python temps
68
__pycache__/
@@ -59,4 +61,3 @@ cwltool/_version.py
5961
cwltool_deps
6062
docs/_build/
6163
docs/autoapi/
62-

README.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#############################################################################################
2-
``cwltool``: The reference reference implementation of the Common Workflow Language standards
2+
``cwltool``: The reference implementation of the Common Workflow Language standards
33
#############################################################################################
44

55
|Linux Status| |Coverage Status| |Docs Status|

cwltool/argparser.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -921,6 +921,11 @@ def add_argument(
921921
action = DirectoryAppendAction
922922
else:
923923
action = AppendAction
924+
items = inptype["items"]
925+
if items == "int" or items == "long":
926+
atype = int
927+
elif items == "double" or items == "float":
928+
atype = float
924929
elif isinstance(inptype, MutableMapping) and inptype["type"] == "enum":
925930
atype = str
926931
elif isinstance(inptype, MutableMapping) and inptype["type"] == "record":

cwltool/builder.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ def bind_input(
282282
and "itemSeparator" not in binding
283283
):
284284
st["inputBinding"] = {}
285-
for k in ("secondaryFiles", "format", "streamable"):
285+
for k in ("secondaryFiles", "format", "streamable", "loadContents"):
286286
if k in schema:
287287
st[k] = schema[k]
288288
if value_from_expression:
@@ -349,7 +349,7 @@ def bind_input(
349349
"type": schema["items"],
350350
"inputBinding": b2,
351351
}
352-
for k in ("secondaryFiles", "format", "streamable"):
352+
for k in ("secondaryFiles", "format", "streamable", "loadContents"):
353353
if k in schema:
354354
itemschema[k] = schema[k]
355355
bindings.extend(

cwltool/checker.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -517,10 +517,13 @@ def is_conditional_step(param_to_step: Dict[str, CWLObjectType], parm_id: str) -
517517

518518

519519
def is_all_output_method_loop_step(param_to_step: Dict[str, CWLObjectType], parm_id: str) -> bool:
520-
"""Check if a step contains a `loop` directive with `all` outputMethod."""
520+
"""Check if a step contains a `loop` directive with `all_iterations` outputMethod."""
521521
source_step: Optional[MutableMapping[str, Any]] = param_to_step.get(parm_id)
522522
if source_step is not None:
523-
if source_step.get("loop") is not None and source_step.get("outputMethod") == "all":
523+
if (
524+
source_step.get("loop") is not None
525+
and source_step.get("outputMethod") == "all_iterations"
526+
):
524527
return True
525528
return False
526529

cwltool/command_line_tool.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -806,7 +806,7 @@ def remove_dirname(d: CWLObjectType) -> None:
806806
def job(
807807
self,
808808
job_order: CWLObjectType,
809-
output_callbacks: Optional[OutputCallbackType],
809+
output_callbacks: OutputCallbackType,
810810
runtimeContext: RuntimeContext,
811811
) -> Generator[Union[JobBase, CallbackJob], None, None]:
812812
workReuse, _ = self.get_requirement("WorkReuse")

cwltool/errors.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,8 @@
88

99
# flake8: noqa: F401
1010

11-
from cwl_utils.errors import WorkflowException as WorkflowException
12-
13-
1411
from cwl_utils.errors import GraphTargetMissingException as GraphTargetMissingException
12+
from cwl_utils.errors import WorkflowException as WorkflowException
1513

1614

1715
class UnsupportedRequirement(WorkflowException):

cwltool/process.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1075,7 +1075,7 @@ def visit(self, op: Callable[[CommentedMap], None]) -> None:
10751075
def job(
10761076
self,
10771077
job_order: CWLObjectType,
1078-
output_callbacks: Optional[OutputCallbackType],
1078+
output_callbacks: OutputCallbackType,
10791079
runtimeContext: RuntimeContext,
10801080
) -> JobsGeneratorType:
10811081
pass

cwltool/procgenerator.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ def receive_output(self, jobout: Optional[CWLObjectType], processStatus: str) ->
3030
def job(
3131
self,
3232
job_order: CWLObjectType,
33-
output_callbacks: Optional[OutputCallbackType],
33+
output_callbacks: OutputCallbackType,
3434
runtimeContext: RuntimeContext,
3535
) -> JobsGeneratorType:
3636
try:
@@ -41,7 +41,7 @@ def job(
4141
while self.processStatus is None:
4242
yield None
4343

44-
if self.processStatus != "success" and output_callbacks:
44+
if self.processStatus != "success":
4545
output_callbacks(self.jobout, self.processStatus)
4646
return
4747

@@ -89,7 +89,7 @@ def __init__(
8989
def job(
9090
self,
9191
job_order: CWLObjectType,
92-
output_callbacks: Optional[OutputCallbackType],
92+
output_callbacks: OutputCallbackType,
9393
runtimeContext: RuntimeContext,
9494
) -> JobsGeneratorType:
9595
return ProcessGeneratorJob(self).job(job_order, output_callbacks, runtimeContext)

cwltool/schemas/v1.3.0-dev1/Workflow.yml

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -497,8 +497,8 @@ $graph:
497497
docParent: "#LoopWorkflowStep"
498498
doc: The loop output method, as described in [workflow step loop](#LoopWorkflowStep).
499499
symbols:
500-
- last
501-
- all
500+
- last_iteration
501+
- all_iterations
502502

503503

504504
- name: AbstractWorkflowStep
@@ -705,14 +705,14 @@ $graph:
705705
The `outputMethod` field describes how to deal with loop outputs after
706706
termination:
707707
708-
* **last** specifies that only the last computed element for each output
709-
parameter should be propagated to the subsequent steps. This is the
710-
default value.
708+
* **last_iteration** specifies that only the last computed element for
709+
each output parameter should be propagated to the subsequent steps.
710+
This is the default value.
711711
712-
* **all** specifies that an array with all output values computed at the
713-
end of each loop iteration should be propagated to the subsequent steps.
714-
Elements in the array must be ordered according to the loop iterations
715-
that produced them.
712+
* **all_iterations** specifies that an array with all output values
713+
computed at the end of each loop iteration should be propagated to
714+
the subsequent steps. Elements in the array must be ordered according
715+
to the loop iterations that produced them.
716716
717717
Iterative execution in CWL is an optional feature and is not required
718718
to be implemented by all consumers of CWL documents. An implementation that
@@ -734,9 +734,9 @@ $graph:
734734
mapPredicate: outputSource
735735
- name: outputMethod
736736
doc: |
737-
If not specified, the default method is "last".
737+
If not specified, the default method is "last_iteration".
738738
type: LoopOutputMethod?
739-
default: last
739+
default: last_iteration
740740
jsonldPredicate:
741741
"_id": "cwl:outputMethod"
742742
"_type": "@vocab"
@@ -748,7 +748,8 @@ $graph:
748748
Only run the next iteration when the expression evaluates to `true`.
749749
If the first iteration evaluates to `false` the step is skipped.
750750
A skipped step produces a `null` on each output if the `outputMethod`
751-
is set to `last`, and an empty array if the `outputMethod` is set to `all`.
751+
is set to `last_iteration`, and an empty array if the `outputMethod`
752+
is set to `all_iterations`.
752753
753754
754755
- name: Workflow

cwltool/update.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,11 @@
1111
cast,
1212
)
1313

14+
from ruamel.yaml.comments import CommentedMap, CommentedSeq
1415
from schema_salad.exceptions import ValidationException
1516
from schema_salad.ref_resolver import Loader
1617
from schema_salad.sourceline import SourceLine
1718

18-
from ruamel.yaml.comments import CommentedMap, CommentedSeq
19-
2019
from .loghandler import _logger
2120
from .utils import CWLObjectType, CWLOutputType, aslist, visit_class, visit_field
2221

@@ -51,7 +50,16 @@ def rewrite_loop_requirements(t: CWLObjectType) -> None:
5150
el["outputSource"] = source
5251
s["loop"] = r["loop"]
5352
if "outputMethod" in r:
54-
s["outputMethod"] = r["outputMethod"]
53+
if r["outputMethod"] == "all":
54+
s["outputMethod"] = "all_iterations"
55+
elif r["outputMethod"] == "last":
56+
s["outputMethod"] = "last_iteration"
57+
else:
58+
raise SourceLine(
59+
r, raise_type=ValidationException
60+
).makeError( # pragma: no cover
61+
f"Invalid value {r['outputMethod']} for `outputMethod`."
62+
)
5563
cast(
5664
MutableSequence[CWLObjectType],
5765
s["requirements"],

cwltool/workflow.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ def make_workflow_step(
153153
def job(
154154
self,
155155
job_order: CWLObjectType,
156-
output_callbacks: Optional[OutputCallbackType],
156+
output_callbacks: OutputCallbackType,
157157
runtimeContext: RuntimeContext,
158158
) -> JobsGeneratorType:
159159
builder = self._init_job(job_order, runtimeContext)
@@ -420,7 +420,7 @@ def receive_output(
420420
def job(
421421
self,
422422
job_order: CWLObjectType,
423-
output_callbacks: Optional[OutputCallbackType],
423+
output_callbacks: OutputCallbackType,
424424
runtimeContext: RuntimeContext,
425425
) -> JobsGeneratorType:
426426
"""Initialize sub-workflow as a step in the parent profile."""

cwltool/workflow_job.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ def __init__(self, step: "WorkflowStep") -> None:
6565
def job(
6666
self,
6767
joborder: CWLObjectType,
68-
output_callback: Optional[OutputCallbackType],
68+
output_callback: OutputCallbackType,
6969
runtimeContext: RuntimeContext,
7070
) -> JobsGeneratorType:
7171
runtimeContext = runtimeContext.copy()
@@ -584,7 +584,7 @@ def receive_output(
584584
def try_make_job(
585585
self,
586586
step: WorkflowJobStep,
587-
final_output_callback: Optional[OutputCallbackType],
587+
final_output_callback: OutputCallbackType,
588588
runtimeContext: RuntimeContext,
589589
) -> JobsGeneratorType:
590590
container_engine = "docker"
@@ -744,7 +744,7 @@ def valueFromFunc(k: str, v: Optional[CWLOutputType]) -> Optional[CWLOutputType]
744744
_logger.info("[%s] will be skipped", step.name)
745745
if (
746746
step.tool.get("loop") is not None
747-
and step.tool.get("outputMethod", "last") == "all"
747+
and step.tool.get("outputMethod", "last_iteration") == "all_iterations"
748748
):
749749
callback({k["id"]: [] for k in outputparms}, "skipped")
750750
else:
@@ -773,7 +773,7 @@ def run(
773773
def job(
774774
self,
775775
joborder: CWLObjectType,
776-
output_callback: Optional[OutputCallbackType],
776+
output_callback: OutputCallbackType,
777777
runtimeContext: RuntimeContext,
778778
) -> JobsGeneratorType:
779779
self.state = {}
@@ -848,7 +848,7 @@ def job(
848848
else:
849849
yield None
850850

851-
if not self.did_callback and output_callback:
851+
if not self.did_callback:
852852
# could have called earlier on line 336;
853853
self.do_output_callback(output_callback)
854854
# depends which one comes first. All steps are completed
@@ -874,7 +874,7 @@ def _set_empty_output(self, outputMethod: str) -> None:
874874
for i in self.step.tool["outputs"]:
875875
if "id" in i:
876876
iid = cast(str, i["id"])
877-
if outputMethod == "all":
877+
if outputMethod == "all_iterations":
878878
self.output_buffer[iid] = cast(MutableSequence[Optional[CWLOutputType]], [])
879879
else:
880880
self.output_buffer[iid] = None
@@ -887,7 +887,7 @@ def job(
887887
) -> JobsGeneratorType:
888888
"""Generate a WorkflowJobStep job until the `when` condition evaluates to False."""
889889
self.joborder = joborder
890-
outputMethod = self.step.tool.get("outputMethod", "last")
890+
outputMethod = self.step.tool.get("outputMethod", "last_iteration")
891891

892892
callback = functools.partial(
893893
self.loop_callback,
@@ -953,14 +953,14 @@ def loop_callback(
953953
self.iteration += 1
954954
try:
955955
loop = cast(MutableSequence[CWLObjectType], self.step.tool.get("loop", []))
956-
outputMethod = self.step.tool.get("outputMethod", "last")
956+
outputMethod = self.step.tool.get("outputMethod", "last_iteration")
957957
state: Dict[str, Optional[WorkflowStateItem]] = {}
958958
for i in self.step.tool["outputs"]:
959959
if "id" in i:
960960
iid = cast(str, i["id"])
961961
if iid in jobout:
962962
state[iid] = WorkflowStateItem(i, jobout[iid], processStatus)
963-
if outputMethod == "all":
963+
if outputMethod == "all_iterations":
964964
if iid not in self.output_buffer:
965965
self.output_buffer[iid] = cast(
966966
MutableSequence[Optional[CWLOutputType]], []

lint-requirements.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
flake8-bugbear<24.3
2-
black~=24.4
1+
flake8-bugbear<24.9
2+
black~=24.8
33
codespell

mypy-requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
mypy==1.10.1 # also update pyproject.toml
1+
mypy==1.11.2 # also update pyproject.toml
22
ruamel.yaml>=0.16.0,<0.19
33
cwl-utils>=0.32
44
types-requests

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
requires = [
33
"setuptools>=45",
44
"setuptools_scm[toml]>=8.0.4,<9",
5-
"mypy==1.10.1", # also update mypy-requirements.txt
5+
"mypy==1.11.2", # also update mypy-requirements.txt
66
"types-requests",
77
"types-psutil",
88
"importlib_resources>=1.4;python_version<'3.9'",

setup.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,13 +145,13 @@
145145
"galaxy-util <24.2",
146146
],
147147
},
148-
python_requires=">=3.8, <4",
148+
python_requires=">=3.8, <3.14",
149149
use_scm_version=True,
150150
setup_requires=PYTEST_RUNNER + ["setuptools_scm>=8.0.4,<9"],
151151
test_suite="tests",
152152
tests_require=[
153153
"bagit >= 1.6.4, < 1.9",
154-
"pytest >= 6.2, < 8.3",
154+
"pytest >= 6.2, < 8.4",
155155
"mock >= 2.0.0",
156156
"pytest-mock >= 1.10.0",
157157
"pytest-httpserver",
@@ -176,6 +176,7 @@
176176
"Programming Language :: Python :: 3.10",
177177
"Programming Language :: Python :: 3.11",
178178
"Programming Language :: Python :: 3.12",
179+
"Programming Language :: Python :: 3.13",
179180
"Topic :: Scientific/Engineering",
180181
"Topic :: Scientific/Engineering :: Bio-Informatics",
181182
"Topic :: Scientific/Engineering :: Astronomy",

test-requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
bagit>=1.6.4,<1.9
2-
pytest>= 6.2,< 8.3
2+
pytest>= 6.2,< 8.4
33
pytest-xdist>=3.2.0 # for the worksteal scheduler
44
psutil # enhances pytest-xdist to allow "-n logical"
55
pytest-httpserver

tests/load_contents-1.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
1

tests/load_contents-2.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
2

tests/load_contents-array.cwl

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
cwlVersion: "v1.2"
2+
class: CommandLineTool
3+
baseCommand: echo
4+
requirements:
5+
InlineJavascriptRequirement: {}
6+
inputs:
7+
files:
8+
type:
9+
type: array
10+
items: File
11+
loadContents: true
12+
inputBinding:
13+
valueFrom: |
14+
${
15+
return JSON.stringify({
16+
"data": inputs.files.map(item => parseInt(item.contents))
17+
});
18+
}
19+
outputs:
20+
out:
21+
type: File
22+
outputBinding:
23+
glob: "data.json"
24+
stdout: "data.json"

0 commit comments

Comments
 (0)