Skip to content

Commit 4e3f5af

Browse files
committed
Use structural pattern matching
1 parent 54c853e commit 4e3f5af

File tree

15 files changed

+587
-572
lines changed

15 files changed

+587
-572
lines changed

cwltool/argparser.py

Lines changed: 43 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import argparse
44
import os
55
import urllib
6-
from collections.abc import Callable, MutableMapping, MutableSequence, Sequence
6+
from collections.abc import Callable, MutableSequence, Sequence
77
from typing import Any, cast
88

99
import rich.markup
@@ -897,55 +897,51 @@ def add_argument(
897897
atype: Any | None = None
898898
typekw: dict[str, Any] = {}
899899

900-
if inptype == "File":
901-
action = FileAction
902-
elif inptype == "Directory":
903-
action = DirectoryAction
904-
elif isinstance(inptype, MutableMapping) and inptype["type"] == "array":
905-
if inptype["items"] == "File":
900+
match inptype:
901+
case "File":
902+
action = FileAction
903+
case "Directory":
904+
action = DirectoryAction
905+
case {"type": "array", "items": "File"}:
906906
action = FileAppendAction
907-
elif inptype["items"] == "Directory":
907+
case {"type": "array", "items": "Directory"}:
908908
action = DirectoryAppendAction
909-
else:
909+
case {"type": "array", "items": str(items)}:
910910
action = AppendAction
911-
items = inptype["items"]
912-
if items == "int" or items == "long":
913-
atype = int
914-
elif items == "double" or items == "float":
915-
atype = float
916-
elif isinstance(inptype, MutableMapping) and inptype["type"] == "enum":
917-
atype = str
918-
elif isinstance(inptype, MutableMapping) and inptype["type"] == "record":
919-
records.append(name)
920-
for field in inptype["fields"]:
921-
fieldname = name + "." + shortname(field["name"])
922-
fieldtype = field["type"]
923-
fielddescription = field.get("doc", "")
924-
add_argument(
925-
toolparser,
926-
fieldname,
927-
fieldtype,
928-
records,
929-
fielddescription,
930-
default=default.get(shortname(field["name"]), None) if default else None,
931-
input_required=required,
932-
)
933-
return
934-
elif inptype == "string":
935-
atype = str
936-
elif inptype == "int":
937-
atype = int
938-
elif inptype == "long":
939-
atype = int
940-
elif inptype == "double":
941-
atype = float
942-
elif inptype == "float":
943-
atype = float
944-
elif inptype == "boolean":
945-
action = "store_true"
946-
else:
947-
_logger.debug("Can't make command line argument from %s", inptype)
948-
return None
911+
match items:
912+
case "int" | "long":
913+
atype = int
914+
case "double" | "float":
915+
atype = float
916+
case {"type": "enum"}:
917+
atype = str
918+
case {"type": "record", "fields": list(fields)}:
919+
records.append(name)
920+
for field in fields:
921+
fieldname = name + "." + shortname(field["name"])
922+
fieldtype = field["type"]
923+
fielddescription = field.get("doc", "")
924+
add_argument(
925+
toolparser,
926+
fieldname,
927+
fieldtype,
928+
records,
929+
fielddescription,
930+
default=default.get(shortname(field["name"]), None) if default else None,
931+
input_required=required,
932+
)
933+
return
934+
case "string":
935+
atype = str
936+
case "int" | "long":
937+
atype = int
938+
case "double" | "float":
939+
atype = float
940+
case "boolean":
941+
action = "store_true"
942+
case _:
943+
_logger.debug("Can't make command line argument from %s", inptype)
944+
return None
949945

950946
if action in (FileAction, DirectoryAction, FileAppendAction, DirectoryAppendAction):
951947
typekw["urljoin"] = urljoin

cwltool/builder.py

Lines changed: 41 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,10 @@ def build_job_script(self, commands: list[str]) -> str | None:
166166
return self.job_script_provider.build_job_script(self, commands)
167167
return None
168168

169+
def _capture_files(self, f: CWLObjectType) -> CWLObjectType:
170+
self.files.append(f)
171+
return f
172+
169173
def bind_input(
170174
self,
171175
schema: CWLObjectType,
@@ -555,7 +559,7 @@ def addsf(
555559
visit_class(
556560
datum.get("secondaryFiles", []),
557561
("File", "Directory"),
558-
_capture_files,
562+
self._capture_files,
559563
)
560564

561565
if schema["type"] == "org.w3id.cwl.cwl.Directory":
@@ -570,7 +574,7 @@ def addsf(
570574
self.files.append(datum)
571575

572576
if schema["type"] == "Any":
573-
visit_class(datum, ("File", "Directory"), _capture_files)
577+
visit_class(datum, ("File", "Directory"), self._capture_files)
574578

575579
# Position to front of the sort key
576580
if binding:
@@ -589,23 +593,21 @@ def tostr(self, value: MutableMapping[str, str] | Any) -> str:
589593
:raises WorkflowException: if the item is a File or Directory and the
590594
"path" is missing.
591595
"""
592-
if isinstance(value, MutableMapping) and value.get("class") in (
593-
"File",
594-
"Directory",
595-
):
596-
if "path" not in value:
597-
raise WorkflowException(
598-
'{} object missing "path": {}'.format(value["class"], value)
599-
)
600-
return value["path"]
601-
elif isinstance(value, ScalarFloat):
602-
rep = RoundTripRepresenter()
603-
dec_value = Decimal(rep.represent_scalar_float(value).value)
604-
if "E" in str(dec_value):
605-
return str(dec_value.quantize(1))
606-
return str(dec_value)
607-
else:
608-
return str(value)
596+
match value:
597+
case {"class": "File" | "Directory" as class_name, **rest}:
598+
if "path" not in rest:
599+
raise WorkflowException(
600+
'{} object missing "path": {}'.format(class_name, value)
601+
)
602+
return str(rest["path"])
603+
case ScalarFloat():
604+
rep = RoundTripRepresenter()
605+
dec_value = Decimal(rep.represent_scalar_float(value).value)
606+
if "E" in str(dec_value):
607+
return str(dec_value.quantize(1))
608+
return str(dec_value)
609+
case _:
610+
return str(value)
609611

610612
def generate_arg(self, binding: CWLObjectType) -> list[str]:
611613
"""Convert an input binding to a list of command line arguments."""
@@ -632,30 +634,28 @@ def generate_arg(self, binding: CWLObjectType) -> list[str]:
632634
raise WorkflowException("'separate' option can not be specified without prefix")
633635

634636
argl: MutableSequence[CWLOutputType] = []
635-
if isinstance(value, MutableSequence):
636-
if binding.get("itemSeparator") and value:
637-
itemSeparator = cast(str, binding["itemSeparator"])
638-
argl = [itemSeparator.join([self.tostr(v) for v in value])]
639-
elif binding.get("valueFrom"):
640-
value = [self.tostr(v) for v in value]
641-
return cast(list[str], ([prefix] if prefix else [])) + cast(list[str], value)
642-
elif prefix and value:
637+
match value:
638+
case MutableSequence():
639+
if binding.get("itemSeparator") and value:
640+
itemSeparator = cast(str, binding["itemSeparator"])
641+
argl = [itemSeparator.join([self.tostr(v) for v in value])]
642+
elif binding.get("valueFrom"):
643+
value = [self.tostr(v) for v in value]
644+
return cast(list[str], ([prefix] if prefix else [])) + cast(list[str], value)
645+
elif prefix and value:
646+
return [prefix]
647+
else:
648+
return []
649+
case {"class": "File" | "Directory"}:
650+
argl = [cast(CWLOutputType, value)]
651+
case MutableMapping():
652+
return [prefix] if prefix else []
653+
case True if prefix:
643654
return [prefix]
644-
else:
655+
case bool() | None:
645656
return []
646-
elif isinstance(value, MutableMapping) and value.get("class") in (
647-
"File",
648-
"Directory",
649-
):
650-
argl = cast(MutableSequence[CWLOutputType], [value])
651-
elif isinstance(value, MutableMapping):
652-
return [prefix] if prefix else []
653-
elif value is True and prefix:
654-
return [prefix]
655-
elif value is False or value is None or (value is True and not prefix):
656-
return []
657-
else:
658-
argl = [value]
657+
case _:
658+
argl = [value]
659659

660660
args = []
661661
for j in argl:

cwltool/checker.py

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -33,31 +33,37 @@ def check_types(
3333
"""
3434
if valueFrom is not None:
3535
return "pass"
36-
if linkMerge is None:
37-
if can_assign_src_to_sink(srctype, sinktype, strict=True):
38-
return "pass"
39-
if can_assign_src_to_sink(srctype, sinktype, strict=False):
40-
return "warning"
41-
return "exception"
42-
if linkMerge == "merge_nested":
43-
return check_types(
44-
{"items": _get_type(srctype), "type": "array"},
45-
_get_type(sinktype),
46-
None,
47-
None,
48-
)
49-
if linkMerge == "merge_flattened":
50-
return check_types(merge_flatten_type(_get_type(srctype)), _get_type(sinktype), None, None)
51-
raise WorkflowException(f"Unrecognized linkMerge enum {linkMerge!r}")
36+
match linkMerge:
37+
case None:
38+
if can_assign_src_to_sink(srctype, sinktype, strict=True):
39+
return "pass"
40+
if can_assign_src_to_sink(srctype, sinktype, strict=False):
41+
return "warning"
42+
return "exception"
43+
case "merge_nested":
44+
return check_types(
45+
{"items": _get_type(srctype), "type": "array"},
46+
_get_type(sinktype),
47+
None,
48+
None,
49+
)
50+
case "merge_flattened":
51+
return check_types(
52+
merge_flatten_type(_get_type(srctype)), _get_type(sinktype), None, None
53+
)
54+
case _:
55+
raise WorkflowException(f"Unrecognized linkMerge enum {linkMerge!r}")
5256

5357

5458
def merge_flatten_type(src: SinkType) -> CWLOutputType:
5559
"""Return the merge flattened type of the source type."""
56-
if isinstance(src, MutableSequence):
57-
return [merge_flatten_type(t) for t in src]
58-
if isinstance(src, MutableMapping) and src.get("type") == "array":
59-
return src
60-
return {"items": src, "type": "array"}
60+
match src:
61+
case MutableSequence():
62+
return [merge_flatten_type(t) for t in src]
63+
case {"type": "array"}:
64+
return src
65+
case _:
66+
return {"items": src, "type": "array"}
6167

6268

6369
def can_assign_src_to_sink(src: SinkType, sink: SinkType | None, strict: bool = False) -> bool:

cwltool/command_line_tool.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1388,13 +1388,14 @@ def collect_output(
13881388

13891389
optional = False
13901390
single = False
1391-
if isinstance(schema["type"], MutableSequence):
1392-
if "null" in schema["type"]:
1393-
optional = True
1394-
if "File" in schema["type"] or "Directory" in schema["type"]:
1391+
match schema["type"]:
1392+
case MutableSequence():
1393+
if "null" in schema["type"]:
1394+
optional = True
1395+
if "File" in schema["type"] or "Directory" in schema["type"]:
1396+
single = True
1397+
case "File" | "Directory":
13951398
single = True
1396-
elif schema["type"] == "File" or schema["type"] == "Directory":
1397-
single = True
13981399

13991400
if "outputEval" in binding:
14001401
with SourceLine(binding, "outputEval", WorkflowException, debug):

0 commit comments

Comments
 (0)