toil 7.0.0__py3-none-any.whl → 8.1.0b1__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 +124 -86
- toil/batchSystems/__init__.py +1 -0
- toil/batchSystems/abstractBatchSystem.py +137 -77
- toil/batchSystems/abstractGridEngineBatchSystem.py +211 -101
- toil/batchSystems/awsBatch.py +237 -128
- toil/batchSystems/cleanup_support.py +22 -16
- toil/batchSystems/contained_executor.py +30 -26
- toil/batchSystems/gridengine.py +85 -49
- toil/batchSystems/htcondor.py +164 -87
- toil/batchSystems/kubernetes.py +622 -386
- toil/batchSystems/local_support.py +17 -12
- toil/batchSystems/lsf.py +132 -79
- toil/batchSystems/lsfHelper.py +13 -11
- toil/batchSystems/mesos/__init__.py +41 -29
- toil/batchSystems/mesos/batchSystem.py +288 -149
- toil/batchSystems/mesos/executor.py +77 -49
- toil/batchSystems/mesos/test/__init__.py +31 -23
- toil/batchSystems/options.py +39 -29
- toil/batchSystems/registry.py +53 -19
- toil/batchSystems/singleMachine.py +293 -123
- toil/batchSystems/slurm.py +651 -155
- toil/batchSystems/torque.py +46 -32
- toil/bus.py +141 -73
- toil/common.py +784 -397
- toil/cwl/__init__.py +1 -1
- toil/cwl/cwltoil.py +1137 -534
- toil/cwl/utils.py +17 -22
- toil/deferred.py +62 -41
- toil/exceptions.py +5 -3
- toil/fileStores/__init__.py +5 -5
- toil/fileStores/abstractFileStore.py +88 -57
- toil/fileStores/cachingFileStore.py +711 -247
- toil/fileStores/nonCachingFileStore.py +113 -75
- toil/job.py +1031 -349
- toil/jobStores/abstractJobStore.py +387 -243
- toil/jobStores/aws/jobStore.py +772 -412
- toil/jobStores/aws/utils.py +161 -109
- toil/jobStores/conftest.py +1 -0
- toil/jobStores/fileJobStore.py +289 -151
- toil/jobStores/googleJobStore.py +137 -70
- toil/jobStores/utils.py +36 -15
- toil/leader.py +614 -269
- toil/lib/accelerators.py +115 -18
- toil/lib/aws/__init__.py +55 -28
- 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 +204 -58
- toil/lib/aws/utils.py +290 -213
- toil/lib/bioio.py +13 -5
- toil/lib/compatibility.py +11 -6
- toil/lib/conversions.py +83 -49
- toil/lib/docker.py +131 -103
- toil/lib/dockstore.py +379 -0
- toil/lib/ec2.py +322 -209
- toil/lib/ec2nodes.py +174 -105
- 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 +4 -2
- toil/lib/ftp_utils.py +217 -0
- toil/lib/generatedEC2Lists.py +127 -19
- toil/lib/history.py +1271 -0
- toil/lib/history_submission.py +681 -0
- toil/lib/humanize.py +6 -2
- toil/lib/io.py +121 -12
- toil/lib/iterables.py +4 -2
- toil/lib/memoize.py +12 -8
- toil/lib/misc.py +83 -18
- toil/lib/objects.py +2 -2
- toil/lib/resources.py +19 -7
- toil/lib/retry.py +125 -87
- toil/lib/threading.py +282 -80
- toil/lib/throttle.py +15 -14
- toil/lib/trs.py +390 -0
- toil/lib/web.py +38 -0
- toil/options/common.py +850 -402
- toil/options/cwl.py +185 -90
- toil/options/runner.py +50 -0
- toil/options/wdl.py +70 -19
- toil/provisioners/__init__.py +111 -46
- toil/provisioners/abstractProvisioner.py +322 -157
- toil/provisioners/aws/__init__.py +62 -30
- toil/provisioners/aws/awsProvisioner.py +980 -627
- toil/provisioners/clusterScaler.py +541 -279
- toil/provisioners/gceProvisioner.py +283 -180
- toil/provisioners/node.py +147 -79
- toil/realtimeLogger.py +34 -22
- toil/resource.py +137 -75
- toil/server/app.py +127 -61
- toil/server/celery_app.py +3 -1
- toil/server/cli/wes_cwl_runner.py +84 -55
- toil/server/utils.py +56 -31
- 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 +183 -65
- toil/test/__init__.py +263 -179
- toil/test/batchSystems/batchSystemTest.py +438 -195
- toil/test/batchSystems/batch_system_plugin_test.py +18 -7
- toil/test/batchSystems/test_gridengine.py +173 -0
- toil/test/batchSystems/test_lsf_helper.py +67 -58
- toil/test/batchSystems/test_slurm.py +265 -49
- toil/test/cactus/test_cactus_integration.py +20 -22
- toil/test/cwl/conftest.py +39 -0
- toil/test/cwl/cwlTest.py +375 -72
- toil/test/cwl/measure_default_memory.cwl +12 -0
- toil/test/cwl/not_run_required_input.cwl +29 -0
- toil/test/cwl/optional-file.cwl +18 -0
- toil/test/cwl/scatter_duplicate_outputs.cwl +40 -0
- toil/test/docs/scriptsTest.py +60 -34
- toil/test/jobStores/jobStoreTest.py +412 -235
- toil/test/lib/aws/test_iam.py +116 -48
- 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 +57 -49
- toil/test/lib/test_history.py +212 -0
- toil/test/lib/test_misc.py +12 -5
- toil/test/lib/test_trs.py +161 -0
- toil/test/mesos/MesosDataStructuresTest.py +23 -10
- toil/test/mesos/helloWorld.py +7 -6
- toil/test/mesos/stress.py +25 -20
- toil/test/options/options.py +7 -2
- toil/test/provisioners/aws/awsProvisionerTest.py +293 -140
- toil/test/provisioners/clusterScalerTest.py +440 -250
- toil/test/provisioners/clusterTest.py +81 -42
- 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 +140 -100
- 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 +33 -26
- toil/test/src/environmentTest.py +20 -10
- toil/test/src/fileStoreTest.py +538 -271
- toil/test/src/helloWorldTest.py +7 -4
- toil/test/src/importExportFileTest.py +61 -31
- toil/test/src/jobDescriptionTest.py +32 -17
- 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 +120 -70
- 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 +6 -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 +33 -16
- toil/test/utils/toilDebugTest.py +70 -58
- toil/test/utils/toilKillTest.py +4 -5
- toil/test/utils/utilsTest.py +239 -102
- toil/test/wdl/wdltoil_test.py +789 -148
- toil/test/wdl/wdltoil_test_kubernetes.py +37 -23
- toil/toilState.py +52 -26
- toil/utils/toilConfig.py +13 -4
- toil/utils/toilDebugFile.py +44 -27
- toil/utils/toilDebugJob.py +85 -25
- toil/utils/toilDestroyCluster.py +11 -6
- toil/utils/toilKill.py +8 -3
- toil/utils/toilLaunchCluster.py +251 -145
- toil/utils/toilMain.py +37 -16
- toil/utils/toilRsyncCluster.py +27 -14
- toil/utils/toilSshCluster.py +45 -22
- toil/utils/toilStats.py +75 -36
- toil/utils/toilStatus.py +226 -119
- toil/utils/toilUpdateEC2Instances.py +3 -1
- toil/version.py +6 -6
- toil/wdl/utils.py +5 -5
- toil/wdl/wdltoil.py +3528 -1053
- toil/worker.py +370 -149
- toil-8.1.0b1.dist-info/METADATA +178 -0
- toil-8.1.0b1.dist-info/RECORD +259 -0
- {toil-7.0.0.dist-info → toil-8.1.0b1.dist-info}/WHEEL +1 -1
- toil-7.0.0.dist-info/METADATA +0 -158
- toil-7.0.0.dist-info/RECORD +0 -244
- {toil-7.0.0.dist-info → toil-8.1.0b1.dist-info}/LICENSE +0 -0
- {toil-7.0.0.dist-info → toil-8.1.0b1.dist-info}/entry_points.txt +0 -0
- {toil-7.0.0.dist-info → toil-8.1.0b1.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,9 +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
|
+
enable_fuse: bool = False,
|
|
36
36
|
) -> Union["AWSProvisioner", "GCEProvisioner"]:
|
|
37
37
|
"""
|
|
38
38
|
Find and instantiate the appropriate provisioner instance to make clusters in the given cloud.
|
|
@@ -46,20 +46,36 @@ def cluster_factory(
|
|
|
46
46
|
:param zone: The cloud zone
|
|
47
47
|
:return: A cluster object for the the cloud type.
|
|
48
48
|
"""
|
|
49
|
-
if provisioner ==
|
|
49
|
+
if provisioner == "aws":
|
|
50
50
|
try:
|
|
51
51
|
from toil.provisioners.aws.awsProvisioner import AWSProvisioner
|
|
52
52
|
except ImportError:
|
|
53
|
-
logger.error(
|
|
53
|
+
logger.error("The aws extra must be installed to use this provisioner")
|
|
54
54
|
raise
|
|
55
|
-
return AWSProvisioner(
|
|
56
|
-
|
|
55
|
+
return AWSProvisioner(
|
|
56
|
+
clusterName,
|
|
57
|
+
clusterType,
|
|
58
|
+
zone,
|
|
59
|
+
nodeStorage,
|
|
60
|
+
nodeStorageOverrides,
|
|
61
|
+
sseKey,
|
|
62
|
+
enable_fuse,
|
|
63
|
+
)
|
|
64
|
+
elif provisioner == "gce":
|
|
57
65
|
try:
|
|
58
66
|
from toil.provisioners.gceProvisioner import GCEProvisioner
|
|
59
67
|
except ImportError:
|
|
60
|
-
logger.error(
|
|
68
|
+
logger.error("The google extra must be installed to use this provisioner")
|
|
61
69
|
raise
|
|
62
|
-
return GCEProvisioner(
|
|
70
|
+
return GCEProvisioner(
|
|
71
|
+
clusterName,
|
|
72
|
+
clusterType,
|
|
73
|
+
zone,
|
|
74
|
+
nodeStorage,
|
|
75
|
+
nodeStorageOverrides,
|
|
76
|
+
sseKey,
|
|
77
|
+
enable_fuse,
|
|
78
|
+
)
|
|
63
79
|
else:
|
|
64
80
|
raise RuntimeError("Invalid provisioner '%s'" % provisioner)
|
|
65
81
|
|
|
@@ -67,22 +83,39 @@ def cluster_factory(
|
|
|
67
83
|
def add_provisioner_options(parser: argparse.ArgumentParser) -> None:
|
|
68
84
|
group = parser.add_argument_group("Provisioner Options.")
|
|
69
85
|
|
|
70
|
-
provisioner_choices = [
|
|
86
|
+
provisioner_choices = ["aws", "gce"]
|
|
71
87
|
# TODO: Better consolidate this provisioner arg and the one in common.py?
|
|
72
|
-
group.add_argument(
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
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]]]:
|
|
86
119
|
"""
|
|
87
120
|
Parse a specification for zero or more node types.
|
|
88
121
|
|
|
@@ -107,27 +140,33 @@ def parse_node_types(node_type_specs: Optional[str]) -> List[Tuple[Set[str], Opt
|
|
|
107
140
|
|
|
108
141
|
if node_type_specs:
|
|
109
142
|
# Some node types were actually specified
|
|
110
|
-
for node_type_spec in node_type_specs.split(
|
|
143
|
+
for node_type_spec in node_type_specs.split(","):
|
|
111
144
|
try:
|
|
112
145
|
# Types are comma-separated
|
|
113
146
|
# Then we have the colon and the bid
|
|
114
|
-
parts = node_type_spec.split(
|
|
147
|
+
parts = node_type_spec.split(":")
|
|
115
148
|
|
|
116
149
|
if len(parts) > 2:
|
|
117
150
|
# Only one bid allowed
|
|
118
|
-
raise ValueError(
|
|
151
|
+
raise ValueError(
|
|
152
|
+
f'Cound not parse node type "{node_type_spec}": multiple bids'
|
|
153
|
+
)
|
|
119
154
|
|
|
120
155
|
# Instance types are slash-separated within an equivalence
|
|
121
156
|
# class
|
|
122
|
-
instance_types = set(parts[0].split(
|
|
157
|
+
instance_types = set(parts[0].split("/"))
|
|
123
158
|
|
|
124
159
|
for instance_type in instance_types:
|
|
125
|
-
if instance_type ==
|
|
160
|
+
if instance_type == "":
|
|
126
161
|
# No empty instance types allowed
|
|
127
|
-
raise ValueError(
|
|
162
|
+
raise ValueError(
|
|
163
|
+
f'Cound not parse node type "{node_type_spec}": empty instance type'
|
|
164
|
+
)
|
|
128
165
|
|
|
129
166
|
# Build the node type tuple
|
|
130
|
-
parsed.append(
|
|
167
|
+
parsed.append(
|
|
168
|
+
(instance_types, float(parts[1]) if len(parts) > 1 else None)
|
|
169
|
+
)
|
|
131
170
|
except Exception as e:
|
|
132
171
|
if isinstance(e, ValueError):
|
|
133
172
|
raise
|
|
@@ -137,7 +176,9 @@ def parse_node_types(node_type_specs: Optional[str]) -> List[Tuple[Set[str], Opt
|
|
|
137
176
|
return parsed
|
|
138
177
|
|
|
139
178
|
|
|
140
|
-
def check_valid_node_types(
|
|
179
|
+
def check_valid_node_types(
|
|
180
|
+
provisioner, node_types: list[tuple[set[str], Optional[float]]]
|
|
181
|
+
):
|
|
141
182
|
"""
|
|
142
183
|
Raises if an invalid nodeType is specified for aws or gce.
|
|
143
184
|
|
|
@@ -148,52 +189,76 @@ def check_valid_node_types(provisioner, node_types: List[Tuple[Set[str], Optiona
|
|
|
148
189
|
|
|
149
190
|
# check if a valid node type for aws
|
|
150
191
|
from toil.lib.generatedEC2Lists import E2Instances, regionDict
|
|
151
|
-
|
|
192
|
+
|
|
193
|
+
if provisioner == "aws":
|
|
152
194
|
from toil.lib.aws import get_current_aws_region
|
|
153
|
-
|
|
195
|
+
|
|
196
|
+
current_region = get_current_aws_region() or "us-west-2"
|
|
154
197
|
# check if instance type exists in this region
|
|
155
198
|
for node_type in node_types:
|
|
156
199
|
for instance_type_name in node_type[0]:
|
|
157
200
|
if instance_type_name not in regionDict[current_region]:
|
|
158
201
|
# They probably misspelled it and can't tell.
|
|
159
|
-
close = get_close_matches(
|
|
202
|
+
close = get_close_matches(
|
|
203
|
+
instance_type_name, regionDict[current_region], 1
|
|
204
|
+
)
|
|
160
205
|
if len(close) > 0:
|
|
161
|
-
helpText =
|
|
206
|
+
helpText = " Did you mean " + close[0] + "?"
|
|
162
207
|
else:
|
|
163
|
-
helpText =
|
|
164
|
-
raise RuntimeError(
|
|
165
|
-
|
|
166
|
-
|
|
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":
|
|
167
214
|
for node_type in node_types:
|
|
168
215
|
for instance_type_name in node_type[0]:
|
|
169
216
|
if instance_type_name in E2Instances:
|
|
170
|
-
raise RuntimeError(
|
|
171
|
-
|
|
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
|
+
)
|
|
172
221
|
else:
|
|
173
222
|
raise RuntimeError(f"Invalid provisioner: {provisioner}")
|
|
174
223
|
|
|
175
224
|
|
|
176
225
|
class NoSuchClusterException(Exception):
|
|
177
226
|
"""Indicates that the specified cluster does not exist."""
|
|
227
|
+
|
|
178
228
|
def __init__(self, cluster_name: str) -> None:
|
|
179
229
|
super().__init__(f"The cluster '{cluster_name}' could not be found")
|
|
180
230
|
|
|
231
|
+
|
|
181
232
|
class NoSuchZoneException(Exception):
|
|
182
233
|
"""Indicates that a valid zone could not be found."""
|
|
234
|
+
|
|
183
235
|
def __init__(self) -> None:
|
|
184
236
|
super().__init__(f"No valid zone could be found!")
|
|
185
237
|
|
|
186
238
|
|
|
187
239
|
class ClusterTypeNotSupportedException(Exception):
|
|
188
240
|
"""Indicates that a provisioner does not support a given cluster type."""
|
|
241
|
+
|
|
189
242
|
def __init__(self, provisioner_class, cluster_type):
|
|
190
|
-
super().__init__(
|
|
243
|
+
super().__init__(
|
|
244
|
+
f"The {provisioner_class} provisioner does not support making {cluster_type} clusters"
|
|
245
|
+
)
|
|
246
|
+
|
|
191
247
|
|
|
192
248
|
class ClusterCombinationNotSupportedException(Exception):
|
|
193
249
|
"""Indicates that a provisioner does not support making a given type of cluster with a given architecture."""
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
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
|
+
)
|
|
197
262
|
if reason is not None:
|
|
198
263
|
message += f" This is because: {reason}"
|
|
199
264
|
super().__init__(message)
|