11import copy
22import logging
33import math
4- import os
54from typing import (
65 IO ,
76 Any ,
1413 Set ,
1514 Tuple ,
1615 Union ,
16+ cast ,
1717)
1818
1919from rdflib import Graph , URIRef
2020from rdflib .namespace import OWL , RDFS
2121from ruamel .yaml .comments import CommentedMap
22- from schema_salad import validate
23- from schema_salad .avro .schema import Schema , make_avsc_object
24- from schema_salad .schema import Names , convert_to_dict
22+ from schema_salad .avro .schema import Names , Schema , make_avsc_object
23+ from schema_salad .exceptions import ValidationException
2524from schema_salad .sourceline import SourceLine
26- from schema_salad .utils import json_dumps
25+ from schema_salad .utils import convert_to_dict , json_dumps
26+ from schema_salad .validate import validate
2727from typing_extensions import TYPE_CHECKING , Type # pylint: disable=unused-import
2828
2929from . import expression
3030from .errors import WorkflowException
3131from .loghandler import _logger
3232from .mutation import MutationManager
33- from .pathmapper import CONTENT_LIMIT , get_listing , normalizeFilesDirs , visit_class
3433from .stdfsaccess import StdFsAccess
35- from .utils import aslist , docker_windows_path_adjust , onWindows
36-
37- # move to a regular typing import when Python 3.3-3.6 is no longer supported
38-
34+ from .utils import (
35+ CONTENT_LIMIT ,
36+ CWLObjectType ,
37+ CWLOutputType ,
38+ aslist ,
39+ docker_windows_path_adjust ,
40+ get_listing ,
41+ normalizeFilesDirs ,
42+ onWindows ,
43+ visit_class ,
44+ )
3945
4046if TYPE_CHECKING :
4147 from .provenance import ProvenanceProfile # pylint: disable=unused-import
@@ -111,28 +117,28 @@ def check_format(
111117 if not afile :
112118 continue
113119 if "format" not in afile :
114- raise validate . ValidationException (
120+ raise ValidationException (
115121 "File has no 'format' defined: {}" .format (json_dumps (afile , indent = 4 ))
116122 )
117123 for inpf in aslist (input_formats ):
118124 if afile ["format" ] == inpf or formatSubclassOf (
119125 afile ["format" ], inpf , ontology , set ()
120126 ):
121127 return
122- raise validate . ValidationException (
128+ raise ValidationException (
123129 "File has an incompatible format: {}" .format (json_dumps (afile , indent = 4 ))
124130 )
125131
126132
127133class HasReqsHints (object ):
128- def __init__ (self ): # type: () -> None
134+ def __init__ (self ) -> None :
129135 """Initialize this reqs decorator."""
130- self .requirements = [] # type: List[Dict[str, Any] ]
131- self .hints = [] # type: List[Dict[str, Any] ]
136+ self .requirements = [] # type: List[CWLObjectType ]
137+ self .hints = [] # type: List[CWLObjectType ]
132138
133139 def get_requirement (
134- self , feature # type : str
135- ): # type: (...) -> Tuple[Optional[Any ], Optional[bool]]
140+ self , feature : str
141+ ) -> Tuple [Optional [CWLObjectType ], Optional [bool ]]:
136142 for item in reversed (self .requirements ):
137143 if item ["class" ] == feature :
138144 return (item , True )
@@ -145,28 +151,28 @@ def get_requirement(
145151class Builder (HasReqsHints ):
146152 def __init__ (
147153 self ,
148- job , # type: Dict[str, expression.JSON]
149- files , # type : List[Dict[str, str]]
150- bindings , # type : List[Dict[str, Any]]
151- schemaDefs , # type : Dict[str, Dict[str, Any]]
152- names , # type : Names
153- requirements , # type : List[Dict[str, Any]]
154- hints , # type : List[Dict[str, Any]]
155- resources , # type : Dict[str, int]
154+ job : CWLObjectType ,
155+ files : List [CWLObjectType ],
156+ bindings : List [CWLObjectType ],
157+ schemaDefs : Dict [str , CWLObjectType ],
158+ names : Names ,
159+ requirements : List [CWLObjectType ],
160+ hints : List [CWLObjectType ],
161+ resources : Dict [str , int ],
156162 mutation_manager : Optional [MutationManager ],
157- formatgraph , # type : Optional[Graph]
163+ formatgraph : Optional [Graph ],
158164 make_fs_access : Type [StdFsAccess ],
159- fs_access , # type : StdFsAccess
160- job_script_provider , # type : Optional[Any]
161- timeout , # type : float
162- debug , # type : bool
163- js_console , # type : bool
164- force_docker_pull , # type : bool
165- loadListing , # type : str
166- outdir , # type : str
167- tmpdir , # type : str
168- stagedir , # type : str
169- ): # type: (...) -> None
165+ fs_access : StdFsAccess ,
166+ job_script_provider : Optional [Any ],
167+ timeout : float ,
168+ debug : bool ,
169+ js_console : bool ,
170+ force_docker_pull : bool ,
171+ loadListing : str ,
172+ outdir : str ,
173+ tmpdir : str ,
174+ stagedir : str ,
175+ ) -> None :
170176 """Initialize this Builder."""
171177 self .job = job
172178 self .files = files
@@ -201,10 +207,10 @@ def __init__(
201207 self .prov_obj = None # type: Optional[ProvenanceProfile]
202208 self .find_default_container = None # type: Optional[Callable[[], str]]
203209
204- def build_job_script (self , commands : List [str ]) -> str :
210+ def build_job_script (self , commands : List [str ]) -> Optional [ str ] :
205211 build_job_script_method = getattr (
206212 self .job_script_provider , "build_job_script" , None
207- ) # type: Callable[[Builder, Union[List[str],List[str]]], str]
213+ ) # type: Optional[ Callable[[Builder, Union[List[str],List[str]]], str] ]
208214 if build_job_script_method is not None :
209215 return build_job_script_method (self , commands )
210216 return None
@@ -215,16 +221,18 @@ def bind_input(
215221 datum : Any ,
216222 discover_secondaryFiles : bool ,
217223 lead_pos : Optional [Union [int , List [int ]]] = None ,
218- tail_pos : Optional [List [int ]] = None ,
224+ tail_pos : Optional [Union [ str , List [int ] ]] = None ,
219225 ) -> List [MutableMapping [str , Any ]]:
220226
221227 if tail_pos is None :
222228 tail_pos = []
223229 if lead_pos is None :
224230 lead_pos = []
225231
226- bindings = [] # type: List[MutableMapping[str, str]]
227- binding = {} # type: Union[MutableMapping[str, str], CommentedMap]
232+ bindings = [] # type: List[MutableMapping[str, Union[str, List[int]]]]
233+ binding = (
234+ {}
235+ ) # type: Union[MutableMapping[str, Union[str, List[int]]], CommentedMap]
228236 value_from_expression = False
229237 if "inputBinding" in schema and isinstance (
230238 schema ["inputBinding" ], MutableMapping
@@ -264,7 +272,7 @@ def bind_input(
264272 avsc = self .names .get_name (t ["name" ], None )
265273 if not avsc :
266274 avsc = make_avsc_object (convert_to_dict (t ), self .names )
267- if validate . validate (avsc , datum ):
275+ if validate (avsc , datum ):
268276 schema = copy .deepcopy (schema )
269277 schema ["type" ] = t
270278 if not value_from_expression :
@@ -285,7 +293,7 @@ def bind_input(
285293 )
286294 bound_input = True
287295 if not bound_input :
288- raise validate . ValidationException (
296+ raise ValidationException (
289297 "'%s' is not a valid union %s" % (datum , schema ["type" ])
290298 )
291299 elif isinstance (schema ["type" ], MutableMapping ):
@@ -359,7 +367,7 @@ def bind_input(
359367 )
360368 binding = {}
361369
362- def _capture_files (f ): # type: (Dict[str, str] ) -> Dict[str, str]
370+ def _capture_files (f ): # type: (CWLObjectType ) -> CWLObjectType
363371 self .files .append (f )
364372 return f
365373
@@ -453,7 +461,7 @@ def addsf(
453461 check_format (
454462 datum , self .do_eval (schema ["format" ]), self .formatgraph
455463 )
456- except validate . ValidationException as ve :
464+ except ValidationException as ve :
457465 raise WorkflowException (
458466 "Expected value of '%s' to have format %s but\n "
459467 " %s" % (schema ["name" ], schema ["format" ], ve )
@@ -477,7 +485,9 @@ def addsf(
477485 # Position to front of the sort key
478486 if binding :
479487 for bi in bindings :
480- bi ["position" ] = binding ["position" ] + bi ["position" ]
488+ bi ["position" ] = cast (List [int ], binding ["position" ]) + cast (
489+ List [int ], bi ["position" ]
490+ )
481491 bindings .append (binding )
482492
483493 return bindings
@@ -503,7 +513,7 @@ def tostr(self, value: Union[MutableMapping[str, str], Any]) -> str:
503513 else :
504514 return str (value )
505515
506- def generate_arg (self , binding ): # type: (Dict[str, Any] ) -> List[str]
516+ def generate_arg (self , binding : CWLObjectType ) -> List [str ]:
507517 value = binding .get ("datum" )
508518 if "valueFrom" in binding :
509519 with SourceLine (
@@ -512,9 +522,9 @@ def generate_arg(self, binding): # type: (Dict[str, Any]) -> List[str]
512522 WorkflowException ,
513523 _logger .isEnabledFor (logging .DEBUG ),
514524 ):
515- value = self .do_eval (binding ["valueFrom" ], context = value )
525+ value = self .do_eval (cast ( str , binding ["valueFrom" ]) , context = value )
516526
517- prefix = binding .get ("prefix" ) # type: Optional[str]
527+ prefix = cast ( Optional [ str ], binding .get ("prefix" ))
518528 sep = binding .get ("separate" , True )
519529 if prefix is None and not sep :
520530 with SourceLine (
@@ -527,13 +537,16 @@ def generate_arg(self, binding): # type: (Dict[str, Any]) -> List[str]
527537 "'separate' option can not be specified without prefix"
528538 )
529539
530- argl = [] # type: MutableSequence[MutableMapping[str, str] ]
540+ argl = [] # type: MutableSequence[CWLOutputType ]
531541 if isinstance (value , MutableSequence ):
532542 if binding .get ("itemSeparator" ) and value :
533- argl = [binding ["itemSeparator" ].join ([self .tostr (v ) for v in value ])]
543+ itemSeparator = cast (str , binding ["itemSeparator" ])
544+ argl = [itemSeparator .join ([self .tostr (v ) for v in value ])]
534545 elif binding .get ("valueFrom" ):
535546 value = [self .tostr (v ) for v in value ]
536- return ([prefix ] if prefix else []) + value
547+ return cast (List [str ], ([prefix ] if prefix else [])) + cast (
548+ List [str ], value
549+ )
537550 elif prefix and value :
538551 return [prefix ]
539552 else :
@@ -542,7 +555,7 @@ def generate_arg(self, binding): # type: (Dict[str, Any]) -> List[str]
542555 "File" ,
543556 "Directory" ,
544557 ):
545- argl = [ value ]
558+ argl = cast ( MutableSequence [ CWLOutputType ], [ value ])
546559 elif isinstance (value , MutableMapping ):
547560 return [prefix ] if prefix else []
548561 elif value is True and prefix :
@@ -561,8 +574,15 @@ def generate_arg(self, binding): # type: (Dict[str, Any]) -> List[str]
561574
562575 return [a for a in args if a is not None ]
563576
564- def do_eval (self , ex , context = None , recursive = False , strip_whitespace = True ):
565- # type: (Union[Dict[str, str], str], Any, bool, bool) -> Any
577+ def do_eval (
578+ self ,
579+ ex : Union [
580+ str , float , bool , None , MutableMapping [str , str ], MutableSequence [str ]
581+ ],
582+ context : Optional [Any ] = None ,
583+ recursive : bool = False ,
584+ strip_whitespace : bool = True ,
585+ ) -> Any :
566586 if recursive :
567587 if isinstance (ex , MutableMapping ):
568588 return {k : self .do_eval (v , context , recursive ) for k , v in ex .items ()}
0 commit comments