Skip to content

Commit 10cabef

Browse files
committed
add strongly-typed visit_* functions
1 parent 54154aa commit 10cabef

8 files changed

Lines changed: 152 additions & 123 deletions

File tree

cwltool/builder.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
aslist,
3333
get_listing,
3434
normalizeFilesDirs,
35-
visit_class,
35+
visit_files_directories,
3636
)
3737

3838
if TYPE_CHECKING:
@@ -165,7 +165,7 @@ def build_job_script(self, commands: list[str]) -> str | None:
165165
return self.job_script_provider.build_job_script(self, commands)
166166
return None
167167

168-
def _capture_files(self, f: CWLFileType) -> CWLFileType:
168+
def _capture_files(self, f: CWLFileType | CWLDirectoryType) -> CWLFileType | CWLDirectoryType:
169169
self.files.append(f)
170170
return f
171171

@@ -549,9 +549,8 @@ def addsf(
549549
f"format {schema['format']!r} but\n {ve}"
550550
) from ve
551551

552-
visit_class(
552+
visit_files_directories(
553553
fdatum.get("secondaryFiles", []),
554-
("File", "Directory"),
555554
self._capture_files,
556555
)
557556

@@ -567,7 +566,7 @@ def addsf(
567566
self.files.append(ddatum)
568567

569568
if schema["type"] == "Any":
570-
visit_class(datum, ("File", "Directory"), self._capture_files)
569+
visit_files_directories(datum, self._capture_files)
571570

572571
# Position to front of the sort key
573572
if binding:

cwltool/command_line_tool.py

Lines changed: 36 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
JobsGeneratorType,
6868
OutputCallbackType,
6969
adjustDirObjs,
70+
adjustFileDirObjs,
7071
adjustFileObjs,
7172
aslist,
7273
get_listing,
@@ -75,7 +76,8 @@
7576
shared_file_lock,
7677
trim_listing,
7778
upgrade_lock,
78-
visit_class,
79+
visit_files,
80+
visit_files_directories,
7981
)
8082

8183
if TYPE_CHECKING:
@@ -223,7 +225,7 @@ def job(
223225
raise WorkflowException("Abstract operation cannot be executed.")
224226

225227

226-
def remove_path(f: CWLObjectType) -> None:
228+
def remove_path(f: CWLFileType | CWLDirectoryType) -> None:
227229
"""Remove any 'path' property, if present."""
228230
if "path" in f:
229231
del f["path"]
@@ -338,7 +340,9 @@ def run(
338340
)
339341

340342

341-
def check_adjust(accept_re: Pattern[str], builder: Builder, file_o: CWLObjectType) -> CWLObjectType:
343+
def check_adjust(
344+
accept_re: Pattern[str], builder: Builder, file_o: CWLFileType | CWLDirectoryType
345+
) -> CWLFileType | CWLDirectoryType:
342346
"""
343347
Map files to assigned path inside a container.
344348
@@ -347,14 +351,14 @@ def check_adjust(accept_re: Pattern[str], builder: Builder, file_o: CWLObjectTyp
347351
"""
348352
if not builder.pathmapper:
349353
raise ValueError("Do not call check_adjust using a builder that doesn't have a pathmapper.")
350-
file_o["path"] = path = builder.pathmapper.mapper(cast(str, file_o["location"]))[1]
354+
file_o["path"] = path = builder.pathmapper.mapper(file_o["location"])[1]
351355
basename = cast(str, file_o.get("basename"))
352356
dn, bn = os.path.split(path)
353-
if file_o.get("dirname") != dn:
354-
file_o["dirname"] = str(dn)
355357
if basename != bn:
356358
file_o["basename"] = basename = str(bn)
357-
if file_o["class"] == "File":
359+
if is_file(file_o):
360+
if file_o.get("dirname") != dn:
361+
file_o["dirname"] = str(dn)
358362
nr, ne = os.path.splitext(basename)
359363
if file_o.get("nameroot") != nr:
360364
file_o["nameroot"] = str(nr)
@@ -469,10 +473,10 @@ def updatePathmap(
469473
("Writable" if fn.get("writable") else "") + cast(str, fn["class"]),
470474
False,
471475
)
472-
if fn["class"] == "File" and "secondaryFiles" in fn:
476+
if is_file(fn) and "secondaryFiles" in fn:
473477
for sf in fn["secondaryFiles"]:
474478
self.updatePathmap(outdir, pathmap, sf)
475-
if fn["class"] == "Directory" and "listing" in fn:
479+
if is_directory(fn) and "listing" in fn:
476480
for ls in fn["listing"]:
477481
self.updatePathmap(os.path.join(outdir, fn["basename"]), pathmap, ls)
478482

@@ -533,26 +537,12 @@ def _initialworkdir(self, j: JobBase | None, builder: Builder) -> None:
533537
)
534538
else:
535539
for entry2 in entry1:
536-
if not (
537-
isinstance(entry2, MutableMapping)
538-
and (
539-
"class" in entry2
540-
and entry2["class"] == "File"
541-
or "Directory"
542-
)
543-
):
540+
if not is_file_or_directory(entry2):
544541
fail = (
545542
"an array with an item ('{entry2}') that is "
546543
"not a File nor a Directory object."
547544
)
548-
elif not (
549-
isinstance(entry1, MutableMapping)
550-
and (
551-
"class" in entry1
552-
and (entry1["class"] == "File" or "Directory")
553-
or "entry" in entry1
554-
)
555-
):
545+
elif not (is_file_or_directory(entry1) or "entry" in entry1):
556546
fail = entry1
557547
if fail is not False:
558548
message = (
@@ -796,19 +786,17 @@ def _initialworkdir(self, j: JobBase | None, builder: Builder) -> None:
796786

797787
if is_directory(entry4) and "listing" in entry4:
798788

799-
def remove_dirname(d: CWLObjectType) -> None:
800-
if "dirname" in d:
789+
def remove_dirname(d: CWLFileType | CWLDirectoryType) -> None:
790+
if is_file(d) and "dirname" in d:
801791
del d["dirname"]
802792

803-
visit_class(
793+
visit_files_directories(
804794
entry4["listing"],
805-
("File", "Directory"),
806795
remove_dirname,
807796
)
808797

809-
visit_class(
798+
visit_files_directories(
810799
[builder.files, builder.bindings],
811-
("File", "Directory"),
812800
partial(check_adjust, self.path_check_mode.value, builder),
813801
)
814802

@@ -839,12 +827,11 @@ def job(
839827
compute_checksums,
840828
runtimeContext.make_fs_access(runtimeContext.basedir),
841829
)
842-
visit_class(
830+
visit_files_directories(
843831
[cachebuilder.files, cachebuilder.bindings],
844-
("File", "Directory"),
845832
_check_adjust,
846833
)
847-
visit_class([cachebuilder.files, cachebuilder.bindings], ("File"), _checksum)
834+
visit_files([cachebuilder.files, cachebuilder.bindings], _checksum)
848835
self._initialworkdir(None, cachebuilder) # test the initial working directory
849836

850837
cmdline = flatten(list(map(cachebuilder.generate_arg, cachebuilder.bindings)))
@@ -1010,7 +997,7 @@ def update_status_output_callback(
1010997

1011998
_check_adjust = partial(check_adjust, self.path_check_mode.value, builder)
1012999

1013-
visit_class([builder.files, builder.bindings], ("File", "Directory"), _check_adjust)
1000+
visit_files_directories([builder.files, builder.bindings], _check_adjust)
10141001

10151002
self._initialworkdir(j, builder)
10161003

@@ -1087,34 +1074,30 @@ def update_status_output_callback(
10871074
j.inplace_update = cast(bool, inplaceUpdateReq["inplaceUpdate"])
10881075
normalizeFilesDirs(j.generatefiles)
10891076

1090-
readers: dict[str, CWLObjectType] = {}
1077+
readers: dict[str, CWLFileType | CWLDirectoryType] = {}
10911078
muts: set[str] = set()
10921079

10931080
if builder.mutation_manager is not None:
10941081

1095-
def register_mut(f: CWLObjectType) -> None:
1082+
def register_mut(f: CWLFileType | CWLDirectoryType) -> None:
10961083
mm = cast(MutationManager, builder.mutation_manager)
1097-
muts.add(cast(str, f["location"]))
1084+
muts.add(f["location"])
10981085
mm.register_mutation(j.name, f)
10991086

1100-
def register_reader(f: CWLObjectType) -> None:
1087+
def register_reader(f: CWLFileType | CWLDirectoryType) -> None:
11011088
mm = cast(MutationManager, builder.mutation_manager)
1102-
if cast(str, f["location"]) not in muts:
1089+
if f["location"] not in muts:
11031090
mm.register_reader(j.name, f)
1104-
readers[cast(str, f["location"])] = copy.deepcopy(f)
1091+
readers[f["location"]] = copy.deepcopy(f)
11051092

11061093
for li in j.generatefiles["listing"]:
11071094
if li.get("writable") and j.inplace_update:
1108-
adjustFileObjs(li, register_mut)
1109-
adjustDirObjs(li, register_mut)
1095+
adjustFileDirObjs(li, register_mut)
11101096
else:
1111-
adjustFileObjs(li, register_reader)
1112-
adjustDirObjs(li, register_reader)
1097+
adjustFileDirObjs(li, register_reader)
11131098

1114-
adjustFileObjs(builder.files, register_reader)
1115-
adjustFileObjs(builder.bindings, register_reader)
1116-
adjustDirObjs(builder.files, register_reader)
1117-
adjustDirObjs(builder.bindings, register_reader)
1099+
adjustFileDirObjs(builder.files, register_reader)
1100+
adjustFileDirObjs(builder.bindings, register_reader)
11181101

11191102
timelimit, _ = self.get_requirement("ToolTimeLimit")
11201103
if timelimit is not None:
@@ -1223,7 +1206,7 @@ def collect_output_ports(
12231206
rcode: int,
12241207
compute_checksum: bool = True,
12251208
jobname: str = "",
1226-
readers: MutableMapping[str, CWLObjectType] | None = None,
1209+
readers: MutableMapping[str, CWLFileType | CWLDirectoryType] | None = None,
12271210
) -> OutputPortsType:
12281211
ret: OutputPortsType = {}
12291212
debug = _logger.isEnabledFor(logging.DEBUG)
@@ -1276,12 +1259,11 @@ def collect_output_ports(
12761259
if ret:
12771260
revmap = partial(revmap_file, builder, outdir)
12781261
adjustDirObjs(ret, trim_listing)
1279-
visit_class(ret, ("File", "Directory"), revmap)
1280-
visit_class(ret, ("File", "Directory"), remove_path)
1262+
visit_files_directories(ret, revmap)
1263+
visit_files_directories(ret, remove_path)
12811264
normalizeFilesDirs(ret)
1282-
visit_class(
1265+
visit_files_directories(
12831266
ret,
1284-
("File", "Directory"),
12851267
partial(check_valid_locations, fs_access),
12861268
)
12871269

cwltool/cwlprov/writablebagfile.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from pathlib import Path, PurePosixPath
1515
from typing import Any, BinaryIO, cast
1616

17-
from cwl_utils.types import CWLObjectType
17+
from cwl_utils.types import CWLObjectType, is_file_or_directory
1818
from schema_salad.utils import json_dumps
1919

2020
from ..loghandler import _logger
@@ -265,7 +265,7 @@ def jdefault(o: Any) -> dict[Any, Any]:
265265
# 2) for other attributes, the actual value.
266266
for key, value in copied.items():
267267
if isinstance(value, MutableMapping):
268-
if value.get("class") in ("File", "Directory"):
268+
if is_file_or_directory(value):
269269
relativised_input_objecttemp[key] = value
270270
else:
271271
relativised_input_objecttemp[key] = value

cwltool/main.py

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,8 @@
102102
processes_to_kill,
103103
trim_listing,
104104
versionstring,
105-
visit_class,
105+
visit_files,
106+
visit_files_directories,
106107
)
107108
from .workflow import Workflow
108109

@@ -473,7 +474,7 @@ def init_job_order(
473474
job_order_object = {}
474475
job_order_object[shortname(inp["id"])] = inp["default"]
475476

476-
def path_to_loc(p: CWLObjectType) -> None:
477+
def path_to_loc(p: CWLFileType | CWLDirectoryType) -> None:
477478
if "location" not in p and "path" in p:
478479
p["location"] = p["path"]
479480
del p["path"]
@@ -483,17 +484,16 @@ def path_to_loc(p: CWLObjectType) -> None:
483484
ns.update(cast(ContextType, process.metadata.get("$namespaces", {})))
484485
ld = Loader(ns)
485486

486-
def expand_formats(p: CWLObjectType) -> None:
487+
def expand_formats(p: CWLFileType) -> None:
487488
if "format" in p:
488-
p["format"] = ld.expand_url(cast(str, p["format"]), "")
489+
p["format"] = ld.expand_url(p["format"], "")
489490

490-
visit_class(job_order_object, ("File", "Directory"), path_to_loc)
491-
visit_class(
491+
visit_files_directories(job_order_object, path_to_loc)
492+
visit_files(
492493
job_order_object,
493-
("File",),
494494
functools.partial(add_sizes, make_fs_access(input_basedir)),
495495
)
496-
visit_class(job_order_object, ("File",), expand_formats)
496+
visit_files(job_order_object, expand_formats)
497497
adjustDirObjs(job_order_object, trim_listing)
498498
normalizeFilesDirs(job_order_object)
499499

@@ -561,7 +561,7 @@ def printdeps(
561561
base = basedir if basedir else os.path.dirname(uri_file_path(str(uri)))
562562
elif relative_deps == "cwd":
563563
base = os.getcwd()
564-
visit_class(deps, ("File", "Directory"), functools.partial(make_relative, base))
564+
visit_files_directories(deps, functools.partial(make_relative, base))
565565
json_dump(deps, stdout, indent=4, default=str)
566566

567567

@@ -1344,23 +1344,22 @@ def remove_at_id(doc: CWLObjectType) -> None:
13441344
remove_at_id(entry)
13451345

13461346
remove_at_id(out)
1347-
visit_class(
1347+
visit_files(
13481348
out,
1349-
("File",),
13501349
functools.partial(add_sizes, runtimeContext.make_fs_access("")),
13511350
)
13521351

1353-
def loc_to_path(obj: CWLObjectType) -> None:
1352+
def loc_to_path(obj: CWLFileType | CWLDirectoryType) -> None:
13541353
for field in ("path", "nameext", "nameroot", "dirname"):
13551354
if field in obj:
1356-
del obj[field]
1357-
if cast(str, obj["location"]).startswith("file://"):
1358-
obj["path"] = uri_file_path(cast(str, obj["location"]))
1355+
del obj[field] # type: ignore[misc]
1356+
if obj["location"].startswith("file://"):
1357+
obj["path"] = uri_file_path(obj["location"])
13591358

1360-
visit_class(out, ("File", "Directory"), loc_to_path)
1359+
visit_files_directories(out, loc_to_path)
13611360

13621361
# Unsetting the Generation from final output object
1363-
visit_class(out, ("File",), MutationManager().unset_generation)
1362+
visit_files(out, MutationManager().unset_generation)
13641363

13651364
if args.write_summary:
13661365
with open(args.write_summary, "w") as output_file:

0 commit comments

Comments
 (0)