toil 7.0.0__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.
Files changed (190) hide show
  1. toil/__init__.py +121 -83
  2. toil/batchSystems/__init__.py +1 -0
  3. toil/batchSystems/abstractBatchSystem.py +137 -77
  4. toil/batchSystems/abstractGridEngineBatchSystem.py +211 -101
  5. toil/batchSystems/awsBatch.py +237 -128
  6. toil/batchSystems/cleanup_support.py +22 -16
  7. toil/batchSystems/contained_executor.py +30 -26
  8. toil/batchSystems/gridengine.py +85 -49
  9. toil/batchSystems/htcondor.py +164 -87
  10. toil/batchSystems/kubernetes.py +622 -386
  11. toil/batchSystems/local_support.py +17 -12
  12. toil/batchSystems/lsf.py +132 -79
  13. toil/batchSystems/lsfHelper.py +13 -11
  14. toil/batchSystems/mesos/__init__.py +41 -29
  15. toil/batchSystems/mesos/batchSystem.py +288 -149
  16. toil/batchSystems/mesos/executor.py +77 -49
  17. toil/batchSystems/mesos/test/__init__.py +31 -23
  18. toil/batchSystems/options.py +38 -29
  19. toil/batchSystems/registry.py +53 -19
  20. toil/batchSystems/singleMachine.py +293 -123
  21. toil/batchSystems/slurm.py +489 -137
  22. toil/batchSystems/torque.py +46 -32
  23. toil/bus.py +141 -73
  24. toil/common.py +630 -359
  25. toil/cwl/__init__.py +1 -1
  26. toil/cwl/cwltoil.py +1114 -532
  27. toil/cwl/utils.py +17 -22
  28. toil/deferred.py +62 -41
  29. toil/exceptions.py +5 -3
  30. toil/fileStores/__init__.py +5 -5
  31. toil/fileStores/abstractFileStore.py +88 -57
  32. toil/fileStores/cachingFileStore.py +711 -247
  33. toil/fileStores/nonCachingFileStore.py +113 -75
  34. toil/job.py +988 -315
  35. toil/jobStores/abstractJobStore.py +387 -243
  36. toil/jobStores/aws/jobStore.py +727 -403
  37. toil/jobStores/aws/utils.py +161 -109
  38. toil/jobStores/conftest.py +1 -0
  39. toil/jobStores/fileJobStore.py +289 -151
  40. toil/jobStores/googleJobStore.py +137 -70
  41. toil/jobStores/utils.py +36 -15
  42. toil/leader.py +614 -269
  43. toil/lib/accelerators.py +115 -18
  44. toil/lib/aws/__init__.py +55 -28
  45. toil/lib/aws/ami.py +122 -87
  46. toil/lib/aws/iam.py +284 -108
  47. toil/lib/aws/s3.py +31 -0
  48. toil/lib/aws/session.py +193 -58
  49. toil/lib/aws/utils.py +238 -218
  50. toil/lib/bioio.py +13 -5
  51. toil/lib/compatibility.py +11 -6
  52. toil/lib/conversions.py +83 -49
  53. toil/lib/docker.py +131 -103
  54. toil/lib/ec2.py +322 -209
  55. toil/lib/ec2nodes.py +174 -106
  56. toil/lib/encryption/_dummy.py +5 -3
  57. toil/lib/encryption/_nacl.py +10 -6
  58. toil/lib/encryption/conftest.py +1 -0
  59. toil/lib/exceptions.py +26 -7
  60. toil/lib/expando.py +4 -2
  61. toil/lib/ftp_utils.py +217 -0
  62. toil/lib/generatedEC2Lists.py +127 -19
  63. toil/lib/humanize.py +6 -2
  64. toil/lib/integration.py +341 -0
  65. toil/lib/io.py +99 -11
  66. toil/lib/iterables.py +4 -2
  67. toil/lib/memoize.py +12 -8
  68. toil/lib/misc.py +65 -18
  69. toil/lib/objects.py +2 -2
  70. toil/lib/resources.py +19 -7
  71. toil/lib/retry.py +115 -77
  72. toil/lib/threading.py +282 -80
  73. toil/lib/throttle.py +15 -14
  74. toil/options/common.py +834 -401
  75. toil/options/cwl.py +175 -90
  76. toil/options/runner.py +50 -0
  77. toil/options/wdl.py +70 -19
  78. toil/provisioners/__init__.py +111 -46
  79. toil/provisioners/abstractProvisioner.py +322 -157
  80. toil/provisioners/aws/__init__.py +62 -30
  81. toil/provisioners/aws/awsProvisioner.py +980 -627
  82. toil/provisioners/clusterScaler.py +541 -279
  83. toil/provisioners/gceProvisioner.py +282 -179
  84. toil/provisioners/node.py +147 -79
  85. toil/realtimeLogger.py +34 -22
  86. toil/resource.py +137 -75
  87. toil/server/app.py +127 -61
  88. toil/server/celery_app.py +3 -1
  89. toil/server/cli/wes_cwl_runner.py +82 -53
  90. toil/server/utils.py +54 -28
  91. toil/server/wes/abstract_backend.py +64 -26
  92. toil/server/wes/amazon_wes_utils.py +21 -15
  93. toil/server/wes/tasks.py +121 -63
  94. toil/server/wes/toil_backend.py +142 -107
  95. toil/server/wsgi_app.py +4 -3
  96. toil/serviceManager.py +58 -22
  97. toil/statsAndLogging.py +148 -64
  98. toil/test/__init__.py +263 -179
  99. toil/test/batchSystems/batchSystemTest.py +438 -195
  100. toil/test/batchSystems/batch_system_plugin_test.py +18 -7
  101. toil/test/batchSystems/test_gridengine.py +173 -0
  102. toil/test/batchSystems/test_lsf_helper.py +67 -58
  103. toil/test/batchSystems/test_slurm.py +93 -47
  104. toil/test/cactus/test_cactus_integration.py +20 -22
  105. toil/test/cwl/cwlTest.py +271 -71
  106. toil/test/cwl/measure_default_memory.cwl +12 -0
  107. toil/test/cwl/not_run_required_input.cwl +29 -0
  108. toil/test/cwl/scatter_duplicate_outputs.cwl +40 -0
  109. toil/test/docs/scriptsTest.py +60 -34
  110. toil/test/jobStores/jobStoreTest.py +412 -235
  111. toil/test/lib/aws/test_iam.py +116 -48
  112. toil/test/lib/aws/test_s3.py +16 -9
  113. toil/test/lib/aws/test_utils.py +5 -6
  114. toil/test/lib/dockerTest.py +118 -141
  115. toil/test/lib/test_conversions.py +113 -115
  116. toil/test/lib/test_ec2.py +57 -49
  117. toil/test/lib/test_integration.py +104 -0
  118. toil/test/lib/test_misc.py +12 -5
  119. toil/test/mesos/MesosDataStructuresTest.py +23 -10
  120. toil/test/mesos/helloWorld.py +7 -6
  121. toil/test/mesos/stress.py +25 -20
  122. toil/test/options/options.py +7 -2
  123. toil/test/provisioners/aws/awsProvisionerTest.py +293 -140
  124. toil/test/provisioners/clusterScalerTest.py +440 -250
  125. toil/test/provisioners/clusterTest.py +81 -42
  126. toil/test/provisioners/gceProvisionerTest.py +174 -100
  127. toil/test/provisioners/provisionerTest.py +25 -13
  128. toil/test/provisioners/restartScript.py +5 -4
  129. toil/test/server/serverTest.py +188 -141
  130. toil/test/sort/restart_sort.py +137 -68
  131. toil/test/sort/sort.py +134 -66
  132. toil/test/sort/sortTest.py +91 -49
  133. toil/test/src/autoDeploymentTest.py +140 -100
  134. toil/test/src/busTest.py +20 -18
  135. toil/test/src/checkpointTest.py +8 -2
  136. toil/test/src/deferredFunctionTest.py +49 -35
  137. toil/test/src/dockerCheckTest.py +33 -26
  138. toil/test/src/environmentTest.py +20 -10
  139. toil/test/src/fileStoreTest.py +538 -271
  140. toil/test/src/helloWorldTest.py +7 -4
  141. toil/test/src/importExportFileTest.py +61 -31
  142. toil/test/src/jobDescriptionTest.py +32 -17
  143. toil/test/src/jobEncapsulationTest.py +2 -0
  144. toil/test/src/jobFileStoreTest.py +74 -50
  145. toil/test/src/jobServiceTest.py +187 -73
  146. toil/test/src/jobTest.py +120 -70
  147. toil/test/src/miscTests.py +19 -18
  148. toil/test/src/promisedRequirementTest.py +82 -36
  149. toil/test/src/promisesTest.py +7 -6
  150. toil/test/src/realtimeLoggerTest.py +6 -6
  151. toil/test/src/regularLogTest.py +71 -37
  152. toil/test/src/resourceTest.py +80 -49
  153. toil/test/src/restartDAGTest.py +36 -22
  154. toil/test/src/resumabilityTest.py +9 -2
  155. toil/test/src/retainTempDirTest.py +45 -14
  156. toil/test/src/systemTest.py +12 -8
  157. toil/test/src/threadingTest.py +44 -25
  158. toil/test/src/toilContextManagerTest.py +10 -7
  159. toil/test/src/userDefinedJobArgTypeTest.py +8 -5
  160. toil/test/src/workerTest.py +33 -16
  161. toil/test/utils/toilDebugTest.py +70 -58
  162. toil/test/utils/toilKillTest.py +4 -5
  163. toil/test/utils/utilsTest.py +239 -102
  164. toil/test/wdl/wdltoil_test.py +789 -148
  165. toil/test/wdl/wdltoil_test_kubernetes.py +37 -23
  166. toil/toilState.py +52 -26
  167. toil/utils/toilConfig.py +13 -4
  168. toil/utils/toilDebugFile.py +44 -27
  169. toil/utils/toilDebugJob.py +85 -25
  170. toil/utils/toilDestroyCluster.py +11 -6
  171. toil/utils/toilKill.py +8 -3
  172. toil/utils/toilLaunchCluster.py +251 -145
  173. toil/utils/toilMain.py +37 -16
  174. toil/utils/toilRsyncCluster.py +27 -14
  175. toil/utils/toilSshCluster.py +45 -22
  176. toil/utils/toilStats.py +75 -36
  177. toil/utils/toilStatus.py +226 -119
  178. toil/utils/toilUpdateEC2Instances.py +3 -1
  179. toil/version.py +11 -11
  180. toil/wdl/utils.py +5 -5
  181. toil/wdl/wdltoil.py +3513 -1052
  182. toil/worker.py +269 -128
  183. toil-8.0.0.dist-info/METADATA +173 -0
  184. toil-8.0.0.dist-info/RECORD +253 -0
  185. {toil-7.0.0.dist-info → toil-8.0.0.dist-info}/WHEEL +1 -1
  186. toil-7.0.0.dist-info/METADATA +0 -158
  187. toil-7.0.0.dist-info/RECORD +0 -244
  188. {toil-7.0.0.dist-info → toil-8.0.0.dist-info}/LICENSE +0 -0
  189. {toil-7.0.0.dist-info → toil-8.0.0.dist-info}/entry_points.txt +0 -0
  190. {toil-7.0.0.dist-info → toil-8.0.0.dist-info}/top_level.txt +0 -0
@@ -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, List, Optional, Set, Tuple, Type, Union
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[List[str]] = None,
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 == 'aws':
49
+ if provisioner == "aws":
50
50
  try:
51
51
  from toil.provisioners.aws.awsProvisioner import AWSProvisioner
52
52
  except ImportError:
53
- logger.error('The aws extra must be installed to use this provisioner')
53
+ logger.error("The aws extra must be installed to use this provisioner")
54
54
  raise
55
- return AWSProvisioner(clusterName, clusterType, zone, nodeStorage, nodeStorageOverrides, sseKey, enable_fuse)
56
- elif provisioner == 'gce':
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('The google extra must be installed to use this provisioner')
68
+ logger.error("The google extra must be installed to use this provisioner")
61
69
  raise
62
- return GCEProvisioner(clusterName, clusterType, zone, nodeStorage, nodeStorageOverrides, sseKey, enable_fuse)
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 = ['aws', 'gce']
86
+ provisioner_choices = ["aws", "gce"]
71
87
  # TODO: Better consolidate this provisioner arg and the one in common.py?
72
- group.add_argument('--provisioner', '-p', dest="provisioner", choices=provisioner_choices, default='aws',
73
- help=f"The provisioner for cluster auto-scaling. This is the '--provisioner' option set for "
74
- f"Toil utils like launch-cluster and destroy-cluster, which always require a provisioner, "
75
- f"and so this defaults to: %(default)s. Choices: {provisioner_choices}.")
76
- group.add_argument('-z', '--zone', dest='zone', required=False, default=None,
77
- help="The availability zone of the leader. This parameter can also be set via the 'TOIL_X_ZONE' "
78
- "environment variable, where X is AWS or GCE, or by the ec2_region_name parameter "
79
- "in your .boto file, or derived from the instance metadata if using this utility on an "
80
- "existing EC2 instance.")
81
- group.add_argument("clusterName", help="The name that the cluster will be identifiable by. "
82
- "Must be lowercase and may not contain the '_' character.")
83
-
84
-
85
- def parse_node_types(node_type_specs: Optional[str]) -> List[Tuple[Set[str], Optional[float]]]:
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(f'Cound not parse node type "{node_type_spec}": multiple bids')
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(f'Cound not parse node type "{node_type_spec}": empty instance type')
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((instance_types, float(parts[1]) if len(parts) > 1 else None))
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(provisioner, node_types: List[Tuple[Set[str], Optional[float]]]):
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
- if provisioner == 'aws':
192
+
193
+ if provisioner == "aws":
152
194
  from toil.lib.aws import get_current_aws_region
153
- current_region = get_current_aws_region() or 'us-west-2'
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(instance_type_name, regionDict[current_region], 1)
202
+ close = get_close_matches(
203
+ instance_type_name, regionDict[current_region], 1
204
+ )
160
205
  if len(close) > 0:
161
- helpText = ' Did you mean ' + close[0] + '?'
206
+ helpText = " Did you mean " + close[0] + "?"
162
207
  else:
163
- helpText = ''
164
- raise RuntimeError(f'Invalid instance type ({instance_type_name}) specified for AWS in '
165
- f'region: {current_region}.{helpText}')
166
- elif provisioner == 'gce':
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(f"It looks like you've specified an AWS nodeType with the {provisioner} "
171
- f"provisioner. Please specify a nodeType for {provisioner}.")
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__(f"The {provisioner_class} provisioner does not support making {cluster_type} clusters")
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
- def __init__(self, provisioner_class: Type, cluster_type: str, architecture: str, reason: Optional[str] = None):
195
- message = (f"The {provisioner_class} provisioner does not support making {cluster_type} clusters "
196
- f"using nodes with the {architecture} architecture.")
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)