toil 8.1.0b1__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 (254) hide show
  1. toil/__init__.py +0 -35
  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/singleMachine.py +1 -1
  11. toil/batchSystems/slurm.py +27 -26
  12. toil/bus.py +5 -3
  13. toil/common.py +39 -11
  14. toil/cwl/cwltoil.py +1 -1
  15. toil/job.py +64 -49
  16. toil/jobStores/abstractJobStore.py +24 -3
  17. toil/jobStores/fileJobStore.py +25 -1
  18. toil/jobStores/googleJobStore.py +104 -30
  19. toil/leader.py +9 -0
  20. toil/lib/accelerators.py +3 -1
  21. toil/lib/aws/utils.py.orig +504 -0
  22. toil/lib/bioio.py +1 -1
  23. toil/lib/docker.py +252 -91
  24. toil/lib/dockstore.py +11 -3
  25. toil/lib/exceptions.py +5 -3
  26. toil/lib/history.py +87 -13
  27. toil/lib/history_submission.py +23 -9
  28. toil/lib/io.py +34 -22
  29. toil/lib/misc.py +7 -1
  30. toil/lib/resources.py +2 -1
  31. toil/lib/threading.py +11 -10
  32. toil/options/common.py +8 -0
  33. toil/options/wdl.py +11 -0
  34. toil/server/api_spec/LICENSE +201 -0
  35. toil/server/api_spec/README.rst +5 -0
  36. toil/server/cli/wes_cwl_runner.py +2 -1
  37. toil/test/__init__.py +275 -115
  38. toil/test/batchSystems/batchSystemTest.py +227 -205
  39. toil/test/batchSystems/test_slurm.py +27 -0
  40. toil/test/cactus/pestis.tar.gz +0 -0
  41. toil/test/conftest.py +7 -0
  42. toil/test/cwl/2.fasta +11 -0
  43. toil/test/cwl/2.fastq +12 -0
  44. toil/test/cwl/conftest.py +1 -1
  45. toil/test/cwl/cwlTest.py +999 -867
  46. toil/test/cwl/directory/directory/file.txt +15 -0
  47. toil/test/cwl/download_directory_file.json +4 -0
  48. toil/test/cwl/download_directory_s3.json +4 -0
  49. toil/test/cwl/download_file.json +6 -0
  50. toil/test/cwl/download_http.json +6 -0
  51. toil/test/cwl/download_https.json +6 -0
  52. toil/test/cwl/download_s3.json +6 -0
  53. toil/test/cwl/download_subdirectory_file.json +5 -0
  54. toil/test/cwl/download_subdirectory_s3.json +5 -0
  55. toil/test/cwl/empty.json +1 -0
  56. toil/test/cwl/mock_mpi/fake_mpi.yml +8 -0
  57. toil/test/cwl/mock_mpi/fake_mpi_run.py +42 -0
  58. toil/test/cwl/optional-file-exists.json +6 -0
  59. toil/test/cwl/optional-file-missing.json +6 -0
  60. toil/test/cwl/preemptible_expression.json +1 -0
  61. toil/test/cwl/revsort-job-missing.json +6 -0
  62. toil/test/cwl/revsort-job.json +6 -0
  63. toil/test/cwl/s3_secondary_file.json +16 -0
  64. toil/test/cwl/seqtk_seq_job.json +6 -0
  65. toil/test/cwl/stream.json +6 -0
  66. toil/test/cwl/test_filename_conflict_resolution.ms/table.dat +0 -0
  67. toil/test/cwl/test_filename_conflict_resolution.ms/table.f0 +0 -0
  68. toil/test/cwl/test_filename_conflict_resolution.ms/table.f1 +0 -0
  69. toil/test/cwl/test_filename_conflict_resolution.ms/table.f1i +0 -0
  70. toil/test/cwl/test_filename_conflict_resolution.ms/table.f2 +0 -0
  71. toil/test/cwl/test_filename_conflict_resolution.ms/table.f2_TSM0 +0 -0
  72. toil/test/cwl/test_filename_conflict_resolution.ms/table.f3 +0 -0
  73. toil/test/cwl/test_filename_conflict_resolution.ms/table.f3_TSM0 +0 -0
  74. toil/test/cwl/test_filename_conflict_resolution.ms/table.f4 +0 -0
  75. toil/test/cwl/test_filename_conflict_resolution.ms/table.f4_TSM0 +0 -0
  76. toil/test/cwl/test_filename_conflict_resolution.ms/table.f5 +0 -0
  77. toil/test/cwl/test_filename_conflict_resolution.ms/table.info +0 -0
  78. toil/test/cwl/test_filename_conflict_resolution.ms/table.lock +0 -0
  79. toil/test/cwl/whale.txt +16 -0
  80. toil/test/docs/scripts/example_alwaysfail.py +38 -0
  81. toil/test/docs/scripts/example_alwaysfail_with_files.wdl +33 -0
  82. toil/test/docs/scripts/example_cachingbenchmark.py +117 -0
  83. toil/test/docs/scripts/stagingExampleFiles/in.txt +1 -0
  84. toil/test/docs/scripts/stagingExampleFiles/out.txt +2 -0
  85. toil/test/docs/scripts/tutorial_arguments.py +23 -0
  86. toil/test/docs/scripts/tutorial_debugging.patch +12 -0
  87. toil/test/docs/scripts/tutorial_debugging_hangs.wdl +126 -0
  88. toil/test/docs/scripts/tutorial_debugging_works.wdl +129 -0
  89. toil/test/docs/scripts/tutorial_docker.py +20 -0
  90. toil/test/docs/scripts/tutorial_dynamic.py +24 -0
  91. toil/test/docs/scripts/tutorial_encapsulation.py +28 -0
  92. toil/test/docs/scripts/tutorial_encapsulation2.py +29 -0
  93. toil/test/docs/scripts/tutorial_helloworld.py +15 -0
  94. toil/test/docs/scripts/tutorial_invokeworkflow.py +27 -0
  95. toil/test/docs/scripts/tutorial_invokeworkflow2.py +30 -0
  96. toil/test/docs/scripts/tutorial_jobfunctions.py +22 -0
  97. toil/test/docs/scripts/tutorial_managing.py +29 -0
  98. toil/test/docs/scripts/tutorial_managing2.py +56 -0
  99. toil/test/docs/scripts/tutorial_multiplejobs.py +25 -0
  100. toil/test/docs/scripts/tutorial_multiplejobs2.py +21 -0
  101. toil/test/docs/scripts/tutorial_multiplejobs3.py +22 -0
  102. toil/test/docs/scripts/tutorial_promises.py +25 -0
  103. toil/test/docs/scripts/tutorial_promises2.py +30 -0
  104. toil/test/docs/scripts/tutorial_quickstart.py +22 -0
  105. toil/test/docs/scripts/tutorial_requirements.py +44 -0
  106. toil/test/docs/scripts/tutorial_services.py +45 -0
  107. toil/test/docs/scripts/tutorial_staging.py +45 -0
  108. toil/test/docs/scripts/tutorial_stats.py +64 -0
  109. toil/test/lib/aws/test_iam.py +3 -1
  110. toil/test/lib/dockerTest.py +205 -122
  111. toil/test/lib/test_history.py +101 -77
  112. toil/test/provisioners/aws/awsProvisionerTest.py +12 -9
  113. toil/test/provisioners/clusterTest.py +4 -4
  114. toil/test/provisioners/gceProvisionerTest.py +16 -14
  115. toil/test/sort/sort.py +4 -1
  116. toil/test/src/busTest.py +17 -17
  117. toil/test/src/deferredFunctionTest.py +145 -132
  118. toil/test/src/importExportFileTest.py +71 -63
  119. toil/test/src/jobEncapsulationTest.py +27 -28
  120. toil/test/src/jobServiceTest.py +149 -133
  121. toil/test/src/jobTest.py +219 -211
  122. toil/test/src/miscTests.py +66 -60
  123. toil/test/src/promisedRequirementTest.py +163 -169
  124. toil/test/src/regularLogTest.py +24 -24
  125. toil/test/src/resourceTest.py +82 -76
  126. toil/test/src/restartDAGTest.py +51 -47
  127. toil/test/src/resumabilityTest.py +24 -19
  128. toil/test/src/retainTempDirTest.py +60 -57
  129. toil/test/src/systemTest.py +17 -13
  130. toil/test/src/threadingTest.py +29 -32
  131. toil/test/utils/ABCWorkflowDebug/B_file.txt +1 -0
  132. toil/test/utils/ABCWorkflowDebug/debugWorkflow.py +204 -0
  133. toil/test/utils/ABCWorkflowDebug/mkFile.py +16 -0
  134. toil/test/utils/ABCWorkflowDebug/sleep.cwl +12 -0
  135. toil/test/utils/ABCWorkflowDebug/sleep.yaml +1 -0
  136. toil/test/utils/toilDebugTest.py +117 -102
  137. toil/test/utils/toilKillTest.py +54 -53
  138. toil/test/utils/utilsTest.py +303 -229
  139. toil/test/wdl/lint_error.wdl +9 -0
  140. toil/test/wdl/md5sum/empty_file.json +1 -0
  141. toil/test/wdl/md5sum/md5sum-gs.json +1 -0
  142. toil/test/wdl/md5sum/md5sum.1.0.wdl +32 -0
  143. toil/test/wdl/md5sum/md5sum.input +1 -0
  144. toil/test/wdl/md5sum/md5sum.json +1 -0
  145. toil/test/wdl/md5sum/md5sum.wdl +25 -0
  146. toil/test/wdl/miniwdl_self_test/inputs-namespaced.json +1 -0
  147. toil/test/wdl/miniwdl_self_test/inputs.json +1 -0
  148. toil/test/wdl/miniwdl_self_test/self_test.wdl +40 -0
  149. toil/test/wdl/standard_library/as_map.json +16 -0
  150. toil/test/wdl/standard_library/as_map_as_input.wdl +23 -0
  151. toil/test/wdl/standard_library/as_pairs.json +7 -0
  152. toil/test/wdl/standard_library/as_pairs_as_input.wdl +23 -0
  153. toil/test/wdl/standard_library/ceil.json +3 -0
  154. toil/test/wdl/standard_library/ceil_as_command.wdl +16 -0
  155. toil/test/wdl/standard_library/ceil_as_input.wdl +16 -0
  156. toil/test/wdl/standard_library/collect_by_key.json +1 -0
  157. toil/test/wdl/standard_library/collect_by_key_as_input.wdl +23 -0
  158. toil/test/wdl/standard_library/cross.json +11 -0
  159. toil/test/wdl/standard_library/cross_as_input.wdl +19 -0
  160. toil/test/wdl/standard_library/flatten.json +7 -0
  161. toil/test/wdl/standard_library/flatten_as_input.wdl +18 -0
  162. toil/test/wdl/standard_library/floor.json +3 -0
  163. toil/test/wdl/standard_library/floor_as_command.wdl +16 -0
  164. toil/test/wdl/standard_library/floor_as_input.wdl +16 -0
  165. toil/test/wdl/standard_library/keys.json +8 -0
  166. toil/test/wdl/standard_library/keys_as_input.wdl +24 -0
  167. toil/test/wdl/standard_library/length.json +7 -0
  168. toil/test/wdl/standard_library/length_as_input.wdl +16 -0
  169. toil/test/wdl/standard_library/length_as_input_with_map.json +7 -0
  170. toil/test/wdl/standard_library/length_as_input_with_map.wdl +17 -0
  171. toil/test/wdl/standard_library/length_invalid.json +3 -0
  172. toil/test/wdl/standard_library/range.json +3 -0
  173. toil/test/wdl/standard_library/range_0.json +3 -0
  174. toil/test/wdl/standard_library/range_as_input.wdl +17 -0
  175. toil/test/wdl/standard_library/range_invalid.json +3 -0
  176. toil/test/wdl/standard_library/read_boolean.json +3 -0
  177. toil/test/wdl/standard_library/read_boolean_as_command.wdl +17 -0
  178. toil/test/wdl/standard_library/read_float.json +3 -0
  179. toil/test/wdl/standard_library/read_float_as_command.wdl +17 -0
  180. toil/test/wdl/standard_library/read_int.json +3 -0
  181. toil/test/wdl/standard_library/read_int_as_command.wdl +17 -0
  182. toil/test/wdl/standard_library/read_json.json +3 -0
  183. toil/test/wdl/standard_library/read_json_as_output.wdl +31 -0
  184. toil/test/wdl/standard_library/read_lines.json +3 -0
  185. toil/test/wdl/standard_library/read_lines_as_output.wdl +31 -0
  186. toil/test/wdl/standard_library/read_map.json +3 -0
  187. toil/test/wdl/standard_library/read_map_as_output.wdl +31 -0
  188. toil/test/wdl/standard_library/read_string.json +3 -0
  189. toil/test/wdl/standard_library/read_string_as_command.wdl +17 -0
  190. toil/test/wdl/standard_library/read_tsv.json +3 -0
  191. toil/test/wdl/standard_library/read_tsv_as_output.wdl +31 -0
  192. toil/test/wdl/standard_library/round.json +3 -0
  193. toil/test/wdl/standard_library/round_as_command.wdl +16 -0
  194. toil/test/wdl/standard_library/round_as_input.wdl +16 -0
  195. toil/test/wdl/standard_library/size.json +3 -0
  196. toil/test/wdl/standard_library/size_as_command.wdl +17 -0
  197. toil/test/wdl/standard_library/size_as_output.wdl +36 -0
  198. toil/test/wdl/standard_library/stderr.json +3 -0
  199. toil/test/wdl/standard_library/stderr_as_output.wdl +30 -0
  200. toil/test/wdl/standard_library/stdout.json +3 -0
  201. toil/test/wdl/standard_library/stdout_as_output.wdl +30 -0
  202. toil/test/wdl/standard_library/sub.json +3 -0
  203. toil/test/wdl/standard_library/sub_as_input.wdl +17 -0
  204. toil/test/wdl/standard_library/sub_as_input_with_file.wdl +17 -0
  205. toil/test/wdl/standard_library/transpose.json +6 -0
  206. toil/test/wdl/standard_library/transpose_as_input.wdl +18 -0
  207. toil/test/wdl/standard_library/write_json.json +6 -0
  208. toil/test/wdl/standard_library/write_json_as_command.wdl +17 -0
  209. toil/test/wdl/standard_library/write_lines.json +7 -0
  210. toil/test/wdl/standard_library/write_lines_as_command.wdl +17 -0
  211. toil/test/wdl/standard_library/write_map.json +6 -0
  212. toil/test/wdl/standard_library/write_map_as_command.wdl +17 -0
  213. toil/test/wdl/standard_library/write_tsv.json +6 -0
  214. toil/test/wdl/standard_library/write_tsv_as_command.wdl +17 -0
  215. toil/test/wdl/standard_library/zip.json +12 -0
  216. toil/test/wdl/standard_library/zip_as_input.wdl +19 -0
  217. toil/test/wdl/test.csv +3 -0
  218. toil/test/wdl/test.tsv +3 -0
  219. toil/test/wdl/testfiles/croo.wdl +38 -0
  220. toil/test/wdl/testfiles/drop_files.wdl +62 -0
  221. toil/test/wdl/testfiles/drop_files_subworkflow.wdl +13 -0
  222. toil/test/wdl/testfiles/empty.txt +0 -0
  223. toil/test/wdl/testfiles/not_enough_outputs.wdl +33 -0
  224. toil/test/wdl/testfiles/random.wdl +66 -0
  225. toil/test/wdl/testfiles/string_file_coercion.json +1 -0
  226. toil/test/wdl/testfiles/string_file_coercion.wdl +35 -0
  227. toil/test/wdl/testfiles/test.json +4 -0
  228. toil/test/wdl/testfiles/test_boolean.txt +1 -0
  229. toil/test/wdl/testfiles/test_float.txt +1 -0
  230. toil/test/wdl/testfiles/test_int.txt +1 -0
  231. toil/test/wdl/testfiles/test_lines.txt +5 -0
  232. toil/test/wdl/testfiles/test_map.txt +2 -0
  233. toil/test/wdl/testfiles/test_string.txt +1 -0
  234. toil/test/wdl/testfiles/url_to_file.wdl +13 -0
  235. toil/test/wdl/testfiles/url_to_optional_file.wdl +13 -0
  236. toil/test/wdl/testfiles/vocab.json +1 -0
  237. toil/test/wdl/testfiles/vocab.wdl +66 -0
  238. toil/test/wdl/testfiles/wait.wdl +34 -0
  239. toil/test/wdl/wdl_specification/type_pair.json +23 -0
  240. toil/test/wdl/wdl_specification/type_pair_basic.wdl +36 -0
  241. toil/test/wdl/wdl_specification/type_pair_with_files.wdl +36 -0
  242. toil/test/wdl/wdl_specification/v1_spec.json +1 -0
  243. toil/test/wdl/wdl_specification/v1_spec_declaration.wdl +39 -0
  244. toil/test/wdl/wdltoil_test.py +680 -407
  245. toil/test/wdl/wdltoil_test_kubernetes.py +2 -2
  246. toil/version.py +9 -9
  247. toil/wdl/wdltoil.py +336 -123
  248. {toil-8.1.0b1.dist-info → toil-8.2.0.dist-info}/METADATA +5 -4
  249. toil-8.2.0.dist-info/RECORD +439 -0
  250. {toil-8.1.0b1.dist-info → toil-8.2.0.dist-info}/WHEEL +1 -1
  251. toil-8.1.0b1.dist-info/RECORD +0 -259
  252. {toil-8.1.0b1.dist-info → toil-8.2.0.dist-info}/entry_points.txt +0 -0
  253. {toil-8.1.0b1.dist-info → toil-8.2.0.dist-info/licenses}/LICENSE +0 -0
  254. {toil-8.1.0b1.dist-info → toil-8.2.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,45 @@
1
+ import os
2
+
3
+ from toil.common import Toil
4
+ from toil.job import Job
5
+ from toil.lib.io import mkdtemp
6
+
7
+
8
+ class HelloWorld(Job):
9
+ def __init__(self, id):
10
+ Job.__init__(self)
11
+ self.inputFileID = id
12
+
13
+ def run(self, fileStore):
14
+ with fileStore.readGlobalFileStream(self.inputFileID, encoding="utf-8") as fi:
15
+ with fileStore.writeGlobalFileStream(encoding="utf-8") as (
16
+ fo,
17
+ outputFileID,
18
+ ):
19
+ fo.write(fi.read() + "World!")
20
+ return outputFileID
21
+
22
+
23
+ if __name__ == "__main__":
24
+ jobstore: str = mkdtemp("tutorial_staging")
25
+ os.rmdir(jobstore)
26
+ options = Job.Runner.getDefaultOptions(jobstore)
27
+ options.logLevel = "INFO"
28
+ options.clean = "always"
29
+
30
+ with Toil(options) as toil:
31
+ if not toil.options.restart:
32
+ ioFileDirectory = os.path.join(
33
+ os.path.dirname(os.path.abspath(__file__)), "stagingExampleFiles"
34
+ )
35
+ inputFileID = toil.importFile(
36
+ "file://" + os.path.abspath(os.path.join(ioFileDirectory, "in.txt"))
37
+ )
38
+ outputFileID = toil.start(HelloWorld(inputFileID))
39
+ else:
40
+ outputFileID = toil.restart()
41
+
42
+ toil.exportFile(
43
+ outputFileID,
44
+ "file://" + os.path.abspath(os.path.join(ioFileDirectory, "out.txt")),
45
+ )
@@ -0,0 +1,64 @@
1
+ import math
2
+ import time
3
+ from multiprocessing import Process
4
+
5
+ from toil.common import Toil
6
+ from toil.job import Job
7
+
8
+
9
+ def think(seconds):
10
+ start = time.time()
11
+ while time.time() - start < seconds:
12
+ # Use CPU
13
+ math.sqrt(123456)
14
+
15
+
16
+ class TimeWaster(Job):
17
+ def __init__(self, time_to_think, time_to_waste, space_to_waste, *args, **kwargs):
18
+ self.time_to_think = time_to_think
19
+ self.time_to_waste = time_to_waste
20
+ self.space_to_waste = space_to_waste
21
+ super().__init__(*args, **kwargs)
22
+
23
+ def run(self, fileStore):
24
+ # Waste some space
25
+ file_path = fileStore.getLocalTempFile()
26
+ with open(file_path, "w") as stream:
27
+ for i in range(self.space_to_waste):
28
+ stream.write("X")
29
+
30
+ # Do some "useful" compute
31
+ processes = []
32
+ for core_number in range(max(1, self.cores)):
33
+ # Use all the assigned cores to think
34
+ p = Process(target=think, args=(self.time_to_think,))
35
+ p.start()
36
+ processes.append(p)
37
+ for p in processes:
38
+ p.join()
39
+
40
+ # Also waste some time
41
+ time.sleep(self.time_to_waste)
42
+
43
+
44
+ def main():
45
+ options = Job.Runner.getDefaultArgumentParser().parse_args()
46
+
47
+ job1 = TimeWaster(0, 0, 0, displayName="doNothing")
48
+ job2 = TimeWaster(10, 0, 4096, displayName="efficientJob")
49
+ job3 = TimeWaster(10, 0, 1024, cores=4, displayName="multithreadedJob")
50
+ job4 = TimeWaster(1, 9, 65536, displayName="inefficientJob")
51
+
52
+ job1.addChild(job2)
53
+ job1.addChild(job3)
54
+ job3.addChild(job4)
55
+
56
+ with Toil(options) as toil:
57
+ if not toil.options.restart:
58
+ toil.start(job1)
59
+ else:
60
+ toil.restart()
61
+
62
+
63
+ if __name__ == "__main__":
64
+ main()
@@ -19,7 +19,7 @@ import boto3
19
19
  from moto import mock_aws
20
20
 
21
21
  from toil.lib.aws import iam
22
- from toil.test import ToilTest
22
+ from toil.test import ToilTest, needs_aws_s3
23
23
 
24
24
  logger = logging.getLogger(__name__)
25
25
  logging.basicConfig(level=logging.DEBUG)
@@ -70,6 +70,7 @@ class IAMTest(ToilTest):
70
70
  assert iam.permission_matches_any("ec2:*", ["iam:*"]) is False
71
71
 
72
72
  @mock_aws
73
+ @needs_aws_s3 # mock is incomplete, this avoid 'botocore.exceptions.NoCredentialsError: Unable to locate credentials'
73
74
  def test_get_policy_permissions(self):
74
75
  mock_iam = boto3.client("iam")
75
76
 
@@ -165,6 +166,7 @@ class IAMTest(ToilTest):
165
166
  assert actions_set == expected_actions
166
167
  assert notactions_set == set()
167
168
 
169
+ @needs_aws_s3
168
170
  def test_create_delete_iam_role(self):
169
171
  region = "us-west-2"
170
172
  role_name = f'test{str(uuid4()).replace("-", "")}'
@@ -13,12 +13,14 @@
13
13
  # limitations under the License.
14
14
  import logging
15
15
  import os
16
+ from pathlib import Path
16
17
  import signal
17
18
  import time
19
+ from typing import Optional
18
20
  import uuid
19
21
  from threading import Thread
20
22
 
21
- from docker.errors import ContainerError
23
+ from docker.errors import ContainerError # type: ignore[import-not-found]
22
24
  from toil.common import Toil
23
25
  from toil.exceptions import FailedJobsException
24
26
  from toil.job import Job
@@ -30,31 +32,31 @@ from toil.lib.docker import (
30
32
  containerIsRunning,
31
33
  dockerKill,
32
34
  )
33
- from toil.test import ToilTest, needs_docker, slow
35
+ from toil.test import pneeds_docker as needs_docker, pslow as slow
36
+
37
+ import pytest
34
38
 
35
39
  logger = logging.getLogger(__name__)
36
40
 
37
41
 
38
42
  @needs_docker
39
- class DockerTest(ToilTest):
43
+ @pytest.mark.docker
44
+ @pytest.mark.online
45
+ class TestDocker:
40
46
  """
41
47
  Tests dockerCall and ensures no containers are left around.
42
- When running tests you may optionally set the TOIL_TEST_TEMP environment
43
- variable to the path of a directory where you want temporary test files be
44
- placed. The directory will be created if it doesn't exist. The path may be
45
- relative in which case it will be assumed to be relative to the project
46
- root. If TOIL_TEST_TEMP is not defined, temporary files and directories will
47
- be created in the system's default location for such files and any temporary
48
- files or directories left over from tests will be removed automatically
49
- removed during tear down.
50
- Otherwise, left-over files will not be removed.
51
48
  """
52
49
 
53
- def setUp(self):
54
- self.tempDir = self._createTempDir(purpose="tempDir")
55
- self.dockerTestLogLevel = "INFO"
50
+ dockerTestLogLevel = "INFO"
56
51
 
57
- def testDockerClean(self, caching=False, detached=True, rm=True, deferParam=None):
52
+ def testDockerClean(
53
+ self,
54
+ tmp_path: Path,
55
+ caching: bool = False,
56
+ detached: bool = True,
57
+ rm: bool = True,
58
+ deferParam: Optional[int] = None,
59
+ ) -> None:
58
60
  """
59
61
  Run the test container that creates a file in the work dir, and sleeps
60
62
  for 5 minutes.
@@ -72,16 +74,15 @@ class DockerTest(ToilTest):
72
74
  # detached X R E X
73
75
  # Neither X R E X
74
76
 
75
- data_dir = os.path.join(self.tempDir, "data")
76
- working_dir = os.path.join(self.tempDir, "working")
77
- test_file = os.path.join(working_dir, "test.txt")
78
-
79
- os.makedirs(data_dir, exist_ok=True)
80
- os.makedirs(working_dir, exist_ok=True)
77
+ data_dir = tmp_path / "data"
78
+ data_dir.mkdir()
79
+ working_dir = tmp_path / "working"
80
+ working_dir.mkdir()
81
+ test_file = working_dir / "test.txt"
81
82
 
82
- options = Job.Runner.getDefaultOptions(os.path.join(self.tempDir, "jobstore"))
83
+ options = Job.Runner.getDefaultOptions(tmp_path / "jobstore")
83
84
  options.logLevel = self.dockerTestLogLevel
84
- options.workDir = working_dir
85
+ options.workDir = str(working_dir)
85
86
  options.clean = "always"
86
87
  options.retryCount = 0 # we're expecting the job to fail so don't retry!
87
88
  options.caching = caching
@@ -99,7 +100,7 @@ class DockerTest(ToilTest):
99
100
  # and since it was created inside the container, it would have had
100
101
  # uid and gid == 0 (root) which may cause problems when docker
101
102
  # attempts to clean up the jobstore.
102
- file_stats = os.stat(test_file)
103
+ file_stats = test_file.stat()
103
104
  assert file_stats.st_gid != 0
104
105
  assert file_stats.st_uid != 0
105
106
 
@@ -124,104 +125,173 @@ class DockerTest(ToilTest):
124
125
  # Clean up
125
126
  try:
126
127
  dockerKill(container_name, remove=True)
127
- os.remove(test_file)
128
+ test_file.unlink()
128
129
  except:
129
130
  pass
130
131
 
131
- def testDockerClean_CRx_FORGO(self):
132
- self.testDockerClean(caching=False, detached=False, rm=True, deferParam=FORGO)
132
+ def testDockerClean_CRx_FORGO(self, tmp_path: Path) -> None:
133
+ self.testDockerClean(
134
+ tmp_path, caching=False, detached=False, rm=True, deferParam=FORGO
135
+ )
133
136
 
134
- def testDockerClean_CRx_STOP(self):
135
- self.testDockerClean(caching=False, detached=False, rm=True, deferParam=STOP)
137
+ def testDockerClean_CRx_STOP(self, tmp_path: Path) -> None:
138
+ self.testDockerClean(
139
+ tmp_path, caching=False, detached=False, rm=True, deferParam=STOP
140
+ )
136
141
 
137
- def testDockerClean_CRx_RM(self):
138
- self.testDockerClean(caching=False, detached=False, rm=True, deferParam=RM)
142
+ def testDockerClean_CRx_RM(self, tmp_path: Path) -> None:
143
+ self.testDockerClean(
144
+ tmp_path, caching=False, detached=False, rm=True, deferParam=RM
145
+ )
139
146
 
140
147
  @slow
141
- def testDockerClean_CRx_None(self):
142
- self.testDockerClean(caching=False, detached=False, rm=True, deferParam=None)
148
+ @pytest.mark.slow
149
+ def testDockerClean_CRx_None(self, tmp_path: Path) -> None:
150
+ self.testDockerClean(
151
+ tmp_path, caching=False, detached=False, rm=True, deferParam=None
152
+ )
143
153
 
144
154
  @slow
145
- def testDockerClean_CxD_FORGO(self):
146
- self.testDockerClean(caching=False, detached=True, rm=False, deferParam=FORGO)
155
+ @pytest.mark.slow
156
+ def testDockerClean_CxD_FORGO(self, tmp_path: Path) -> None:
157
+ self.testDockerClean(
158
+ tmp_path, caching=False, detached=True, rm=False, deferParam=FORGO
159
+ )
147
160
 
148
161
  @slow
149
- def testDockerClean_CxD_STOP(self):
150
- self.testDockerClean(caching=False, detached=True, rm=False, deferParam=STOP)
162
+ @pytest.mark.slow
163
+ def testDockerClean_CxD_STOP(self, tmp_path: Path) -> None:
164
+ self.testDockerClean(
165
+ tmp_path, caching=False, detached=True, rm=False, deferParam=STOP
166
+ )
151
167
 
152
168
  @slow
153
- def testDockerClean_CxD_RM(self):
154
- self.testDockerClean(caching=False, detached=True, rm=False, deferParam=RM)
169
+ @pytest.mark.slow
170
+ def testDockerClean_CxD_RM(self, tmp_path: Path) -> None:
171
+ self.testDockerClean(
172
+ tmp_path, caching=False, detached=True, rm=False, deferParam=RM
173
+ )
155
174
 
156
175
  @slow
157
- def testDockerClean_CxD_None(self):
158
- self.testDockerClean(caching=False, detached=True, rm=False, deferParam=None)
176
+ @pytest.mark.slow
177
+ def testDockerClean_CxD_None(self, tmp_path: Path) -> None:
178
+ self.testDockerClean(
179
+ tmp_path, caching=False, detached=True, rm=False, deferParam=None
180
+ )
159
181
 
160
182
  @slow
161
- def testDockerClean_Cxx_FORGO(self):
162
- self.testDockerClean(caching=False, detached=False, rm=False, deferParam=FORGO)
183
+ @pytest.mark.slow
184
+ def testDockerClean_Cxx_FORGO(self, tmp_path: Path) -> None:
185
+ self.testDockerClean(
186
+ tmp_path, caching=False, detached=False, rm=False, deferParam=FORGO
187
+ )
163
188
 
164
189
  @slow
165
- def testDockerClean_Cxx_STOP(self):
166
- self.testDockerClean(caching=False, detached=False, rm=False, deferParam=STOP)
190
+ @pytest.mark.slow
191
+ def testDockerClean_Cxx_STOP(self, tmp_path: Path) -> None:
192
+ self.testDockerClean(
193
+ tmp_path, caching=False, detached=False, rm=False, deferParam=STOP
194
+ )
167
195
 
168
196
  @slow
169
- def testDockerClean_Cxx_RM(self):
170
- self.testDockerClean(caching=False, detached=False, rm=False, deferParam=RM)
197
+ @pytest.mark.slow
198
+ def testDockerClean_Cxx_RM(self, tmp_path: Path) -> None:
199
+ self.testDockerClean(
200
+ tmp_path, caching=False, detached=False, rm=False, deferParam=RM
201
+ )
171
202
 
172
203
  @slow
173
- def testDockerClean_Cxx_None(self):
174
- self.testDockerClean(caching=False, detached=False, rm=False, deferParam=None)
204
+ @pytest.mark.slow
205
+ def testDockerClean_Cxx_None(self, tmp_path: Path) -> None:
206
+ self.testDockerClean(
207
+ tmp_path, caching=False, detached=False, rm=False, deferParam=None
208
+ )
175
209
 
176
210
  @slow
177
- def testDockerClean_xRx_FORGO(self):
178
- self.testDockerClean(caching=True, detached=False, rm=True, deferParam=FORGO)
211
+ @pytest.mark.slow
212
+ def testDockerClean_xRx_FORGO(self, tmp_path: Path) -> None:
213
+ self.testDockerClean(
214
+ tmp_path, caching=True, detached=False, rm=True, deferParam=FORGO
215
+ )
179
216
 
180
217
  @slow
181
- def testDockerClean_xRx_STOP(self):
182
- self.testDockerClean(caching=True, detached=False, rm=True, deferParam=STOP)
218
+ @pytest.mark.slow
219
+ def testDockerClean_xRx_STOP(self, tmp_path: Path) -> None:
220
+ self.testDockerClean(
221
+ tmp_path, caching=True, detached=False, rm=True, deferParam=STOP
222
+ )
183
223
 
184
224
  @slow
185
- def testDockerClean_xRx_RM(self):
186
- self.testDockerClean(caching=True, detached=False, rm=True, deferParam=RM)
225
+ @pytest.mark.slow
226
+ def testDockerClean_xRx_RM(self, tmp_path: Path) -> None:
227
+ self.testDockerClean(
228
+ tmp_path, caching=True, detached=False, rm=True, deferParam=RM
229
+ )
187
230
 
188
231
  @slow
189
- def testDockerClean_xRx_None(self):
190
- self.testDockerClean(caching=True, detached=False, rm=True, deferParam=None)
232
+ @pytest.mark.slow
233
+ def testDockerClean_xRx_None(self, tmp_path: Path) -> None:
234
+ self.testDockerClean(
235
+ tmp_path, caching=True, detached=False, rm=True, deferParam=None
236
+ )
191
237
 
192
238
  @slow
193
- def testDockerClean_xxD_FORGO(self):
194
- self.testDockerClean(caching=True, detached=True, rm=False, deferParam=FORGO)
239
+ @pytest.mark.slow
240
+ def testDockerClean_xxD_FORGO(self, tmp_path: Path) -> None:
241
+ self.testDockerClean(
242
+ tmp_path, caching=True, detached=True, rm=False, deferParam=FORGO
243
+ )
195
244
 
196
245
  @slow
197
- def testDockerClean_xxD_STOP(self):
198
- self.testDockerClean(caching=True, detached=True, rm=False, deferParam=STOP)
246
+ @pytest.mark.slow
247
+ def testDockerClean_xxD_STOP(self, tmp_path: Path) -> None:
248
+ self.testDockerClean(
249
+ tmp_path, caching=True, detached=True, rm=False, deferParam=STOP
250
+ )
199
251
 
200
252
  @slow
201
- def testDockerClean_xxD_RM(self):
202
- self.testDockerClean(caching=True, detached=True, rm=False, deferParam=RM)
253
+ @pytest.mark.slow
254
+ def testDockerClean_xxD_RM(self, tmp_path: Path) -> None:
255
+ self.testDockerClean(
256
+ tmp_path, caching=True, detached=True, rm=False, deferParam=RM
257
+ )
203
258
 
204
259
  @slow
205
- def testDockerClean_xxD_None(self):
206
- self.testDockerClean(caching=True, detached=True, rm=False, deferParam=None)
260
+ @pytest.mark.slow
261
+ def testDockerClean_xxD_None(self, tmp_path: Path) -> None:
262
+ self.testDockerClean(
263
+ tmp_path, caching=True, detached=True, rm=False, deferParam=None
264
+ )
207
265
 
208
266
  @slow
209
- def testDockerClean_xxx_FORGO(self):
210
- self.testDockerClean(caching=True, detached=False, rm=False, deferParam=FORGO)
267
+ @pytest.mark.slow
268
+ def testDockerClean_xxx_FORGO(self, tmp_path: Path) -> None:
269
+ self.testDockerClean(
270
+ tmp_path, caching=True, detached=False, rm=False, deferParam=FORGO
271
+ )
211
272
 
212
273
  @slow
213
- def testDockerClean_xxx_STOP(self):
214
- self.testDockerClean(caching=True, detached=False, rm=False, deferParam=STOP)
274
+ @pytest.mark.slow
275
+ def testDockerClean_xxx_STOP(self, tmp_path: Path) -> None:
276
+ self.testDockerClean(
277
+ tmp_path, caching=True, detached=False, rm=False, deferParam=STOP
278
+ )
215
279
 
216
280
  @slow
217
- def testDockerClean_xxx_RM(self):
218
- self.testDockerClean(caching=True, detached=False, rm=False, deferParam=RM)
281
+ @pytest.mark.slow
282
+ def testDockerClean_xxx_RM(self, tmp_path: Path) -> None:
283
+ self.testDockerClean(
284
+ tmp_path, caching=True, detached=False, rm=False, deferParam=RM
285
+ )
219
286
 
220
287
  @slow
221
- def testDockerClean_xxx_None(self):
222
- self.testDockerClean(caching=True, detached=False, rm=False, deferParam=None)
288
+ @pytest.mark.slow
289
+ def testDockerClean_xxx_None(self, tmp_path: Path) -> None:
290
+ self.testDockerClean(
291
+ tmp_path, caching=True, detached=False, rm=False, deferParam=None
292
+ )
223
293
 
224
- def testDockerPipeChain(self, caching=False):
294
+ def testDockerPipeChain(self, tmp_path: Path, caching: bool = False) -> None:
225
295
  r"""
226
296
  Test for piping API for dockerCall(). Using this API (activated when
227
297
  list of argument lists is given as parameters), commands a piped
@@ -229,9 +299,11 @@ class DockerTest(ToilTest):
229
299
  ex: ``parameters=[ ['printf', 'x\n y\n'], ['wc', '-l'] ]`` should execute:
230
300
  ``printf 'x\n y\n' | wc -l``
231
301
  """
232
- options = Job.Runner.getDefaultOptions(os.path.join(self.tempDir, "jobstore"))
302
+ workdir = tmp_path / "workdir"
303
+ workdir.mkdir()
304
+ options = Job.Runner.getDefaultOptions(tmp_path / "jobstore")
233
305
  options.logLevel = self.dockerTestLogLevel
234
- options.workDir = self.tempDir
306
+ options.workDir = str(workdir)
235
307
  options.clean = "always"
236
308
  options.caching = caching
237
309
  A = Job.wrapJobFn(_testDockerPipeChainFn)
@@ -240,38 +312,44 @@ class DockerTest(ToilTest):
240
312
  rv = rv.decode("utf-8")
241
313
  assert rv.strip() == "2"
242
314
 
243
- def testDockerPipeChainErrorDetection(self, caching=False):
315
+ def testDockerPipeChainErrorDetection(
316
+ self, tmp_path: Path, caching: bool = False
317
+ ) -> None:
244
318
  """
245
319
  By default, executing cmd1 | cmd2 | ... | cmdN, will only return an
246
320
  error if cmdN fails. This can lead to all manor of errors being
247
321
  silently missed. This tests to make sure that the piping API for
248
322
  dockerCall() throws an exception if non-last commands in the chain fail.
249
323
  """
250
- options = Job.Runner.getDefaultOptions(os.path.join(self.tempDir, "jobstore"))
324
+ workdir = tmp_path / "workdir"
325
+ workdir.mkdir()
326
+ options = Job.Runner.getDefaultOptions(tmp_path / "jobstore")
251
327
  options.logLevel = self.dockerTestLogLevel
252
- options.workDir = self.tempDir
328
+ options.workDir = str(workdir)
253
329
  options.clean = "always"
254
330
  options.caching = caching
255
331
  A = Job.wrapJobFn(_testDockerPipeChainErrorFn)
256
332
  rv = Job.Runner.startToil(A, options)
257
333
  assert rv is True
258
334
 
259
- def testNonCachingDockerChain(self):
260
- self.testDockerPipeChain(caching=True)
335
+ def testNonCachingDockerChain(self, tmp_path: Path) -> None:
336
+ self.testDockerPipeChain(tmp_path, caching=True)
261
337
 
262
- def testNonCachingDockerChainErrorDetection(self):
263
- self.testDockerPipeChainErrorDetection(caching=True)
338
+ def testNonCachingDockerChainErrorDetection(self, tmp_path: Path) -> None:
339
+ self.testDockerPipeChainErrorDetection(tmp_path, caching=True)
264
340
 
265
- def testDockerLogs(self, stream=False, demux=False):
341
+ def testDockerLogs(
342
+ self, tmp_path: Path, stream: bool = False, demux: bool = False
343
+ ) -> None:
266
344
  """Test for the different log outputs when deatch=False."""
267
345
 
268
- working_dir = os.path.join(self.tempDir, "working")
269
- script_file = os.path.join(working_dir, "script.sh")
270
- os.makedirs(working_dir, exist_ok=True)
346
+ working_dir = tmp_path / "working"
347
+ working_dir.mkdir()
348
+ script_file = working_dir / "script.sh"
271
349
 
272
- options = Job.Runner.getDefaultOptions(os.path.join(self.tempDir, "jobstore"))
350
+ options = Job.Runner.getDefaultOptions(tmp_path / "jobstore")
273
351
  options.logLevel = self.dockerTestLogLevel
274
- options.workDir = working_dir
352
+ options.workDir = str(working_dir)
275
353
  options.clean = "always"
276
354
  A = Job.wrapJobFn(
277
355
  _testDockerLogsFn,
@@ -281,43 +359,42 @@ class DockerTest(ToilTest):
281
359
  demux=demux,
282
360
  )
283
361
 
284
- try:
285
- rv = Job.Runner.startToil(A, options)
286
- assert rv is True
287
- finally:
288
- try:
289
- os.remove(script_file)
290
- except:
291
- pass
362
+ rv = Job.Runner.startToil(A, options)
363
+ assert rv is True
292
364
 
293
- def testDockerLogs_Stream(self):
294
- self.testDockerLogs(stream=True, demux=False)
365
+ def testDockerLogs_Stream(self, tmp_path: Path) -> None:
366
+ self.testDockerLogs(tmp_path, stream=True, demux=False)
295
367
 
296
- def testDockerLogs_Demux(self):
297
- self.testDockerLogs(stream=False, demux=True)
368
+ def testDockerLogs_Demux(self, tmp_path: Path) -> None:
369
+ self.testDockerLogs(tmp_path, stream=False, demux=True)
298
370
 
299
- def testDockerLogs_Demux_Stream(self):
300
- self.testDockerLogs(stream=True, demux=True)
371
+ def testDockerLogs_Demux_Stream(self, tmp_path: Path) -> None:
372
+ self.testDockerLogs(tmp_path, stream=True, demux=True)
301
373
 
302
374
 
303
375
  def _testDockerCleanFn(
304
- job, working_dir, detached=None, rm=None, deferParam=None, containerName=None
305
- ):
376
+ job: Job,
377
+ working_dir: Path,
378
+ detached: bool = True,
379
+ rm: Optional[bool] = None,
380
+ deferParam: Optional[int] = None,
381
+ containerName: Optional[str] = None,
382
+ ) -> None:
306
383
  """
307
384
  Test function for test docker_clean. Runs a container with given flags and
308
385
  then dies leaving behind a zombie container.
309
- :param toil.job.Job job: job
386
+ :param job: job
310
387
  :param working_dir: See `work_dir=` in :func:`dockerCall`
311
- :param bool rm: See `rm=` in :func:`dockerCall`
312
- :param bool detached: See `detached=` in :func:`dockerCall`
313
- :param int deferParam: See `deferParam=` in :func:`dockerCall`
314
- :param str containerName: See `container_name=` in :func:`dockerCall`
388
+ :param detached: See `detached=` in :func:`dockerCall`
389
+ :param rm: See `rm=` in :func:`dockerCall`
390
+ :param deferParam: See `deferParam=` in :func:`dockerCall`
391
+ :param containerName: See `container_name=` in :func:`dockerCall`
315
392
  """
316
393
 
317
- def killSelf():
318
- test_file = os.path.join(working_dir, "test.txt")
394
+ def killSelf() -> None:
395
+ test_file = working_dir / "test.txt"
319
396
  # Kill the worker once we are sure the docker container is started
320
- while not os.path.exists(test_file):
397
+ while not test_file.exists():
321
398
  logger.debug("Waiting on the file created by spooky_container.")
322
399
  time.sleep(1)
323
400
  # By the time we reach here, we are sure the container is running.
@@ -331,8 +408,8 @@ def _testDockerCleanFn(
331
408
  apiDockerCall(
332
409
  job,
333
410
  image="quay.io/ucsc_cgl/spooky_test",
334
- working_dir=working_dir,
335
411
  deferParam=deferParam,
412
+ working_dir=str(working_dir),
336
413
  containerName=containerName,
337
414
  detach=detached,
338
415
  remove=rm,
@@ -340,7 +417,7 @@ def _testDockerCleanFn(
340
417
  )
341
418
 
342
419
 
343
- def _testDockerPipeChainFn(job):
420
+ def _testDockerPipeChainFn(job: Job) -> str:
344
421
  """Return the result of a simple pipe chain. Should be 2."""
345
422
  parameters = [["printf", "x\n y\n"], ["wc", "-l"]]
346
423
  return apiDockerCall(
@@ -351,7 +428,7 @@ def _testDockerPipeChainFn(job):
351
428
  )
352
429
 
353
430
 
354
- def _testDockerPipeChainErrorFn(job):
431
+ def _testDockerPipeChainErrorFn(job: Job) -> bool:
355
432
  """Return True if the command exit 1 | wc -l raises a ContainerError."""
356
433
  parameters = [["exit", "1"], ["wc", "-l"]]
357
434
  try:
@@ -361,7 +438,13 @@ def _testDockerPipeChainErrorFn(job):
361
438
  return False
362
439
 
363
440
 
364
- def _testDockerLogsFn(job, working_dir, script_file, stream=False, demux=False):
441
+ def _testDockerLogsFn(
442
+ job: Job,
443
+ working_dir: Path,
444
+ script_file: Path,
445
+ stream: bool = False,
446
+ demux: bool = False,
447
+ ) -> bool:
365
448
  """Return True if the test succeeds. Otherwise Exception is raised."""
366
449
 
367
450
  # we write a script file because the redirection operator, '>&2', is wrapped
@@ -380,15 +463,15 @@ def _testDockerLogsFn(job, working_dir, script_file, stream=False, demux=False):
380
463
  """
381
464
  )
382
465
 
383
- with open(script_file, "w") as file:
466
+ with script_file.open("w") as file:
384
467
  file.write(bash_script)
385
468
 
386
469
  out = apiDockerCall(
387
470
  job,
388
471
  image="quay.io/ucsc_cgl/ubuntu:20.04",
389
- working_dir=working_dir,
390
- parameters=[script_file],
391
- volumes={working_dir: {"bind": working_dir, "mode": "rw"}},
472
+ working_dir=str(working_dir),
473
+ parameters=[str(script_file)],
474
+ volumes={str(working_dir): {"bind": str(working_dir), "mode": "rw"}},
392
475
  entrypoint="/bin/bash",
393
476
  stdout=True,
394
477
  stderr=True,