Skip to content

Commit a3d24f8

Browse files
committed
add type hints
1 parent 3f385ec commit a3d24f8

23 files changed

+518
-237
lines changed

cwltool/aslist.py

Lines changed: 0 additions & 5 deletions
This file was deleted.

cwltool/builder.py

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,23 @@
11
import copy
2-
from aslist import aslist
3-
import expression
2+
from .utils import aslist
3+
from . import expression
44
import avro
55
import schema_salad.validate as validate
6+
from typing import Any, Union, AnyStr, Callable
7+
from .errors import WorkflowException
8+
from .stdfsaccess import StdFsAccess
9+
from .pathmapper import PathMapper
610

711
CONTENT_LIMIT = 64 * 1024
812

9-
def substitute(value, replace):
13+
14+
def substitute(value, replace): # type: (str, str) -> str
1015
if replace[0] == "^":
1116
return substitute(value[0:value.rindex('.')], replace[1:])
1217
else:
1318
return value + replace
1419

15-
def adjustFileObjs(rec, op):
20+
def adjustFileObjs(rec, op): # type: (Any, Callable[[Any], Any]) -> None
1621
"""Apply an update function to each File object in the object `rec`."""
1722

1823
if isinstance(rec, dict):
@@ -26,9 +31,24 @@ def adjustFileObjs(rec, op):
2631

2732
class Builder(object):
2833

34+
def __init__(self): # type: () -> None
35+
self.names = None # type: avro.schema.Names
36+
self.schemaDefs = None # type: Dict[str,Dict[str,str]]
37+
self.files = None # type: List[str]
38+
self.fs_access = None # type: StdFsAccess
39+
self.job = None # type: Dict[str,str]
40+
self.requirements = None # type: List[Dict[str,Any]]
41+
self.outdir = None # type: str
42+
self.tmpdir = None # type: str
43+
self.resources = None # type: Dict[str,str]
44+
self.bindings = [] # type: List[Dict[str,str]]
45+
self.timeout = None # type: int
46+
self.pathmapper = None # type: PathMapper
47+
2948
def bind_input(self, schema, datum, lead_pos=[], tail_pos=[]):
30-
bindings = []
31-
binding = None
49+
# type: (Dict[str,Any], Any, List[int], List[int]) -> List[Dict[str,str]]
50+
bindings = [] # type: List[Dict[str,str]]
51+
binding = None # type: Dict[str,Any]
3252
if "inputBinding" in schema and isinstance(schema["inputBinding"], dict):
3353
binding = copy.copy(schema["inputBinding"])
3454

@@ -102,9 +122,11 @@ def bind_input(self, schema, datum, lead_pos=[], tail_pos=[]):
102122
datum["secondaryFiles"] = []
103123
for sf in aslist(schema["secondaryFiles"]):
104124
if isinstance(sf, dict) or "$(" in sf or "${" in sf:
105-
sfpath = self.do_eval(sf, context=datum)
106-
if isinstance(sfpath, basestring):
125+
secondary_eval = self.do_eval(sf, context=datum)
126+
if isinstance(secondary_eval, basestring):
107127
sfpath = {"path": sfpath, "class": "File"}
128+
else:
129+
sfpath = secondary_eval
108130
else:
109131
sfpath = {"path": substitute(datum["path"], sf), "class": "File"}
110132
if isinstance(sfpath, list):
@@ -126,23 +148,23 @@ def _capture_files(f):
126148

127149
return bindings
128150

129-
def tostr(self, value):
151+
def tostr(self, value): # type(Any) -> str
130152
if isinstance(value, dict) and value.get("class") == "File":
131153
if "path" not in value:
132154
raise WorkflowException(u"File object must have \"path\": %s" % (value))
133155
return value["path"]
134156
else:
135157
return str(value)
136158

137-
def generate_arg(self, binding):
159+
def generate_arg(self, binding): # type: (Dict[str,Any]) -> List[str]
138160
value = binding["valueFrom"]
139161
if "do_eval" in binding:
140162
value = self.do_eval(binding["do_eval"], context=value)
141163

142164
prefix = binding.get("prefix")
143165
sep = binding.get("separate", True)
144166

145-
l = []
167+
l = [] # type: List[Dict[str,str]]
146168
if isinstance(value, list):
147169
if binding.get("itemSeparator"):
148170
l = [binding["itemSeparator"].join([self.tostr(v) for v in value])]
@@ -174,6 +196,7 @@ def generate_arg(self, binding):
174196
return [a for a in args if a is not None]
175197

176198
def do_eval(self, ex, context=None, pull_image=True):
199+
# type: (Dict[str,str], Any, bool) -> Any
177200
return expression.do_eval(ex, self.job, self.requirements,
178201
self.outdir, self.tmpdir,
179202
self.resources,

cwltool/cwlrdf.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22
import urlparse
33
from rdflib import Graph, plugin, URIRef
44
from rdflib.serializer import Serializer
5+
from typing import Any, Union, Dict, IO
56

67
def makerdf(workflow, wf, ctx):
8+
# type: (str, Dict[str,Any], Dict[str,Union[str, Dict[str,str]]]) -> Graph
79
prefixes = {}
810
for k,v in ctx.iteritems():
911
if isinstance(v, dict):
@@ -26,17 +28,18 @@ def makerdf(workflow, wf, ctx):
2628
return g
2729

2830
def printrdf(workflow, wf, ctx, sr, stdout):
31+
# type: (str, Dict[str,Any], Dict[str,Union[str, Dict[str,str]]], str, IO[Any]) -> None
2932
stdout.write(makerdf(workflow, wf, ctx).serialize(format=sr))
3033

31-
def lastpart(uri):
34+
def lastpart(uri): # type: (Any) -> str
3235
uri = str(uri)
3336
if "/" in uri:
3437
return uri[uri.rindex("/")+1:]
3538
else:
3639
return uri
3740

3841

39-
def dot_with_parameters(g, stdout):
42+
def dot_with_parameters(g, stdout): # type: (Graph, IO[Any]) -> None
4043
qres = g.query(
4144
"""SELECT ?step ?run ?runtype
4245
WHERE {
@@ -92,8 +95,8 @@ def dot_with_parameters(g, stdout):
9295
for (inp,) in qres:
9396
stdout.write(u'"%s" [shape=octagon]\n' % (lastpart(inp)))
9497

95-
def dot_without_parameters(g, stdout):
96-
dotname = {}
98+
def dot_without_parameters(g, stdout): # type: (Graph, IO[Any]) -> None
99+
dotname = {} # type: Dict[str,str]
97100
clusternode = {}
98101

99102
stdout.write("compound=true\n")
@@ -166,14 +169,15 @@ def dot_without_parameters(g, stdout):
166169

167170

168171
def printdot(workflow, wf, ctx, stdout, include_parameters=False):
172+
# type: (str, Dict[str,Any], Dict[str,Union[str, Dict[str,str]]], Any, bool) -> None
169173
g = makerdf(workflow, wf, ctx)
170174

171175
stdout.write("digraph {")
172176

173177
#g.namespace_manager.qname(predicate)
174178

175179
if include_parameters:
176-
dot_with_parmeters(g, stdout)
180+
dot_with_parameters(g, stdout)
177181
else:
178182
dot_without_parameters(g, stdout)
179183

cwltool/cwltest.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@
88
import shutil
99
import tempfile
1010
import yaml
11+
import yaml.scanner
1112
import pipes
1213
import logging
1314
import schema_salad.ref_resolver
15+
from typing import Any, Union
1416

1517
_logger = logging.getLogger("cwltest")
1618
_logger.addHandler(logging.StreamHandler())
@@ -21,7 +23,8 @@
2123
class CompareFail(Exception):
2224
pass
2325

24-
def compare(a, b):
26+
27+
def compare(a, b): # type: (Any, Any) -> bool
2528
try:
2629
if isinstance(a, dict):
2730
if a.get("class") == "File":
@@ -54,8 +57,9 @@ def compare(a, b):
5457
except Exception as e:
5558
raise CompareFail(str(e))
5659

57-
def run_test(args, i, t):
58-
out = {}
60+
61+
def run_test(args, i, t): # type: (argparse.Namespace, Any, Dict[str,str]) -> int
62+
out = {} # type: Dict[str,Any]
5963
outdir = None
6064
try:
6165
if "output" in t:
@@ -84,7 +88,7 @@ def run_test(args, i, t):
8488
outstr = subprocess.check_output(test_command)
8589
out = yaml.load(outstr)
8690
except ValueError as v:
87-
_logger.error(v)
91+
_logger.error(str(v))
8892
_logger.error(outstr)
8993
except subprocess.CalledProcessError as err:
9094
if err.returncode == UNSUPPORTED_FEATURE:
@@ -123,15 +127,16 @@ def run_test(args, i, t):
123127
failed = True
124128

125129
if outdir:
126-
shutil.rmtree(outdir, True)
130+
shutil.rmtree(outdir, True) # type: ignore
131+
# Weird AnyStr != basestring issue
127132

128133
if failed:
129134
return 1
130135
else:
131136
return 0
132137

133138

134-
def main():
139+
def main(): # type: () -> int
135140
parser = argparse.ArgumentParser(description='Compliance tests for cwltool')
136141
parser.add_argument("--test", type=str, help="YAML file describing test cases", required=True)
137142
parser.add_argument("--basedir", type=str, help="Basedir to use for tests", default=".")

cwltool/docker.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@
33
import sys
44
import requests
55
import os
6-
import process
6+
from .errors import WorkflowException
77
import re
88
import tempfile
9+
from typing import Any, Union
910

1011
_logger = logging.getLogger("cwltool")
1112

1213
def get_image(dockerRequirement, pull_image, dry_run=False):
14+
# type: (Dict[str,str], bool, bool) -> bool
1315
found = False
1416

1517
if "dockerImageId" not in dockerRequirement and "dockerPull" in dockerRequirement:
@@ -36,7 +38,7 @@ def get_image(dockerRequirement, pull_image, dry_run=False):
3638
subprocess.check_call(cmd, stdout=sys.stderr)
3739
found = True
3840
elif "dockerFile" in dockerRequirement:
39-
dockerfile_dir = tempfile.mkdtemp()
41+
dockerfile_dir = str(tempfile.mkdtemp())
4042
with open(os.path.join(dockerfile_dir, "Dockerfile"), "w") as df:
4143
df.write(dockerRequirement["dockerFile"])
4244
cmd = ["docker", "build", "--tag=%s" % dockerRequirement["dockerImageId"], dockerfile_dir]
@@ -64,7 +66,7 @@ def get_image(dockerRequirement, pull_image, dry_run=False):
6466
loadproc.stdin.close()
6567
rcode = loadproc.wait()
6668
if rcode != 0:
67-
raise process.WorkflowException("Docker load returned non-zero exit status %i" % (rcode))
69+
raise WorkflowException("Docker load returned non-zero exit status %i" % (rcode))
6870
found = True
6971
elif "dockerImport" in dockerRequirement:
7072
cmd = ["docker", "import", dockerRequirement["dockerImport"], dockerRequirement["dockerImageId"]]
@@ -77,6 +79,7 @@ def get_image(dockerRequirement, pull_image, dry_run=False):
7779

7880

7981
def get_from_requirements(r, req, pull_image, dry_run=False):
82+
# type: (Dict[str,str], bool, bool, bool) -> Union[None,str]
8083
if r:
8184
errmsg = None
8285
try:
@@ -88,14 +91,14 @@ def get_from_requirements(r, req, pull_image, dry_run=False):
8891

8992
if errmsg:
9093
if req:
91-
raise process.WorkflowException(errmsg)
94+
raise WorkflowException(errmsg)
9295
else:
9396
return None
9497

9598
if get_image(r, pull_image, dry_run):
9699
return r["dockerImageId"]
97100
else:
98101
if req:
99-
raise process.WorkflowException(u"Docker image %s not found" % r["dockerImageId"])
102+
raise WorkflowException(u"Docker image %s not found" % r["dockerImageId"])
100103

101104
return None

cwltool/docker_uid.py

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import subprocess
2+
from typing import Union
23

34

4-
def docker_vm_uid():
5+
def docker_vm_uid(): # type: () -> Union[int,None]
56
"""
67
Returns the UID of the default docker user inside the VM
78
@@ -19,7 +20,7 @@ def docker_vm_uid():
1920
return None
2021

2122

22-
def check_output_and_strip(cmd):
23+
def check_output_and_strip(cmd): # type: (List[str]) -> Union[str,None]
2324
"""
2425
Passes a command list to subprocess.check_output, returning None
2526
if an expected exception is raised
@@ -36,7 +37,7 @@ def check_output_and_strip(cmd):
3637
return None
3738

3839

39-
def docker_machine_name():
40+
def docker_machine_name(): # type: () -> Union[str,None]
4041
"""
4142
Get the machine name of the active docker-machine machine
4243
:return: Name of the active machine or None if error
@@ -45,6 +46,7 @@ def docker_machine_name():
4546

4647

4748
def cmd_output_matches(check_cmd, expected_status):
49+
# type: (List[str], str) -> bool
4850
"""
4951
Runs a command and compares output to expected
5052
:param check_cmd: Command list to execute
@@ -57,15 +59,15 @@ def cmd_output_matches(check_cmd, expected_status):
5759
return False
5860

5961

60-
def boot2docker_running():
62+
def boot2docker_running(): # type: () -> bool
6163
"""
6264
Checks if boot2docker CLI reports that boot2docker vm is running
6365
:return: True if vm is running, False otherwise
6466
"""
6567
return cmd_output_matches(['boot2docker', 'status'], 'running')
6668

6769

68-
def docker_machine_running():
70+
def docker_machine_running(): # type: () -> bool
6971
"""
7072
Asks docker-machine for active machine and checks if its VM is running
7173
:return: True if vm is running, False otherwise
@@ -74,7 +76,7 @@ def docker_machine_running():
7476
return cmd_output_matches(['docker-machine', 'status', machine_name], 'Running')
7577

7678

77-
def cmd_output_to_int(cmd):
79+
def cmd_output_to_int(cmd): # type: (List[str]) -> Union[int,None]
7880
"""
7981
Runs the provided command and returns the integer value of the result
8082
:param cmd: The command to run
@@ -83,22 +85,21 @@ def cmd_output_to_int(cmd):
8385
result = check_output_and_strip(cmd) # may return None
8486
if result is not None:
8587
try:
86-
result = int(result)
88+
return int(result)
8789
except ValueError:
8890
# ValueError is raised if int conversion fails
89-
result = None
90-
return result
91+
return None
9192

9293

93-
def boot2docker_uid():
94+
def boot2docker_uid(): # type: () -> Union[int,None]
9495
"""
9596
Gets the UID of the docker user inside a running boot2docker vm
9697
:return: the UID, or None if error (e.g. boot2docker not present or stopped)
9798
"""
9899
return cmd_output_to_int(['boot2docker', 'ssh', 'id', '-u'])
99100

100101

101-
def docker_machine_uid():
102+
def docker_machine_uid(): # type: () -> Union[int,None]
102103
"""
103104
Asks docker-machine for active machine and gets the UID of the docker user
104105
inside the vm

0 commit comments

Comments
 (0)