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
toil/__init__.py CHANGED
@@ -11,21 +11,19 @@
11
11
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
- import errno
15
14
  import logging
16
15
  import os
17
16
  import re
18
17
  import socket
19
18
  import sys
20
- import time
21
19
  from datetime import datetime
22
- from typing import TYPE_CHECKING, Optional, Tuple
20
+ from typing import TYPE_CHECKING, Optional
23
21
 
24
22
  import requests
25
23
 
26
24
  from docker.errors import ImageNotFound
27
25
  from toil.lib.memoize import memoize
28
- from toil.lib.retry import retry
26
+ from toil.lib.retry import retry as retry
29
27
  from toil.version import currentCommit
30
28
 
31
29
  if TYPE_CHECKING:
@@ -43,15 +41,15 @@ def which(cmd, mode=os.F_OK | os.X_OK, path=None) -> Optional[str]:
43
41
  `mode` defaults to os.F_OK | os.X_OK. `path` defaults to the result
44
42
  of os.environ.get("PATH"), or can be overridden with a custom search
45
43
  path.
46
-
44
+
47
45
  :returns: The path found, or None.
48
46
  """
47
+
49
48
  # Check that a given file can be accessed with the correct mode.
50
49
  # Additionally check that `file` is not a directory, as on Windows
51
50
  # directories pass the os.access check.
52
51
  def _access_check(fn, mode):
53
- return (os.path.exists(fn) and os.access(fn, mode)
54
- and not os.path.isdir(fn))
52
+ return os.path.exists(fn) and os.access(fn, mode) and not os.path.isdir(fn)
55
53
 
56
54
  # If we're given a path with a directory part, look it up directly rather
57
55
  # than referring to PATH directories. This includes checking relative to the
@@ -106,17 +104,19 @@ def toilPackageDirPath() -> str:
106
104
  The return value is guaranteed to end in '/toil'.
107
105
  """
108
106
  result = os.path.dirname(os.path.realpath(__file__))
109
- if not result.endswith('/toil'):
107
+ if not result.endswith("/toil"):
110
108
  raise RuntimeError("The top-level toil package is not named Toil.")
111
109
  return result
112
110
 
113
111
 
114
112
  def inVirtualEnv() -> bool:
115
113
  """Test if we are inside a virtualenv or Conda virtual environment."""
116
- return ('VIRTUAL_ENV' in os.environ or
117
- 'CONDA_DEFAULT_ENV' in os.environ or
118
- hasattr(sys, 'real_prefix') or
119
- (hasattr(sys, 'base_prefix') and sys.base_prefix != sys.prefix))
114
+ return (
115
+ "VIRTUAL_ENV" in os.environ
116
+ or "CONDA_DEFAULT_ENV" in os.environ
117
+ or hasattr(sys, "real_prefix")
118
+ or (hasattr(sys, "base_prefix") and sys.base_prefix != sys.prefix)
119
+ )
120
120
 
121
121
 
122
122
  def resolveEntryPoint(entryPoint: str) -> str:
@@ -125,7 +125,7 @@ def resolveEntryPoint(entryPoint: str) -> str:
125
125
 
126
126
  :returns: The path found, which may be an absolute or a relative path.
127
127
  """
128
- if os.environ.get("TOIL_CHECK_ENV", None) == 'True' and inVirtualEnv():
128
+ if os.environ.get("TOIL_CHECK_ENV", None) == "True" and inVirtualEnv():
129
129
  path = os.path.join(os.path.dirname(sys.executable), entryPoint)
130
130
  # Inside a virtualenv we try to use absolute paths to the entrypoints.
131
131
  if os.path.isfile(path):
@@ -134,7 +134,9 @@ def resolveEntryPoint(entryPoint: str) -> str:
134
134
  # if Toil is installed in a virtualenv on the leader, it must be installed in
135
135
  # a virtualenv located at the same path on each worker as well.
136
136
  if not os.access(path, os.X_OK):
137
- raise RuntimeError("Cannot access the Toil virtualenv. If installed in a virtualenv on a cluster, make sure that the virtualenv path is the same for the leader and workers.")
137
+ raise RuntimeError(
138
+ "Cannot access the Toil virtualenv. If installed in a virtualenv on a cluster, make sure that the virtualenv path is the same for the leader and workers."
139
+ )
138
140
  return path
139
141
  # Otherwise, we aren't in a virtualenv, or we're in a virtualenv but Toil
140
142
  # came in via --system-site-packages, or we think the virtualenv might not
@@ -154,10 +156,15 @@ def physicalMemory() -> int:
154
156
  True
155
157
  """
156
158
  try:
157
- return os.sysconf('SC_PAGE_SIZE') * os.sysconf('SC_PHYS_PAGES')
159
+ return os.sysconf("SC_PAGE_SIZE") * os.sysconf("SC_PHYS_PAGES")
158
160
  except ValueError:
159
161
  import subprocess
160
- return int(subprocess.check_output(['sysctl', '-n', 'hw.memsize']).decode('utf-8').strip())
162
+
163
+ return int(
164
+ subprocess.check_output(["sysctl", "-n", "hw.memsize"])
165
+ .decode("utf-8")
166
+ .strip()
167
+ )
161
168
 
162
169
 
163
170
  def physicalDisk(directory: str) -> int:
@@ -181,15 +188,22 @@ def applianceSelf(forceDockerAppliance: bool = False) -> str:
181
188
  Setting TOIL_APPLIANCE_SELF will not be necessary in most cases.
182
189
  """
183
190
  import toil.version
184
- registry = lookupEnvVar(name='docker registry',
185
- envName='TOIL_DOCKER_REGISTRY',
186
- defaultValue=toil.version.dockerRegistry)
187
- name = lookupEnvVar(name='docker name',
188
- envName='TOIL_DOCKER_NAME',
189
- defaultValue=toil.version.dockerName)
190
- appliance = lookupEnvVar(name='docker appliance',
191
- envName='TOIL_APPLIANCE_SELF',
192
- defaultValue=registry + '/' + name + ':' + toil.version.dockerTag)
191
+
192
+ registry = lookupEnvVar(
193
+ name="docker registry",
194
+ envName="TOIL_DOCKER_REGISTRY",
195
+ defaultValue=toil.version.dockerRegistry,
196
+ )
197
+ name = lookupEnvVar(
198
+ name="docker name",
199
+ envName="TOIL_DOCKER_NAME",
200
+ defaultValue=toil.version.dockerName,
201
+ )
202
+ appliance = lookupEnvVar(
203
+ name="docker appliance",
204
+ envName="TOIL_APPLIANCE_SELF",
205
+ defaultValue=registry + "/" + name + ":" + toil.version.dockerTag,
206
+ )
193
207
 
194
208
  checkDockerSchema(appliance)
195
209
 
@@ -211,9 +225,11 @@ def customDockerInitCmd() -> str:
211
225
 
212
226
  :returns: The custom command, or an empty string is returned if the environment variable is not set.
213
227
  """
214
- command = lookupEnvVar(name='user-defined custom docker init command',
215
- envName='TOIL_CUSTOM_DOCKER_INIT_COMMAND',
216
- defaultValue='')
228
+ command = lookupEnvVar(
229
+ name="user-defined custom docker init command",
230
+ envName="TOIL_CUSTOM_DOCKER_INIT_COMMAND",
231
+ defaultValue="",
232
+ )
217
233
  _check_custom_bash_cmd(command)
218
234
  return command.replace("'", "'\\''") # Ensure any single quotes are escaped.
219
235
 
@@ -224,24 +240,28 @@ def customInitCmd() -> str:
224
240
 
225
241
  The custom init command is run prior to running Toil appliance itself in workers and/or the
226
242
  primary node (i.e. this is run one stage before ``TOIL_CUSTOM_DOCKER_INIT_COMMAND``).
227
-
243
+
228
244
  This can be useful for doing any custom initialization on instances (e.g. authenticating to
229
245
  private docker registries). Any single quotes are escaped and the command cannot contain a
230
246
  set of blacklisted chars (newline or tab).
231
247
 
232
248
  returns: the custom command or n empty string is returned if the environment variable is not set.
233
249
  """
234
- command = lookupEnvVar(name='user-defined custom init command',
235
- envName='TOIL_CUSTOM_INIT_COMMAND',
236
- defaultValue='')
250
+ command = lookupEnvVar(
251
+ name="user-defined custom init command",
252
+ envName="TOIL_CUSTOM_INIT_COMMAND",
253
+ defaultValue="",
254
+ )
237
255
  _check_custom_bash_cmd(command)
238
256
  return command.replace("'", "'\\''") # Ensure any single quotes are escaped.
239
257
 
240
258
 
241
259
  def _check_custom_bash_cmd(cmd_str):
242
260
  """Ensure that the Bash command doesn't contain invalid characters."""
243
- if re.search(r'[\n\r\t]', cmd_str):
244
- raise RuntimeError(f'"{cmd_str}" contains invalid characters (newline and/or tab).')
261
+ if re.search(r"[\n\r\t]", cmd_str):
262
+ raise RuntimeError(
263
+ f'"{cmd_str}" contains invalid characters (newline and/or tab).'
264
+ )
245
265
 
246
266
 
247
267
  def lookupEnvVar(name: str, envName: str, defaultValue: str) -> str:
@@ -256,10 +276,14 @@ def lookupEnvVar(name: str, envName: str, defaultValue: str) -> str:
256
276
  try:
257
277
  value = os.environ[envName]
258
278
  except KeyError:
259
- log.info('Using default %s of %s as %s is not set.', name, defaultValue, envName)
279
+ log.info(
280
+ "Using default %s of %s as %s is not set.", name, defaultValue, envName
281
+ )
260
282
  return defaultValue
261
283
  else:
262
- log.info('Overriding %s of %s with %s from %s.', name, defaultValue, value, envName)
284
+ log.info(
285
+ "Overriding %s of %s with %s from %s.", name, defaultValue, value, envName
286
+ )
263
287
  return value
264
288
 
265
289
 
@@ -278,14 +302,20 @@ def checkDockerImageExists(appliance: str) -> str:
278
302
  return appliance
279
303
  registryName, imageName, tag = parseDockerAppliance(appliance)
280
304
 
281
- if registryName == 'docker.io':
282
- return requestCheckDockerIo(origAppliance=appliance, imageName=imageName, tag=tag)
305
+ if registryName == "docker.io":
306
+ return requestCheckDockerIo(
307
+ origAppliance=appliance, imageName=imageName, tag=tag
308
+ )
283
309
  else:
284
- return requestCheckRegularDocker(origAppliance=appliance, registryName=registryName, imageName=imageName,
285
- tag=tag)
310
+ return requestCheckRegularDocker(
311
+ origAppliance=appliance,
312
+ registryName=registryName,
313
+ imageName=imageName,
314
+ tag=tag,
315
+ )
286
316
 
287
317
 
288
- def parseDockerAppliance(appliance: str) -> Tuple[str, str, str]:
318
+ def parseDockerAppliance(appliance: str) -> tuple[str, str, str]:
289
319
  """
290
320
  Derive parsed registry, image reference, and tag from a docker image string.
291
321
 
@@ -303,21 +333,21 @@ def parseDockerAppliance(appliance: str) -> Tuple[str, str, str]:
303
333
  appliance = appliance.lower()
304
334
 
305
335
  # get the tag
306
- if ':' in appliance:
307
- tag = appliance.split(':')[-1]
308
- appliance = appliance[:-(len(':' + tag))] # remove only the tag
336
+ if ":" in appliance:
337
+ tag = appliance.split(":")[-1]
338
+ appliance = appliance[: -(len(":" + tag))] # remove only the tag
309
339
  else:
310
340
  # default to 'latest' if no tag is specified
311
- tag = 'latest'
341
+ tag = "latest"
312
342
 
313
343
  # get the registry and image
314
- registryName = 'docker.io' # default if not specified
344
+ registryName = "docker.io" # default if not specified
315
345
  imageName = appliance # will be true if not specified
316
- if '/' in appliance and '.' in appliance.split('/')[0]:
317
- registryName = appliance.split('/')[0]
318
- imageName = appliance[len(registryName):]
319
- registryName = registryName.strip('/')
320
- imageName = imageName.strip('/')
346
+ if "/" in appliance and "." in appliance.split("/")[0]:
347
+ registryName = appliance.split("/")[0]
348
+ imageName = appliance[len(registryName) :]
349
+ registryName = registryName.strip("/")
350
+ imageName = imageName.strip("/")
321
351
 
322
352
  return registryName, imageName, tag
323
353
 
@@ -325,12 +355,14 @@ def parseDockerAppliance(appliance: str) -> Tuple[str, str, str]:
325
355
  def checkDockerSchema(appliance):
326
356
  if not appliance:
327
357
  raise ImageNotFound("No docker image specified.")
328
- elif '://' in appliance:
329
- raise ImageNotFound("Docker images cannot contain a schema (such as '://'): %s"
330
- "" % appliance)
358
+ elif "://" in appliance:
359
+ raise ImageNotFound(
360
+ "Docker images cannot contain a schema (such as '://'): %s" "" % appliance
361
+ )
331
362
  elif len(appliance) > 256:
332
- raise ImageNotFound("Docker image must be less than 256 chars: %s"
333
- "" % appliance)
363
+ raise ImageNotFound(
364
+ "Docker image must be less than 256 chars: %s" "" % appliance
365
+ )
334
366
 
335
367
 
336
368
  class ApplianceImageNotFound(ImageNotFound):
@@ -345,22 +377,28 @@ class ApplianceImageNotFound(ImageNotFound):
345
377
  """
346
378
 
347
379
  def __init__(self, origAppliance, url, statusCode):
348
- msg = ("The docker image that TOIL_APPLIANCE_SELF specifies (%s) produced "
349
- "a nonfunctional manifest URL (%s). The HTTP status returned was %s. "
350
- "The specifier is most likely unsupported or malformed. "
351
- "Please supply a docker image with the format: "
352
- "'<websitehost>.io/<repo_path>:<tag>' or '<repo_path>:<tag>' "
353
- "(for official docker.io images). Examples: "
354
- "'quay.io/ucsc_cgl/toil:latest', 'ubuntu:latest', or "
355
- "'broadinstitute/genomes-in-the-cloud:2.0.0'."
356
- "" % (origAppliance, url, str(statusCode)))
380
+ msg = (
381
+ "The docker image that TOIL_APPLIANCE_SELF specifies (%s) produced "
382
+ "a nonfunctional manifest URL (%s). The HTTP status returned was %s. "
383
+ "The specifier is most likely unsupported or malformed. "
384
+ "Please supply a docker image with the format: "
385
+ "'<websitehost>.io/<repo_path>:<tag>' or '<repo_path>:<tag>' "
386
+ "(for official docker.io images). Examples: "
387
+ "'quay.io/ucsc_cgl/toil:latest', 'ubuntu:latest', or "
388
+ "'broadinstitute/genomes-in-the-cloud:2.0.0'."
389
+ "" % (origAppliance, url, str(statusCode))
390
+ )
357
391
  super().__init__(msg)
358
392
 
393
+
359
394
  # Cache images we know exist so we don't have to ask the registry about them
360
395
  # all the time.
361
396
  KNOWN_EXTANT_IMAGES = set()
362
397
 
363
- def requestCheckRegularDocker(origAppliance: str, registryName: str, imageName: str, tag: str) -> bool:
398
+
399
+ def requestCheckRegularDocker(
400
+ origAppliance: str, registryName: str, imageName: str, tag: str
401
+ ) -> bool:
364
402
  """
365
403
  Check if an image exists using the requests library.
366
404
 
@@ -384,8 +422,9 @@ def requestCheckRegularDocker(origAppliance: str, registryName: str, imageName:
384
422
  # Check the cache first
385
423
  return origAppliance
386
424
 
387
- ioURL = 'https://{webhost}/v2/{pathName}/manifests/{tag}' \
388
- ''.format(webhost=registryName, pathName=imageName, tag=tag)
425
+ ioURL = "https://{webhost}/v2/{pathName}/manifests/{tag}" "".format(
426
+ webhost=registryName, pathName=imageName, tag=tag
427
+ )
389
428
  response = requests.head(ioURL)
390
429
  if not response.ok:
391
430
  raise ApplianceImageNotFound(origAppliance, ioURL, response.status_code)
@@ -412,17 +451,20 @@ def requestCheckDockerIo(origAppliance: str, imageName: str, tag: str) -> bool:
412
451
  return origAppliance
413
452
 
414
453
  # only official images like 'busybox' or 'ubuntu'
415
- if '/' not in imageName:
416
- imageName = 'library/' + imageName
454
+ if "/" not in imageName:
455
+ imageName = "library/" + imageName
417
456
 
418
- token_url = 'https://auth.docker.io/token?service=registry.docker.io&scope=repository:{repo}:pull'.format(
419
- repo=imageName)
420
- requests_url = f'https://registry-1.docker.io/v2/{imageName}/manifests/{tag}'
457
+ token_url = "https://auth.docker.io/token?service=registry.docker.io&scope=repository:{repo}:pull".format(
458
+ repo=imageName
459
+ )
460
+ requests_url = f"https://registry-1.docker.io/v2/{imageName}/manifests/{tag}"
421
461
 
422
462
  token = requests.get(token_url)
423
463
  jsonToken = token.json()
424
464
  bearer = jsonToken["token"]
425
- response = requests.head(requests_url, headers={'Authorization': f'Bearer {bearer}'})
465
+ response = requests.head(
466
+ requests_url, headers={"Authorization": f"Bearer {bearer}"}
467
+ )
426
468
  if not response.ok:
427
469
  raise ApplianceImageNotFound(origAppliance, requests_url, response.status_code)
428
470
  else:
@@ -434,21 +476,18 @@ def logProcessContext(config: "Config") -> None:
434
476
  # toil.version.version (string) cannot be imported at top level because it conflicts with
435
477
  # toil.version (module) and Sphinx doesn't like that.
436
478
  from toil.version import version
479
+
437
480
  log.info("Running Toil version %s on host %s.", version, socket.gethostname())
438
481
  log.debug("Configuration: %s", config.__dict__)
439
482
 
440
483
 
441
484
  try:
442
- from botocore.credentials import (JSONFileCache,
443
- RefreshableCredentials,
444
- create_credential_resolver)
445
- from botocore.session import Session
446
-
447
- cache_path = '~/.cache/aws/cached_temporary_credentials'
448
- datetime_format = "%Y-%m-%dT%H:%M:%SZ" # incidentally the same as the format used by AWS
485
+ cache_path = "~/.cache/aws/cached_temporary_credentials"
486
+ datetime_format = (
487
+ "%Y-%m-%dT%H:%M:%SZ" # incidentally the same as the format used by AWS
488
+ )
449
489
  log = logging.getLogger(__name__)
450
490
 
451
-
452
491
  # But in addition to our manual cache, we also are going to turn on boto3's
453
492
  # new built-in caching layer.
454
493
 
@@ -461,7 +500,6 @@ try:
461
500
  """
462
501
  return dt.strftime(datetime_format)
463
502
 
464
-
465
503
  def str_to_datetime(s):
466
504
  """
467
505
  Convert a string, explicitly UTC into a naive (implicitly UTC) datetime object.
@@ -18,6 +18,7 @@ class DeadlockException(Exception):
18
18
  Exception thrown by the Leader or BatchSystem when a deadlock is encountered due to insufficient
19
19
  resources to run the workflow
20
20
  """
21
+
21
22
  def __init__(self, msg):
22
23
  self.msg = f"Deadlock encountered: {msg}"
23
24
  super().__init__()