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
@@ -13,54 +13,58 @@
13
13
  # limitations under the License.
14
14
 
15
15
 
16
+ from argparse import Namespace
16
17
  import os
18
+ from pathlib import Path
17
19
  import stat
18
20
  import uuid
19
21
 
20
22
  from toil.common import Toil
21
23
  from toil.exceptions import FailedJobsException
22
24
  from toil.fileStores import FileID
25
+ from toil.fileStores.abstractFileStore import AbstractFileStore
23
26
  from toil.job import Job
24
- from toil.test import ToilTest, slow
27
+ from toil.test import pslow as slow
25
28
 
29
+ import pytest
30
+ from pytest_subtests import SubTests
26
31
 
27
- class ImportExportFileTest(ToilTest):
28
- def setUp(self):
29
- super().setUp()
30
- self.tmp_dir = self._createTempDir()
31
- self.output_file_path = f"{self.tmp_dir}/out"
32
- self.message_portion_1 = (
33
- "What do you get when you cross a seal and a polar bear?"
34
- )
35
- self.message_portion_2 = " A polar bear."
36
32
 
37
- def create_file(self, content, executable=False):
38
- file_path = f"{self.tmp_dir}/{uuid.uuid4()}"
33
+ def create_file(tmp_path: Path, content: str, executable: bool = False) -> Path:
34
+ file_path = tmp_path / str(uuid.uuid4())
39
35
 
40
- with open(file_path, "w") as f:
41
- f.write(content)
36
+ with file_path.open("w") as f:
37
+ f.write(content)
42
38
 
43
- if executable:
44
- # Add file owner execute permissions
45
- os.chmod(file_path, os.stat(file_path).st_mode | stat.S_IXUSR)
39
+ if executable:
40
+ # Add file owner execute permissions
41
+ file_path.chmod(file_path.stat().st_mode | stat.S_IXUSR)
46
42
 
47
- return file_path
43
+ return file_path
48
44
 
49
- def _import_export_workflow(self, options, fail):
45
+
46
+ class TestImportExportFile:
47
+ message_portion_1 = "What do you get when you cross a seal and a polar bear?"
48
+ message_portion_2 = " A polar bear."
49
+
50
+ def _import_export_workflow(
51
+ self, tmp_path: Path, options: Namespace, fail: bool
52
+ ) -> None:
50
53
  with Toil(options) as toil:
51
54
  if not options.restart:
52
- msg_portion_file_path = self.create_file(content=self.message_portion_1)
53
- msg_portion_file_id = toil.importFile(f"file://{msg_portion_file_path}")
54
- self.assertIsInstance(msg_portion_file_id, FileID)
55
- self.assertEqual(
56
- os.stat(msg_portion_file_path).st_size, msg_portion_file_id.size
55
+ msg_portion_file_path = create_file(
56
+ tmp_path, content=self.message_portion_1
57
57
  )
58
+ msg_portion_file_id = toil.importFile(msg_portion_file_path.as_uri())
59
+ assert isinstance(msg_portion_file_id, FileID)
60
+ assert msg_portion_file_path.stat().st_size == msg_portion_file_id.size
58
61
 
59
- file_that_can_trigger_failure_when_job_starts = self.create_file(
60
- content="Time to freak out!" if fail else "Keep calm and carry on."
62
+ file_that_can_trigger_failure_when_job_starts = create_file(
63
+ tmp_path,
64
+ content="Time to freak out!" if fail else "Keep calm and carry on.",
61
65
  )
62
66
  self.trigger_file_id = toil.importFile(
63
- f"file://{file_that_can_trigger_failure_when_job_starts}"
67
+ file_that_can_trigger_failure_when_job_starts.as_uri()
64
68
  )
65
69
  workflow_final_output_file_id = toil.start(
66
70
  RestartingJob(
@@ -81,89 +85,93 @@ class ImportExportFileTest(ToilTest):
81
85
 
82
86
  workflow_final_output_file_id = toil.restart()
83
87
 
84
- toil.exportFile(
85
- workflow_final_output_file_id, f"file://{self.output_file_path}"
86
- )
87
- with open(self.output_file_path) as f:
88
- self.assertEqual(
89
- f.read(), f"{self.message_portion_1}{self.message_portion_2}"
90
- )
88
+ toil.exportFile(workflow_final_output_file_id, str(tmp_path / "out"))
89
+ with (tmp_path / "out").open() as f:
90
+ assert f.read() == f"{self.message_portion_1}{self.message_portion_2}"
91
91
 
92
- def _run_import_export_workflow(self, restart):
93
- options = Job.Runner.getDefaultOptions(self._getTestJobStorePath())
92
+ def _run_import_export_workflow(self, tmp_path: Path, restart: bool) -> None:
93
+ options = Job.Runner.getDefaultOptions(tmp_path / "jobstore")
94
94
  options.logLevel = "INFO"
95
95
 
96
96
  if restart:
97
97
  try:
98
- self._import_export_workflow(options, fail=True)
98
+ self._import_export_workflow(tmp_path, options, fail=True)
99
99
  except FailedJobsException:
100
100
  options.restart = True
101
101
 
102
- self._import_export_workflow(options, fail=False)
102
+ self._import_export_workflow(tmp_path, options, fail=False)
103
103
 
104
104
  @slow
105
- def test_import_export_restart_true(self):
106
- self._run_import_export_workflow(restart=True)
105
+ @pytest.mark.slow
106
+ def test_import_export_restart_true(self, tmp_path: Path) -> None:
107
+ self._run_import_export_workflow(tmp_path, restart=True)
107
108
 
108
- def test_import_export_restart_false(self):
109
- self._run_import_export_workflow(restart=False)
109
+ def test_import_export_restart_false(self, tmp_path: Path) -> None:
110
+ self._run_import_export_workflow(tmp_path, restart=False)
110
111
 
111
- def test_basic_import_export(self):
112
+ def test_basic_import_export(self, tmp_path: Path, subtests: SubTests) -> None:
112
113
  """
113
114
  Ensures that uploaded files preserve their file permissions when they
114
115
  are downloaded again. This function checks that an imported executable file
115
116
  maintains its executability after being exported.
116
117
  """
117
- options = Job.Runner.getDefaultOptions(self._getTestJobStorePath())
118
+ options = Job.Runner.getDefaultOptions(tmp_path / "jobstore")
118
119
  options.logLevel = "INFO"
119
120
 
120
121
  with Toil(options) as toil:
121
122
  # TODO: test this with non-local (AWS, Google)
122
123
  # Note: this is somewhat done in src/toil/test/src/fileStoreTest.py
123
- with self.subTest(
124
- "Testing permissions are preserved for local importFile/exportFile"
124
+
125
+ with subtests.test(
126
+ msg="Testing permissions are preserved for local importFile/exportFile"
125
127
  ):
126
128
  for executable in True, False:
127
- file_path = self.create_file(content="Hello", executable=executable)
128
- initial_permissions = os.stat(file_path).st_mode & stat.S_IXUSR
129
- file_id = toil.importFile(f"file://{file_path}")
130
- toil.exportFile(file_id, f"file://{self.output_file_path}")
131
- current_permissions = (
132
- os.stat(self.output_file_path).st_mode & stat.S_IXUSR
129
+ file_path = create_file(
130
+ tmp_path, content="Hello", executable=executable
133
131
  )
132
+ initial_permissions = file_path.stat().st_mode & stat.S_IXUSR
133
+ file_id = toil.importFile(file_path.as_uri())
134
+ output_file_path = tmp_path / f"out_{executable}"
135
+ toil.exportFile(file_id, output_file_path.as_uri())
136
+ current_permissions = output_file_path.stat().st_mode & stat.S_IXUSR
134
137
  assert initial_permissions == current_permissions
135
138
 
136
- with self.subTest("Testing relative paths without the file:// schema."):
139
+ with subtests.test(
140
+ msg="Testing relative paths without the file:// schema."
141
+ ):
137
142
  relative_path_data = "Everything is relative."
138
- file_path = self.create_file(content=relative_path_data)
143
+ file_path = create_file(tmp_path, content=relative_path_data)
139
144
 
140
145
  file_id = toil.importFile(os.path.relpath(file_path))
141
- toil.exportFile(file_id, os.path.relpath(self.output_file_path))
142
- with open(self.output_file_path) as f:
143
- self.assertEqual(f.read(), relative_path_data)
146
+ output_file_path = tmp_path / "out2"
147
+ toil.exportFile(file_id, os.path.relpath(output_file_path))
148
+ with output_file_path.open() as f:
149
+ assert f.read() == relative_path_data
144
150
 
145
- with self.subTest("Test local importFile accepts a shared_file_name."):
151
+ with subtests.test(msg="Test local importFile accepts a shared_file_name."):
146
152
  # TODO: whyyyy do we allow this? shared file names are not unique and can overwrite each other
147
153
  # ...not only that... we can't use exportFile on them afterwards!?
148
- file_path = self.create_file(content="why")
154
+ file_path = create_file(tmp_path, content="why")
149
155
  shared_file_name = (
150
156
  "users_should_probably_not_be_allowed_to_make_shared_files.bad"
151
157
  )
152
- toil.importFile(f"file://{file_path}", sharedFileName=shared_file_name)
158
+ toil.importFile(file_path.as_uri(), sharedFileName=shared_file_name)
153
159
  with toil._jobStore.read_shared_file_stream(
154
160
  shared_file_name, encoding="utf-8"
155
161
  ) as f:
156
- self.assertEqual(f.read(), "why")
162
+ assert f.read() == "why"
157
163
 
158
164
 
159
165
  class RestartingJob(Job):
160
- def __init__(self, msg_portion_file_id, trigger_file_id, message_portion_2):
166
+ def __init__(
167
+ self, msg_portion_file_id: str, trigger_file_id: str, message_portion_2: str
168
+ ) -> None:
161
169
  Job.__init__(self, memory=100000, cores=1, disk="1M")
162
170
  self.msg_portion_file_id = msg_portion_file_id
163
171
  self.trigger_file_id = trigger_file_id
164
172
  self.message_portion_2 = message_portion_2
165
173
 
166
- def run(self, file_store):
174
+ def run(self, file_store: AbstractFileStore) -> str:
167
175
  with file_store.readGlobalFileStream(self.trigger_file_id) as readable:
168
176
  if readable.read() == b"Time to freak out!":
169
177
  raise RuntimeError("D:")
@@ -11,43 +11,42 @@
11
11
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
- import os
14
+ from pathlib import Path
15
15
 
16
- from toil.job import Job
17
- from toil.test import ToilTest, get_temp_file
16
+ from toil.job import Job, Promise
18
17
  from toil.test.src.jobTest import fn1Test
19
18
 
20
19
 
21
- class JobEncapsulationTest(ToilTest):
20
+ class TestJobEncapsulation:
22
21
  """Tests testing the EncapsulationJob class."""
23
22
 
24
- def testEncapsulation(self):
23
+ def testEncapsulation(self, tmp_path: Path) -> None:
25
24
  """
26
25
  Tests the Job.encapsulation method, which uses the EncapsulationJob
27
26
  class.
28
27
  """
29
28
  # Temporary file
30
- outFile = get_temp_file(rootDir=self._createTempDir())
31
- try:
32
- # Encapsulate a job graph
33
- a = Job.wrapJobFn(encapsulatedJobFn, "A", outFile, name="a")
34
- a = a.encapsulate(name="a-encap")
35
- # Now add children/follow to the encapsulated graph
36
- d = Job.wrapFn(fn1Test, a.rv(), outFile, name="d")
37
- e = Job.wrapFn(fn1Test, d.rv(), outFile, name="e")
38
- a.addChild(d)
39
- a.addFollowOn(e)
40
- # Create the runner for the workflow.
41
- options = Job.Runner.getDefaultOptions(self._getTestJobStorePath())
42
- options.logLevel = "INFO"
43
- # Run the workflow, the return value being the number of failed jobs
44
- Job.Runner.startToil(a, options)
45
- # Check output
46
- self.assertEqual(open(outFile).readline(), "ABCDE")
47
- finally:
48
- os.remove(outFile)
29
+ rootDir = tmp_path / "out"
30
+ rootDir.mkdir()
31
+ outFile = rootDir / "out"
32
+ # Encapsulate a job graph
33
+ a = Job.wrapJobFn(encapsulatedJobFn, "A", outFile, name="a").encapsulate(
34
+ name="a-encap"
35
+ )
36
+ # Now add children/follow to the encapsulated graph
37
+ d = Job.wrapFn(fn1Test, a.rv(), outFile, name="d")
38
+ e = Job.wrapFn(fn1Test, d.rv(), outFile, name="e")
39
+ a.addChild(d)
40
+ a.addFollowOn(e)
41
+ # Create the runner for the workflow.
42
+ options = Job.Runner.getDefaultOptions(tmp_path / "jobstore")
43
+ options.logLevel = "INFO"
44
+ # Run the workflow, the return value being the number of failed jobs
45
+ Job.Runner.startToil(a, options)
46
+ # Check output
47
+ assert outFile.read_text() == "ABCDE"
49
48
 
50
- def testAddChildEncapsulate(self):
49
+ def testAddChildEncapsulate(self) -> None:
51
50
  """
52
51
  Make sure that the encapsulate child does not have two parents
53
52
  with unique roots.
@@ -56,14 +55,14 @@ class JobEncapsulationTest(ToilTest):
56
55
  a = Job.wrapFn(noOp)
57
56
  b = Job.wrapFn(noOp)
58
57
  a.addChild(b).encapsulate()
59
- self.assertEqual(len(a.getRootJobs()), 1)
58
+ assert len(a.getRootJobs()) == 1
60
59
 
61
60
 
62
- def noOp():
61
+ def noOp() -> None:
63
62
  pass
64
63
 
65
64
 
66
- def encapsulatedJobFn(job, string, outFile):
65
+ def encapsulatedJobFn(job: Job, string: str, outFile: Path) -> Promise:
67
66
  a = job.addChildFn(fn1Test, string, outFile, name="inner-a")
68
67
  b = a.addFollowOnFn(fn1Test, a.rv(), outFile, name="inner-b")
69
68
  return b.rv()