toil 8.0.0__py3-none-any.whl → 8.2.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 (270) hide show
  1. toil/__init__.py +4 -39
  2. toil/batchSystems/abstractBatchSystem.py +1 -1
  3. toil/batchSystems/abstractGridEngineBatchSystem.py +1 -1
  4. toil/batchSystems/awsBatch.py +1 -1
  5. toil/batchSystems/cleanup_support.py +1 -1
  6. toil/batchSystems/kubernetes.py +53 -7
  7. toil/batchSystems/local_support.py +1 -1
  8. toil/batchSystems/mesos/batchSystem.py +13 -8
  9. toil/batchSystems/mesos/test/__init__.py +3 -2
  10. toil/batchSystems/options.py +1 -0
  11. toil/batchSystems/singleMachine.py +1 -1
  12. toil/batchSystems/slurm.py +229 -84
  13. toil/bus.py +5 -3
  14. toil/common.py +198 -54
  15. toil/cwl/cwltoil.py +32 -11
  16. toil/job.py +110 -86
  17. toil/jobStores/abstractJobStore.py +24 -3
  18. toil/jobStores/aws/jobStore.py +46 -10
  19. toil/jobStores/fileJobStore.py +25 -1
  20. toil/jobStores/googleJobStore.py +104 -30
  21. toil/leader.py +9 -0
  22. toil/lib/accelerators.py +3 -1
  23. toil/lib/aws/session.py +14 -3
  24. toil/lib/aws/utils.py +92 -35
  25. toil/lib/aws/utils.py.orig +504 -0
  26. toil/lib/bioio.py +1 -1
  27. toil/lib/docker.py +252 -91
  28. toil/lib/dockstore.py +387 -0
  29. toil/lib/ec2nodes.py +3 -2
  30. toil/lib/exceptions.py +5 -3
  31. toil/lib/history.py +1345 -0
  32. toil/lib/history_submission.py +695 -0
  33. toil/lib/io.py +56 -23
  34. toil/lib/misc.py +25 -1
  35. toil/lib/resources.py +2 -1
  36. toil/lib/retry.py +10 -10
  37. toil/lib/threading.py +11 -10
  38. toil/lib/{integration.py → trs.py} +95 -46
  39. toil/lib/web.py +38 -0
  40. toil/options/common.py +25 -2
  41. toil/options/cwl.py +10 -0
  42. toil/options/wdl.py +11 -0
  43. toil/provisioners/gceProvisioner.py +4 -4
  44. toil/server/api_spec/LICENSE +201 -0
  45. toil/server/api_spec/README.rst +5 -0
  46. toil/server/cli/wes_cwl_runner.py +5 -4
  47. toil/server/utils.py +2 -3
  48. toil/statsAndLogging.py +35 -1
  49. toil/test/__init__.py +275 -115
  50. toil/test/batchSystems/batchSystemTest.py +227 -205
  51. toil/test/batchSystems/test_slurm.py +199 -2
  52. toil/test/cactus/pestis.tar.gz +0 -0
  53. toil/test/conftest.py +7 -0
  54. toil/test/cwl/2.fasta +11 -0
  55. toil/test/cwl/2.fastq +12 -0
  56. toil/test/cwl/conftest.py +39 -0
  57. toil/test/cwl/cwlTest.py +1015 -780
  58. toil/test/cwl/directory/directory/file.txt +15 -0
  59. toil/test/cwl/download_directory_file.json +4 -0
  60. toil/test/cwl/download_directory_s3.json +4 -0
  61. toil/test/cwl/download_file.json +6 -0
  62. toil/test/cwl/download_http.json +6 -0
  63. toil/test/cwl/download_https.json +6 -0
  64. toil/test/cwl/download_s3.json +6 -0
  65. toil/test/cwl/download_subdirectory_file.json +5 -0
  66. toil/test/cwl/download_subdirectory_s3.json +5 -0
  67. toil/test/cwl/empty.json +1 -0
  68. toil/test/cwl/mock_mpi/fake_mpi.yml +8 -0
  69. toil/test/cwl/mock_mpi/fake_mpi_run.py +42 -0
  70. toil/test/cwl/optional-file-exists.json +6 -0
  71. toil/test/cwl/optional-file-missing.json +6 -0
  72. toil/test/cwl/optional-file.cwl +18 -0
  73. toil/test/cwl/preemptible_expression.json +1 -0
  74. toil/test/cwl/revsort-job-missing.json +6 -0
  75. toil/test/cwl/revsort-job.json +6 -0
  76. toil/test/cwl/s3_secondary_file.json +16 -0
  77. toil/test/cwl/seqtk_seq_job.json +6 -0
  78. toil/test/cwl/stream.json +6 -0
  79. toil/test/cwl/test_filename_conflict_resolution.ms/table.dat +0 -0
  80. toil/test/cwl/test_filename_conflict_resolution.ms/table.f0 +0 -0
  81. toil/test/cwl/test_filename_conflict_resolution.ms/table.f1 +0 -0
  82. toil/test/cwl/test_filename_conflict_resolution.ms/table.f1i +0 -0
  83. toil/test/cwl/test_filename_conflict_resolution.ms/table.f2 +0 -0
  84. toil/test/cwl/test_filename_conflict_resolution.ms/table.f2_TSM0 +0 -0
  85. toil/test/cwl/test_filename_conflict_resolution.ms/table.f3 +0 -0
  86. toil/test/cwl/test_filename_conflict_resolution.ms/table.f3_TSM0 +0 -0
  87. toil/test/cwl/test_filename_conflict_resolution.ms/table.f4 +0 -0
  88. toil/test/cwl/test_filename_conflict_resolution.ms/table.f4_TSM0 +0 -0
  89. toil/test/cwl/test_filename_conflict_resolution.ms/table.f5 +0 -0
  90. toil/test/cwl/test_filename_conflict_resolution.ms/table.info +0 -0
  91. toil/test/cwl/test_filename_conflict_resolution.ms/table.lock +0 -0
  92. toil/test/cwl/whale.txt +16 -0
  93. toil/test/docs/scripts/example_alwaysfail.py +38 -0
  94. toil/test/docs/scripts/example_alwaysfail_with_files.wdl +33 -0
  95. toil/test/docs/scripts/example_cachingbenchmark.py +117 -0
  96. toil/test/docs/scripts/stagingExampleFiles/in.txt +1 -0
  97. toil/test/docs/scripts/stagingExampleFiles/out.txt +2 -0
  98. toil/test/docs/scripts/tutorial_arguments.py +23 -0
  99. toil/test/docs/scripts/tutorial_debugging.patch +12 -0
  100. toil/test/docs/scripts/tutorial_debugging_hangs.wdl +126 -0
  101. toil/test/docs/scripts/tutorial_debugging_works.wdl +129 -0
  102. toil/test/docs/scripts/tutorial_docker.py +20 -0
  103. toil/test/docs/scripts/tutorial_dynamic.py +24 -0
  104. toil/test/docs/scripts/tutorial_encapsulation.py +28 -0
  105. toil/test/docs/scripts/tutorial_encapsulation2.py +29 -0
  106. toil/test/docs/scripts/tutorial_helloworld.py +15 -0
  107. toil/test/docs/scripts/tutorial_invokeworkflow.py +27 -0
  108. toil/test/docs/scripts/tutorial_invokeworkflow2.py +30 -0
  109. toil/test/docs/scripts/tutorial_jobfunctions.py +22 -0
  110. toil/test/docs/scripts/tutorial_managing.py +29 -0
  111. toil/test/docs/scripts/tutorial_managing2.py +56 -0
  112. toil/test/docs/scripts/tutorial_multiplejobs.py +25 -0
  113. toil/test/docs/scripts/tutorial_multiplejobs2.py +21 -0
  114. toil/test/docs/scripts/tutorial_multiplejobs3.py +22 -0
  115. toil/test/docs/scripts/tutorial_promises.py +25 -0
  116. toil/test/docs/scripts/tutorial_promises2.py +30 -0
  117. toil/test/docs/scripts/tutorial_quickstart.py +22 -0
  118. toil/test/docs/scripts/tutorial_requirements.py +44 -0
  119. toil/test/docs/scripts/tutorial_services.py +45 -0
  120. toil/test/docs/scripts/tutorial_staging.py +45 -0
  121. toil/test/docs/scripts/tutorial_stats.py +64 -0
  122. toil/test/lib/aws/test_iam.py +3 -1
  123. toil/test/lib/dockerTest.py +205 -122
  124. toil/test/lib/test_history.py +236 -0
  125. toil/test/lib/test_trs.py +161 -0
  126. toil/test/provisioners/aws/awsProvisionerTest.py +12 -9
  127. toil/test/provisioners/clusterTest.py +4 -4
  128. toil/test/provisioners/gceProvisionerTest.py +16 -14
  129. toil/test/sort/sort.py +4 -1
  130. toil/test/src/busTest.py +17 -17
  131. toil/test/src/deferredFunctionTest.py +145 -132
  132. toil/test/src/importExportFileTest.py +71 -63
  133. toil/test/src/jobEncapsulationTest.py +27 -28
  134. toil/test/src/jobServiceTest.py +149 -133
  135. toil/test/src/jobTest.py +219 -211
  136. toil/test/src/miscTests.py +66 -60
  137. toil/test/src/promisedRequirementTest.py +163 -169
  138. toil/test/src/regularLogTest.py +24 -24
  139. toil/test/src/resourceTest.py +82 -76
  140. toil/test/src/restartDAGTest.py +51 -47
  141. toil/test/src/resumabilityTest.py +24 -19
  142. toil/test/src/retainTempDirTest.py +60 -57
  143. toil/test/src/systemTest.py +17 -13
  144. toil/test/src/threadingTest.py +29 -32
  145. toil/test/utils/ABCWorkflowDebug/B_file.txt +1 -0
  146. toil/test/utils/ABCWorkflowDebug/debugWorkflow.py +204 -0
  147. toil/test/utils/ABCWorkflowDebug/mkFile.py +16 -0
  148. toil/test/utils/ABCWorkflowDebug/sleep.cwl +12 -0
  149. toil/test/utils/ABCWorkflowDebug/sleep.yaml +1 -0
  150. toil/test/utils/toilDebugTest.py +117 -102
  151. toil/test/utils/toilKillTest.py +54 -53
  152. toil/test/utils/utilsTest.py +303 -229
  153. toil/test/wdl/lint_error.wdl +9 -0
  154. toil/test/wdl/md5sum/empty_file.json +1 -0
  155. toil/test/wdl/md5sum/md5sum-gs.json +1 -0
  156. toil/test/wdl/md5sum/md5sum.1.0.wdl +32 -0
  157. toil/test/wdl/md5sum/md5sum.input +1 -0
  158. toil/test/wdl/md5sum/md5sum.json +1 -0
  159. toil/test/wdl/md5sum/md5sum.wdl +25 -0
  160. toil/test/wdl/miniwdl_self_test/inputs-namespaced.json +1 -0
  161. toil/test/wdl/miniwdl_self_test/inputs.json +1 -0
  162. toil/test/wdl/miniwdl_self_test/self_test.wdl +40 -0
  163. toil/test/wdl/standard_library/as_map.json +16 -0
  164. toil/test/wdl/standard_library/as_map_as_input.wdl +23 -0
  165. toil/test/wdl/standard_library/as_pairs.json +7 -0
  166. toil/test/wdl/standard_library/as_pairs_as_input.wdl +23 -0
  167. toil/test/wdl/standard_library/ceil.json +3 -0
  168. toil/test/wdl/standard_library/ceil_as_command.wdl +16 -0
  169. toil/test/wdl/standard_library/ceil_as_input.wdl +16 -0
  170. toil/test/wdl/standard_library/collect_by_key.json +1 -0
  171. toil/test/wdl/standard_library/collect_by_key_as_input.wdl +23 -0
  172. toil/test/wdl/standard_library/cross.json +11 -0
  173. toil/test/wdl/standard_library/cross_as_input.wdl +19 -0
  174. toil/test/wdl/standard_library/flatten.json +7 -0
  175. toil/test/wdl/standard_library/flatten_as_input.wdl +18 -0
  176. toil/test/wdl/standard_library/floor.json +3 -0
  177. toil/test/wdl/standard_library/floor_as_command.wdl +16 -0
  178. toil/test/wdl/standard_library/floor_as_input.wdl +16 -0
  179. toil/test/wdl/standard_library/keys.json +8 -0
  180. toil/test/wdl/standard_library/keys_as_input.wdl +24 -0
  181. toil/test/wdl/standard_library/length.json +7 -0
  182. toil/test/wdl/standard_library/length_as_input.wdl +16 -0
  183. toil/test/wdl/standard_library/length_as_input_with_map.json +7 -0
  184. toil/test/wdl/standard_library/length_as_input_with_map.wdl +17 -0
  185. toil/test/wdl/standard_library/length_invalid.json +3 -0
  186. toil/test/wdl/standard_library/range.json +3 -0
  187. toil/test/wdl/standard_library/range_0.json +3 -0
  188. toil/test/wdl/standard_library/range_as_input.wdl +17 -0
  189. toil/test/wdl/standard_library/range_invalid.json +3 -0
  190. toil/test/wdl/standard_library/read_boolean.json +3 -0
  191. toil/test/wdl/standard_library/read_boolean_as_command.wdl +17 -0
  192. toil/test/wdl/standard_library/read_float.json +3 -0
  193. toil/test/wdl/standard_library/read_float_as_command.wdl +17 -0
  194. toil/test/wdl/standard_library/read_int.json +3 -0
  195. toil/test/wdl/standard_library/read_int_as_command.wdl +17 -0
  196. toil/test/wdl/standard_library/read_json.json +3 -0
  197. toil/test/wdl/standard_library/read_json_as_output.wdl +31 -0
  198. toil/test/wdl/standard_library/read_lines.json +3 -0
  199. toil/test/wdl/standard_library/read_lines_as_output.wdl +31 -0
  200. toil/test/wdl/standard_library/read_map.json +3 -0
  201. toil/test/wdl/standard_library/read_map_as_output.wdl +31 -0
  202. toil/test/wdl/standard_library/read_string.json +3 -0
  203. toil/test/wdl/standard_library/read_string_as_command.wdl +17 -0
  204. toil/test/wdl/standard_library/read_tsv.json +3 -0
  205. toil/test/wdl/standard_library/read_tsv_as_output.wdl +31 -0
  206. toil/test/wdl/standard_library/round.json +3 -0
  207. toil/test/wdl/standard_library/round_as_command.wdl +16 -0
  208. toil/test/wdl/standard_library/round_as_input.wdl +16 -0
  209. toil/test/wdl/standard_library/size.json +3 -0
  210. toil/test/wdl/standard_library/size_as_command.wdl +17 -0
  211. toil/test/wdl/standard_library/size_as_output.wdl +36 -0
  212. toil/test/wdl/standard_library/stderr.json +3 -0
  213. toil/test/wdl/standard_library/stderr_as_output.wdl +30 -0
  214. toil/test/wdl/standard_library/stdout.json +3 -0
  215. toil/test/wdl/standard_library/stdout_as_output.wdl +30 -0
  216. toil/test/wdl/standard_library/sub.json +3 -0
  217. toil/test/wdl/standard_library/sub_as_input.wdl +17 -0
  218. toil/test/wdl/standard_library/sub_as_input_with_file.wdl +17 -0
  219. toil/test/wdl/standard_library/transpose.json +6 -0
  220. toil/test/wdl/standard_library/transpose_as_input.wdl +18 -0
  221. toil/test/wdl/standard_library/write_json.json +6 -0
  222. toil/test/wdl/standard_library/write_json_as_command.wdl +17 -0
  223. toil/test/wdl/standard_library/write_lines.json +7 -0
  224. toil/test/wdl/standard_library/write_lines_as_command.wdl +17 -0
  225. toil/test/wdl/standard_library/write_map.json +6 -0
  226. toil/test/wdl/standard_library/write_map_as_command.wdl +17 -0
  227. toil/test/wdl/standard_library/write_tsv.json +6 -0
  228. toil/test/wdl/standard_library/write_tsv_as_command.wdl +17 -0
  229. toil/test/wdl/standard_library/zip.json +12 -0
  230. toil/test/wdl/standard_library/zip_as_input.wdl +19 -0
  231. toil/test/wdl/test.csv +3 -0
  232. toil/test/wdl/test.tsv +3 -0
  233. toil/test/wdl/testfiles/croo.wdl +38 -0
  234. toil/test/wdl/testfiles/drop_files.wdl +62 -0
  235. toil/test/wdl/testfiles/drop_files_subworkflow.wdl +13 -0
  236. toil/test/wdl/testfiles/empty.txt +0 -0
  237. toil/test/wdl/testfiles/not_enough_outputs.wdl +33 -0
  238. toil/test/wdl/testfiles/random.wdl +66 -0
  239. toil/test/wdl/testfiles/string_file_coercion.json +1 -0
  240. toil/test/wdl/testfiles/string_file_coercion.wdl +35 -0
  241. toil/test/wdl/testfiles/test.json +4 -0
  242. toil/test/wdl/testfiles/test_boolean.txt +1 -0
  243. toil/test/wdl/testfiles/test_float.txt +1 -0
  244. toil/test/wdl/testfiles/test_int.txt +1 -0
  245. toil/test/wdl/testfiles/test_lines.txt +5 -0
  246. toil/test/wdl/testfiles/test_map.txt +2 -0
  247. toil/test/wdl/testfiles/test_string.txt +1 -0
  248. toil/test/wdl/testfiles/url_to_file.wdl +13 -0
  249. toil/test/wdl/testfiles/url_to_optional_file.wdl +13 -0
  250. toil/test/wdl/testfiles/vocab.json +1 -0
  251. toil/test/wdl/testfiles/vocab.wdl +66 -0
  252. toil/test/wdl/testfiles/wait.wdl +34 -0
  253. toil/test/wdl/wdl_specification/type_pair.json +23 -0
  254. toil/test/wdl/wdl_specification/type_pair_basic.wdl +36 -0
  255. toil/test/wdl/wdl_specification/type_pair_with_files.wdl +36 -0
  256. toil/test/wdl/wdl_specification/v1_spec.json +1 -0
  257. toil/test/wdl/wdl_specification/v1_spec_declaration.wdl +39 -0
  258. toil/test/wdl/wdltoil_test.py +681 -408
  259. toil/test/wdl/wdltoil_test_kubernetes.py +2 -2
  260. toil/version.py +10 -10
  261. toil/wdl/wdltoil.py +350 -123
  262. toil/worker.py +113 -33
  263. {toil-8.0.0.dist-info → toil-8.2.0.dist-info}/METADATA +13 -7
  264. toil-8.2.0.dist-info/RECORD +439 -0
  265. {toil-8.0.0.dist-info → toil-8.2.0.dist-info}/WHEEL +1 -1
  266. toil/test/lib/test_integration.py +0 -104
  267. toil-8.0.0.dist-info/RECORD +0 -253
  268. {toil-8.0.0.dist-info → toil-8.2.0.dist-info}/entry_points.txt +0 -0
  269. {toil-8.0.0.dist-info → toil-8.2.0.dist-info/licenses}/LICENSE +0 -0
  270. {toil-8.0.0.dist-info → toil-8.2.0.dist-info}/top_level.txt +0 -0
@@ -11,10 +11,13 @@
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
+ from collections.abc import Iterable, Generator
15
+ import argparse
14
16
  import fcntl
15
17
  import itertools
16
18
  import logging
17
19
  import os
20
+ from pathlib import Path
18
21
  import subprocess
19
22
  import sys
20
23
  import tempfile
@@ -23,6 +26,7 @@ import time
23
26
  from abc import ABCMeta, abstractmethod
24
27
  from fractions import Fraction
25
28
  from unittest import skipIf
29
+ from typing import Optional, Any, TYPE_CHECKING
26
30
 
27
31
  from toil.batchSystems.abstractBatchSystem import (
28
32
  AbstractBatchSystem,
@@ -43,7 +47,9 @@ from toil.batchSystems.registry import (
43
47
  )
44
48
  from toil.batchSystems.singleMachine import SingleMachineBatchSystem
45
49
  from toil.common import Config, Toil
46
- from toil.job import Job, JobDescription, Requirer
50
+ from toil.fileStores.abstractFileStore import AbstractFileStore
51
+ from toil.job import Job, JobDescription, Requirer, ServiceHostJob
52
+ from toil.lib.misc import StrPath
47
53
  from toil.lib.retry import retry_flaky_test
48
54
  from toil.lib.threading import cpu_count
49
55
  from toil.test import (
@@ -60,8 +66,16 @@ from toil.test import (
60
66
  needs_slurm,
61
67
  needs_torque,
62
68
  slow,
69
+ pslow,
70
+ pneeds_mesos,
63
71
  )
64
72
 
73
+ import pytest
74
+
75
+ if TYPE_CHECKING:
76
+ from toil.batchSystems.mesos.batchSystem import MesosBatchSystem
77
+
78
+
65
79
  logger = logging.getLogger(__name__)
66
80
 
67
81
  # How many cores should be utilized by this test. The test will fail if the running system
@@ -83,19 +97,19 @@ class BatchSystemPluginTest(ToilTest):
83
97
  Class for testing batch system plugin functionality.
84
98
  """
85
99
 
86
- def setUp(self):
100
+ def setUp(self) -> None:
87
101
  # Save plugin state so our plugin doesn't stick around after the test
88
102
  # (and create duplicate options)
89
103
  self.__state = save_batch_system_plugin_state()
90
104
  super().setUp()
91
105
 
92
- def tearDown(self):
106
+ def tearDown(self) -> None:
93
107
  # Restore plugin state
94
108
  restore_batch_system_plugin_state(self.__state)
95
109
  super().tearDown()
96
110
 
97
- def test_add_batch_system_factory(self):
98
- def test_batch_system_factory():
111
+ def test_add_batch_system_factory(self) -> None:
112
+ def test_batch_system_factory() -> type[SingleMachineBatchSystem]:
99
113
  # TODO: Adding the same batch system under multiple names means we
100
114
  # can't actually create Toil options, because each version tries to
101
115
  # add its arguments.
@@ -112,7 +126,6 @@ class hidden:
112
126
 
113
127
  http://stackoverflow.com/questions/1323455/python-unit-test-with-base-and-sub-class#answer-25695512
114
128
  """
115
-
116
129
  class AbstractBatchSystemTest(ToilTest, metaclass=ABCMeta):
117
130
  """
118
131
  A base test case with generic tests that every batch system should pass.
@@ -124,11 +137,11 @@ class hidden:
124
137
  def createBatchSystem(self) -> AbstractBatchSystem:
125
138
  raise NotImplementedError
126
139
 
127
- def supportsWallTime(self):
140
+ def supportsWallTime(self) -> bool:
128
141
  return False
129
142
 
130
143
  @classmethod
131
- def createConfig(cls):
144
+ def createConfig(cls) -> Config:
132
145
  """
133
146
  Returns a dummy config for the batch system tests. We need a workflowID to be set up
134
147
  since we are running tests without setting up a jobstore. This is the class version
@@ -143,7 +156,7 @@ class hidden:
143
156
  config.cleanWorkDir = "always"
144
157
  return config
145
158
 
146
- def _createConfig(self):
159
+ def _createConfig(self) -> Config:
147
160
  """
148
161
  Returns a dummy config for the batch system tests. We need a workflowID to be set up
149
162
  since we are running tests without setting up a jobstore.
@@ -152,7 +165,9 @@ class hidden:
152
165
  """
153
166
  return self.createConfig()
154
167
 
155
- def _mockJobDescription(self, jobStoreID=None, **kwargs):
168
+ def _mockJobDescription(
169
+ self, jobStoreID: Optional[str] = None, **kwargs: Any
170
+ ) -> JobDescription:
156
171
  """
157
172
  Create a mock-up JobDescription with the given ID and other parameters.
158
173
  """
@@ -168,17 +183,17 @@ class hidden:
168
183
  return desc
169
184
 
170
185
  @classmethod
171
- def setUpClass(cls):
186
+ def setUpClass(cls) -> None:
172
187
  super().setUpClass()
173
188
  logging.basicConfig(level=logging.DEBUG)
174
189
 
175
- def setUp(self):
190
+ def setUp(self) -> None:
176
191
  super().setUp()
177
192
  self.config = self._createConfig()
178
193
  self.batchSystem = self.createBatchSystem()
179
194
  self.tempDir = self._createTempDir("testFiles")
180
195
 
181
- def tearDown(self):
196
+ def tearDown(self) -> None:
182
197
  self.batchSystem.shutdown()
183
198
  super().tearDown()
184
199
 
@@ -189,11 +204,11 @@ class hidden:
189
204
  """
190
205
  return 120
191
206
 
192
- def test_available_cores(self):
207
+ def test_available_cores(self) -> None:
193
208
  self.assertTrue(cpu_count() >= numCores)
194
209
 
195
210
  @retry_flaky_test(prepare=[tearDown, setUp])
196
- def test_run_jobs(self):
211
+ def test_run_jobs(self) -> None:
197
212
  jobDesc1 = self._mockJobDescription(
198
213
  jobName="test1",
199
214
  unitName=None,
@@ -247,6 +262,7 @@ class hidden:
247
262
  job3 = self.batchSystem.issueBatchJob("mktemp -d", jobDesc3)
248
263
 
249
264
  jobUpdateInfo = self.batchSystem.getUpdatedBatchJob(maxWait=1000)
265
+ assert jobUpdateInfo is not None
250
266
  jobID, exitStatus, wallTime = (
251
267
  jobUpdateInfo.jobID,
252
268
  jobUpdateInfo.exitStatus,
@@ -260,6 +276,7 @@ class hidden:
260
276
  self.assertEqual(jobID, job3)
261
277
  self.assertEqual(exitStatus, 0)
262
278
  if self.supportsWallTime():
279
+ assert wallTime is not None
263
280
  self.assertTrue(wallTime > 0)
264
281
  else:
265
282
  self.assertIsNone(wallTime)
@@ -270,7 +287,7 @@ class hidden:
270
287
  # Make sure killBatchJobs can handle jobs that don't exist
271
288
  self.batchSystem.killBatchJobs([10])
272
289
 
273
- def test_set_env(self):
290
+ def test_set_env(self) -> None:
274
291
  # Start with a relatively safe script
275
292
  script_shell = (
276
293
  'if [ "x${FOO}" == "xbar" ] ; then exit 23 ; else exit 42 ; fi'
@@ -289,6 +306,7 @@ class hidden:
289
306
  )
290
307
  job4 = self.batchSystem.issueBatchJob(command, jobDesc4)
291
308
  jobUpdateInfo = self.batchSystem.getUpdatedBatchJob(maxWait=1000)
309
+ assert jobUpdateInfo is not None
292
310
  jobID, exitStatus, wallTime = (
293
311
  jobUpdateInfo.jobID,
294
312
  jobUpdateInfo.exitStatus,
@@ -305,11 +323,12 @@ class hidden:
305
323
  requirements=defaultRequirements,
306
324
  )
307
325
  job5 = self.batchSystem.issueBatchJob(command, jobDesc5)
308
- jobUpdateInfo = self.batchSystem.getUpdatedBatchJob(maxWait=1000)
309
- self.assertEqual(jobUpdateInfo.exitStatus, 23)
310
- self.assertEqual(jobUpdateInfo.jobID, job5)
326
+ jobUpdateInfo2 = self.batchSystem.getUpdatedBatchJob(maxWait=1000)
327
+ assert jobUpdateInfo2 is not None
328
+ self.assertEqual(jobUpdateInfo2.exitStatus, 23)
329
+ self.assertEqual(jobUpdateInfo2.jobID, job5)
311
330
 
312
- def test_set_job_env(self):
331
+ def test_set_job_env(self) -> None:
313
332
  """Test the mechanism for setting per-job environment variables to batch system jobs."""
314
333
  script = 'if [ "x${FOO}" == "xbar" ] ; then exit 23 ; else exit 42 ; fi'
315
334
  command = 'bash -c "\\${@}" bash eval ' + script.replace(";", r"\;")
@@ -325,6 +344,7 @@ class hidden:
325
344
  command, job_desc_6, job_environment={"FOO": "bar"}
326
345
  )
327
346
  job_update_info = self.batchSystem.getUpdatedBatchJob(maxWait=1000)
347
+ assert job_update_info is not None
328
348
  self.assertEqual(job_update_info.exitStatus, 23) # this should succeed
329
349
  self.assertEqual(job_update_info.jobID, job6)
330
350
  # Now check that the environment variable doesn't exist for other jobs
@@ -335,11 +355,12 @@ class hidden:
335
355
  requirements=defaultRequirements,
336
356
  )
337
357
  job7 = self.batchSystem.issueBatchJob(command, job_desc_7)
338
- job_update_info = self.batchSystem.getUpdatedBatchJob(maxWait=1000)
339
- self.assertEqual(job_update_info.exitStatus, 42)
340
- self.assertEqual(job_update_info.jobID, job7)
358
+ job_update_info2 = self.batchSystem.getUpdatedBatchJob(maxWait=1000)
359
+ assert job_update_info2 is not None
360
+ self.assertEqual(job_update_info2.exitStatus, 42)
361
+ self.assertEqual(job_update_info2.jobID, job7)
341
362
 
342
- def testCheckResourceRequest(self):
363
+ def testCheckResourceRequest(self) -> None:
343
364
  if isinstance(self.batchSystem, BatchSystemSupport):
344
365
  check_resource_request = self.batchSystem.check_resource_request
345
366
  # Assuming we have <2000 cores, this should be too many cores
@@ -405,11 +426,11 @@ class hidden:
405
426
  Requirer(dict(memory=10, cores=1, disk=100, accelerators=[]))
406
427
  )
407
428
 
408
- def testScalableBatchSystem(self):
429
+ def testScalableBatchSystem(self) -> None:
409
430
  # If instance of scalable batch system
410
431
  pass
411
432
 
412
- def _waitForJobsToIssue(self, numJobs):
433
+ def _waitForJobsToIssue(self, numJobs: int) -> list[int]:
413
434
  issuedIDs = []
414
435
  for it in range(20):
415
436
  issuedIDs = self.batchSystem.getIssuedBatchJobIDs()
@@ -418,7 +439,7 @@ class hidden:
418
439
  time.sleep(1)
419
440
  return issuedIDs
420
441
 
421
- def _waitForJobsToStart(self, numJobs, tries=20):
442
+ def _waitForJobsToStart(self, numJobs: int, tries: int = 20) -> list[int]:
422
443
  """
423
444
  Loop until the given number of distinct jobs are in the
424
445
  running state, or until the given number of tries is exhausted
@@ -437,114 +458,109 @@ class hidden:
437
458
  time.sleep(1)
438
459
  return runningIDs
439
460
 
440
- class AbstractBatchSystemJobTest(ToilTest, metaclass=ABCMeta):
461
+ class AbstractGridEngineBatchSystemTest(AbstractBatchSystemTest):
441
462
  """
442
- An abstract base class for batch system tests that use a full Toil workflow rather
443
- than using the batch system directly.
463
+ An abstract class to reduce redundancy between Grid Engine, Slurm, and other similar batch
464
+ systems
444
465
  """
445
466
 
446
- cpuCount = cpu_count()
447
- allocatedCores = sorted({1, 2, cpuCount})
448
- sleepTime = 30
467
+ def _createConfig(self) -> Config:
468
+ config = super()._createConfig()
469
+ config.statePollingWait = 0.5 # Reduce polling wait so tests run faster
470
+ # can't use _getTestJobStorePath since that method removes the directory
471
+ config.jobStore = "file:" + self._createTempDir("jobStore")
472
+ return config
449
473
 
450
- @abstractmethod
451
- def getBatchSystemName(self):
452
- """
453
- :rtype: (str, AbstractBatchSystem)
454
- """
455
- raise NotImplementedError
456
474
 
457
- def getOptions(self, tempDir):
458
- """
459
- Configures options for Toil workflow and makes job store.
460
- :param str tempDir: path to test directory
461
- :return: Toil options object
462
- """
463
- options = Job.Runner.getDefaultOptions(self._getTestJobStorePath())
464
- options.logLevel = "DEBUG"
465
- options.batchSystem = self.batchSystemName
466
- options.workDir = tempDir
467
- options.maxCores = self.cpuCount
468
- return options
469
-
470
- def setUp(self):
471
- self.batchSystemName = self.getBatchSystemName()
472
- super().setUp()
475
+ class AbstractBatchSystemJobTest:
476
+ """
477
+ An abstract base class for batch system tests that use a full Toil workflow rather
478
+ than using the batch system directly.
479
+ """
473
480
 
474
- def tearDown(self):
475
- super().tearDown()
481
+ cpuCount = cpu_count() if cpu_count() < 4 else 4
482
+ allocatedCores = sorted({1, 2, cpuCount})
483
+ sleepTime = 30
476
484
 
477
- @slow
478
- def testJobConcurrency(self):
479
- """
480
- Tests that the batch system is allocating core resources properly for concurrent tasks.
481
- """
482
- for coresPerJob in self.allocatedCores:
483
- tempDir = self._createTempDir("testFiles")
484
- options = self.getOptions(tempDir)
485
-
486
- counterPath = os.path.join(tempDir, "counter")
487
- resetCounters(counterPath)
488
- value, maxValue = getCounters(counterPath)
489
- assert (value, maxValue) == (0, 0)
490
-
491
- root = Job()
492
- for _ in range(self.cpuCount):
493
- root.addFollowOn(
494
- Job.wrapFn(
495
- measureConcurrency,
496
- counterPath,
497
- self.sleepTime,
498
- cores=coresPerJob,
499
- memory="1M",
500
- disk="1Mi",
501
- )
502
- )
503
- with Toil(options) as toil:
504
- toil.start(root)
505
- _, maxValue = getCounters(counterPath)
506
- self.assertEqual(maxValue, self.cpuCount // coresPerJob)
485
+ @abstractmethod
486
+ def getBatchSystemName(self) -> str:
487
+ """
488
+ :rtype: (str, AbstractBatchSystem)
489
+ """
490
+ raise NotImplementedError
507
491
 
508
- def test_omp_threads(self):
509
- """
510
- Test if the OMP_NUM_THREADS env var is set correctly based on jobs.cores.
511
- """
512
- test_cases = {
513
- # mapping of the number of cores to the OMP_NUM_THREADS value
514
- 0.1: "1",
515
- 1: "1",
516
- 2: "2",
517
- }
518
-
519
- temp_dir = self._createTempDir()
520
- options = self.getOptions(temp_dir)
521
-
522
- for cores, expected_omp_threads in test_cases.items():
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
- )
528
- with Toil(options) as toil:
529
- output = toil.start(
530
- Job.wrapFn(
531
- get_omp_threads, memory="1Mi", cores=cores, disk="1Mi"
532
- )
533
- )
534
- self.assertEqual(output, expected_omp_threads)
492
+ def getOptions(self, tempDir: Path) -> argparse.Namespace:
493
+ """
494
+ Configures options for Toil workflow and makes job store.
495
+ :param str tempDir: path to test directory
496
+ :return: Toil options object
497
+ """
498
+ workdir = tempDir / "workdir"
499
+ workdir.mkdir()
500
+ options = Job.Runner.getDefaultOptions(tempDir / "jobstore")
501
+ options.logLevel = "DEBUG"
502
+ options.batchSystem = self.getBatchSystemName()
503
+ options.workDir = str(workdir)
504
+ options.maxCores = self.cpuCount
505
+ return options
535
506
 
536
- class AbstractGridEngineBatchSystemTest(AbstractBatchSystemTest):
507
+ @pslow
508
+ @pytest.mark.slow
509
+ def testJobConcurrency(self, tmp_path: Path) -> None:
537
510
  """
538
- An abstract class to reduce redundancy between Grid Engine, Slurm, and other similar batch
539
- systems
511
+ Tests that the batch system is allocating core resources properly for concurrent tasks.
540
512
  """
513
+ for coresPerJob in self.allocatedCores:
514
+ tempDir = tmp_path / f"testFiles_{coresPerJob}"
515
+ tempDir.mkdir()
516
+ options = self.getOptions(tempDir)
517
+
518
+ counterPath = tempDir / "counter"
519
+ resetCounters(counterPath)
520
+ value, maxValue = getCounters(counterPath)
521
+ assert (value, maxValue) == (0, 0)
522
+
523
+ root = Job()
524
+ for _ in range(self.cpuCount):
525
+ root.addFollowOn(
526
+ Job.wrapFn(
527
+ measureConcurrency,
528
+ counterPath,
529
+ self.sleepTime,
530
+ cores=coresPerJob,
531
+ memory="1M",
532
+ disk="1Mi",
533
+ )
534
+ )
535
+ with Toil(options) as toil:
536
+ toil.start(root)
537
+ _, maxValue = getCounters(counterPath)
538
+ assert maxValue == (self.cpuCount // coresPerJob)
541
539
 
542
- def _createConfig(self):
543
- config = super()._createConfig()
544
- config.statePollingWait = 0.5 # Reduce polling wait so tests run faster
545
- # can't use _getTestJobStorePath since that method removes the directory
546
- config.jobStore = "file:" + self._createTempDir("jobStore")
547
- return config
540
+ def test_omp_threads(self, tmp_path: Path) -> None:
541
+ """
542
+ Test if the OMP_NUM_THREADS env var is set correctly based on jobs.cores.
543
+ """
544
+ test_cases = {
545
+ # mapping of the number of cores to the OMP_NUM_THREADS value
546
+ 0.1: "1",
547
+ 1: "1",
548
+ 2: "2",
549
+ }
550
+
551
+ options = self.getOptions(tmp_path)
552
+
553
+ for cores, expected_omp_threads in test_cases.items():
554
+ if eont := os.environ.get("OMP_NUM_THREADS"):
555
+ expected_omp_threads = eont
556
+ logger.info(
557
+ f"OMP_NUM_THREADS is set. Using OMP_NUM_THREADS={expected_omp_threads} instead."
558
+ )
559
+ with Toil(options) as toil:
560
+ output = toil.start(
561
+ Job.wrapFn(get_omp_threads, memory="1Mi", cores=cores, disk="1Mi")
562
+ )
563
+ assert output == expected_omp_threads
548
564
 
549
565
 
550
566
  @needs_kubernetes
@@ -555,10 +571,10 @@ class KubernetesBatchSystemTest(hidden.AbstractBatchSystemTest):
555
571
  Tests against the Kubernetes batch system
556
572
  """
557
573
 
558
- def supportsWallTime(self):
574
+ def supportsWallTime(self) -> bool:
559
575
  return True
560
576
 
561
- def createBatchSystem(self):
577
+ def createBatchSystem(self) -> AbstractBatchSystem:
562
578
  # We know we have Kubernetes so we can import the batch system
563
579
  from toil.batchSystems.kubernetes import KubernetesBatchSystem
564
580
 
@@ -573,7 +589,7 @@ class KubernetesBatchSystemBenchTest(ToilTest):
573
589
  Kubernetes batch system unit tests that don't need to actually talk to a cluster.
574
590
  """
575
591
 
576
- def test_preemptability_constraints(self):
592
+ def test_preemptability_constraints(self) -> None:
577
593
  """
578
594
  Make sure we generate the right preemptability constraints.
579
595
  """
@@ -645,7 +661,7 @@ class KubernetesBatchSystemBenchTest(ToilTest):
645
661
  str(spot_spec.tolerations),
646
662
  )
647
663
 
648
- def test_label_constraints(self):
664
+ def test_label_constraints(self) -> None:
649
665
  """
650
666
  Make sure we generate the right preemptability constraints.
651
667
  """
@@ -694,10 +710,10 @@ class AWSBatchBatchSystemTest(hidden.AbstractBatchSystemTest):
694
710
  Tests against the AWS Batch batch system
695
711
  """
696
712
 
697
- def supportsWallTime(self):
713
+ def supportsWallTime(self) -> bool:
698
714
  return True
699
715
 
700
- def createBatchSystem(self):
716
+ def createBatchSystem(self) -> AbstractBatchSystem:
701
717
  from toil.batchSystems.awsBatch import AWSBatchBatchSystem
702
718
 
703
719
  return AWSBatchBatchSystem(
@@ -716,8 +732,10 @@ class MesosBatchSystemTest(hidden.AbstractBatchSystemTest, MesosTestSupport):
716
732
  Tests against the Mesos batch system
717
733
  """
718
734
 
735
+ batchSystem: "MesosBatchSystem"
736
+
719
737
  @classmethod
720
- def createConfig(cls):
738
+ def createConfig(cls) -> Config:
721
739
  """
722
740
  needs to set mesos_endpoint to localhost for testing since the default is now the
723
741
  private IP address
@@ -726,10 +744,10 @@ class MesosBatchSystemTest(hidden.AbstractBatchSystemTest, MesosTestSupport):
726
744
  config.mesos_endpoint = "localhost:5050"
727
745
  return config
728
746
 
729
- def supportsWallTime(self):
747
+ def supportsWallTime(self) -> bool:
730
748
  return True
731
749
 
732
- def createBatchSystem(self):
750
+ def createBatchSystem(self) -> "MesosBatchSystem":
733
751
  # We know we have Mesos so we can import the batch system
734
752
  from toil.batchSystems.mesos.batchSystem import MesosBatchSystem
735
753
 
@@ -738,11 +756,11 @@ class MesosBatchSystemTest(hidden.AbstractBatchSystemTest, MesosTestSupport):
738
756
  config=self.config, maxCores=numCores, maxMemory=1e9, maxDisk=1001
739
757
  )
740
758
 
741
- def tearDown(self):
759
+ def tearDown(self) -> None:
742
760
  self._stopMesos()
743
761
  super().tearDown()
744
762
 
745
- def testIgnoreNode(self):
763
+ def testIgnoreNode(self) -> None:
746
764
  self.batchSystem.ignoreNode("localhost")
747
765
  jobDesc = self._mockJobDescription(
748
766
  jobName="test2",
@@ -807,14 +825,14 @@ class SingleMachineBatchSystemTest(hidden.AbstractBatchSystemTest):
807
825
  import signal
808
826
  import sys
809
827
  import time
810
- from typing import Any
828
+ from typing import Any, Iterable
811
829
 
812
830
  def handle_signal(sig: Any, frame: Any) -> None:
813
831
  sys.stderr.write(f"{os.getpid()} ignoring signal {sig}\n")
814
832
 
815
833
  if hasattr(signal, "valid_signals"):
816
834
  # We can just ask about the signals
817
- all_signals = signal.valid_signals()
835
+ all_signals: Iterable[signal.Signals] = signal.valid_signals()
818
836
  else:
819
837
  # Fish them out by name
820
838
  all_signals = [
@@ -901,7 +919,7 @@ class SingleMachineBatchSystemTest(hidden.AbstractBatchSystemTest):
901
919
  os.unlink(script_path)
902
920
  os.unlink(lockable_path)
903
921
 
904
- def testHidingProcessEscape(self):
922
+ def testHidingProcessEscape(self) -> None:
905
923
  """
906
924
  Test to make sure that child processes and their descendants go away
907
925
  when the Toil workflow stops, even if the job process stops and leaves children.
@@ -980,7 +998,7 @@ class MaxCoresSingleMachineBatchSystemTest(ToilTest):
980
998
  return " ".join([sys.executable, self.scriptPath, self.counterPath])
981
999
 
982
1000
  @retry_flaky_test(prepare=[tearDown, setUp])
983
- def test(self):
1001
+ def test(self) -> None:
984
1002
  # We'll use fractions to avoid rounding errors. Remember that not every fraction can be
985
1003
  # represented as a floating point number.
986
1004
  F = Fraction
@@ -1025,7 +1043,7 @@ class MaxCoresSingleMachineBatchSystemTest(ToilTest):
1025
1043
  self.assertEqual(len(jobIds), jobs)
1026
1044
  while jobIds:
1027
1045
  job = bs.getUpdatedBatchJob(maxWait=10)
1028
- self.assertIsNotNone(job)
1046
+ assert job is not None
1029
1047
  jobId, status, wallTime = (
1030
1048
  job.jobID,
1031
1049
  job.exitStatus,
@@ -1057,7 +1075,7 @@ class MaxCoresSingleMachineBatchSystemTest(ToilTest):
1057
1075
  SingleMachineBatchSystem.numCores < 3,
1058
1076
  "Need at least three cores to run this test",
1059
1077
  )
1060
- def testServices(self):
1078
+ def testServices(self) -> None:
1061
1079
  options = Job.Runner.getDefaultOptions(self._getTestJobStorePath())
1062
1080
  options.logLevel = "DEBUG"
1063
1081
  options.maxCores = 3
@@ -1072,38 +1090,38 @@ class MaxCoresSingleMachineBatchSystemTest(ToilTest):
1072
1090
  # Toil can use only top-level functions so we have to add them here:
1073
1091
 
1074
1092
 
1075
- def parentJob(job, cmd):
1093
+ def parentJob(job: Job, cmd: str) -> None:
1076
1094
  job.addChildJobFn(childJob, cmd)
1077
1095
 
1078
1096
 
1079
- def childJob(job, cmd):
1097
+ def childJob(job: Job, cmd: str) -> None:
1080
1098
  job.addService(Service(cmd))
1081
1099
  job.addChildJobFn(grandChildJob, cmd)
1082
1100
  subprocess.check_call(cmd, shell=True)
1083
1101
 
1084
1102
 
1085
- def grandChildJob(job, cmd):
1103
+ def grandChildJob(job: Job, cmd: str) -> None:
1086
1104
  job.addService(Service(cmd))
1087
1105
  job.addChildFn(greatGrandChild, cmd)
1088
1106
  subprocess.check_call(cmd, shell=True)
1089
1107
 
1090
1108
 
1091
- def greatGrandChild(cmd):
1109
+ def greatGrandChild(cmd: str) -> None:
1092
1110
  subprocess.check_call(cmd, shell=True)
1093
1111
 
1094
1112
 
1095
1113
  class Service(Job.Service):
1096
- def __init__(self, cmd):
1114
+ def __init__(self, cmd: str) -> None:
1097
1115
  super().__init__()
1098
1116
  self.cmd = cmd
1099
1117
 
1100
- def start(self, fileStore):
1118
+ def start(self, job: ServiceHostJob) -> None:
1101
1119
  subprocess.check_call(self.cmd + " 1", shell=True)
1102
1120
 
1103
- def check(self):
1121
+ def check(self) -> bool:
1104
1122
  return True
1105
1123
 
1106
- def stop(self, fileStore):
1124
+ def stop(self, job: ServiceHostJob) -> None:
1107
1125
  subprocess.check_call(self.cmd + " -1", shell=True)
1108
1126
 
1109
1127
 
@@ -1121,7 +1139,7 @@ class GridEngineBatchSystemTest(hidden.AbstractGridEngineBatchSystemTest):
1121
1139
  config=self.config, maxCores=numCores, maxMemory=1000e9, maxDisk=1e9
1122
1140
  )
1123
1141
 
1124
- def tearDown(self):
1142
+ def tearDown(self) -> None:
1125
1143
  super().tearDown()
1126
1144
  # Cleanup GridEngine output log file from qsub
1127
1145
  from glob import glob
@@ -1144,7 +1162,7 @@ class SlurmBatchSystemTest(hidden.AbstractGridEngineBatchSystemTest):
1144
1162
  config=self.config, maxCores=numCores, maxMemory=1000e9, maxDisk=1e9
1145
1163
  )
1146
1164
 
1147
- def tearDown(self):
1165
+ def tearDown(self) -> None:
1148
1166
  super().tearDown()
1149
1167
  # Cleanup 'slurm-%j.out' produced by sbatch
1150
1168
  from glob import glob
@@ -1175,8 +1193,8 @@ class TorqueBatchSystemTest(hidden.AbstractGridEngineBatchSystemTest):
1175
1193
  Tests against the Torque batch system
1176
1194
  """
1177
1195
 
1178
- def _createDummyConfig(self):
1179
- config = super()._createDummyConfig()
1196
+ def _createDummyConfig(self) -> Config:
1197
+ config = super()._createConfig()
1180
1198
  # can't use _getTestJobStorePath since that method removes the directory
1181
1199
  config.jobStore = self._createTempDir("jobStore")
1182
1200
  return config
@@ -1188,7 +1206,7 @@ class TorqueBatchSystemTest(hidden.AbstractGridEngineBatchSystemTest):
1188
1206
  config=self.config, maxCores=numCores, maxMemory=1000e9, maxDisk=1e9
1189
1207
  )
1190
1208
 
1191
- def tearDown(self):
1209
+ def tearDown(self) -> None:
1192
1210
  super().tearDown()
1193
1211
  # Cleanup 'toil_job-%j.out' produced by sbatch
1194
1212
  from glob import glob
@@ -1211,42 +1229,39 @@ class HTCondorBatchSystemTest(hidden.AbstractGridEngineBatchSystemTest):
1211
1229
  config=self.config, maxCores=numCores, maxMemory=1000e9, maxDisk=1e9
1212
1230
  )
1213
1231
 
1214
- def tearDown(self):
1232
+ def tearDown(self) -> None:
1215
1233
  super().tearDown()
1216
1234
 
1217
1235
 
1218
- class SingleMachineBatchSystemJobTest(hidden.AbstractBatchSystemJobTest):
1236
+ class TestSingleMachineBatchSystemJob(AbstractBatchSystemJobTest):
1219
1237
  """
1220
1238
  Tests Toil workflow against the SingleMachine batch system
1221
1239
  """
1222
1240
 
1223
- def getBatchSystemName(self):
1241
+ def getBatchSystemName(self) -> str:
1224
1242
  return "single_machine"
1225
1243
 
1226
- @slow
1227
- @retry_flaky_test(
1228
- prepare=[
1229
- hidden.AbstractBatchSystemJobTest.tearDown,
1230
- hidden.AbstractBatchSystemJobTest.setUp,
1231
- ]
1232
- )
1233
- def testConcurrencyWithDisk(self):
1244
+ @pslow
1245
+ @pytest.mark.slow
1246
+ @retry_flaky_test(prepare=[])
1247
+ def testConcurrencyWithDisk(self, tmp_path: Path) -> None:
1234
1248
  """
1235
1249
  Tests that the batch system is allocating disk resources properly
1236
1250
  """
1237
- tempDir = self._createTempDir("testFiles")
1238
1251
 
1239
- options = Job.Runner.getDefaultOptions(self._getTestJobStorePath())
1240
- options.workDir = tempDir
1252
+ workdir = tmp_path / "workdir"
1253
+ workdir.mkdir()
1254
+ options = Job.Runner.getDefaultOptions(tmp_path / "jobstore")
1255
+ options.workDir = str(workdir)
1241
1256
  from toil import physicalDisk
1242
1257
 
1243
1258
  availableDisk = physicalDisk(options.workDir)
1244
1259
  logger.info("Testing disk concurrency limits with %s disk space", availableDisk)
1245
1260
  # More disk might become available by the time Toil starts, so we limit it here
1246
1261
  options.maxDisk = availableDisk
1247
- options.batchSystem = self.batchSystemName
1262
+ options.batchSystem = self.getBatchSystemName()
1248
1263
 
1249
- counterPath = os.path.join(tempDir, "counter")
1264
+ counterPath = tmp_path / "counter"
1250
1265
  resetCounters(counterPath)
1251
1266
  value, maxValue = getCounters(counterPath)
1252
1267
  assert (value, maxValue) == (0, 0)
@@ -1283,31 +1298,32 @@ class SingleMachineBatchSystemJobTest(hidden.AbstractBatchSystemJobTest):
1283
1298
 
1284
1299
  logger.info("After run: %s disk space", physicalDisk(options.workDir))
1285
1300
 
1286
- self.assertEqual(maxValue, 1)
1301
+ assert maxValue == 1
1287
1302
 
1288
- @skipIf(
1303
+ @pytest.mark.skipif(
1289
1304
  SingleMachineBatchSystem.numCores < 4,
1290
- "Need at least four cores to run this test",
1305
+ reason="Need at least four cores to run this test",
1291
1306
  )
1292
- @slow
1293
- def testNestedResourcesDoNotBlock(self):
1307
+ @pslow
1308
+ @pytest.mark.slow
1309
+ def testNestedResourcesDoNotBlock(self, tmp_path: Path) -> None:
1294
1310
  """
1295
1311
  Resources are requested in the order Memory > Cpu > Disk.
1296
1312
  Test that unavailability of cpus for one job that is scheduled does not block another job
1297
1313
  that can run.
1298
1314
  """
1299
- tempDir = self._createTempDir("testFiles")
1300
-
1301
- options = Job.Runner.getDefaultOptions(self._getTestJobStorePath())
1302
- options.workDir = tempDir
1315
+ workdir = tmp_path / "workdir"
1316
+ workdir.mkdir()
1317
+ options = Job.Runner.getDefaultOptions(tmp_path / "jobstore")
1318
+ options.workDir = str(workdir)
1303
1319
  options.maxCores = 4
1304
1320
  from toil import physicalMemory
1305
1321
 
1306
1322
  availableMemory = physicalMemory()
1307
- options.batchSystem = self.batchSystemName
1323
+ options.batchSystem = self.getBatchSystemName()
1308
1324
 
1309
- outFile = os.path.join(tempDir, "counter")
1310
- open(outFile, "w").close()
1325
+ outFile = tmp_path / "counter"
1326
+ outFile.open("w").close()
1311
1327
 
1312
1328
  root = Job()
1313
1329
 
@@ -1395,7 +1411,7 @@ class SingleMachineBatchSystemJobTest(hidden.AbstractBatchSystemJobTest):
1395
1411
  should not block them, and should only run after they finish.
1396
1412
  """
1397
1413
  Job.Runner.startToil(root, options)
1398
- with open(outFile) as oFH:
1414
+ with outFile.open() as oFH:
1399
1415
  outString = oFH.read()
1400
1416
  # The ordering of b, fJ and sJ is non-deterministic since they are scheduled at the same
1401
1417
  # time. We look for all possible permutations.
@@ -1406,12 +1422,12 @@ class SingleMachineBatchSystemJobTest(hidden.AbstractBatchSystemJobTest):
1406
1422
  assert outString.endswith("sJCsJGCfJC")
1407
1423
 
1408
1424
 
1409
- def _resourceBlockTestAuxFn(outFile, sleepTime, writeVal):
1425
+ def _resourceBlockTestAuxFn(outFile: StrPath, sleepTime: int, writeVal: str) -> None:
1410
1426
  """
1411
1427
  Write a value to the out file and then sleep for requested seconds.
1412
- :param str outFile: File to write to
1413
- :param int sleepTime: Time to sleep for
1414
- :param str writeVal: Character to write
1428
+ :param outFile: File to write to
1429
+ :param sleepTime: Time to sleep for
1430
+ :param writeVal: Character to write
1415
1431
  """
1416
1432
  with open(outFile, "a") as oFH:
1417
1433
  fcntl.flock(oFH, fcntl.LOCK_EX)
@@ -1419,33 +1435,38 @@ def _resourceBlockTestAuxFn(outFile, sleepTime, writeVal):
1419
1435
  time.sleep(sleepTime)
1420
1436
 
1421
1437
 
1422
- @slow
1423
- @needs_mesos
1424
- class MesosBatchSystemJobTest(hidden.AbstractBatchSystemJobTest, MesosTestSupport):
1438
+ @pslow
1439
+ @pytest.mark.slow
1440
+ @pneeds_mesos
1441
+ class TestMesosBatchSystemJob(AbstractBatchSystemJobTest, MesosTestSupport):
1425
1442
  """
1426
1443
  Tests Toil workflow against the Mesos batch system
1427
1444
  """
1428
1445
 
1429
- def getOptions(self, tempDir):
1446
+ @pytest.fixture(autouse=True)
1447
+ def mesos_support(self) -> Generator[None]:
1448
+ try:
1449
+ self._startMesos(self.cpuCount)
1450
+ yield
1451
+ finally:
1452
+ self._stopMesos()
1453
+
1454
+ def getOptions(self, tempDir: Path) -> argparse.Namespace:
1430
1455
  options = super().getOptions(tempDir)
1431
1456
  options.mesos_endpoint = "localhost:5050"
1432
1457
  return options
1433
1458
 
1434
- def getBatchSystemName(self):
1435
- self._startMesos(self.cpuCount)
1459
+ def getBatchSystemName(self) -> "str":
1436
1460
  return "mesos"
1437
1461
 
1438
- def tearDown(self):
1439
- self._stopMesos()
1440
-
1441
1462
 
1442
- def measureConcurrency(filepath, sleep_time=10):
1463
+ def measureConcurrency(filepath: StrPath, sleep_time: int = 10) -> int:
1443
1464
  """
1444
1465
  Run in parallel to determine the number of concurrent tasks.
1445
1466
  This code was copied from toil.batchSystemTestMaxCoresSingleMachineBatchSystemTest
1446
- :param str filepath: path to counter file
1447
- :param int sleep_time: number of seconds to sleep before counting down
1448
- :return int max concurrency value:
1467
+ :param filepath: path to counter file
1468
+ :param sleep_time: number of seconds to sleep before counting down
1469
+ :return: max concurrency value
1449
1470
  """
1450
1471
  count(1, filepath)
1451
1472
  try:
@@ -1454,16 +1475,17 @@ def measureConcurrency(filepath, sleep_time=10):
1454
1475
  return count(-1, filepath)
1455
1476
 
1456
1477
 
1457
- def count(delta, file_path):
1478
+ def count(delta: int, file_path: StrPath) -> int:
1458
1479
  """
1459
1480
  Increments counter file and returns the max number of times the file
1460
1481
  has been modified. Counter data must be in the form:
1461
1482
  concurrent tasks, max concurrent tasks (counter should be initialized to 0,0)
1462
1483
 
1463
- :param int delta: increment value
1464
- :param str file_path: path to shared counter file
1465
- :return int max concurrent tasks:
1484
+ :param delta: increment value
1485
+ :param file_path: path to shared counter file
1486
+ :return: max concurrent tasks
1466
1487
  """
1488
+
1467
1489
  fd = os.open(file_path, os.O_RDWR)
1468
1490
  try:
1469
1491
  fcntl.flock(fd, fcntl.LOCK_EX)
@@ -1483,13 +1505,13 @@ def count(delta, file_path):
1483
1505
  return maxValue
1484
1506
 
1485
1507
 
1486
- def getCounters(path):
1508
+ def getCounters(path: StrPath) -> tuple[int, int]:
1487
1509
  with open(path, "r+") as f:
1488
1510
  concurrentTasks, maxConcurrentTasks = (int(i) for i in f.read().split(","))
1489
1511
  return concurrentTasks, maxConcurrentTasks
1490
1512
 
1491
1513
 
1492
- def resetCounters(path):
1514
+ def resetCounters(path: StrPath) -> None:
1493
1515
  with open(path, "w") as f:
1494
1516
  f.write("0,0")
1495
1517
  f.close()