Skip to content

Commit 1abe042

Browse files
committed
initial implementation of parameter groups
1 parent 6c86caa commit 1abe042

File tree

4 files changed

+98
-6
lines changed

4 files changed

+98
-6
lines changed

cwltool/argparser.py

+34-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""Command line argument parsing for cwltool."""
22

33
import argparse
4+
import copy
45
import os
56
import urllib
67
from collections.abc import MutableMapping, MutableSequence, Sequence
@@ -10,7 +11,7 @@
1011
from .process import Process, shortname
1112
from .resolver import ga4gh_tool_registries
1213
from .software_requirements import SOFTWARE_REQUIREMENTS_ENABLED
13-
from .utils import DEFAULT_TMP_PREFIX
14+
from .utils import DEFAULT_TMP_PREFIX, CWLObjectType
1415

1516

1617
def arg_parser() -> argparse.ArgumentParser:
@@ -845,7 +846,7 @@ def __call__(
845846

846847

847848
def add_argument(
848-
toolparser: argparse.ArgumentParser,
849+
toolparser: Union[argparse.ArgumentParser, "argparse._ArgumentGroup"],
849850
name: str,
850851
inptype: Any,
851852
records: list[str],
@@ -962,14 +963,18 @@ def generate_parser(
962963
toolparser.add_argument("job_order", nargs="?", help="Job input json file")
963964
namemap["job_order"] = "job_order"
964965

965-
for inp in tool.tool["inputs"]:
966-
name = shortname(inp["id"])
966+
inps = copy.deepcopy(tool.tool["inputs"])
967+
968+
def process_input(
969+
inp: CWLObjectType, parser: Union[argparse.ArgumentParser, "argparse._ArgumentGroup"]
970+
) -> None:
971+
name = shortname(cast(str, inp["id"]))
967972
namemap[name.replace("-", "_")] = name
968973
inptype = inp["type"]
969-
description = inp.get("doc", inp.get("label", ""))
974+
description = cast(str, inp.get("doc", inp.get("label", "")))
970975
default = inp.get("default", None)
971976
add_argument(
972-
toolparser,
977+
parser,
973978
name,
974979
inptype,
975980
records,
@@ -980,4 +985,27 @@ def generate_parser(
980985
base_uri,
981986
)
982987

988+
if (groups := tool.tool.get("http://commonwl.org/cwltool#groups", None)) is not None:
989+
for group_name in groups.keys():
990+
group_inputs: list[CWLObjectType] = []
991+
for input_name in groups[group_name]["groupMembers"]:
992+
new_inps: list[CWLObjectType] = []
993+
for inp in inps:
994+
if shortname(inp["id"]) == input_name:
995+
group_inputs.append(inp)
996+
else:
997+
new_inps.append(inp)
998+
inps = new_inps
999+
1000+
if len(group_inputs) > 0:
1001+
group = toolparser.add_argument_group(
1002+
title=groups[group_name].get("label", group_name),
1003+
description=groups[group_name].get("doc", None),
1004+
)
1005+
for inp in group_inputs:
1006+
process_input(inp, group)
1007+
1008+
for inp in inps:
1009+
process_input(inp, toolparser)
1010+
9831011
return toolparser

cwltool/extensions-v1.2.yml

+22
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@ $graph:
240240
- Specify the desired method of dealing with loop outputs
241241
- Default. Propagates only the last computed element to the subsequent steps when the loop terminates.
242242
- Propagates a single array with all output values to the subsequent steps when the loop terminates.
243+
243244
- name: ShmSize
244245
type: record
245246
extends: cwl:ProcessRequirement
@@ -258,3 +259,24 @@ $graph:
258259
than 0. Unit is optional and can be `b` (bytes), `k` (kilobytes), `m`
259260
(megabytes), or `g` (gigabytes). If you omit the unit, the default is
260261
bytes. If you omit the size entirely, the value is `64m`."
262+
263+
- name: Grouping
264+
type: record
265+
extends: [ sld:Documented ]
266+
fields:
267+
- name: GroupName
268+
type: string
269+
- name: groupMembers
270+
type: string[]
271+
jsonldPredicate:
272+
"_type": "@id"
273+
"_container": "@list"
274+
refScope: 0
275+
276+
- name: groups
277+
type:
278+
- type: array
279+
items: "#Grouping"
280+
inVocab: false
281+
jsonldPredicate:
282+
mapSubject: GroupName

tests/echo-groups.cwl

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#!/usr/bin/env cwl-runner
2+
cwlVersion: v1.0
3+
class: CommandLineTool
4+
inputs:
5+
first:
6+
type: string
7+
inputBinding: {}
8+
second:
9+
type: string
10+
inputBinding: {}
11+
outputs:
12+
- id: out
13+
type: string
14+
outputBinding:
15+
glob: out.txt
16+
loadContents: true
17+
outputEval: $(self[0].contents)
18+
baseCommand: echo
19+
stdout: out.txt
20+
21+
22+
$namespaces:
23+
cwltool: "http://commonwl.org/cwltool#"
24+
25+
cwltool:groups:
26+
my_groups:
27+
groupMembers: [first, second]
28+
label: my great inputs
29+
doc: "parameters related to the foobar feature"

tests/test_ext.py

+13
Original file line numberDiff line numberDiff line change
@@ -285,3 +285,16 @@ def test_ext_validation_no_namespace_warning() -> None:
285285
"URI prefix 'cwltool' of 'cwltool:loop' not recognized, are you "
286286
"missing a $namespaces section?"
287287
) not in stderr
288+
289+
290+
def test_ext_groups_help(capsys: pytest.CaptureFixture[str]) -> None:
291+
error_code, stdout, stderr = get_main_output([get_data("tests/echo-groups.cwl"), "--help"])
292+
assert error_code == 0
293+
assert (
294+
"""my great inputs:
295+
parameters related to the foobar feature
296+
297+
--first FIRST
298+
--second SECOND"""
299+
in capsys.readouterr().out
300+
)

0 commit comments

Comments
 (0)