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.
Files changed (193) hide show
  1. toil/__init__.py +122 -315
  2. toil/batchSystems/__init__.py +1 -0
  3. toil/batchSystems/abstractBatchSystem.py +173 -89
  4. toil/batchSystems/abstractGridEngineBatchSystem.py +272 -148
  5. toil/batchSystems/awsBatch.py +244 -135
  6. toil/batchSystems/cleanup_support.py +26 -16
  7. toil/batchSystems/contained_executor.py +31 -28
  8. toil/batchSystems/gridengine.py +86 -50
  9. toil/batchSystems/htcondor.py +166 -89
  10. toil/batchSystems/kubernetes.py +632 -382
  11. toil/batchSystems/local_support.py +20 -15
  12. toil/batchSystems/lsf.py +134 -81
  13. toil/batchSystems/lsfHelper.py +13 -11
  14. toil/batchSystems/mesos/__init__.py +41 -29
  15. toil/batchSystems/mesos/batchSystem.py +290 -151
  16. toil/batchSystems/mesos/executor.py +79 -50
  17. toil/batchSystems/mesos/test/__init__.py +31 -23
  18. toil/batchSystems/options.py +46 -28
  19. toil/batchSystems/registry.py +53 -19
  20. toil/batchSystems/singleMachine.py +296 -125
  21. toil/batchSystems/slurm.py +603 -138
  22. toil/batchSystems/torque.py +47 -33
  23. toil/bus.py +186 -76
  24. toil/common.py +664 -368
  25. toil/cwl/__init__.py +1 -1
  26. toil/cwl/cwltoil.py +1136 -483
  27. toil/cwl/utils.py +17 -22
  28. toil/deferred.py +63 -42
  29. toil/exceptions.py +5 -3
  30. toil/fileStores/__init__.py +5 -5
  31. toil/fileStores/abstractFileStore.py +140 -60
  32. toil/fileStores/cachingFileStore.py +717 -269
  33. toil/fileStores/nonCachingFileStore.py +116 -87
  34. toil/job.py +1225 -368
  35. toil/jobStores/abstractJobStore.py +416 -266
  36. toil/jobStores/aws/jobStore.py +863 -477
  37. toil/jobStores/aws/utils.py +201 -120
  38. toil/jobStores/conftest.py +3 -2
  39. toil/jobStores/fileJobStore.py +292 -154
  40. toil/jobStores/googleJobStore.py +140 -74
  41. toil/jobStores/utils.py +36 -15
  42. toil/leader.py +668 -272
  43. toil/lib/accelerators.py +115 -18
  44. toil/lib/aws/__init__.py +74 -31
  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 +214 -39
  49. toil/lib/aws/utils.py +287 -231
  50. toil/lib/bioio.py +13 -5
  51. toil/lib/compatibility.py +11 -6
  52. toil/lib/conversions.py +104 -47
  53. toil/lib/docker.py +131 -103
  54. toil/lib/ec2.py +361 -199
  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 +5 -3
  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 +141 -15
  66. toil/lib/iterables.py +4 -2
  67. toil/lib/memoize.py +12 -8
  68. toil/lib/misc.py +66 -21
  69. toil/lib/objects.py +2 -2
  70. toil/lib/resources.py +68 -15
  71. toil/lib/retry.py +126 -81
  72. toil/lib/threading.py +299 -82
  73. toil/lib/throttle.py +16 -15
  74. toil/options/common.py +843 -409
  75. toil/options/cwl.py +175 -90
  76. toil/options/runner.py +50 -0
  77. toil/options/wdl.py +73 -17
  78. toil/provisioners/__init__.py +117 -46
  79. toil/provisioners/abstractProvisioner.py +332 -157
  80. toil/provisioners/aws/__init__.py +70 -33
  81. toil/provisioners/aws/awsProvisioner.py +1145 -715
  82. toil/provisioners/clusterScaler.py +541 -279
  83. toil/provisioners/gceProvisioner.py +282 -179
  84. toil/provisioners/node.py +155 -79
  85. toil/realtimeLogger.py +34 -22
  86. toil/resource.py +137 -75
  87. toil/server/app.py +128 -62
  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 +224 -70
  98. toil/test/__init__.py +282 -183
  99. toil/test/batchSystems/batchSystemTest.py +460 -210
  100. toil/test/batchSystems/batch_system_plugin_test.py +90 -0
  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 +110 -49
  104. toil/test/cactus/__init__.py +0 -0
  105. toil/test/cactus/test_cactus_integration.py +56 -0
  106. toil/test/cwl/cwlTest.py +496 -287
  107. toil/test/cwl/measure_default_memory.cwl +12 -0
  108. toil/test/cwl/not_run_required_input.cwl +29 -0
  109. toil/test/cwl/scatter_duplicate_outputs.cwl +40 -0
  110. toil/test/cwl/seqtk_seq.cwl +1 -1
  111. toil/test/docs/scriptsTest.py +69 -46
  112. toil/test/jobStores/jobStoreTest.py +427 -264
  113. toil/test/lib/aws/test_iam.py +118 -50
  114. toil/test/lib/aws/test_s3.py +16 -9
  115. toil/test/lib/aws/test_utils.py +5 -6
  116. toil/test/lib/dockerTest.py +118 -141
  117. toil/test/lib/test_conversions.py +113 -115
  118. toil/test/lib/test_ec2.py +58 -50
  119. toil/test/lib/test_integration.py +104 -0
  120. toil/test/lib/test_misc.py +12 -5
  121. toil/test/mesos/MesosDataStructuresTest.py +23 -10
  122. toil/test/mesos/helloWorld.py +7 -6
  123. toil/test/mesos/stress.py +25 -20
  124. toil/test/options/__init__.py +13 -0
  125. toil/test/options/options.py +42 -0
  126. toil/test/provisioners/aws/awsProvisionerTest.py +320 -150
  127. toil/test/provisioners/clusterScalerTest.py +440 -250
  128. toil/test/provisioners/clusterTest.py +166 -44
  129. toil/test/provisioners/gceProvisionerTest.py +174 -100
  130. toil/test/provisioners/provisionerTest.py +25 -13
  131. toil/test/provisioners/restartScript.py +5 -4
  132. toil/test/server/serverTest.py +188 -141
  133. toil/test/sort/restart_sort.py +137 -68
  134. toil/test/sort/sort.py +134 -66
  135. toil/test/sort/sortTest.py +91 -49
  136. toil/test/src/autoDeploymentTest.py +141 -101
  137. toil/test/src/busTest.py +20 -18
  138. toil/test/src/checkpointTest.py +8 -2
  139. toil/test/src/deferredFunctionTest.py +49 -35
  140. toil/test/src/dockerCheckTest.py +32 -24
  141. toil/test/src/environmentTest.py +135 -0
  142. toil/test/src/fileStoreTest.py +539 -272
  143. toil/test/src/helloWorldTest.py +7 -4
  144. toil/test/src/importExportFileTest.py +61 -31
  145. toil/test/src/jobDescriptionTest.py +46 -21
  146. toil/test/src/jobEncapsulationTest.py +2 -0
  147. toil/test/src/jobFileStoreTest.py +74 -50
  148. toil/test/src/jobServiceTest.py +187 -73
  149. toil/test/src/jobTest.py +121 -71
  150. toil/test/src/miscTests.py +19 -18
  151. toil/test/src/promisedRequirementTest.py +82 -36
  152. toil/test/src/promisesTest.py +7 -6
  153. toil/test/src/realtimeLoggerTest.py +10 -6
  154. toil/test/src/regularLogTest.py +71 -37
  155. toil/test/src/resourceTest.py +80 -49
  156. toil/test/src/restartDAGTest.py +36 -22
  157. toil/test/src/resumabilityTest.py +9 -2
  158. toil/test/src/retainTempDirTest.py +45 -14
  159. toil/test/src/systemTest.py +12 -8
  160. toil/test/src/threadingTest.py +44 -25
  161. toil/test/src/toilContextManagerTest.py +10 -7
  162. toil/test/src/userDefinedJobArgTypeTest.py +8 -5
  163. toil/test/src/workerTest.py +73 -23
  164. toil/test/utils/toilDebugTest.py +103 -33
  165. toil/test/utils/toilKillTest.py +4 -5
  166. toil/test/utils/utilsTest.py +245 -106
  167. toil/test/wdl/wdltoil_test.py +818 -149
  168. toil/test/wdl/wdltoil_test_kubernetes.py +91 -0
  169. toil/toilState.py +120 -35
  170. toil/utils/toilConfig.py +13 -4
  171. toil/utils/toilDebugFile.py +44 -27
  172. toil/utils/toilDebugJob.py +214 -27
  173. toil/utils/toilDestroyCluster.py +11 -6
  174. toil/utils/toilKill.py +8 -3
  175. toil/utils/toilLaunchCluster.py +256 -140
  176. toil/utils/toilMain.py +37 -16
  177. toil/utils/toilRsyncCluster.py +32 -14
  178. toil/utils/toilSshCluster.py +49 -22
  179. toil/utils/toilStats.py +356 -273
  180. toil/utils/toilStatus.py +292 -139
  181. toil/utils/toilUpdateEC2Instances.py +3 -1
  182. toil/version.py +12 -12
  183. toil/wdl/utils.py +5 -5
  184. toil/wdl/wdltoil.py +3913 -1033
  185. toil/worker.py +367 -184
  186. {toil-6.1.0a1.dist-info → toil-8.0.0.dist-info}/LICENSE +25 -0
  187. toil-8.0.0.dist-info/METADATA +173 -0
  188. toil-8.0.0.dist-info/RECORD +253 -0
  189. {toil-6.1.0a1.dist-info → toil-8.0.0.dist-info}/WHEEL +1 -1
  190. toil-6.1.0a1.dist-info/METADATA +0 -125
  191. toil-6.1.0a1.dist-info/RECORD +0 -237
  192. {toil-6.1.0a1.dist-info → toil-8.0.0.dist-info}/entry_points.txt +0 -0
  193. {toil-6.1.0a1.dist-info → toil-8.0.0.dist-info}/top_level.txt +0 -0
toil/resource.py CHANGED
@@ -20,17 +20,12 @@ import os
20
20
  import shutil
21
21
  import sys
22
22
  from collections import namedtuple
23
+ from collections.abc import Sequence
23
24
  from contextlib import closing
24
25
  from io import BytesIO
25
26
  from pydoc import locate
26
27
  from types import ModuleType
27
- from typing import (IO,
28
- TYPE_CHECKING,
29
- BinaryIO,
30
- Callable,
31
- Optional,
32
- Sequence,
33
- Type)
28
+ from typing import IO, TYPE_CHECKING, BinaryIO, Callable, Optional
34
29
  from urllib.error import HTTPError
35
30
  from urllib.request import urlopen
36
31
  from zipfile import ZipFile
@@ -47,7 +42,8 @@ if TYPE_CHECKING:
47
42
 
48
43
  logger = logging.getLogger(__name__)
49
44
 
50
- class Resource(namedtuple('Resource', ('name', 'pathHash', 'url', 'contentHash'))):
45
+
46
+ class Resource(namedtuple("Resource", ("name", "pathHash", "url", "contentHash"))):
51
47
  """
52
48
  Represents a file or directory that will be deployed to each node before any jobs in the user script are invoked.
53
49
 
@@ -67,9 +63,9 @@ class Resource(namedtuple('Resource', ('name', 'pathHash', 'url', 'contentHash')
67
63
  ZIP archive of that directory.
68
64
  """
69
65
 
70
- resourceEnvNamePrefix = 'JTRES_'
66
+ resourceEnvNamePrefix = "JTRES_"
71
67
 
72
- rootDirPathEnvName = resourceEnvNamePrefix + 'ROOT'
68
+ rootDirPathEnvName = resourceEnvNamePrefix + "ROOT"
73
69
 
74
70
  @classmethod
75
71
  def create(cls, jobStore: "AbstractJobStore", leaderPath: str) -> "Resource":
@@ -86,20 +82,26 @@ class Resource(namedtuple('Resource', ('name', 'pathHash', 'url', 'contentHash')
86
82
  contentHash = hashlib.md5()
87
83
  # noinspection PyProtectedMember
88
84
  with cls._load(leaderPath) as src:
89
- with jobStore.write_shared_file_stream(shared_file_name=pathHash, encrypted=False) as dst:
85
+ with jobStore.write_shared_file_stream(
86
+ shared_file_name=pathHash, encrypted=False
87
+ ) as dst:
90
88
  userScript = src.read()
91
89
  contentHash.update(userScript)
92
90
  dst.write(userScript)
93
- return cls(name=os.path.basename(leaderPath),
94
- pathHash=pathHash,
95
- url=jobStore.getSharedPublicUrl(sharedFileName=pathHash),
96
- contentHash=contentHash.hexdigest())
91
+ return cls(
92
+ name=os.path.basename(leaderPath),
93
+ pathHash=pathHash,
94
+ url=jobStore.getSharedPublicUrl(sharedFileName=pathHash),
95
+ contentHash=contentHash.hexdigest(),
96
+ )
97
97
 
98
98
  def refresh(self, jobStore: "AbstractJobStore") -> "Resource":
99
- return type(self)(name=self.name,
100
- pathHash=self.pathHash,
101
- url=jobStore.get_shared_public_url(shared_file_name=self.pathHash),
102
- contentHash=self.contentHash)
99
+ return type(self)(
100
+ name=self.name,
101
+ pathHash=self.pathHash,
102
+ url=jobStore.get_shared_public_url(shared_file_name=self.pathHash),
103
+ contentHash=self.contentHash,
104
+ )
103
105
 
104
106
  @classmethod
105
107
  def prepareSystem(cls) -> None:
@@ -165,7 +167,9 @@ class Resource(namedtuple('Resource', ('name', 'pathHash', 'url', 'contentHash')
165
167
  """
166
168
  dirPath = self.localDirPath
167
169
  if not os.path.exists(dirPath):
168
- tempDirPath = mkdtemp(dir=os.path.dirname(dirPath), prefix=self.contentHash + "-")
170
+ tempDirPath = mkdtemp(
171
+ dir=os.path.dirname(dirPath), prefix=self.contentHash + "-"
172
+ )
169
173
  self._save(tempDirPath)
170
174
  if callback is not None:
171
175
  callback(tempDirPath)
@@ -199,16 +203,22 @@ class Resource(namedtuple('Resource', ('name', 'pathHash', 'url', 'contentHash')
199
203
  return os.path.join(rootDirPath, self.contentHash)
200
204
 
201
205
  def pickle(self) -> str:
202
- return self.__class__.__module__ + "." + self.__class__.__name__ + ':' + json.dumps(self)
206
+ return (
207
+ self.__class__.__module__
208
+ + "."
209
+ + self.__class__.__name__
210
+ + ":"
211
+ + json.dumps(self)
212
+ )
203
213
 
204
214
  @classmethod
205
215
  def unpickle(cls, s: str) -> "Resource":
206
- className, _json = s.split(':', 1)
207
- return locate(className)(*json.loads(_json)) # type: ignore
216
+ className, _json = s.split(":", 1)
217
+ return locate(className)(*json.loads(_json)) # type: ignore
208
218
 
209
219
  @classmethod
210
220
  def _pathHash(cls, path: str) -> str:
211
- return hashlib.md5(path.encode('utf-8')).hexdigest()
221
+ return hashlib.md5(path.encode("utf-8")).hexdigest()
212
222
 
213
223
  @classmethod
214
224
  def _load(cls, path: str) -> IO[bytes]:
@@ -230,11 +240,7 @@ class Resource(namedtuple('Resource', ('name', 'pathHash', 'url', 'contentHash')
230
240
  """
231
241
  raise NotImplementedError()
232
242
 
233
- @retry(errors=[
234
- ErrorCondition(
235
- error=HTTPError,
236
- error_codes=[400])
237
- ])
243
+ @retry(errors=[ErrorCondition(error=HTTPError, error_codes=[400])])
238
244
  def _download(self, dstFile: IO[bytes]) -> None:
239
245
  """
240
246
  Download this resource from its URL to the given file object.
@@ -254,10 +260,10 @@ class FileResource(Resource):
254
260
 
255
261
  @classmethod
256
262
  def _load(cls, path: str) -> BinaryIO:
257
- return open(path, 'rb')
263
+ return open(path, "rb")
258
264
 
259
265
  def _save(self, dirPath: str) -> None:
260
- with open(os.path.join(dirPath, self.name), mode='wb') as localFile:
266
+ with open(os.path.join(dirPath, self.name), mode="wb") as localFile:
261
267
  self._download(localFile)
262
268
 
263
269
  @property
@@ -277,7 +283,7 @@ class DirectoryResource(Resource):
277
283
  @classmethod
278
284
  def _load(cls, path: str) -> BytesIO:
279
285
  bytesIO = BytesIO()
280
- initfile = os.path.join(path, '__init__.py')
286
+ initfile = os.path.join(path, "__init__.py")
281
287
  if os.path.isfile(initfile):
282
288
  # This is a package directory. To emulate
283
289
  # PyZipFile.writepy's behavior, we need to keep everything
@@ -286,20 +292,37 @@ class DirectoryResource(Resource):
286
292
  else:
287
293
  # This is a simple user script (with possibly a few helper files)
288
294
  rootDir = path
289
- skipdirList = ['/tmp', '/var', '/etc', '/bin', '/sbin', '/home', '/dev', '/sys', '/usr', '/run']
295
+ skipdirList = [
296
+ "/tmp",
297
+ "/var",
298
+ "/etc",
299
+ "/bin",
300
+ "/sbin",
301
+ "/home",
302
+ "/dev",
303
+ "/sys",
304
+ "/usr",
305
+ "/run",
306
+ ]
290
307
  if path not in skipdirList:
291
- with ZipFile(file=bytesIO, mode='w') as zipFile:
308
+ with ZipFile(file=bytesIO, mode="w") as zipFile:
292
309
  for dirName, _, fileList in os.walk(path):
293
310
  for fileName in fileList:
294
311
  try:
295
312
  fullPath = os.path.join(dirName, fileName)
296
313
  zipFile.write(fullPath, os.path.relpath(fullPath, rootDir))
297
314
  except OSError:
298
- logger.critical('Cannot access and read the file at path: %s' % fullPath)
315
+ logger.critical(
316
+ "Cannot access and read the file at path: %s" % fullPath
317
+ )
299
318
  sys.exit(1)
300
319
  else:
301
- logger.critical("Couldn't package the directory at {} for hot deployment. Would recommend to create a \
302
- subdirectory (ie {}/MYDIR_HERE/)".format(path, path))
320
+ logger.critical(
321
+ "Couldn't package the directory at {} for hot deployment. Would recommend to create a \
322
+ subdirectory (ie {}/MYDIR_HERE/)".format(
323
+ path, path
324
+ )
325
+ )
303
326
  sys.exit(1)
304
327
  bytesIO.seek(0)
305
328
  return bytesIO
@@ -308,7 +331,7 @@ class DirectoryResource(Resource):
308
331
  bytesIO = BytesIO()
309
332
  self._download(bytesIO)
310
333
  bytesIO.seek(0)
311
- with ZipFile(file=bytesIO, mode='r') as zipFile:
334
+ with ZipFile(file=bytesIO, mode="r") as zipFile:
312
335
  zipFile.extractall(path=dirPath)
313
336
 
314
337
  @property
@@ -325,10 +348,10 @@ class VirtualEnvResource(DirectoryResource):
325
348
 
326
349
  @classmethod
327
350
  def _load(cls, path: str) -> BytesIO:
328
- if os.path.basename(path) != 'site-packages':
351
+ if os.path.basename(path) != "site-packages":
329
352
  raise RuntimeError("An incorrect path was passed through.")
330
353
  bytesIO = BytesIO()
331
- with ZipFile(file=bytesIO, mode='w') as zipFile:
354
+ with ZipFile(file=bytesIO, mode="w") as zipFile:
332
355
  for dirName, _, fileList in os.walk(path):
333
356
  zipFile.write(dirName)
334
357
  for fileName in fileList:
@@ -338,7 +361,9 @@ class VirtualEnvResource(DirectoryResource):
338
361
  return bytesIO
339
362
 
340
363
 
341
- class ModuleDescriptor(namedtuple('ModuleDescriptor', ('dirPath', 'name', 'fromVirtualEnv'))):
364
+ class ModuleDescriptor(
365
+ namedtuple("ModuleDescriptor", ("dirPath", "name", "fromVirtualEnv"))
366
+ ):
342
367
  """
343
368
  A path to a Python module decomposed into a namedtuple of three elements
344
369
 
@@ -378,6 +403,7 @@ class ModuleDescriptor(namedtuple('ModuleDescriptor', ('dirPath', 'name', 'fromV
378
403
  Clean up
379
404
  >>> rmtree( dirPath )
380
405
  """
406
+
381
407
  dirPath: str
382
408
  name: str
383
409
 
@@ -392,7 +418,7 @@ class ModuleDescriptor(namedtuple('ModuleDescriptor', ('dirPath', 'name', 'fromV
392
418
  """
393
419
  module = sys.modules[name]
394
420
  if module.__file__ is None:
395
- raise Exception(f'Module {name} does not exist.')
421
+ raise Exception(f"Module {name} does not exist.")
396
422
  fileAbsPath = os.path.abspath(module.__file__)
397
423
  filePath = fileAbsPath.split(os.path.sep)
398
424
  filePath[-1], extension = os.path.splitext(filePath[-1])
@@ -405,12 +431,12 @@ class ModuleDescriptor(namedtuple('ModuleDescriptor', ('dirPath', 'name', 'fromV
405
431
  # Invoked as a module via python -m foo.bar
406
432
  logger.debug("Script was invoked as a module")
407
433
  nameList = [filePath.pop()]
408
- for package in reversed(module.__package__.split('.')):
434
+ for package in reversed(module.__package__.split(".")):
409
435
  dirPathTail = filePath.pop()
410
436
  if dirPathTail != package:
411
437
  raise RuntimeError("Incorrect path to package.")
412
438
  nameList.append(dirPathTail)
413
- name = '.'.join(reversed(nameList))
439
+ name = ".".join(reversed(nameList))
414
440
  dirPath = os.path.sep.join(filePath)
415
441
  else:
416
442
  # Invoked as a script via python foo/bar.py
@@ -419,20 +445,27 @@ class ModuleDescriptor(namedtuple('ModuleDescriptor', ('dirPath', 'name', 'fromV
419
445
  cls._check_conflict(dirPath, name)
420
446
  else:
421
447
  # User module was imported. Determine the directory containing the top-level package
422
- if filePath[-1] == '__init__':
448
+ if filePath[-1] == "__init__":
423
449
  # module is a subpackage
424
450
  filePath.pop()
425
451
 
426
- for package in reversed(name.split('.')):
452
+ for package in reversed(name.split(".")):
427
453
  dirPathTail = filePath.pop()
428
454
  if dirPathTail != package:
429
455
  raise RuntimeError("Incorrect path to package.")
430
456
  dirPath = os.path.abspath(os.path.sep.join(filePath))
431
457
  absPrefix = os.path.abspath(sys.prefix)
432
458
  inVenv = inVirtualEnv()
433
- logger.debug("Module dir is %s, our prefix is %s, virtualenv: %s", dirPath, absPrefix, inVenv)
459
+ logger.debug(
460
+ "Module dir is %s, our prefix is %s, virtualenv: %s",
461
+ dirPath,
462
+ absPrefix,
463
+ inVenv,
464
+ )
434
465
  if not os.path.isdir(dirPath):
435
- raise Exception(f'Bad directory path {dirPath} for module {name}. Note that hot-deployment does not support .egg-link files yet, or scripts located in the root directory.')
466
+ raise Exception(
467
+ f"Bad directory path {dirPath} for module {name}. Note that hot-deployment does not support .egg-link files yet, or scripts located in the root directory."
468
+ )
436
469
  fromVirtualEnv = inVenv and dirPath.startswith(absPrefix)
437
470
  return cls(dirPath=dirPath, name=name, fromVirtualEnv=fromVirtualEnv)
438
471
 
@@ -446,7 +479,11 @@ class ModuleDescriptor(namedtuple('ModuleDescriptor', ('dirPath', 'name', 'fromV
446
479
  """
447
480
  old_sys_path = sys.path
448
481
  try:
449
- sys.path = [d for d in old_sys_path if os.path.realpath(d) != os.path.realpath(dirPath)]
482
+ sys.path = [
483
+ d
484
+ for d in old_sys_path
485
+ if os.path.realpath(d) != os.path.realpath(dirPath)
486
+ ]
450
487
  try:
451
488
  colliding_module = importlib.import_module(name)
452
489
  except ImportError:
@@ -454,7 +491,9 @@ class ModuleDescriptor(namedtuple('ModuleDescriptor', ('dirPath', 'name', 'fromV
454
491
  else:
455
492
  raise ResourceException(
456
493
  "The user module '{}' collides with module '{} from '{}'.".format(
457
- name, colliding_module.__name__, colliding_module.__file__))
494
+ name, colliding_module.__name__, colliding_module.__file__
495
+ )
496
+ )
458
497
  finally:
459
498
  sys.path = old_sys_path
460
499
 
@@ -463,7 +502,7 @@ class ModuleDescriptor(namedtuple('ModuleDescriptor', ('dirPath', 'name', 'fromV
463
502
  """
464
503
  True if this module is part of the Toil distribution
465
504
  """
466
- return self.name.startswith('toil.')
505
+ return self.name.startswith("toil.")
467
506
 
468
507
  def saveAsResourceTo(self, jobStore: "AbstractJobStore") -> Resource:
469
508
  """
@@ -475,11 +514,11 @@ class ModuleDescriptor(namedtuple('ModuleDescriptor', ('dirPath', 'name', 'fromV
475
514
  """
476
515
  return self._getResourceClass().create(jobStore, self._resourcePath)
477
516
 
478
- def _getResourceClass(self) -> Type[Resource]:
517
+ def _getResourceClass(self) -> type[Resource]:
479
518
  """
480
519
  Return the concrete subclass of Resource that's appropriate for auto-deploying this module.
481
520
  """
482
- subcls: Type[Resource]
521
+ subcls: type[Resource]
483
522
  if self.fromVirtualEnv:
484
523
  subcls = VirtualEnvResource
485
524
  elif os.path.isdir(self._resourcePath):
@@ -487,7 +526,9 @@ class ModuleDescriptor(namedtuple('ModuleDescriptor', ('dirPath', 'name', 'fromV
487
526
  elif os.path.isfile(self._resourcePath):
488
527
  subcls = FileResource
489
528
  elif os.path.exists(self._resourcePath):
490
- raise AssertionError("Neither a file or a directory: '%s'" % self._resourcePath)
529
+ raise AssertionError(
530
+ "Neither a file or a directory: '%s'" % self._resourcePath
531
+ )
491
532
  else:
492
533
  raise AssertionError("No such file or directory: '%s'" % self._resourcePath)
493
534
  return subcls
@@ -501,27 +542,30 @@ class ModuleDescriptor(namedtuple('ModuleDescriptor', ('dirPath', 'name', 'fromV
501
542
  the leader, this method returns this resource, i.e. self.
502
543
  """
503
544
  if not self._runningOnWorker():
504
- logger.warning('The localize() method should only be invoked on a worker.')
545
+ logger.warning("The localize() method should only be invoked on a worker.")
505
546
  resource = Resource.lookup(self._resourcePath)
506
547
  if resource is None:
507
548
  return self
508
549
  else:
550
+
509
551
  def stash(tmpDirPath: str) -> None:
510
552
  # Save the original dirPath such that we can restore it in globalize()
511
- with open(os.path.join(tmpDirPath, '.stash'), 'w') as f:
512
- f.write('1' if self.fromVirtualEnv else '0')
553
+ with open(os.path.join(tmpDirPath, ".stash"), "w") as f:
554
+ f.write("1" if self.fromVirtualEnv else "0")
513
555
  f.write(self.dirPath)
514
556
 
515
557
  resource.download(callback=stash)
516
- return self.__class__(dirPath=resource.localDirPath,
517
- name=self.name,
518
- fromVirtualEnv=self.fromVirtualEnv)
558
+ return self.__class__(
559
+ dirPath=resource.localDirPath,
560
+ name=self.name,
561
+ fromVirtualEnv=self.fromVirtualEnv,
562
+ )
519
563
 
520
564
  def _runningOnWorker(self) -> bool:
521
565
  try:
522
- mainModule = sys.modules['__main__']
566
+ mainModule = sys.modules["__main__"]
523
567
  except KeyError:
524
- logger.warning('Cannot determine main program module.')
568
+ logger.warning("Cannot determine main program module.")
525
569
  return False
526
570
  else:
527
571
  # If __file__ is not a valid attribute, it's because
@@ -535,7 +579,12 @@ class ModuleDescriptor(namedtuple('ModuleDescriptor', ('dirPath', 'name', 'fromV
535
579
  except AttributeError:
536
580
  return False
537
581
 
538
- workerModuleFiles = ['worker.py', 'worker.pyc', 'worker.pyo', '_toil_worker'] # setuptools entry point
582
+ workerModuleFiles = [
583
+ "worker.py",
584
+ "worker.pyc",
585
+ "worker.pyo",
586
+ "_toil_worker",
587
+ ] # setuptools entry point
539
588
  return mainModuleFile in workerModuleFiles
540
589
 
541
590
  def globalize(self) -> "ModuleDescriptor":
@@ -543,7 +592,7 @@ class ModuleDescriptor(namedtuple('ModuleDescriptor', ('dirPath', 'name', 'fromV
543
592
  Reverse the effect of localize().
544
593
  """
545
594
  try:
546
- with open(os.path.join(self.dirPath, '.stash')) as f:
595
+ with open(os.path.join(self.dirPath, ".stash")) as f:
547
596
  fromVirtualEnv = [False, True][int(f.read(1))]
548
597
  dirPath = f.read()
549
598
  except OSError as e:
@@ -552,9 +601,9 @@ class ModuleDescriptor(namedtuple('ModuleDescriptor', ('dirPath', 'name', 'fromV
552
601
  else:
553
602
  raise
554
603
  else:
555
- return self.__class__(dirPath=dirPath,
556
- name=self.name,
557
- fromVirtualEnv=fromVirtualEnv)
604
+ return self.__class__(
605
+ dirPath=dirPath, name=self.name, fromVirtualEnv=fromVirtualEnv
606
+ )
558
607
 
559
608
  @property
560
609
  def _resourcePath(self) -> str:
@@ -564,7 +613,7 @@ class ModuleDescriptor(namedtuple('ModuleDescriptor', ('dirPath', 'name', 'fromV
564
613
  """
565
614
  if self.fromVirtualEnv:
566
615
  return self.dirPath
567
- elif '.' in self.name:
616
+ elif "." in self.name:
568
617
  return os.path.join(self.dirPath, self._rootPackage())
569
618
  else:
570
619
  initName = self._initModuleName(self.dirPath)
@@ -572,22 +621,31 @@ class ModuleDescriptor(namedtuple('ModuleDescriptor', ('dirPath', 'name', 'fromV
572
621
  raise ResourceException(
573
622
  "Toil does not support loading a user script from a package directory. You "
574
623
  "may want to remove %s from %s or invoke the user script as a module via "
575
- "'PYTHONPATH=\"%s\" %s -m %s.%s'." %
576
- tuple(concat(initName, self.dirPath, exactPython, os.path.split(self.dirPath), self.name)))
624
+ "'PYTHONPATH=\"%s\" %s -m %s.%s'."
625
+ % tuple(
626
+ concat(
627
+ initName,
628
+ self.dirPath,
629
+ exactPython,
630
+ os.path.split(self.dirPath),
631
+ self.name,
632
+ )
633
+ )
634
+ )
577
635
  return self.dirPath
578
636
 
579
637
  @classmethod
580
638
  def _initModuleName(cls, dirPath: str) -> Optional[str]:
581
- for name in ('__init__.py', '__init__.pyc', '__init__.pyo'):
639
+ for name in ("__init__.py", "__init__.pyc", "__init__.pyo"):
582
640
  if os.path.exists(os.path.join(dirPath, name)):
583
641
  return name
584
642
  return None
585
643
 
586
644
  def _rootPackage(self) -> str:
587
645
  try:
588
- head, tail = self.name.split('.', 1)
646
+ head, tail = self.name.split(".", 1)
589
647
  except ValueError:
590
- raise ValueError('%r is stand-alone module.' % self.__repr__())
648
+ raise ValueError("%r is stand-alone module." % self.__repr__())
591
649
  else:
592
650
  return head
593
651
 
@@ -598,7 +656,9 @@ class ModuleDescriptor(namedtuple('ModuleDescriptor', ('dirPath', 'name', 'fromV
598
656
  def fromCommand(cls, command: Sequence[str]) -> "ModuleDescriptor":
599
657
  if len(command) != 3:
600
658
  raise RuntimeError("Incorrect number of arguments (Expected 3).")
601
- return cls(dirPath=command[0], name=command[1], fromVirtualEnv=strict_bool(command[2]))
659
+ return cls(
660
+ dirPath=command[0], name=command[1], fromVirtualEnv=strict_bool(command[2])
661
+ )
602
662
 
603
663
  def makeLoadable(self) -> "ModuleDescriptor":
604
664
  module = self if self.belongsToToil else self.localize()
@@ -611,7 +671,9 @@ class ModuleDescriptor(namedtuple('ModuleDescriptor', ('dirPath', 'name', 'fromV
611
671
  try:
612
672
  return importlib.import_module(module.name)
613
673
  except ImportError:
614
- logger.error('Failed to import user module %r from sys.path (%r).', module, sys.path)
674
+ logger.error(
675
+ "Failed to import user module %r from sys.path (%r).", module, sys.path
676
+ )
615
677
  raise
616
678
 
617
679