Skip to content

Commit e5420a6

Browse files
Add more TypedDict definitions
This commit adds more `TypedDict` definitions for `File`, `Dirent`, and `Directory` objects. In addition, it adds the `exitCode` entry to the `CWLRuntimeParameterContext`, which was missing.
1 parent b9de378 commit e5420a6

File tree

3 files changed

+145
-11
lines changed

3 files changed

+145
-11
lines changed

cwl_utils/expression.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ def evaluator(
125125
try:
126126
if first_symbol in ("inputs", "self", "runtime"):
127127
symbol = cast(
128-
Literal["inputs"] | Literal["self"] | Literal["runtime"],
128+
Literal["inputs", "self", "runtime"],
129129
first_symbol,
130130
)
131131
if inspect.iscoroutinefunction(js_engine.regex_eval):

cwl_utils/sandboxjs.py

Lines changed: 77 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@
1616
from importlib.resources import files
1717
from io import BytesIO
1818
from pathlib import Path
19-
from typing import Any, Deque, cast
19+
from typing import Any, Deque, Literal, cast
2020

2121
from schema_salad.utils import json_dumps
2222

2323
from cwl_utils.errors import JavascriptException, WorkflowException
2424
from cwl_utils.loghandler import _logger
25-
from cwl_utils.types import CWLOutputType
25+
from cwl_utils.types import CWLOutputType, is_directory, is_file
2626
from cwl_utils.utils import singularity_supports_userns
2727

2828
default_timeout = 20
@@ -549,11 +549,81 @@ def regex_eval(
549549

550550
if isinstance(current_value, Mapping):
551551
try:
552-
return self.regex_eval(
553-
parsed_string + remaining_string,
554-
remaining_string[m.end(1) :],
555-
cast(CWLOutputType, current_value[cast(str, key)]),
556-
)
552+
if is_directory(current_value):
553+
if key in ("class", "location", "path", "basename", "listing"):
554+
return self.regex_eval(
555+
parsed_string + remaining_string,
556+
remaining_string[m.end(1) :],
557+
cast(
558+
CWLOutputType,
559+
current_value[
560+
cast(
561+
Literal[
562+
"class",
563+
"location",
564+
"path",
565+
"basename",
566+
"listing",
567+
],
568+
key,
569+
)
570+
],
571+
),
572+
)
573+
else:
574+
raise WorkflowException(f"Key {key} is unexpected.")
575+
elif is_file(current_value):
576+
if key in (
577+
"class",
578+
"location",
579+
"path",
580+
"basename",
581+
"dirname",
582+
"nameroot",
583+
"nameext",
584+
"checksum",
585+
"size",
586+
"secondaryFiles",
587+
"format",
588+
"contents",
589+
):
590+
return self.regex_eval(
591+
parsed_string + remaining_string,
592+
remaining_string[m.end(1) :],
593+
cast(
594+
CWLOutputType,
595+
current_value[
596+
cast(
597+
Literal[
598+
"class",
599+
"location",
600+
"path",
601+
"basename",
602+
"dirname",
603+
"nameroot",
604+
"nameext",
605+
"checksum",
606+
"size",
607+
"secondaryFiles",
608+
"format",
609+
"contents",
610+
],
611+
key,
612+
)
613+
],
614+
),
615+
)
616+
else:
617+
raise WorkflowException(f"Key {key} is unexpected.")
618+
else:
619+
return self.regex_eval(
620+
parsed_string + remaining_string,
621+
remaining_string[m.end(1) :],
622+
cast(
623+
CWLOutputType,
624+
cast(MutableMapping[str, Any], current_value)[cast(str, key)],
625+
),
626+
)
557627
except KeyError as exc:
558628
raise WorkflowException(
559629
f"{parsed_string!r} doesn't have property {key!r}."

cwl_utils/types.py

Lines changed: 67 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
11
# SPDX-License-Identifier: Apache-2.0
22
# From https://github.com/rabix/sbpack/blob/b8404a0859ffcbe1edae6d8f934e51847b003320/sbpack/lib.py
33
"""Shared Python type definitions for commons JSON like CWL objects."""
4-
from collections.abc import MutableMapping, MutableSequence
5-
from typing import TypeAlias, TypedDict
4+
import sys
5+
from collections.abc import Mapping, MutableMapping, MutableSequence
6+
from typing import Any, Literal, TypeAlias, TypeGuard, TypedDict
7+
8+
if sys.version_info >= (3, 11):
9+
from typing import Required
10+
else:
11+
from typing_extensions import Required
12+
613

714
built_in_types: list[str] = [
815
"null",
@@ -21,12 +28,46 @@
2128
]
2229

2330

31+
DirectoryDict = TypedDict(
32+
"DirectoryDict",
33+
{
34+
"class": Required[Literal["Directory"]],
35+
"location": str,
36+
"path": str,
37+
"basename": str,
38+
"listing": MutableSequence["FileDict | DirectoryDict"],
39+
},
40+
total=False,
41+
)
42+
43+
44+
FileDict = TypedDict(
45+
"FileDict",
46+
{
47+
"class": Required[Literal["File"]],
48+
"location": str,
49+
"path": str,
50+
"basename": str,
51+
"dirname": str,
52+
"nameroot": str,
53+
"nameext": str,
54+
"checksum": str,
55+
"size": int,
56+
"secondaryFiles": MutableSequence["FileDict | DirectoryDict"],
57+
"format": str,
58+
"contents": str,
59+
},
60+
total=False,
61+
)
62+
63+
2464
CWLOutputAtomType: TypeAlias = (
2565
None
2666
| bool
2767
| str
2868
| int
29-
| float
69+
| FileDict
70+
| DirectoryDict
3071
| MutableSequence["CWLOutputAtomType"]
3172
| MutableMapping[str, "CWLOutputAtomType"]
3273
)
@@ -35,6 +76,8 @@
3576
| str
3677
| int
3778
| float
79+
| FileDict
80+
| DirectoryDict
3881
| MutableSequence[CWLOutputAtomType]
3982
| MutableMapping[str, CWLOutputAtomType]
4083
)
@@ -49,9 +92,30 @@ class CWLRuntimeParameterContext(TypedDict, total=False):
4992
ram: float | str
5093
outdirSize: float | str
5194
tmpdirSize: float | str
95+
exitCode: int
5296

5397

5498
class CWLParameterContext(TypedDict, total=False):
5599
inputs: CWLObjectType
56100
self: CWLOutputType | None
57101
runtime: CWLRuntimeParameterContext
102+
103+
104+
class DirentDict(TypedDict, total=False):
105+
entry: Required[str]
106+
entryname: str
107+
writable: bool
108+
109+
110+
def is_directory(value: Any) -> TypeGuard[DirectoryDict]:
111+
return isinstance(value, Mapping) and value.get("class") == "Directory"
112+
113+
114+
def is_file(value: Any) -> TypeGuard[FileDict]:
115+
return isinstance(value, Mapping) and value.get("class") == "File"
116+
117+
118+
def is_file_or_directory(
119+
value: Any,
120+
) -> TypeGuard[FileDict | DirectoryDict]:
121+
return isinstance(value, Mapping) and value.get("class") in ("File", "Directory")

0 commit comments

Comments
 (0)