Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 14 additions & 4 deletions WDL/CLI.py
Original file line number Diff line number Diff line change
Expand Up @@ -1035,11 +1035,21 @@ def runner_input(
decl = available_inputs.get(name)

if not decl:
# allow arbitrary runtime overrides
# allow arbitrary runtime overrides (or "requirements" in WDL 1.2)
nmparts = name.split(".")
runtime_idx = next((i for i, term in enumerate(nmparts) if term in ("runtime",)), -1)
if runtime_idx >= 0 and len(nmparts) > (runtime_idx + 1):
decl = available_inputs.get(".".join(nmparts[:runtime_idx] + ["_runtime"]))
for override in (
"requirements",
"runtime",
):
runtime_idx = next(
(i for i, term in enumerate(nmparts) if term == override),
-1,
)
if runtime_idx >= 0 and len(nmparts) > (runtime_idx + 1):
if decl := available_inputs.get(
".".join(nmparts[:runtime_idx] + ["_" + override])
):
break

if not decl:
runner_input_help(target)
Expand Down
2 changes: 2 additions & 0 deletions WDL/Tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,8 @@ def available_inputs(self) -> Env.Bindings[Decl]:
if self.effective_wdl_version not in ("draft-2", "1.0"):
# synthetic placeholder to expose runtime overrides
ans = ans.bind("_runtime", Decl(self.pos, Type.Any(), "_runtime"))
if self.effective_wdl_version not in ("1.1",):
ans = ans.bind("_requirements", Decl(self.pos, Type.Any(), "_requirements"))

for decl in reversed(self.inputs if self.inputs is not None else self.postinputs):
ans = ans.bind(decl.name, decl)
Expand Down
30 changes: 21 additions & 9 deletions WDL/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,17 +244,29 @@ def values_from_json(
else:
key2parts = key2.split(".")

runtime_idx = next(
(i for i, term in enumerate(key2parts) if term in ("runtime",)), -1
)
for override in (
"requirements",
"runtime",
):
runtime_idx = next(
(i for i, term in enumerate(key2parts) if term == override),
-1,
)
if (
runtime_idx >= 0
and len(key2parts) > (runtime_idx + 1)
and ".".join(key2parts[:runtime_idx] + ["_" + override]) in available
):
# allow arbitrary keys for runtime
ty = Type.Any()

if (
runtime_idx >= 0
and len(key2parts) > (runtime_idx + 1)
and ".".join(key2parts[:runtime_idx] + ["_runtime"]) in available
not ty
and len(key2parts) == 3
and key2parts[0]
and key2parts[1]
and key2parts[2]
):
# allow arbitrary keys for runtime
ty = Type.Any()
elif len(key2parts) == 3 and key2parts[0] and key2parts[1] and key2parts[2]:
# attempt to simplify <call>.<subworkflow>.<input> from old Cromwell JSON
key2 = ".".join([key2parts[0], key2parts[2]])
if key2 in available:
Expand Down
2 changes: 2 additions & 0 deletions WDL/runtime/task.py
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,8 @@ def _eval_task_runtime(
runtime_values[key] = expr.eval(env, stdlib)
for b in inputs.enter_namespace("runtime"):
runtime_values[b.name] = b.value # input overrides
for b in inputs.enter_namespace("requirements"):
runtime_values[b.name] = b.value
logger.debug(_("runtime values", **dict((key, str(v)) for key, v in runtime_values.items())))

# have container implementation validate & postprocess into container.runtime_values
Expand Down
6 changes: 5 additions & 1 deletion tests/runner.t
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ source tests/bash-tap/bash-tap-bootstrap
export PYTHONPATH="$SOURCE_DIR:$PYTHONPATH"
miniwdl="python3 -m WDL"

plan tests 97
plan tests 99

$miniwdl run_self_test
is "$?" "0" "run_self_test"
Expand Down Expand Up @@ -372,6 +372,10 @@ is "$?" "0" "directory input"
is `jq -r '.["w.dsz"]' _LAST/outputs.json` "10" "use of directory input"
grep -q 20.10 _LAST/out/issue/issue
is "$?" "0" "override t.runtime.docker"
$miniwdl run dir_io.wdl d=indir t.requirements.docker=ubuntu:24.04
is "$?" "0" "directory input 2"
grep -q 24.04 _LAST/out/issue/issue
is "$?" "0" "override t.requirements.docker"

cat << 'EOF' > uri_inputs.json
{
Expand Down
43 changes: 40 additions & 3 deletions tests/test_7runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -751,7 +751,7 @@ def test_runtime_override(self):
input {
String who
}
call t {
call t as tc {
input:
who = who
}
Expand All @@ -775,9 +775,46 @@ def test_runtime_override(self):
"""
outp = self._run(wdl, {
"who": "Alice",
"t.runtime.container": ["ubuntu:20.10"]
"tc.runtime.container": ["ubuntu:20.10"]
})
assert "20.10" in outp["tc.issue"]

outp = self._run(wdl, {
"who": "Alice",
"tc.requirements.container": ["ubuntu:24.04"]
})
assert "24.04" in outp["tc.issue"]

def test_task_named_requirements(self):
# "requirements" became a keyword in WDL 1.2, so before that a task or one of its inputs
# could be named "requirements" -- ensure that still works as expected
wdl = """
version 1.1
workflow w {
call requirements
}
task requirements {
input {
Int requirements = 21
}
command {}
output {
Int result = requirements
}
runtime {
docker: "ubuntu:24.04"
}
}
"""
outp = self._run(wdl, {
"requirements.requirements": 42
})
assert "20.10" in outp["t.issue"]
assert outp["requirements.result"] == 42

with self.assertRaises(WDL.Error.InputError):
outp = self._run(wdl, {
"requirements.requirements": "bogus"
})


class MiscRegressionTests(RunnerTestCase):
Expand Down
Loading