toil 6.1.0a1__py3-none-any.whl → 8.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- toil/__init__.py +122 -315
- toil/batchSystems/__init__.py +1 -0
- toil/batchSystems/abstractBatchSystem.py +173 -89
- toil/batchSystems/abstractGridEngineBatchSystem.py +272 -148
- toil/batchSystems/awsBatch.py +244 -135
- toil/batchSystems/cleanup_support.py +26 -16
- toil/batchSystems/contained_executor.py +31 -28
- toil/batchSystems/gridengine.py +86 -50
- toil/batchSystems/htcondor.py +166 -89
- toil/batchSystems/kubernetes.py +632 -382
- toil/batchSystems/local_support.py +20 -15
- toil/batchSystems/lsf.py +134 -81
- toil/batchSystems/lsfHelper.py +13 -11
- toil/batchSystems/mesos/__init__.py +41 -29
- toil/batchSystems/mesos/batchSystem.py +290 -151
- toil/batchSystems/mesos/executor.py +79 -50
- toil/batchSystems/mesos/test/__init__.py +31 -23
- toil/batchSystems/options.py +46 -28
- toil/batchSystems/registry.py +53 -19
- toil/batchSystems/singleMachine.py +296 -125
- toil/batchSystems/slurm.py +603 -138
- toil/batchSystems/torque.py +47 -33
- toil/bus.py +186 -76
- toil/common.py +664 -368
- toil/cwl/__init__.py +1 -1
- toil/cwl/cwltoil.py +1136 -483
- toil/cwl/utils.py +17 -22
- toil/deferred.py +63 -42
- toil/exceptions.py +5 -3
- toil/fileStores/__init__.py +5 -5
- toil/fileStores/abstractFileStore.py +140 -60
- toil/fileStores/cachingFileStore.py +717 -269
- toil/fileStores/nonCachingFileStore.py +116 -87
- toil/job.py +1225 -368
- toil/jobStores/abstractJobStore.py +416 -266
- toil/jobStores/aws/jobStore.py +863 -477
- toil/jobStores/aws/utils.py +201 -120
- toil/jobStores/conftest.py +3 -2
- toil/jobStores/fileJobStore.py +292 -154
- toil/jobStores/googleJobStore.py +140 -74
- toil/jobStores/utils.py +36 -15
- toil/leader.py +668 -272
- toil/lib/accelerators.py +115 -18
- toil/lib/aws/__init__.py +74 -31
- toil/lib/aws/ami.py +122 -87
- toil/lib/aws/iam.py +284 -108
- toil/lib/aws/s3.py +31 -0
- toil/lib/aws/session.py +214 -39
- toil/lib/aws/utils.py +287 -231
- toil/lib/bioio.py +13 -5
- toil/lib/compatibility.py +11 -6
- toil/lib/conversions.py +104 -47
- toil/lib/docker.py +131 -103
- toil/lib/ec2.py +361 -199
- toil/lib/ec2nodes.py +174 -106
- toil/lib/encryption/_dummy.py +5 -3
- toil/lib/encryption/_nacl.py +10 -6
- toil/lib/encryption/conftest.py +1 -0
- toil/lib/exceptions.py +26 -7
- toil/lib/expando.py +5 -3
- toil/lib/ftp_utils.py +217 -0
- toil/lib/generatedEC2Lists.py +127 -19
- toil/lib/humanize.py +6 -2
- toil/lib/integration.py +341 -0
- toil/lib/io.py +141 -15
- toil/lib/iterables.py +4 -2
- toil/lib/memoize.py +12 -8
- toil/lib/misc.py +66 -21
- toil/lib/objects.py +2 -2
- toil/lib/resources.py +68 -15
- toil/lib/retry.py +126 -81
- toil/lib/threading.py +299 -82
- toil/lib/throttle.py +16 -15
- toil/options/common.py +843 -409
- toil/options/cwl.py +175 -90
- toil/options/runner.py +50 -0
- toil/options/wdl.py +73 -17
- toil/provisioners/__init__.py +117 -46
- toil/provisioners/abstractProvisioner.py +332 -157
- toil/provisioners/aws/__init__.py +70 -33
- toil/provisioners/aws/awsProvisioner.py +1145 -715
- toil/provisioners/clusterScaler.py +541 -279
- toil/provisioners/gceProvisioner.py +282 -179
- toil/provisioners/node.py +155 -79
- toil/realtimeLogger.py +34 -22
- toil/resource.py +137 -75
- toil/server/app.py +128 -62
- toil/server/celery_app.py +3 -1
- toil/server/cli/wes_cwl_runner.py +82 -53
- toil/server/utils.py +54 -28
- toil/server/wes/abstract_backend.py +64 -26
- toil/server/wes/amazon_wes_utils.py +21 -15
- toil/server/wes/tasks.py +121 -63
- toil/server/wes/toil_backend.py +142 -107
- toil/server/wsgi_app.py +4 -3
- toil/serviceManager.py +58 -22
- toil/statsAndLogging.py +224 -70
- toil/test/__init__.py +282 -183
- toil/test/batchSystems/batchSystemTest.py +460 -210
- toil/test/batchSystems/batch_system_plugin_test.py +90 -0
- toil/test/batchSystems/test_gridengine.py +173 -0
- toil/test/batchSystems/test_lsf_helper.py +67 -58
- toil/test/batchSystems/test_slurm.py +110 -49
- toil/test/cactus/__init__.py +0 -0
- toil/test/cactus/test_cactus_integration.py +56 -0
- toil/test/cwl/cwlTest.py +496 -287
- toil/test/cwl/measure_default_memory.cwl +12 -0
- toil/test/cwl/not_run_required_input.cwl +29 -0
- toil/test/cwl/scatter_duplicate_outputs.cwl +40 -0
- toil/test/cwl/seqtk_seq.cwl +1 -1
- toil/test/docs/scriptsTest.py +69 -46
- toil/test/jobStores/jobStoreTest.py +427 -264
- toil/test/lib/aws/test_iam.py +118 -50
- toil/test/lib/aws/test_s3.py +16 -9
- toil/test/lib/aws/test_utils.py +5 -6
- toil/test/lib/dockerTest.py +118 -141
- toil/test/lib/test_conversions.py +113 -115
- toil/test/lib/test_ec2.py +58 -50
- toil/test/lib/test_integration.py +104 -0
- toil/test/lib/test_misc.py +12 -5
- toil/test/mesos/MesosDataStructuresTest.py +23 -10
- toil/test/mesos/helloWorld.py +7 -6
- toil/test/mesos/stress.py +25 -20
- toil/test/options/__init__.py +13 -0
- toil/test/options/options.py +42 -0
- toil/test/provisioners/aws/awsProvisionerTest.py +320 -150
- toil/test/provisioners/clusterScalerTest.py +440 -250
- toil/test/provisioners/clusterTest.py +166 -44
- toil/test/provisioners/gceProvisionerTest.py +174 -100
- toil/test/provisioners/provisionerTest.py +25 -13
- toil/test/provisioners/restartScript.py +5 -4
- toil/test/server/serverTest.py +188 -141
- toil/test/sort/restart_sort.py +137 -68
- toil/test/sort/sort.py +134 -66
- toil/test/sort/sortTest.py +91 -49
- toil/test/src/autoDeploymentTest.py +141 -101
- toil/test/src/busTest.py +20 -18
- toil/test/src/checkpointTest.py +8 -2
- toil/test/src/deferredFunctionTest.py +49 -35
- toil/test/src/dockerCheckTest.py +32 -24
- toil/test/src/environmentTest.py +135 -0
- toil/test/src/fileStoreTest.py +539 -272
- toil/test/src/helloWorldTest.py +7 -4
- toil/test/src/importExportFileTest.py +61 -31
- toil/test/src/jobDescriptionTest.py +46 -21
- toil/test/src/jobEncapsulationTest.py +2 -0
- toil/test/src/jobFileStoreTest.py +74 -50
- toil/test/src/jobServiceTest.py +187 -73
- toil/test/src/jobTest.py +121 -71
- toil/test/src/miscTests.py +19 -18
- toil/test/src/promisedRequirementTest.py +82 -36
- toil/test/src/promisesTest.py +7 -6
- toil/test/src/realtimeLoggerTest.py +10 -6
- toil/test/src/regularLogTest.py +71 -37
- toil/test/src/resourceTest.py +80 -49
- toil/test/src/restartDAGTest.py +36 -22
- toil/test/src/resumabilityTest.py +9 -2
- toil/test/src/retainTempDirTest.py +45 -14
- toil/test/src/systemTest.py +12 -8
- toil/test/src/threadingTest.py +44 -25
- toil/test/src/toilContextManagerTest.py +10 -7
- toil/test/src/userDefinedJobArgTypeTest.py +8 -5
- toil/test/src/workerTest.py +73 -23
- toil/test/utils/toilDebugTest.py +103 -33
- toil/test/utils/toilKillTest.py +4 -5
- toil/test/utils/utilsTest.py +245 -106
- toil/test/wdl/wdltoil_test.py +818 -149
- toil/test/wdl/wdltoil_test_kubernetes.py +91 -0
- toil/toilState.py +120 -35
- toil/utils/toilConfig.py +13 -4
- toil/utils/toilDebugFile.py +44 -27
- toil/utils/toilDebugJob.py +214 -27
- toil/utils/toilDestroyCluster.py +11 -6
- toil/utils/toilKill.py +8 -3
- toil/utils/toilLaunchCluster.py +256 -140
- toil/utils/toilMain.py +37 -16
- toil/utils/toilRsyncCluster.py +32 -14
- toil/utils/toilSshCluster.py +49 -22
- toil/utils/toilStats.py +356 -273
- toil/utils/toilStatus.py +292 -139
- toil/utils/toilUpdateEC2Instances.py +3 -1
- toil/version.py +12 -12
- toil/wdl/utils.py +5 -5
- toil/wdl/wdltoil.py +3913 -1033
- toil/worker.py +367 -184
- {toil-6.1.0a1.dist-info → toil-8.0.0.dist-info}/LICENSE +25 -0
- toil-8.0.0.dist-info/METADATA +173 -0
- toil-8.0.0.dist-info/RECORD +253 -0
- {toil-6.1.0a1.dist-info → toil-8.0.0.dist-info}/WHEEL +1 -1
- toil-6.1.0a1.dist-info/METADATA +0 -125
- toil-6.1.0a1.dist-info/RECORD +0 -237
- {toil-6.1.0a1.dist-info → toil-8.0.0.dist-info}/entry_points.txt +0 -0
- {toil-6.1.0a1.dist-info → toil-8.0.0.dist-info}/top_level.txt +0 -0
toil/provisioners/__init__.py
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
import argparse
|
|
15
15
|
import logging
|
|
16
16
|
from difflib import get_close_matches
|
|
17
|
-
from typing import TYPE_CHECKING,
|
|
17
|
+
from typing import TYPE_CHECKING, Optional, Union
|
|
18
18
|
|
|
19
19
|
if TYPE_CHECKING:
|
|
20
20
|
from toil.provisioners.aws.awsProvisioner import AWSProvisioner
|
|
@@ -30,8 +30,9 @@ def cluster_factory(
|
|
|
30
30
|
clusterType: str = "mesos",
|
|
31
31
|
zone: Optional[str] = None,
|
|
32
32
|
nodeStorage: int = 50,
|
|
33
|
-
nodeStorageOverrides: Optional[
|
|
33
|
+
nodeStorageOverrides: Optional[list[str]] = None,
|
|
34
34
|
sseKey: Optional[str] = None,
|
|
35
|
+
enable_fuse: bool = False,
|
|
35
36
|
) -> Union["AWSProvisioner", "GCEProvisioner"]:
|
|
36
37
|
"""
|
|
37
38
|
Find and instantiate the appropriate provisioner instance to make clusters in the given cloud.
|
|
@@ -45,20 +46,36 @@ def cluster_factory(
|
|
|
45
46
|
:param zone: The cloud zone
|
|
46
47
|
:return: A cluster object for the the cloud type.
|
|
47
48
|
"""
|
|
48
|
-
if provisioner ==
|
|
49
|
+
if provisioner == "aws":
|
|
49
50
|
try:
|
|
50
51
|
from toil.provisioners.aws.awsProvisioner import AWSProvisioner
|
|
51
52
|
except ImportError:
|
|
52
|
-
logger.error(
|
|
53
|
+
logger.error("The aws extra must be installed to use this provisioner")
|
|
53
54
|
raise
|
|
54
|
-
return AWSProvisioner(
|
|
55
|
-
|
|
55
|
+
return AWSProvisioner(
|
|
56
|
+
clusterName,
|
|
57
|
+
clusterType,
|
|
58
|
+
zone,
|
|
59
|
+
nodeStorage,
|
|
60
|
+
nodeStorageOverrides,
|
|
61
|
+
sseKey,
|
|
62
|
+
enable_fuse,
|
|
63
|
+
)
|
|
64
|
+
elif provisioner == "gce":
|
|
56
65
|
try:
|
|
57
66
|
from toil.provisioners.gceProvisioner import GCEProvisioner
|
|
58
67
|
except ImportError:
|
|
59
|
-
logger.error(
|
|
68
|
+
logger.error("The google extra must be installed to use this provisioner")
|
|
60
69
|
raise
|
|
61
|
-
return GCEProvisioner(
|
|
70
|
+
return GCEProvisioner(
|
|
71
|
+
clusterName,
|
|
72
|
+
clusterType,
|
|
73
|
+
zone,
|
|
74
|
+
nodeStorage,
|
|
75
|
+
nodeStorageOverrides,
|
|
76
|
+
sseKey,
|
|
77
|
+
enable_fuse,
|
|
78
|
+
)
|
|
62
79
|
else:
|
|
63
80
|
raise RuntimeError("Invalid provisioner '%s'" % provisioner)
|
|
64
81
|
|
|
@@ -66,22 +83,39 @@ def cluster_factory(
|
|
|
66
83
|
def add_provisioner_options(parser: argparse.ArgumentParser) -> None:
|
|
67
84
|
group = parser.add_argument_group("Provisioner Options.")
|
|
68
85
|
|
|
69
|
-
provisioner_choices = [
|
|
86
|
+
provisioner_choices = ["aws", "gce"]
|
|
70
87
|
# TODO: Better consolidate this provisioner arg and the one in common.py?
|
|
71
|
-
group.add_argument(
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
88
|
+
group.add_argument(
|
|
89
|
+
"--provisioner",
|
|
90
|
+
"-p",
|
|
91
|
+
dest="provisioner",
|
|
92
|
+
choices=provisioner_choices,
|
|
93
|
+
default="aws",
|
|
94
|
+
help=f"The provisioner for cluster auto-scaling. This is the '--provisioner' option set for "
|
|
95
|
+
f"Toil utils like launch-cluster and destroy-cluster, which always require a provisioner, "
|
|
96
|
+
f"and so this defaults to: %(default)s. Choices: {provisioner_choices}.",
|
|
97
|
+
)
|
|
98
|
+
group.add_argument(
|
|
99
|
+
"-z",
|
|
100
|
+
"--zone",
|
|
101
|
+
dest="zone",
|
|
102
|
+
required=False,
|
|
103
|
+
default=None,
|
|
104
|
+
help="The availability zone of the leader. This parameter can also be set via the 'TOIL_X_ZONE' "
|
|
105
|
+
"environment variable, where X is AWS or GCE, or by the ec2_region_name parameter "
|
|
106
|
+
"in your .boto file, or derived from the instance metadata if using this utility on an "
|
|
107
|
+
"existing EC2 instance.",
|
|
108
|
+
)
|
|
109
|
+
group.add_argument(
|
|
110
|
+
"clusterName",
|
|
111
|
+
help="The name that the cluster will be identifiable by. "
|
|
112
|
+
"Must be lowercase and may not contain the '_' character.",
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def parse_node_types(
|
|
117
|
+
node_type_specs: Optional[str],
|
|
118
|
+
) -> list[tuple[set[str], Optional[float]]]:
|
|
85
119
|
"""
|
|
86
120
|
Parse a specification for zero or more node types.
|
|
87
121
|
|
|
@@ -106,27 +140,33 @@ def parse_node_types(node_type_specs: Optional[str]) -> List[Tuple[Set[str], Opt
|
|
|
106
140
|
|
|
107
141
|
if node_type_specs:
|
|
108
142
|
# Some node types were actually specified
|
|
109
|
-
for node_type_spec in node_type_specs.split(
|
|
143
|
+
for node_type_spec in node_type_specs.split(","):
|
|
110
144
|
try:
|
|
111
145
|
# Types are comma-separated
|
|
112
146
|
# Then we have the colon and the bid
|
|
113
|
-
parts = node_type_spec.split(
|
|
147
|
+
parts = node_type_spec.split(":")
|
|
114
148
|
|
|
115
149
|
if len(parts) > 2:
|
|
116
150
|
# Only one bid allowed
|
|
117
|
-
raise ValueError(
|
|
151
|
+
raise ValueError(
|
|
152
|
+
f'Cound not parse node type "{node_type_spec}": multiple bids'
|
|
153
|
+
)
|
|
118
154
|
|
|
119
155
|
# Instance types are slash-separated within an equivalence
|
|
120
156
|
# class
|
|
121
|
-
instance_types = set(parts[0].split(
|
|
157
|
+
instance_types = set(parts[0].split("/"))
|
|
122
158
|
|
|
123
159
|
for instance_type in instance_types:
|
|
124
|
-
if instance_type ==
|
|
160
|
+
if instance_type == "":
|
|
125
161
|
# No empty instance types allowed
|
|
126
|
-
raise ValueError(
|
|
162
|
+
raise ValueError(
|
|
163
|
+
f'Cound not parse node type "{node_type_spec}": empty instance type'
|
|
164
|
+
)
|
|
127
165
|
|
|
128
166
|
# Build the node type tuple
|
|
129
|
-
parsed.append(
|
|
167
|
+
parsed.append(
|
|
168
|
+
(instance_types, float(parts[1]) if len(parts) > 1 else None)
|
|
169
|
+
)
|
|
130
170
|
except Exception as e:
|
|
131
171
|
if isinstance(e, ValueError):
|
|
132
172
|
raise
|
|
@@ -136,7 +176,9 @@ def parse_node_types(node_type_specs: Optional[str]) -> List[Tuple[Set[str], Opt
|
|
|
136
176
|
return parsed
|
|
137
177
|
|
|
138
178
|
|
|
139
|
-
def check_valid_node_types(
|
|
179
|
+
def check_valid_node_types(
|
|
180
|
+
provisioner, node_types: list[tuple[set[str], Optional[float]]]
|
|
181
|
+
):
|
|
140
182
|
"""
|
|
141
183
|
Raises if an invalid nodeType is specified for aws or gce.
|
|
142
184
|
|
|
@@ -147,47 +189,76 @@ def check_valid_node_types(provisioner, node_types: List[Tuple[Set[str], Optiona
|
|
|
147
189
|
|
|
148
190
|
# check if a valid node type for aws
|
|
149
191
|
from toil.lib.generatedEC2Lists import E2Instances, regionDict
|
|
150
|
-
|
|
192
|
+
|
|
193
|
+
if provisioner == "aws":
|
|
151
194
|
from toil.lib.aws import get_current_aws_region
|
|
152
|
-
|
|
195
|
+
|
|
196
|
+
current_region = get_current_aws_region() or "us-west-2"
|
|
153
197
|
# check if instance type exists in this region
|
|
154
198
|
for node_type in node_types:
|
|
155
199
|
for instance_type_name in node_type[0]:
|
|
156
200
|
if instance_type_name not in regionDict[current_region]:
|
|
157
201
|
# They probably misspelled it and can't tell.
|
|
158
|
-
close = get_close_matches(
|
|
202
|
+
close = get_close_matches(
|
|
203
|
+
instance_type_name, regionDict[current_region], 1
|
|
204
|
+
)
|
|
159
205
|
if len(close) > 0:
|
|
160
|
-
helpText =
|
|
206
|
+
helpText = " Did you mean " + close[0] + "?"
|
|
161
207
|
else:
|
|
162
|
-
helpText =
|
|
163
|
-
raise RuntimeError(
|
|
164
|
-
|
|
165
|
-
|
|
208
|
+
helpText = ""
|
|
209
|
+
raise RuntimeError(
|
|
210
|
+
f"Invalid instance type ({instance_type_name}) specified for AWS in "
|
|
211
|
+
f"region: {current_region}.{helpText}"
|
|
212
|
+
)
|
|
213
|
+
elif provisioner == "gce":
|
|
166
214
|
for node_type in node_types:
|
|
167
215
|
for instance_type_name in node_type[0]:
|
|
168
216
|
if instance_type_name in E2Instances:
|
|
169
|
-
raise RuntimeError(
|
|
170
|
-
|
|
217
|
+
raise RuntimeError(
|
|
218
|
+
f"It looks like you've specified an AWS nodeType with the {provisioner} "
|
|
219
|
+
f"provisioner. Please specify a nodeType for {provisioner}."
|
|
220
|
+
)
|
|
171
221
|
else:
|
|
172
222
|
raise RuntimeError(f"Invalid provisioner: {provisioner}")
|
|
173
223
|
|
|
174
224
|
|
|
175
225
|
class NoSuchClusterException(Exception):
|
|
176
226
|
"""Indicates that the specified cluster does not exist."""
|
|
177
|
-
|
|
227
|
+
|
|
228
|
+
def __init__(self, cluster_name: str) -> None:
|
|
178
229
|
super().__init__(f"The cluster '{cluster_name}' could not be found")
|
|
179
230
|
|
|
180
231
|
|
|
232
|
+
class NoSuchZoneException(Exception):
|
|
233
|
+
"""Indicates that a valid zone could not be found."""
|
|
234
|
+
|
|
235
|
+
def __init__(self) -> None:
|
|
236
|
+
super().__init__(f"No valid zone could be found!")
|
|
237
|
+
|
|
238
|
+
|
|
181
239
|
class ClusterTypeNotSupportedException(Exception):
|
|
182
240
|
"""Indicates that a provisioner does not support a given cluster type."""
|
|
241
|
+
|
|
183
242
|
def __init__(self, provisioner_class, cluster_type):
|
|
184
|
-
super().__init__(
|
|
243
|
+
super().__init__(
|
|
244
|
+
f"The {provisioner_class} provisioner does not support making {cluster_type} clusters"
|
|
245
|
+
)
|
|
246
|
+
|
|
185
247
|
|
|
186
248
|
class ClusterCombinationNotSupportedException(Exception):
|
|
187
249
|
"""Indicates that a provisioner does not support making a given type of cluster with a given architecture."""
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
250
|
+
|
|
251
|
+
def __init__(
|
|
252
|
+
self,
|
|
253
|
+
provisioner_class: type,
|
|
254
|
+
cluster_type: str,
|
|
255
|
+
architecture: str,
|
|
256
|
+
reason: Optional[str] = None,
|
|
257
|
+
):
|
|
258
|
+
message = (
|
|
259
|
+
f"The {provisioner_class} provisioner does not support making {cluster_type} clusters "
|
|
260
|
+
f"using nodes with the {architecture} architecture."
|
|
261
|
+
)
|
|
191
262
|
if reason is not None:
|
|
192
263
|
message += f" This is because: {reason}"
|
|
193
264
|
super().__init__(message)
|