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.
Files changed (197) hide show
  1. toil/__init__.py +124 -86
  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 +39 -29
  19. toil/batchSystems/registry.py +53 -19
  20. toil/batchSystems/singleMachine.py +293 -123
  21. toil/batchSystems/slurm.py +651 -155
  22. toil/batchSystems/torque.py +46 -32
  23. toil/bus.py +141 -73
  24. toil/common.py +784 -397
  25. toil/cwl/__init__.py +1 -1
  26. toil/cwl/cwltoil.py +1137 -534
  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 +1031 -349
  35. toil/jobStores/abstractJobStore.py +387 -243
  36. toil/jobStores/aws/jobStore.py +772 -412
  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 +204 -58
  49. toil/lib/aws/utils.py +290 -213
  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/dockstore.py +379 -0
  55. toil/lib/ec2.py +322 -209
  56. toil/lib/ec2nodes.py +174 -105
  57. toil/lib/encryption/_dummy.py +5 -3
  58. toil/lib/encryption/_nacl.py +10 -6
  59. toil/lib/encryption/conftest.py +1 -0
  60. toil/lib/exceptions.py +26 -7
  61. toil/lib/expando.py +4 -2
  62. toil/lib/ftp_utils.py +217 -0
  63. toil/lib/generatedEC2Lists.py +127 -19
  64. toil/lib/history.py +1271 -0
  65. toil/lib/history_submission.py +681 -0
  66. toil/lib/humanize.py +6 -2
  67. toil/lib/io.py +121 -12
  68. toil/lib/iterables.py +4 -2
  69. toil/lib/memoize.py +12 -8
  70. toil/lib/misc.py +83 -18
  71. toil/lib/objects.py +2 -2
  72. toil/lib/resources.py +19 -7
  73. toil/lib/retry.py +125 -87
  74. toil/lib/threading.py +282 -80
  75. toil/lib/throttle.py +15 -14
  76. toil/lib/trs.py +390 -0
  77. toil/lib/web.py +38 -0
  78. toil/options/common.py +850 -402
  79. toil/options/cwl.py +185 -90
  80. toil/options/runner.py +50 -0
  81. toil/options/wdl.py +70 -19
  82. toil/provisioners/__init__.py +111 -46
  83. toil/provisioners/abstractProvisioner.py +322 -157
  84. toil/provisioners/aws/__init__.py +62 -30
  85. toil/provisioners/aws/awsProvisioner.py +980 -627
  86. toil/provisioners/clusterScaler.py +541 -279
  87. toil/provisioners/gceProvisioner.py +283 -180
  88. toil/provisioners/node.py +147 -79
  89. toil/realtimeLogger.py +34 -22
  90. toil/resource.py +137 -75
  91. toil/server/app.py +127 -61
  92. toil/server/celery_app.py +3 -1
  93. toil/server/cli/wes_cwl_runner.py +84 -55
  94. toil/server/utils.py +56 -31
  95. toil/server/wes/abstract_backend.py +64 -26
  96. toil/server/wes/amazon_wes_utils.py +21 -15
  97. toil/server/wes/tasks.py +121 -63
  98. toil/server/wes/toil_backend.py +142 -107
  99. toil/server/wsgi_app.py +4 -3
  100. toil/serviceManager.py +58 -22
  101. toil/statsAndLogging.py +183 -65
  102. toil/test/__init__.py +263 -179
  103. toil/test/batchSystems/batchSystemTest.py +438 -195
  104. toil/test/batchSystems/batch_system_plugin_test.py +18 -7
  105. toil/test/batchSystems/test_gridengine.py +173 -0
  106. toil/test/batchSystems/test_lsf_helper.py +67 -58
  107. toil/test/batchSystems/test_slurm.py +265 -49
  108. toil/test/cactus/test_cactus_integration.py +20 -22
  109. toil/test/cwl/conftest.py +39 -0
  110. toil/test/cwl/cwlTest.py +375 -72
  111. toil/test/cwl/measure_default_memory.cwl +12 -0
  112. toil/test/cwl/not_run_required_input.cwl +29 -0
  113. toil/test/cwl/optional-file.cwl +18 -0
  114. toil/test/cwl/scatter_duplicate_outputs.cwl +40 -0
  115. toil/test/docs/scriptsTest.py +60 -34
  116. toil/test/jobStores/jobStoreTest.py +412 -235
  117. toil/test/lib/aws/test_iam.py +116 -48
  118. toil/test/lib/aws/test_s3.py +16 -9
  119. toil/test/lib/aws/test_utils.py +5 -6
  120. toil/test/lib/dockerTest.py +118 -141
  121. toil/test/lib/test_conversions.py +113 -115
  122. toil/test/lib/test_ec2.py +57 -49
  123. toil/test/lib/test_history.py +212 -0
  124. toil/test/lib/test_misc.py +12 -5
  125. toil/test/lib/test_trs.py +161 -0
  126. toil/test/mesos/MesosDataStructuresTest.py +23 -10
  127. toil/test/mesos/helloWorld.py +7 -6
  128. toil/test/mesos/stress.py +25 -20
  129. toil/test/options/options.py +7 -2
  130. toil/test/provisioners/aws/awsProvisionerTest.py +293 -140
  131. toil/test/provisioners/clusterScalerTest.py +440 -250
  132. toil/test/provisioners/clusterTest.py +81 -42
  133. toil/test/provisioners/gceProvisionerTest.py +174 -100
  134. toil/test/provisioners/provisionerTest.py +25 -13
  135. toil/test/provisioners/restartScript.py +5 -4
  136. toil/test/server/serverTest.py +188 -141
  137. toil/test/sort/restart_sort.py +137 -68
  138. toil/test/sort/sort.py +134 -66
  139. toil/test/sort/sortTest.py +91 -49
  140. toil/test/src/autoDeploymentTest.py +140 -100
  141. toil/test/src/busTest.py +20 -18
  142. toil/test/src/checkpointTest.py +8 -2
  143. toil/test/src/deferredFunctionTest.py +49 -35
  144. toil/test/src/dockerCheckTest.py +33 -26
  145. toil/test/src/environmentTest.py +20 -10
  146. toil/test/src/fileStoreTest.py +538 -271
  147. toil/test/src/helloWorldTest.py +7 -4
  148. toil/test/src/importExportFileTest.py +61 -31
  149. toil/test/src/jobDescriptionTest.py +32 -17
  150. toil/test/src/jobEncapsulationTest.py +2 -0
  151. toil/test/src/jobFileStoreTest.py +74 -50
  152. toil/test/src/jobServiceTest.py +187 -73
  153. toil/test/src/jobTest.py +120 -70
  154. toil/test/src/miscTests.py +19 -18
  155. toil/test/src/promisedRequirementTest.py +82 -36
  156. toil/test/src/promisesTest.py +7 -6
  157. toil/test/src/realtimeLoggerTest.py +6 -6
  158. toil/test/src/regularLogTest.py +71 -37
  159. toil/test/src/resourceTest.py +80 -49
  160. toil/test/src/restartDAGTest.py +36 -22
  161. toil/test/src/resumabilityTest.py +9 -2
  162. toil/test/src/retainTempDirTest.py +45 -14
  163. toil/test/src/systemTest.py +12 -8
  164. toil/test/src/threadingTest.py +44 -25
  165. toil/test/src/toilContextManagerTest.py +10 -7
  166. toil/test/src/userDefinedJobArgTypeTest.py +8 -5
  167. toil/test/src/workerTest.py +33 -16
  168. toil/test/utils/toilDebugTest.py +70 -58
  169. toil/test/utils/toilKillTest.py +4 -5
  170. toil/test/utils/utilsTest.py +239 -102
  171. toil/test/wdl/wdltoil_test.py +789 -148
  172. toil/test/wdl/wdltoil_test_kubernetes.py +37 -23
  173. toil/toilState.py +52 -26
  174. toil/utils/toilConfig.py +13 -4
  175. toil/utils/toilDebugFile.py +44 -27
  176. toil/utils/toilDebugJob.py +85 -25
  177. toil/utils/toilDestroyCluster.py +11 -6
  178. toil/utils/toilKill.py +8 -3
  179. toil/utils/toilLaunchCluster.py +251 -145
  180. toil/utils/toilMain.py +37 -16
  181. toil/utils/toilRsyncCluster.py +27 -14
  182. toil/utils/toilSshCluster.py +45 -22
  183. toil/utils/toilStats.py +75 -36
  184. toil/utils/toilStatus.py +226 -119
  185. toil/utils/toilUpdateEC2Instances.py +3 -1
  186. toil/version.py +6 -6
  187. toil/wdl/utils.py +5 -5
  188. toil/wdl/wdltoil.py +3528 -1053
  189. toil/worker.py +370 -149
  190. toil-8.1.0b1.dist-info/METADATA +178 -0
  191. toil-8.1.0b1.dist-info/RECORD +259 -0
  192. {toil-7.0.0.dist-info → toil-8.1.0b1.dist-info}/WHEEL +1 -1
  193. toil-7.0.0.dist-info/METADATA +0 -158
  194. toil-7.0.0.dist-info/RECORD +0 -244
  195. {toil-7.0.0.dist-info → toil-8.1.0b1.dist-info}/LICENSE +0 -0
  196. {toil-7.0.0.dist-info → toil-8.1.0b1.dist-info}/entry_points.txt +0 -0
  197. {toil-7.0.0.dist-info → toil-8.1.0b1.dist-info}/top_level.txt +0 -0
@@ -24,36 +24,43 @@ from abc import ABCMeta, abstractmethod
24
24
  from fractions import Fraction
25
25
  from unittest import skipIf
26
26
 
27
- from toil.batchSystems.abstractBatchSystem import (AbstractBatchSystem,
28
- BatchSystemSupport,
29
- InsufficientSystemResources)
27
+ from toil.batchSystems.abstractBatchSystem import (
28
+ AbstractBatchSystem,
29
+ BatchSystemSupport,
30
+ InsufficientSystemResources,
31
+ )
32
+
30
33
  # Don't import any batch systems here that depend on extras
31
34
  # in order to import properly. Import them later, in tests
32
35
  # protected by annotations.
33
36
  from toil.batchSystems.mesos.test import MesosTestSupport
34
- from toil.batchSystems.registry import (add_batch_system_factory,
35
- get_batch_system,
36
- get_batch_systems,
37
- restore_batch_system_plugin_state,
38
- save_batch_system_plugin_state)
37
+ from toil.batchSystems.registry import (
38
+ add_batch_system_factory,
39
+ get_batch_system,
40
+ get_batch_systems,
41
+ restore_batch_system_plugin_state,
42
+ save_batch_system_plugin_state,
43
+ )
39
44
  from toil.batchSystems.singleMachine import SingleMachineBatchSystem
40
45
  from toil.common import Config, Toil
41
46
  from toil.job import Job, JobDescription, Requirer
42
47
  from toil.lib.retry import retry_flaky_test
43
48
  from toil.lib.threading import cpu_count
44
- from toil.test import (ToilTest,
45
- needs_aws_batch,
46
- needs_aws_s3,
47
- needs_fetchable_appliance,
48
- needs_gridengine,
49
- needs_htcondor,
50
- needs_kubernetes,
51
- needs_kubernetes_installed,
52
- needs_lsf,
53
- needs_mesos,
54
- needs_slurm,
55
- needs_torque,
56
- slow)
49
+ from toil.test import (
50
+ ToilTest,
51
+ needs_aws_batch,
52
+ needs_aws_s3,
53
+ needs_fetchable_appliance,
54
+ needs_gridengine,
55
+ needs_htcondor,
56
+ needs_kubernetes,
57
+ needs_kubernetes_installed,
58
+ needs_lsf,
59
+ needs_mesos,
60
+ needs_slurm,
61
+ needs_torque,
62
+ slow,
63
+ )
57
64
 
58
65
  logger = logging.getLogger(__name__)
59
66
 
@@ -66,7 +73,10 @@ preemptible = False
66
73
 
67
74
  # Since we aren't always attaching the config to the jobs for these tests, we
68
75
  # need to use fully specified requirements.
69
- defaultRequirements = dict(memory=int(100e6), cores=1, disk=1000, preemptible=preemptible, accelerators=[])
76
+ defaultRequirements = dict(
77
+ memory=int(100e6), cores=1, disk=1000, preemptible=preemptible, accelerators=[]
78
+ )
79
+
70
80
 
71
81
  class BatchSystemPluginTest(ToilTest):
72
82
  """
@@ -91,9 +101,10 @@ class BatchSystemPluginTest(ToilTest):
91
101
  # add its arguments.
92
102
  return SingleMachineBatchSystem
93
103
 
94
- add_batch_system_factory('testBatchSystem', test_batch_system_factory)
95
- assert 'testBatchSystem' in get_batch_systems()
96
- assert get_batch_system('testBatchSystem') == SingleMachineBatchSystem
104
+ add_batch_system_factory("testBatchSystem", test_batch_system_factory)
105
+ assert "testBatchSystem" in get_batch_systems()
106
+ assert get_batch_system("testBatchSystem") == SingleMachineBatchSystem
107
+
97
108
 
98
109
  class hidden:
99
110
  """
@@ -127,8 +138,9 @@ class hidden:
127
138
  """
128
139
  config = Config()
129
140
  from uuid import uuid4
141
+
130
142
  config.workflowID = str(uuid4())
131
- config.cleanWorkDir = 'always'
143
+ config.cleanWorkDir = "always"
132
144
  return config
133
145
 
134
146
  def _createConfig(self):
@@ -164,7 +176,7 @@ class hidden:
164
176
  super().setUp()
165
177
  self.config = self._createConfig()
166
178
  self.batchSystem = self.createBatchSystem()
167
- self.tempDir = self._createTempDir('testFiles')
179
+ self.tempDir = self._createTempDir("testFiles")
168
180
 
169
181
  def tearDown(self):
170
182
  self.batchSystem.shutdown()
@@ -182,12 +194,20 @@ class hidden:
182
194
 
183
195
  @retry_flaky_test(prepare=[tearDown, setUp])
184
196
  def test_run_jobs(self):
185
- jobDesc1 = self._mockJobDescription(jobName='test1', unitName=None,
186
- jobStoreID='1', requirements=defaultRequirements)
187
- jobDesc2 = self._mockJobDescription(jobName='test2', unitName=None,
188
- jobStoreID='2', requirements=defaultRequirements)
189
- job1 = self.batchSystem.issueBatchJob('sleep 1000', jobDesc1)
190
- job2 = self.batchSystem.issueBatchJob('sleep 1000', jobDesc2)
197
+ jobDesc1 = self._mockJobDescription(
198
+ jobName="test1",
199
+ unitName=None,
200
+ jobStoreID="1",
201
+ requirements=defaultRequirements,
202
+ )
203
+ jobDesc2 = self._mockJobDescription(
204
+ jobName="test2",
205
+ unitName=None,
206
+ jobStoreID="2",
207
+ requirements=defaultRequirements,
208
+ )
209
+ job1 = self.batchSystem.issueBatchJob("sleep 1000", jobDesc1)
210
+ job2 = self.batchSystem.issueBatchJob("sleep 1000", jobDesc2)
191
211
 
192
212
  issuedIDs = self._waitForJobsToIssue(2)
193
213
  self.assertEqual(set(issuedIDs), {job1, job2})
@@ -202,7 +222,9 @@ class hidden:
202
222
  # getUpdatedBatchJob, and the sleep time is longer than the time we
203
223
  # should spend waiting for both to start, so if our cluster can
204
224
  # only run one job at a time, we will fail the test.
205
- runningJobIDs = self._waitForJobsToStart(2, tries=self.get_max_startup_seconds())
225
+ runningJobIDs = self._waitForJobsToStart(
226
+ 2, tries=self.get_max_startup_seconds()
227
+ )
206
228
  self.assertEqual(set(runningJobIDs), {job1, job2})
207
229
 
208
230
  # Killing the jobs instead of allowing them to complete means this test can run very
@@ -216,13 +238,21 @@ class hidden:
216
238
  # then check for it having happened, but we can't guarantee that
217
239
  # the batch system will run against the same filesystem we are
218
240
  # looking at.
219
- jobDesc3 = self._mockJobDescription(jobName='test3', unitName=None,
220
- jobStoreID='3', requirements=defaultRequirements)
241
+ jobDesc3 = self._mockJobDescription(
242
+ jobName="test3",
243
+ unitName=None,
244
+ jobStoreID="3",
245
+ requirements=defaultRequirements,
246
+ )
221
247
  job3 = self.batchSystem.issueBatchJob("mktemp -d", jobDesc3)
222
248
 
223
249
  jobUpdateInfo = self.batchSystem.getUpdatedBatchJob(maxWait=1000)
224
- jobID, exitStatus, wallTime = jobUpdateInfo.jobID, jobUpdateInfo.exitStatus, jobUpdateInfo.wallTime
225
- logger.info(f'Third job completed: {jobID} {exitStatus} {wallTime}')
250
+ jobID, exitStatus, wallTime = (
251
+ jobUpdateInfo.jobID,
252
+ jobUpdateInfo.exitStatus,
253
+ jobUpdateInfo.wallTime,
254
+ )
255
+ logger.info(f"Third job completed: {jobID} {exitStatus} {wallTime}")
226
256
 
227
257
  # Since the first two jobs were killed, the only job in the updated jobs queue should
228
258
  # be job 3. If the first two jobs were (incorrectly) added to the queue, this will
@@ -242,46 +272,68 @@ class hidden:
242
272
 
243
273
  def test_set_env(self):
244
274
  # Start with a relatively safe script
245
- script_shell = 'if [ "x${FOO}" == "xbar" ] ; then exit 23 ; else exit 42 ; fi'
275
+ script_shell = (
276
+ 'if [ "x${FOO}" == "xbar" ] ; then exit 23 ; else exit 42 ; fi'
277
+ )
246
278
 
247
279
  # Escape the semicolons
248
- script_protected = script_shell.replace(';', r'\;')
280
+ script_protected = script_shell.replace(";", r"\;")
249
281
 
250
282
  # Turn into a string which convinces bash to take all args and paste them back together and run them
251
- command = "bash -c \"\\${@}\" bash eval " + script_protected
252
- jobDesc4 = self._mockJobDescription(jobName='test4', unitName=None,
253
- jobStoreID='4', requirements=defaultRequirements)
283
+ command = 'bash -c "\\${@}" bash eval ' + script_protected
284
+ jobDesc4 = self._mockJobDescription(
285
+ jobName="test4",
286
+ unitName=None,
287
+ jobStoreID="4",
288
+ requirements=defaultRequirements,
289
+ )
254
290
  job4 = self.batchSystem.issueBatchJob(command, jobDesc4)
255
291
  jobUpdateInfo = self.batchSystem.getUpdatedBatchJob(maxWait=1000)
256
- jobID, exitStatus, wallTime = jobUpdateInfo.jobID, jobUpdateInfo.exitStatus, jobUpdateInfo.wallTime
292
+ jobID, exitStatus, wallTime = (
293
+ jobUpdateInfo.jobID,
294
+ jobUpdateInfo.exitStatus,
295
+ jobUpdateInfo.wallTime,
296
+ )
257
297
  self.assertEqual(exitStatus, 42)
258
298
  self.assertEqual(jobID, job4)
259
299
  # Now set the variable and ensure that it is present
260
- self.batchSystem.setEnv('FOO', 'bar')
261
- jobDesc5 = self._mockJobDescription(jobName='test5', unitName=None,
262
- jobStoreID='5', requirements=defaultRequirements)
300
+ self.batchSystem.setEnv("FOO", "bar")
301
+ jobDesc5 = self._mockJobDescription(
302
+ jobName="test5",
303
+ unitName=None,
304
+ jobStoreID="5",
305
+ requirements=defaultRequirements,
306
+ )
263
307
  job5 = self.batchSystem.issueBatchJob(command, jobDesc5)
264
308
  jobUpdateInfo = self.batchSystem.getUpdatedBatchJob(maxWait=1000)
265
309
  self.assertEqual(jobUpdateInfo.exitStatus, 23)
266
310
  self.assertEqual(jobUpdateInfo.jobID, job5)
267
311
 
268
312
  def test_set_job_env(self):
269
- """ Test the mechanism for setting per-job environment variables to batch system jobs."""
313
+ """Test the mechanism for setting per-job environment variables to batch system jobs."""
270
314
  script = 'if [ "x${FOO}" == "xbar" ] ; then exit 23 ; else exit 42 ; fi'
271
- command = "bash -c \"\\${@}\" bash eval " + script.replace(';', r'\;')
315
+ command = 'bash -c "\\${@}" bash eval ' + script.replace(";", r"\;")
272
316
 
273
317
  # Issue a job with a job environment variable
274
- job_desc_6 = self._mockJobDescription(jobName='test6', unitName=None,
275
- jobStoreID='6', requirements=defaultRequirements)
276
- job6 = self.batchSystem.issueBatchJob(command, job_desc_6, job_environment={
277
- 'FOO': 'bar'
278
- })
318
+ job_desc_6 = self._mockJobDescription(
319
+ jobName="test6",
320
+ unitName=None,
321
+ jobStoreID="6",
322
+ requirements=defaultRequirements,
323
+ )
324
+ job6 = self.batchSystem.issueBatchJob(
325
+ command, job_desc_6, job_environment={"FOO": "bar"}
326
+ )
279
327
  job_update_info = self.batchSystem.getUpdatedBatchJob(maxWait=1000)
280
328
  self.assertEqual(job_update_info.exitStatus, 23) # this should succeed
281
329
  self.assertEqual(job_update_info.jobID, job6)
282
330
  # Now check that the environment variable doesn't exist for other jobs
283
- job_desc_7 = self._mockJobDescription(jobName='test7', unitName=None,
284
- jobStoreID='7', requirements=defaultRequirements)
331
+ job_desc_7 = self._mockJobDescription(
332
+ jobName="test7",
333
+ unitName=None,
334
+ jobStoreID="7",
335
+ requirements=defaultRequirements,
336
+ )
285
337
  job7 = self.batchSystem.issueBatchJob(command, job_desc_7)
286
338
  job_update_info = self.batchSystem.getUpdatedBatchJob(maxWait=1000)
287
339
  self.assertEqual(job_update_info.exitStatus, 42)
@@ -291,34 +343,67 @@ class hidden:
291
343
  if isinstance(self.batchSystem, BatchSystemSupport):
292
344
  check_resource_request = self.batchSystem.check_resource_request
293
345
  # Assuming we have <2000 cores, this should be too many cores
294
- self.assertRaises(InsufficientSystemResources, check_resource_request,
295
- Requirer(dict(memory=1000, cores=2000, disk='1G', accelerators=[])))
296
- self.assertRaises(InsufficientSystemResources, check_resource_request,
297
- Requirer(dict(memory=5, cores=2000, disk='1G', accelerators=[])))
346
+ self.assertRaises(
347
+ InsufficientSystemResources,
348
+ check_resource_request,
349
+ Requirer(dict(memory=1000, cores=2000, disk="1G", accelerators=[])),
350
+ )
351
+ self.assertRaises(
352
+ InsufficientSystemResources,
353
+ check_resource_request,
354
+ Requirer(dict(memory=5, cores=2000, disk="1G", accelerators=[])),
355
+ )
298
356
 
299
357
  # This should be too much memory
300
- self.assertRaises(InsufficientSystemResources, check_resource_request,
301
- Requirer(dict(memory='5000G', cores=1, disk='1G', accelerators=[])))
358
+ self.assertRaises(
359
+ InsufficientSystemResources,
360
+ check_resource_request,
361
+ Requirer(dict(memory="5000G", cores=1, disk="1G", accelerators=[])),
362
+ )
302
363
 
303
364
  # This should be too much disk
304
- self.assertRaises(InsufficientSystemResources, check_resource_request,
305
- Requirer(dict(memory=5, cores=1, disk='2G', accelerators=[])))
365
+ self.assertRaises(
366
+ InsufficientSystemResources,
367
+ check_resource_request,
368
+ Requirer(dict(memory=5, cores=1, disk="2G", accelerators=[])),
369
+ )
306
370
 
307
371
  # This should be an accelerator we don't have.
308
372
  # All the batch systems need code to know they don't have these accelerators.
309
- self.assertRaises(InsufficientSystemResources, check_resource_request,
310
- Requirer(dict(memory=5, cores=1, disk=100, accelerators=[{'kind': 'turbo-encabulator', 'count': 1}])))
373
+ self.assertRaises(
374
+ InsufficientSystemResources,
375
+ check_resource_request,
376
+ Requirer(
377
+ dict(
378
+ memory=5,
379
+ cores=1,
380
+ disk=100,
381
+ accelerators=[{"kind": "turbo-encabulator", "count": 1}],
382
+ )
383
+ ),
384
+ )
311
385
 
312
386
  # These should be missing attributes
313
- self.assertRaises(AttributeError, check_resource_request,
314
- Requirer(dict(memory=5, cores=1, disk=1000)))
315
- self.assertRaises(AttributeError, check_resource_request,
316
- Requirer(dict(cores=1, disk=1000, accelerators=[])))
317
- self.assertRaises(AttributeError, check_resource_request,
318
- Requirer(dict(memory=10, disk=1000, accelerators=[])))
387
+ self.assertRaises(
388
+ AttributeError,
389
+ check_resource_request,
390
+ Requirer(dict(memory=5, cores=1, disk=1000)),
391
+ )
392
+ self.assertRaises(
393
+ AttributeError,
394
+ check_resource_request,
395
+ Requirer(dict(cores=1, disk=1000, accelerators=[])),
396
+ )
397
+ self.assertRaises(
398
+ AttributeError,
399
+ check_resource_request,
400
+ Requirer(dict(memory=10, disk=1000, accelerators=[])),
401
+ )
319
402
 
320
403
  # This should actually work
321
- check_resource_request(Requirer(dict(memory=10, cores=1, disk=100, accelerators=[])))
404
+ check_resource_request(
405
+ Requirer(dict(memory=10, cores=1, disk=100, accelerators=[]))
406
+ )
322
407
 
323
408
  def testScalableBatchSystem(self):
324
409
  # If instance of scalable batch system
@@ -345,7 +430,7 @@ class hidden:
345
430
  # prevent an endless loop, give it a few tries
346
431
  for it in range(tries):
347
432
  running = self.batchSystem.getRunningBatchJobIDs()
348
- logger.info(f'Running jobs now: {running}')
433
+ logger.info(f"Running jobs now: {running}")
349
434
  runningIDs = list(running.keys())
350
435
  if len(runningIDs) == numJobs:
351
436
  break
@@ -360,7 +445,7 @@ class hidden:
360
445
 
361
446
  cpuCount = cpu_count()
362
447
  allocatedCores = sorted({1, 2, cpuCount})
363
- sleepTime = 5
448
+ sleepTime = 30
364
449
 
365
450
  @abstractmethod
366
451
  def getBatchSystemName(self):
@@ -395,18 +480,26 @@ class hidden:
395
480
  Tests that the batch system is allocating core resources properly for concurrent tasks.
396
481
  """
397
482
  for coresPerJob in self.allocatedCores:
398
- tempDir = self._createTempDir('testFiles')
483
+ tempDir = self._createTempDir("testFiles")
399
484
  options = self.getOptions(tempDir)
400
485
 
401
- counterPath = os.path.join(tempDir, 'counter')
486
+ counterPath = os.path.join(tempDir, "counter")
402
487
  resetCounters(counterPath)
403
488
  value, maxValue = getCounters(counterPath)
404
489
  assert (value, maxValue) == (0, 0)
405
490
 
406
491
  root = Job()
407
492
  for _ in range(self.cpuCount):
408
- root.addFollowOn(Job.wrapFn(measureConcurrency, counterPath, self.sleepTime,
409
- cores=coresPerJob, memory='1M', disk='1Mi'))
493
+ root.addFollowOn(
494
+ Job.wrapFn(
495
+ measureConcurrency,
496
+ counterPath,
497
+ self.sleepTime,
498
+ cores=coresPerJob,
499
+ memory="1M",
500
+ disk="1Mi",
501
+ )
502
+ )
410
503
  with Toil(options) as toil:
411
504
  toil.start(root)
412
505
  _, maxValue = getCounters(counterPath)
@@ -420,18 +513,24 @@ class hidden:
420
513
  # mapping of the number of cores to the OMP_NUM_THREADS value
421
514
  0.1: "1",
422
515
  1: "1",
423
- 2: "2"
516
+ 2: "2",
424
517
  }
425
518
 
426
519
  temp_dir = self._createTempDir()
427
520
  options = self.getOptions(temp_dir)
428
521
 
429
522
  for cores, expected_omp_threads in test_cases.items():
430
- if os.environ.get('OMP_NUM_THREADS'):
431
- expected_omp_threads = os.environ.get('OMP_NUM_THREADS')
432
- logger.info(f"OMP_NUM_THREADS is set. Using OMP_NUM_THREADS={expected_omp_threads} instead.")
523
+ if os.environ.get("OMP_NUM_THREADS"):
524
+ expected_omp_threads = os.environ.get("OMP_NUM_THREADS")
525
+ logger.info(
526
+ f"OMP_NUM_THREADS is set. Using OMP_NUM_THREADS={expected_omp_threads} instead."
527
+ )
433
528
  with Toil(options) as toil:
434
- output = toil.start(Job.wrapFn(get_omp_threads, memory='1Mi', cores=cores, disk='1Mi'))
529
+ output = toil.start(
530
+ Job.wrapFn(
531
+ get_omp_threads, memory="1Mi", cores=cores, disk="1Mi"
532
+ )
533
+ )
435
534
  self.assertEqual(output, expected_omp_threads)
436
535
 
437
536
  class AbstractGridEngineBatchSystemTest(AbstractBatchSystemTest):
@@ -444,9 +543,10 @@ class hidden:
444
543
  config = super()._createConfig()
445
544
  config.statePollingWait = 0.5 # Reduce polling wait so tests run faster
446
545
  # can't use _getTestJobStorePath since that method removes the directory
447
- config.jobStore = 'file:' + self._createTempDir('jobStore')
546
+ config.jobStore = "file:" + self._createTempDir("jobStore")
448
547
  return config
449
548
 
549
+
450
550
  @needs_kubernetes
451
551
  @needs_aws_s3
452
552
  @needs_fetchable_appliance
@@ -461,8 +561,11 @@ class KubernetesBatchSystemTest(hidden.AbstractBatchSystemTest):
461
561
  def createBatchSystem(self):
462
562
  # We know we have Kubernetes so we can import the batch system
463
563
  from toil.batchSystems.kubernetes import KubernetesBatchSystem
464
- return KubernetesBatchSystem(config=self.config,
465
- maxCores=numCores, maxMemory=1e9, maxDisk=2001)
564
+
565
+ return KubernetesBatchSystem(
566
+ config=self.config, maxCores=numCores, maxMemory=1e9, maxDisk=2001
567
+ )
568
+
466
569
 
467
570
  @needs_kubernetes_installed
468
571
  class KubernetesBatchSystemBenchTest(ToilTest):
@@ -486,7 +589,9 @@ class KubernetesBatchSystemBenchTest(ToilTest):
486
589
  constraints = KubernetesBatchSystem.Placement()
487
590
  constraints.set_preemptible(False)
488
591
  constraints.apply(normal_spec)
489
- self.assertEqual(textwrap.dedent("""
592
+ self.assertEqual(
593
+ textwrap.dedent(
594
+ """
490
595
  {'node_affinity': {'preferred_during_scheduling_ignored_during_execution': None,
491
596
  'required_during_scheduling_ignored_during_execution': {'node_selector_terms': [{'match_expressions': [{'key': 'eks.amazonaws.com/capacityType',
492
597
  'operator': 'NotIn',
@@ -497,14 +602,19 @@ class KubernetesBatchSystemBenchTest(ToilTest):
497
602
  'match_fields': None}]}},
498
603
  'pod_affinity': None,
499
604
  'pod_anti_affinity': None}
500
- """).strip(), str(normal_spec.affinity))
605
+ """
606
+ ).strip(),
607
+ str(normal_spec.affinity),
608
+ )
501
609
  self.assertEqual(str(normal_spec.tolerations), "None")
502
610
 
503
611
  spot_spec = V1PodSpec(containers=[])
504
612
  constraints = KubernetesBatchSystem.Placement()
505
613
  constraints.set_preemptible(True)
506
614
  constraints.apply(spot_spec)
507
- self.assertEqual(textwrap.dedent("""
615
+ self.assertEqual(
616
+ textwrap.dedent(
617
+ """
508
618
  {'node_affinity': {'preferred_during_scheduling_ignored_during_execution': [{'preference': {'match_expressions': [{'key': 'eks.amazonaws.com/capacityType',
509
619
  'operator': 'In',
510
620
  'values': ['SPOT']}],
@@ -518,14 +628,22 @@ class KubernetesBatchSystemBenchTest(ToilTest):
518
628
  'required_during_scheduling_ignored_during_execution': None},
519
629
  'pod_affinity': None,
520
630
  'pod_anti_affinity': None}
521
- """).strip(), str(spot_spec.affinity), )
522
- self.assertEqual(textwrap.dedent("""
631
+ """
632
+ ).strip(),
633
+ str(spot_spec.affinity),
634
+ )
635
+ self.assertEqual(
636
+ textwrap.dedent(
637
+ """
523
638
  [{'effect': None,
524
639
  'key': 'cloud.google.com/gke-preemptible',
525
640
  'operator': None,
526
641
  'toleration_seconds': None,
527
642
  'value': 'true'}]
528
- """).strip(), str(spot_spec.tolerations))
643
+ """
644
+ ).strip(),
645
+ str(spot_spec.tolerations),
646
+ )
529
647
 
530
648
  def test_label_constraints(self):
531
649
  """
@@ -541,11 +659,13 @@ class KubernetesBatchSystemBenchTest(ToilTest):
541
659
 
542
660
  spec = V1PodSpec(containers=[])
543
661
  constraints = KubernetesBatchSystem.Placement()
544
- constraints.required_labels = [('GottaBeSetTo', ['This'])]
545
- constraints.desired_labels = [('OutghtToBeSetTo', ['That'])]
546
- constraints.prohibited_labels = [('CannotBe', ['ABadThing'])]
662
+ constraints.required_labels = [("GottaBeSetTo", ["This"])]
663
+ constraints.desired_labels = [("OutghtToBeSetTo", ["That"])]
664
+ constraints.prohibited_labels = [("CannotBe", ["ABadThing"])]
547
665
  constraints.apply(spec)
548
- self.assertEqual(textwrap.dedent("""
666
+ self.assertEqual(
667
+ textwrap.dedent(
668
+ """
549
669
  {'node_affinity': {'preferred_during_scheduling_ignored_during_execution': [{'preference': {'match_expressions': [{'key': 'OutghtToBeSetTo',
550
670
  'operator': 'In',
551
671
  'values': ['That']}],
@@ -560,7 +680,10 @@ class KubernetesBatchSystemBenchTest(ToilTest):
560
680
  'match_fields': None}]}},
561
681
  'pod_affinity': None,
562
682
  'pod_anti_affinity': None}
563
- """).strip(), str(spec.affinity),)
683
+ """
684
+ ).strip(),
685
+ str(spec.affinity),
686
+ )
564
687
  self.assertEqual(str(spec.tolerations), "None")
565
688
 
566
689
 
@@ -576,13 +699,16 @@ class AWSBatchBatchSystemTest(hidden.AbstractBatchSystemTest):
576
699
 
577
700
  def createBatchSystem(self):
578
701
  from toil.batchSystems.awsBatch import AWSBatchBatchSystem
579
- return AWSBatchBatchSystem(config=self.config,
580
- maxCores=numCores, maxMemory=1e9, maxDisk=2001)
702
+
703
+ return AWSBatchBatchSystem(
704
+ config=self.config, maxCores=numCores, maxMemory=1e9, maxDisk=2001
705
+ )
581
706
 
582
707
  def get_max_startup_seconds(self) -> int:
583
708
  # AWS Batch may need to scale out the compute environment.
584
709
  return 300
585
710
 
711
+
586
712
  @slow
587
713
  @needs_mesos
588
714
  class MesosBatchSystemTest(hidden.AbstractBatchSystemTest, MesosTestSupport):
@@ -597,7 +723,7 @@ class MesosBatchSystemTest(hidden.AbstractBatchSystemTest, MesosTestSupport):
597
723
  private IP address
598
724
  """
599
725
  config = super().createConfig()
600
- config.mesos_endpoint = 'localhost:5050'
726
+ config.mesos_endpoint = "localhost:5050"
601
727
  return config
602
728
 
603
729
  def supportsWallTime(self):
@@ -606,19 +732,25 @@ class MesosBatchSystemTest(hidden.AbstractBatchSystemTest, MesosTestSupport):
606
732
  def createBatchSystem(self):
607
733
  # We know we have Mesos so we can import the batch system
608
734
  from toil.batchSystems.mesos.batchSystem import MesosBatchSystem
735
+
609
736
  self._startMesos(numCores)
610
- return MesosBatchSystem(config=self.config,
611
- maxCores=numCores, maxMemory=1e9, maxDisk=1001)
737
+ return MesosBatchSystem(
738
+ config=self.config, maxCores=numCores, maxMemory=1e9, maxDisk=1001
739
+ )
612
740
 
613
741
  def tearDown(self):
614
742
  self._stopMesos()
615
743
  super().tearDown()
616
744
 
617
745
  def testIgnoreNode(self):
618
- self.batchSystem.ignoreNode('localhost')
619
- jobDesc = self._mockJobDescription(jobName='test2', unitName=None,
620
- jobStoreID='1', requirements=defaultRequirements)
621
- job = self.batchSystem.issueBatchJob('sleep 1000', jobDesc)
746
+ self.batchSystem.ignoreNode("localhost")
747
+ jobDesc = self._mockJobDescription(
748
+ jobName="test2",
749
+ unitName=None,
750
+ jobStoreID="1",
751
+ requirements=defaultRequirements,
752
+ )
753
+ job = self.batchSystem.issueBatchJob("sleep 1000", jobDesc)
622
754
 
623
755
  issuedID = self._waitForJobsToIssue(1)
624
756
  self.assertEqual(set(issuedID), {job})
@@ -635,7 +767,7 @@ def write_temp_file(s: str, temp_dir: str) -> str:
635
767
  """
636
768
  fd, path = tempfile.mkstemp(dir=temp_dir)
637
769
  try:
638
- encoded = s.encode('utf-8')
770
+ encoded = s.encode("utf-8")
639
771
  assert os.write(fd, encoded) == len(encoded)
640
772
  except:
641
773
  os.unlink(path)
@@ -655,8 +787,9 @@ class SingleMachineBatchSystemTest(hidden.AbstractBatchSystemTest):
655
787
  return True
656
788
 
657
789
  def createBatchSystem(self) -> AbstractBatchSystem:
658
- return SingleMachineBatchSystem(config=self.config,
659
- maxCores=numCores, maxMemory=1e9, maxDisk=2001)
790
+ return SingleMachineBatchSystem(
791
+ config=self.config, maxCores=numCores, maxMemory=1e9, maxDisk=2001
792
+ )
660
793
 
661
794
  def testProcessEscape(self, hide: bool = False) -> None:
662
795
  """
@@ -677,14 +810,18 @@ class SingleMachineBatchSystemTest(hidden.AbstractBatchSystemTest):
677
810
  from typing import Any
678
811
 
679
812
  def handle_signal(sig: Any, frame: Any) -> None:
680
- sys.stderr.write(f'{os.getpid()} ignoring signal {sig}\n')
813
+ sys.stderr.write(f"{os.getpid()} ignoring signal {sig}\n")
681
814
 
682
- if hasattr(signal, 'valid_signals'):
815
+ if hasattr(signal, "valid_signals"):
683
816
  # We can just ask about the signals
684
817
  all_signals = signal.valid_signals()
685
818
  else:
686
819
  # Fish them out by name
687
- all_signals = [getattr(signal, n) for n in dir(signal) if n.startswith('SIG') and not n.startswith('SIG_')]
820
+ all_signals = [
821
+ getattr(signal, n)
822
+ for n in dir(signal)
823
+ if n.startswith("SIG") and not n.startswith("SIG_")
824
+ ]
688
825
 
689
826
  for sig in all_signals:
690
827
  # Set up to ignore all signals we can and generally be obstinate
@@ -706,7 +843,7 @@ class SingleMachineBatchSystemTest(hidden.AbstractBatchSystemTest):
706
843
  fd = os.open(sys.argv[1], os.O_RDONLY)
707
844
  fcntl.lockf(fd, fcntl.LOCK_SH)
708
845
 
709
- sys.stderr.write(f'{os.getpid()} waiting...\n')
846
+ sys.stderr.write(f"{os.getpid()} waiting...\n")
710
847
 
711
848
  while True:
712
849
  # Wait around forever
@@ -718,27 +855,26 @@ class SingleMachineBatchSystemTest(hidden.AbstractBatchSystemTest):
718
855
  script_path = write_temp_file(self._getScriptSource(script), temp_dir)
719
856
 
720
857
  # We will have all the job processes try and lock this file shared while they are alive.
721
- lockable_path = write_temp_file('', temp_dir)
858
+ lockable_path = write_temp_file("", temp_dir)
722
859
 
723
860
  try:
724
- command = f'{sys.executable} {script_path} {lockable_path}'
861
+ command = f"{sys.executable} {script_path} {lockable_path}"
725
862
  if hide:
726
863
  # Tell the children to stop the first child and hide out in the
727
864
  # process group it made.
728
- command += ' hide'
865
+ command += " hide"
729
866
 
730
867
  # Start the job
731
868
  self.batchSystem.issueBatchJob(
732
- command,
869
+ command,
733
870
  self._mockJobDescription(
734
- jobName='fork',
735
- jobStoreID='1',
736
- requirements=defaultRequirements)
871
+ jobName="fork", jobStoreID="1", requirements=defaultRequirements
872
+ ),
737
873
  )
738
874
  # Wait
739
875
  time.sleep(10)
740
876
 
741
- lockfile = open(lockable_path, 'w')
877
+ lockfile = open(lockable_path, "w")
742
878
 
743
879
  if not hide:
744
880
  # In hiding mode the job will finish, and the batch system will
@@ -793,13 +929,14 @@ class MaxCoresSingleMachineBatchSystemTest(ToilTest):
793
929
 
794
930
  # Write initial value of counter file containing a tuple of two integers (i, n) where i
795
931
  # is the number of currently executing tasks and n the maximum observed value of i
796
- self.counterPath = write_temp_file('0,0', temp_dir)
932
+ self.counterPath = write_temp_file("0,0", temp_dir)
797
933
 
798
934
  def script() -> None:
799
935
  import fcntl
800
936
  import os
801
937
  import sys
802
938
  import time
939
+
803
940
  def count(delta: int) -> None:
804
941
  """
805
942
  Adjust the first integer value in a file by the given amount. If the result
@@ -809,13 +946,14 @@ class MaxCoresSingleMachineBatchSystemTest(ToilTest):
809
946
  try:
810
947
  fcntl.flock(fd, fcntl.LOCK_EX)
811
948
  try:
812
- s = os.read(fd, 10).decode('utf-8')
813
- value, maxValue = list(map(int, s.split(',')))
949
+ s = os.read(fd, 10).decode("utf-8")
950
+ value, maxValue = list(map(int, s.split(",")))
814
951
  value += delta
815
- if value > maxValue: maxValue = value
952
+ if value > maxValue:
953
+ maxValue = value
816
954
  os.lseek(fd, 0, 0)
817
955
  os.ftruncate(fd, 0)
818
- os.write(fd, f'{value},{maxValue}'.encode())
956
+ os.write(fd, f"{value},{maxValue}".encode())
819
957
  finally:
820
958
  fcntl.flock(fd, fcntl.LOCK_UN)
821
959
  finally:
@@ -839,7 +977,7 @@ class MaxCoresSingleMachineBatchSystemTest(ToilTest):
839
977
  os.unlink(self.counterPath)
840
978
 
841
979
  def scriptCommand(self) -> str:
842
- return ' '.join([sys.executable, self.scriptPath, self.counterPath])
980
+ return " ".join([sys.executable, self.scriptPath, self.counterPath])
843
981
 
844
982
  @retry_flaky_test(prepare=[tearDown, setUp])
845
983
  def test(self):
@@ -851,7 +989,13 @@ class MaxCoresSingleMachineBatchSystemTest(ToilTest):
851
989
  minCores = F(1, 10)
852
990
  self.assertEqual(float(minCores), SingleMachineBatchSystem.minCores)
853
991
  for maxCores in {F(minCores), minCores * 10, F(1), F(numCores, 2), F(numCores)}:
854
- for coresPerJob in {F(minCores), F(minCores * 10), F(1), F(maxCores, 2), F(maxCores)}:
992
+ for coresPerJob in {
993
+ F(minCores),
994
+ F(minCores * 10),
995
+ F(1),
996
+ F(maxCores, 2),
997
+ F(maxCores),
998
+ }:
855
999
  for load in (F(1, 10), F(1), F(10)):
856
1000
  jobs = int(maxCores / coresPerJob * load)
857
1001
  if jobs >= 1 and minCores <= coresPerJob < maxCores:
@@ -861,7 +1005,8 @@ class MaxCoresSingleMachineBatchSystemTest(ToilTest):
861
1005
  maxCores=float(maxCores),
862
1006
  # Ensure that memory or disk requirements don't get in the way.
863
1007
  maxMemory=jobs * 10,
864
- maxDisk=jobs * 10)
1008
+ maxDisk=jobs * 10,
1009
+ )
865
1010
  try:
866
1011
  jobIds = set()
867
1012
  for i in range(0, int(jobs)):
@@ -871,48 +1016,62 @@ class MaxCoresSingleMachineBatchSystemTest(ToilTest):
871
1016
  memory=1,
872
1017
  disk=1,
873
1018
  accelerators=[],
874
- preemptible=preemptible
1019
+ preemptible=preemptible,
875
1020
  ),
876
1021
  jobName=str(i),
877
- unitName=''
1022
+ unitName="",
878
1023
  )
879
1024
  jobIds.add(bs.issueBatchJob(self.scriptCommand(), desc))
880
1025
  self.assertEqual(len(jobIds), jobs)
881
1026
  while jobIds:
882
1027
  job = bs.getUpdatedBatchJob(maxWait=10)
883
1028
  self.assertIsNotNone(job)
884
- jobId, status, wallTime = job.jobID, job.exitStatus, job.wallTime
1029
+ jobId, status, wallTime = (
1030
+ job.jobID,
1031
+ job.exitStatus,
1032
+ job.wallTime,
1033
+ )
885
1034
  self.assertEqual(status, 0)
886
1035
  # would raise KeyError on absence
887
1036
  jobIds.remove(jobId)
888
1037
  finally:
889
1038
  bs.shutdown()
890
- concurrentTasks, maxConcurrentTasks = getCounters(self.counterPath)
1039
+ concurrentTasks, maxConcurrentTasks = getCounters(
1040
+ self.counterPath
1041
+ )
891
1042
  self.assertEqual(concurrentTasks, 0)
892
- logger.info(f'maxCores: {maxCores}, '
893
- f'coresPerJob: {coresPerJob}, '
894
- f'load: {load}')
1043
+ logger.info(
1044
+ f"maxCores: {maxCores}, "
1045
+ f"coresPerJob: {coresPerJob}, "
1046
+ f"load: {load}"
1047
+ )
895
1048
  # This is the key assertion: we shouldn't run too many jobs.
896
1049
  # Because of nondeterminism we can't guarantee hitting the limit.
897
1050
  expectedMaxConcurrentTasks = min(maxCores // coresPerJob, jobs)
898
- self.assertLessEqual(maxConcurrentTasks, expectedMaxConcurrentTasks)
1051
+ self.assertLessEqual(
1052
+ maxConcurrentTasks, expectedMaxConcurrentTasks
1053
+ )
899
1054
  resetCounters(self.counterPath)
900
1055
 
901
- @skipIf(SingleMachineBatchSystem.numCores < 3, 'Need at least three cores to run this test')
1056
+ @skipIf(
1057
+ SingleMachineBatchSystem.numCores < 3,
1058
+ "Need at least three cores to run this test",
1059
+ )
902
1060
  def testServices(self):
903
1061
  options = Job.Runner.getDefaultOptions(self._getTestJobStorePath())
904
1062
  options.logLevel = "DEBUG"
905
1063
  options.maxCores = 3
906
1064
  self.assertTrue(options.maxCores <= SingleMachineBatchSystem.numCores)
907
1065
  Job.Runner.startToil(Job.wrapJobFn(parentJob, self.scriptCommand()), options)
908
- with open(self.counterPath, 'r+') as f:
1066
+ with open(self.counterPath, "r+") as f:
909
1067
  s = f.read()
910
- logger.info('Counter is %s', s)
1068
+ logger.info("Counter is %s", s)
911
1069
  self.assertEqual(getCounters(self.counterPath), (0, 3))
912
1070
 
913
1071
 
914
1072
  # Toil can use only top-level functions so we have to add them here:
915
1073
 
1074
+
916
1075
  def parentJob(job, cmd):
917
1076
  job.addChildJobFn(childJob, cmd)
918
1077
 
@@ -939,13 +1098,13 @@ class Service(Job.Service):
939
1098
  self.cmd = cmd
940
1099
 
941
1100
  def start(self, fileStore):
942
- subprocess.check_call(self.cmd + ' 1', shell=True)
1101
+ subprocess.check_call(self.cmd + " 1", shell=True)
943
1102
 
944
1103
  def check(self):
945
1104
  return True
946
1105
 
947
1106
  def stop(self, fileStore):
948
- subprocess.check_call(self.cmd + ' -1', shell=True)
1107
+ subprocess.check_call(self.cmd + " -1", shell=True)
949
1108
 
950
1109
 
951
1110
  @slow
@@ -957,14 +1116,17 @@ class GridEngineBatchSystemTest(hidden.AbstractGridEngineBatchSystemTest):
957
1116
 
958
1117
  def createBatchSystem(self) -> AbstractBatchSystem:
959
1118
  from toil.batchSystems.gridengine import GridEngineBatchSystem
960
- return GridEngineBatchSystem(config=self.config, maxCores=numCores, maxMemory=1000e9,
961
- maxDisk=1e9)
1119
+
1120
+ return GridEngineBatchSystem(
1121
+ config=self.config, maxCores=numCores, maxMemory=1000e9, maxDisk=1e9
1122
+ )
962
1123
 
963
1124
  def tearDown(self):
964
1125
  super().tearDown()
965
1126
  # Cleanup GridEngine output log file from qsub
966
1127
  from glob import glob
967
- for f in glob('toil_job*.o*'):
1128
+
1129
+ for f in glob("toil_job*.o*"):
968
1130
  os.unlink(f)
969
1131
 
970
1132
 
@@ -977,14 +1139,17 @@ class SlurmBatchSystemTest(hidden.AbstractGridEngineBatchSystemTest):
977
1139
 
978
1140
  def createBatchSystem(self) -> AbstractBatchSystem:
979
1141
  from toil.batchSystems.slurm import SlurmBatchSystem
980
- return SlurmBatchSystem(config=self.config, maxCores=numCores, maxMemory=1000e9,
981
- maxDisk=1e9)
1142
+
1143
+ return SlurmBatchSystem(
1144
+ config=self.config, maxCores=numCores, maxMemory=1000e9, maxDisk=1e9
1145
+ )
982
1146
 
983
1147
  def tearDown(self):
984
1148
  super().tearDown()
985
1149
  # Cleanup 'slurm-%j.out' produced by sbatch
986
1150
  from glob import glob
987
- for f in glob('slurm-*.out'):
1151
+
1152
+ for f in glob("slurm-*.out"):
988
1153
  os.unlink(f)
989
1154
 
990
1155
 
@@ -994,10 +1159,13 @@ class LSFBatchSystemTest(hidden.AbstractGridEngineBatchSystemTest):
994
1159
  """
995
1160
  Tests against the LSF batch system
996
1161
  """
1162
+
997
1163
  def createBatchSystem(self) -> AbstractBatchSystem:
998
1164
  from toil.batchSystems.lsf import LSFBatchSystem
999
- return LSFBatchSystem(config=self.config, maxCores=numCores,
1000
- maxMemory=1000e9, maxDisk=1e9)
1165
+
1166
+ return LSFBatchSystem(
1167
+ config=self.config, maxCores=numCores, maxMemory=1000e9, maxDisk=1e9
1168
+ )
1001
1169
 
1002
1170
 
1003
1171
  @slow
@@ -1010,19 +1178,22 @@ class TorqueBatchSystemTest(hidden.AbstractGridEngineBatchSystemTest):
1010
1178
  def _createDummyConfig(self):
1011
1179
  config = super()._createDummyConfig()
1012
1180
  # can't use _getTestJobStorePath since that method removes the directory
1013
- config.jobStore = self._createTempDir('jobStore')
1181
+ config.jobStore = self._createTempDir("jobStore")
1014
1182
  return config
1015
1183
 
1016
1184
  def createBatchSystem(self) -> AbstractBatchSystem:
1017
1185
  from toil.batchSystems.torque import TorqueBatchSystem
1018
- return TorqueBatchSystem(config=self.config, maxCores=numCores, maxMemory=1000e9,
1019
- maxDisk=1e9)
1186
+
1187
+ return TorqueBatchSystem(
1188
+ config=self.config, maxCores=numCores, maxMemory=1000e9, maxDisk=1e9
1189
+ )
1020
1190
 
1021
1191
  def tearDown(self):
1022
1192
  super().tearDown()
1023
1193
  # Cleanup 'toil_job-%j.out' produced by sbatch
1024
1194
  from glob import glob
1025
- for f in glob('toil_job_*.[oe]*'):
1195
+
1196
+ for f in glob("toil_job_*.[oe]*"):
1026
1197
  os.unlink(f)
1027
1198
 
1028
1199
 
@@ -1035,8 +1206,10 @@ class HTCondorBatchSystemTest(hidden.AbstractGridEngineBatchSystemTest):
1035
1206
 
1036
1207
  def createBatchSystem(self) -> AbstractBatchSystem:
1037
1208
  from toil.batchSystems.htcondor import HTCondorBatchSystem
1038
- return HTCondorBatchSystem(config=self.config, maxCores=numCores, maxMemory=1000e9,
1039
- maxDisk=1e9)
1209
+
1210
+ return HTCondorBatchSystem(
1211
+ config=self.config, maxCores=numCores, maxMemory=1000e9, maxDisk=1e9
1212
+ )
1040
1213
 
1041
1214
  def tearDown(self):
1042
1215
  super().tearDown()
@@ -1051,46 +1224,71 @@ class SingleMachineBatchSystemJobTest(hidden.AbstractBatchSystemJobTest):
1051
1224
  return "single_machine"
1052
1225
 
1053
1226
  @slow
1054
- @retry_flaky_test(prepare=[hidden.AbstractBatchSystemJobTest.tearDown, hidden.AbstractBatchSystemJobTest.setUp])
1227
+ @retry_flaky_test(
1228
+ prepare=[
1229
+ hidden.AbstractBatchSystemJobTest.tearDown,
1230
+ hidden.AbstractBatchSystemJobTest.setUp,
1231
+ ]
1232
+ )
1055
1233
  def testConcurrencyWithDisk(self):
1056
1234
  """
1057
1235
  Tests that the batch system is allocating disk resources properly
1058
1236
  """
1059
- tempDir = self._createTempDir('testFiles')
1237
+ tempDir = self._createTempDir("testFiles")
1060
1238
 
1061
1239
  options = Job.Runner.getDefaultOptions(self._getTestJobStorePath())
1062
1240
  options.workDir = tempDir
1063
1241
  from toil import physicalDisk
1242
+
1064
1243
  availableDisk = physicalDisk(options.workDir)
1065
- logger.info('Testing disk concurrency limits with %s disk space', availableDisk)
1244
+ logger.info("Testing disk concurrency limits with %s disk space", availableDisk)
1066
1245
  # More disk might become available by the time Toil starts, so we limit it here
1067
1246
  options.maxDisk = availableDisk
1068
1247
  options.batchSystem = self.batchSystemName
1069
1248
 
1070
- counterPath = os.path.join(tempDir, 'counter')
1249
+ counterPath = os.path.join(tempDir, "counter")
1071
1250
  resetCounters(counterPath)
1072
1251
  value, maxValue = getCounters(counterPath)
1073
1252
  assert (value, maxValue) == (0, 0)
1074
1253
 
1075
1254
  half_disk = availableDisk // 2
1076
1255
  more_than_half_disk = half_disk + 500
1077
- logger.info('Dividing into parts of %s and %s', half_disk, more_than_half_disk)
1256
+ logger.info("Dividing into parts of %s and %s", half_disk, more_than_half_disk)
1078
1257
 
1079
1258
  root = Job()
1080
1259
  # Physically, we're asking for 50% of disk and 50% of disk + 500bytes in the two jobs. The
1081
1260
  # batchsystem should not allow the 2 child jobs to run concurrently.
1082
- root.addChild(Job.wrapFn(measureConcurrency, counterPath, self.sleepTime, cores=1,
1083
- memory='1M', disk=half_disk))
1084
- root.addChild(Job.wrapFn(measureConcurrency, counterPath, self.sleepTime, cores=1,
1085
- memory='1M', disk=more_than_half_disk))
1261
+ root.addChild(
1262
+ Job.wrapFn(
1263
+ measureConcurrency,
1264
+ counterPath,
1265
+ self.sleepTime,
1266
+ cores=1,
1267
+ memory="1M",
1268
+ disk=half_disk,
1269
+ )
1270
+ )
1271
+ root.addChild(
1272
+ Job.wrapFn(
1273
+ measureConcurrency,
1274
+ counterPath,
1275
+ self.sleepTime,
1276
+ cores=1,
1277
+ memory="1M",
1278
+ disk=more_than_half_disk,
1279
+ )
1280
+ )
1086
1281
  Job.Runner.startToil(root, options)
1087
1282
  _, maxValue = getCounters(counterPath)
1088
1283
 
1089
- logger.info('After run: %s disk space', physicalDisk(options.workDir))
1284
+ logger.info("After run: %s disk space", physicalDisk(options.workDir))
1090
1285
 
1091
1286
  self.assertEqual(maxValue, 1)
1092
1287
 
1093
- @skipIf(SingleMachineBatchSystem.numCores < 4, 'Need at least four cores to run this test')
1288
+ @skipIf(
1289
+ SingleMachineBatchSystem.numCores < 4,
1290
+ "Need at least four cores to run this test",
1291
+ )
1094
1292
  @slow
1095
1293
  def testNestedResourcesDoNotBlock(self):
1096
1294
  """
@@ -1098,39 +1296,80 @@ class SingleMachineBatchSystemJobTest(hidden.AbstractBatchSystemJobTest):
1098
1296
  Test that unavailability of cpus for one job that is scheduled does not block another job
1099
1297
  that can run.
1100
1298
  """
1101
- tempDir = self._createTempDir('testFiles')
1299
+ tempDir = self._createTempDir("testFiles")
1102
1300
 
1103
1301
  options = Job.Runner.getDefaultOptions(self._getTestJobStorePath())
1104
1302
  options.workDir = tempDir
1105
1303
  options.maxCores = 4
1106
1304
  from toil import physicalMemory
1305
+
1107
1306
  availableMemory = physicalMemory()
1108
1307
  options.batchSystem = self.batchSystemName
1109
1308
 
1110
- outFile = os.path.join(tempDir, 'counter')
1111
- open(outFile, 'w').close()
1309
+ outFile = os.path.join(tempDir, "counter")
1310
+ open(outFile, "w").close()
1112
1311
 
1113
1312
  root = Job()
1114
1313
 
1115
- blocker = Job.wrapFn(_resourceBlockTestAuxFn, outFile=outFile, sleepTime=30, writeVal='b',
1116
- cores=2, memory='1M', disk='1M')
1117
- firstJob = Job.wrapFn(_resourceBlockTestAuxFn, outFile=outFile, sleepTime=5, writeVal='fJ',
1118
- cores=1, memory='1M', disk='1M')
1119
- secondJob = Job.wrapFn(_resourceBlockTestAuxFn, outFile=outFile, sleepTime=10,
1120
- writeVal='sJ', cores=1, memory='1M', disk='1M')
1314
+ blocker = Job.wrapFn(
1315
+ _resourceBlockTestAuxFn,
1316
+ outFile=outFile,
1317
+ sleepTime=30,
1318
+ writeVal="b",
1319
+ cores=2,
1320
+ memory="1M",
1321
+ disk="1M",
1322
+ )
1323
+ firstJob = Job.wrapFn(
1324
+ _resourceBlockTestAuxFn,
1325
+ outFile=outFile,
1326
+ sleepTime=5,
1327
+ writeVal="fJ",
1328
+ cores=1,
1329
+ memory="1M",
1330
+ disk="1M",
1331
+ )
1332
+ secondJob = Job.wrapFn(
1333
+ _resourceBlockTestAuxFn,
1334
+ outFile=outFile,
1335
+ sleepTime=10,
1336
+ writeVal="sJ",
1337
+ cores=1,
1338
+ memory="1M",
1339
+ disk="1M",
1340
+ )
1121
1341
 
1122
1342
  # Should block off 50% of memory while waiting for it's 3 cores
1123
- firstJobChild = Job.wrapFn(_resourceBlockTestAuxFn, outFile=outFile, sleepTime=0,
1124
- writeVal='fJC', cores=3, memory=int(availableMemory // 2), disk='1M')
1343
+ firstJobChild = Job.wrapFn(
1344
+ _resourceBlockTestAuxFn,
1345
+ outFile=outFile,
1346
+ sleepTime=0,
1347
+ writeVal="fJC",
1348
+ cores=3,
1349
+ memory=int(availableMemory // 2),
1350
+ disk="1M",
1351
+ )
1125
1352
 
1126
1353
  # These two shouldn't be able to run before B because there should be only
1127
1354
  # (50% of memory - 1M) available (firstJobChild should be blocking 50%)
1128
- secondJobChild = Job.wrapFn(_resourceBlockTestAuxFn, outFile=outFile, sleepTime=5,
1129
- writeVal='sJC', cores=2, memory=int(availableMemory // 1.5),
1130
- disk='1M')
1131
- secondJobGrandChild = Job.wrapFn(_resourceBlockTestAuxFn, outFile=outFile, sleepTime=5,
1132
- writeVal='sJGC', cores=2, memory=int(availableMemory // 1.5),
1133
- disk='1M')
1355
+ secondJobChild = Job.wrapFn(
1356
+ _resourceBlockTestAuxFn,
1357
+ outFile=outFile,
1358
+ sleepTime=5,
1359
+ writeVal="sJC",
1360
+ cores=2,
1361
+ memory=int(availableMemory // 1.5),
1362
+ disk="1M",
1363
+ )
1364
+ secondJobGrandChild = Job.wrapFn(
1365
+ _resourceBlockTestAuxFn,
1366
+ outFile=outFile,
1367
+ sleepTime=5,
1368
+ writeVal="sJGC",
1369
+ cores=2,
1370
+ memory=int(availableMemory // 1.5),
1371
+ disk="1M",
1372
+ )
1134
1373
 
1135
1374
  root.addChild(blocker)
1136
1375
  root.addChild(firstJob)
@@ -1160,9 +1399,11 @@ class SingleMachineBatchSystemJobTest(hidden.AbstractBatchSystemJobTest):
1160
1399
  outString = oFH.read()
1161
1400
  # The ordering of b, fJ and sJ is non-deterministic since they are scheduled at the same
1162
1401
  # time. We look for all possible permutations.
1163
- possibleStarts = tuple(''.join(x) for x in itertools.permutations(['b', 'fJ', 'sJ']))
1402
+ possibleStarts = tuple(
1403
+ "".join(x) for x in itertools.permutations(["b", "fJ", "sJ"])
1404
+ )
1164
1405
  assert outString.startswith(possibleStarts)
1165
- assert outString.endswith('sJCsJGCfJC')
1406
+ assert outString.endswith("sJCsJGCfJC")
1166
1407
 
1167
1408
 
1168
1409
  def _resourceBlockTestAuxFn(outFile, sleepTime, writeVal):
@@ -1172,7 +1413,7 @@ def _resourceBlockTestAuxFn(outFile, sleepTime, writeVal):
1172
1413
  :param int sleepTime: Time to sleep for
1173
1414
  :param str writeVal: Character to write
1174
1415
  """
1175
- with open(outFile, 'a') as oFH:
1416
+ with open(outFile, "a") as oFH:
1176
1417
  fcntl.flock(oFH, fcntl.LOCK_EX)
1177
1418
  oFH.write(writeVal)
1178
1419
  time.sleep(sleepTime)
@@ -1184,9 +1425,10 @@ class MesosBatchSystemJobTest(hidden.AbstractBatchSystemJobTest, MesosTestSuppor
1184
1425
  """
1185
1426
  Tests Toil workflow against the Mesos batch system
1186
1427
  """
1428
+
1187
1429
  def getOptions(self, tempDir):
1188
1430
  options = super().getOptions(tempDir)
1189
- options.mesos_endpoint = 'localhost:5050'
1431
+ options.mesos_endpoint = "localhost:5050"
1190
1432
  return options
1191
1433
 
1192
1434
  def getBatchSystemName(self):
@@ -1227,12 +1469,13 @@ def count(delta, file_path):
1227
1469
  fcntl.flock(fd, fcntl.LOCK_EX)
1228
1470
  try:
1229
1471
  s = os.read(fd, 10)
1230
- value, maxValue = (int(i) for i in s.decode('utf-8').split(','))
1472
+ value, maxValue = (int(i) for i in s.decode("utf-8").split(","))
1231
1473
  value += delta
1232
- if value > maxValue: maxValue = value
1474
+ if value > maxValue:
1475
+ maxValue = value
1233
1476
  os.lseek(fd, 0, 0)
1234
1477
  os.ftruncate(fd, 0)
1235
- os.write(fd, f'{value},{maxValue}'.encode())
1478
+ os.write(fd, f"{value},{maxValue}".encode())
1236
1479
  finally:
1237
1480
  fcntl.flock(fd, fcntl.LOCK_UN)
1238
1481
  finally:
@@ -1241,8 +1484,8 @@ def count(delta, file_path):
1241
1484
 
1242
1485
 
1243
1486
  def getCounters(path):
1244
- with open(path, 'r+') as f:
1245
- concurrentTasks, maxConcurrentTasks = (int(i) for i in f.read().split(','))
1487
+ with open(path, "r+") as f:
1488
+ concurrentTasks, maxConcurrentTasks = (int(i) for i in f.read().split(","))
1246
1489
  return concurrentTasks, maxConcurrentTasks
1247
1490
 
1248
1491
 
@@ -1253,4 +1496,4 @@ def resetCounters(path):
1253
1496
 
1254
1497
 
1255
1498
  def get_omp_threads() -> str:
1256
- return os.environ['OMP_NUM_THREADS']
1499
+ return os.environ["OMP_NUM_THREADS"]