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.
- toil/__init__.py +4 -39
- toil/batchSystems/abstractBatchSystem.py +1 -1
- toil/batchSystems/abstractGridEngineBatchSystem.py +1 -1
- toil/batchSystems/awsBatch.py +1 -1
- toil/batchSystems/cleanup_support.py +1 -1
- toil/batchSystems/kubernetes.py +53 -7
- toil/batchSystems/local_support.py +1 -1
- toil/batchSystems/mesos/batchSystem.py +13 -8
- toil/batchSystems/mesos/test/__init__.py +3 -2
- toil/batchSystems/options.py +1 -0
- toil/batchSystems/singleMachine.py +1 -1
- toil/batchSystems/slurm.py +229 -84
- toil/bus.py +5 -3
- toil/common.py +198 -54
- toil/cwl/cwltoil.py +32 -11
- toil/job.py +110 -86
- toil/jobStores/abstractJobStore.py +24 -3
- toil/jobStores/aws/jobStore.py +46 -10
- toil/jobStores/fileJobStore.py +25 -1
- toil/jobStores/googleJobStore.py +104 -30
- toil/leader.py +9 -0
- toil/lib/accelerators.py +3 -1
- toil/lib/aws/session.py +14 -3
- toil/lib/aws/utils.py +92 -35
- toil/lib/aws/utils.py.orig +504 -0
- toil/lib/bioio.py +1 -1
- toil/lib/docker.py +252 -91
- toil/lib/dockstore.py +387 -0
- toil/lib/ec2nodes.py +3 -2
- toil/lib/exceptions.py +5 -3
- toil/lib/history.py +1345 -0
- toil/lib/history_submission.py +695 -0
- toil/lib/io.py +56 -23
- toil/lib/misc.py +25 -1
- toil/lib/resources.py +2 -1
- toil/lib/retry.py +10 -10
- toil/lib/threading.py +11 -10
- toil/lib/{integration.py → trs.py} +95 -46
- toil/lib/web.py +38 -0
- toil/options/common.py +25 -2
- toil/options/cwl.py +10 -0
- toil/options/wdl.py +11 -0
- toil/provisioners/gceProvisioner.py +4 -4
- toil/server/api_spec/LICENSE +201 -0
- toil/server/api_spec/README.rst +5 -0
- toil/server/cli/wes_cwl_runner.py +5 -4
- toil/server/utils.py +2 -3
- toil/statsAndLogging.py +35 -1
- toil/test/__init__.py +275 -115
- toil/test/batchSystems/batchSystemTest.py +227 -205
- toil/test/batchSystems/test_slurm.py +199 -2
- toil/test/cactus/pestis.tar.gz +0 -0
- toil/test/conftest.py +7 -0
- toil/test/cwl/2.fasta +11 -0
- toil/test/cwl/2.fastq +12 -0
- toil/test/cwl/conftest.py +39 -0
- toil/test/cwl/cwlTest.py +1015 -780
- toil/test/cwl/directory/directory/file.txt +15 -0
- toil/test/cwl/download_directory_file.json +4 -0
- toil/test/cwl/download_directory_s3.json +4 -0
- toil/test/cwl/download_file.json +6 -0
- toil/test/cwl/download_http.json +6 -0
- toil/test/cwl/download_https.json +6 -0
- toil/test/cwl/download_s3.json +6 -0
- toil/test/cwl/download_subdirectory_file.json +5 -0
- toil/test/cwl/download_subdirectory_s3.json +5 -0
- toil/test/cwl/empty.json +1 -0
- toil/test/cwl/mock_mpi/fake_mpi.yml +8 -0
- toil/test/cwl/mock_mpi/fake_mpi_run.py +42 -0
- toil/test/cwl/optional-file-exists.json +6 -0
- toil/test/cwl/optional-file-missing.json +6 -0
- toil/test/cwl/optional-file.cwl +18 -0
- toil/test/cwl/preemptible_expression.json +1 -0
- toil/test/cwl/revsort-job-missing.json +6 -0
- toil/test/cwl/revsort-job.json +6 -0
- toil/test/cwl/s3_secondary_file.json +16 -0
- toil/test/cwl/seqtk_seq_job.json +6 -0
- toil/test/cwl/stream.json +6 -0
- toil/test/cwl/test_filename_conflict_resolution.ms/table.dat +0 -0
- toil/test/cwl/test_filename_conflict_resolution.ms/table.f0 +0 -0
- toil/test/cwl/test_filename_conflict_resolution.ms/table.f1 +0 -0
- toil/test/cwl/test_filename_conflict_resolution.ms/table.f1i +0 -0
- toil/test/cwl/test_filename_conflict_resolution.ms/table.f2 +0 -0
- toil/test/cwl/test_filename_conflict_resolution.ms/table.f2_TSM0 +0 -0
- toil/test/cwl/test_filename_conflict_resolution.ms/table.f3 +0 -0
- toil/test/cwl/test_filename_conflict_resolution.ms/table.f3_TSM0 +0 -0
- toil/test/cwl/test_filename_conflict_resolution.ms/table.f4 +0 -0
- toil/test/cwl/test_filename_conflict_resolution.ms/table.f4_TSM0 +0 -0
- toil/test/cwl/test_filename_conflict_resolution.ms/table.f5 +0 -0
- toil/test/cwl/test_filename_conflict_resolution.ms/table.info +0 -0
- toil/test/cwl/test_filename_conflict_resolution.ms/table.lock +0 -0
- toil/test/cwl/whale.txt +16 -0
- toil/test/docs/scripts/example_alwaysfail.py +38 -0
- toil/test/docs/scripts/example_alwaysfail_with_files.wdl +33 -0
- toil/test/docs/scripts/example_cachingbenchmark.py +117 -0
- toil/test/docs/scripts/stagingExampleFiles/in.txt +1 -0
- toil/test/docs/scripts/stagingExampleFiles/out.txt +2 -0
- toil/test/docs/scripts/tutorial_arguments.py +23 -0
- toil/test/docs/scripts/tutorial_debugging.patch +12 -0
- toil/test/docs/scripts/tutorial_debugging_hangs.wdl +126 -0
- toil/test/docs/scripts/tutorial_debugging_works.wdl +129 -0
- toil/test/docs/scripts/tutorial_docker.py +20 -0
- toil/test/docs/scripts/tutorial_dynamic.py +24 -0
- toil/test/docs/scripts/tutorial_encapsulation.py +28 -0
- toil/test/docs/scripts/tutorial_encapsulation2.py +29 -0
- toil/test/docs/scripts/tutorial_helloworld.py +15 -0
- toil/test/docs/scripts/tutorial_invokeworkflow.py +27 -0
- toil/test/docs/scripts/tutorial_invokeworkflow2.py +30 -0
- toil/test/docs/scripts/tutorial_jobfunctions.py +22 -0
- toil/test/docs/scripts/tutorial_managing.py +29 -0
- toil/test/docs/scripts/tutorial_managing2.py +56 -0
- toil/test/docs/scripts/tutorial_multiplejobs.py +25 -0
- toil/test/docs/scripts/tutorial_multiplejobs2.py +21 -0
- toil/test/docs/scripts/tutorial_multiplejobs3.py +22 -0
- toil/test/docs/scripts/tutorial_promises.py +25 -0
- toil/test/docs/scripts/tutorial_promises2.py +30 -0
- toil/test/docs/scripts/tutorial_quickstart.py +22 -0
- toil/test/docs/scripts/tutorial_requirements.py +44 -0
- toil/test/docs/scripts/tutorial_services.py +45 -0
- toil/test/docs/scripts/tutorial_staging.py +45 -0
- toil/test/docs/scripts/tutorial_stats.py +64 -0
- toil/test/lib/aws/test_iam.py +3 -1
- toil/test/lib/dockerTest.py +205 -122
- toil/test/lib/test_history.py +236 -0
- toil/test/lib/test_trs.py +161 -0
- toil/test/provisioners/aws/awsProvisionerTest.py +12 -9
- toil/test/provisioners/clusterTest.py +4 -4
- toil/test/provisioners/gceProvisionerTest.py +16 -14
- toil/test/sort/sort.py +4 -1
- toil/test/src/busTest.py +17 -17
- toil/test/src/deferredFunctionTest.py +145 -132
- toil/test/src/importExportFileTest.py +71 -63
- toil/test/src/jobEncapsulationTest.py +27 -28
- toil/test/src/jobServiceTest.py +149 -133
- toil/test/src/jobTest.py +219 -211
- toil/test/src/miscTests.py +66 -60
- toil/test/src/promisedRequirementTest.py +163 -169
- toil/test/src/regularLogTest.py +24 -24
- toil/test/src/resourceTest.py +82 -76
- toil/test/src/restartDAGTest.py +51 -47
- toil/test/src/resumabilityTest.py +24 -19
- toil/test/src/retainTempDirTest.py +60 -57
- toil/test/src/systemTest.py +17 -13
- toil/test/src/threadingTest.py +29 -32
- toil/test/utils/ABCWorkflowDebug/B_file.txt +1 -0
- toil/test/utils/ABCWorkflowDebug/debugWorkflow.py +204 -0
- toil/test/utils/ABCWorkflowDebug/mkFile.py +16 -0
- toil/test/utils/ABCWorkflowDebug/sleep.cwl +12 -0
- toil/test/utils/ABCWorkflowDebug/sleep.yaml +1 -0
- toil/test/utils/toilDebugTest.py +117 -102
- toil/test/utils/toilKillTest.py +54 -53
- toil/test/utils/utilsTest.py +303 -229
- toil/test/wdl/lint_error.wdl +9 -0
- toil/test/wdl/md5sum/empty_file.json +1 -0
- toil/test/wdl/md5sum/md5sum-gs.json +1 -0
- toil/test/wdl/md5sum/md5sum.1.0.wdl +32 -0
- toil/test/wdl/md5sum/md5sum.input +1 -0
- toil/test/wdl/md5sum/md5sum.json +1 -0
- toil/test/wdl/md5sum/md5sum.wdl +25 -0
- toil/test/wdl/miniwdl_self_test/inputs-namespaced.json +1 -0
- toil/test/wdl/miniwdl_self_test/inputs.json +1 -0
- toil/test/wdl/miniwdl_self_test/self_test.wdl +40 -0
- toil/test/wdl/standard_library/as_map.json +16 -0
- toil/test/wdl/standard_library/as_map_as_input.wdl +23 -0
- toil/test/wdl/standard_library/as_pairs.json +7 -0
- toil/test/wdl/standard_library/as_pairs_as_input.wdl +23 -0
- toil/test/wdl/standard_library/ceil.json +3 -0
- toil/test/wdl/standard_library/ceil_as_command.wdl +16 -0
- toil/test/wdl/standard_library/ceil_as_input.wdl +16 -0
- toil/test/wdl/standard_library/collect_by_key.json +1 -0
- toil/test/wdl/standard_library/collect_by_key_as_input.wdl +23 -0
- toil/test/wdl/standard_library/cross.json +11 -0
- toil/test/wdl/standard_library/cross_as_input.wdl +19 -0
- toil/test/wdl/standard_library/flatten.json +7 -0
- toil/test/wdl/standard_library/flatten_as_input.wdl +18 -0
- toil/test/wdl/standard_library/floor.json +3 -0
- toil/test/wdl/standard_library/floor_as_command.wdl +16 -0
- toil/test/wdl/standard_library/floor_as_input.wdl +16 -0
- toil/test/wdl/standard_library/keys.json +8 -0
- toil/test/wdl/standard_library/keys_as_input.wdl +24 -0
- toil/test/wdl/standard_library/length.json +7 -0
- toil/test/wdl/standard_library/length_as_input.wdl +16 -0
- toil/test/wdl/standard_library/length_as_input_with_map.json +7 -0
- toil/test/wdl/standard_library/length_as_input_with_map.wdl +17 -0
- toil/test/wdl/standard_library/length_invalid.json +3 -0
- toil/test/wdl/standard_library/range.json +3 -0
- toil/test/wdl/standard_library/range_0.json +3 -0
- toil/test/wdl/standard_library/range_as_input.wdl +17 -0
- toil/test/wdl/standard_library/range_invalid.json +3 -0
- toil/test/wdl/standard_library/read_boolean.json +3 -0
- toil/test/wdl/standard_library/read_boolean_as_command.wdl +17 -0
- toil/test/wdl/standard_library/read_float.json +3 -0
- toil/test/wdl/standard_library/read_float_as_command.wdl +17 -0
- toil/test/wdl/standard_library/read_int.json +3 -0
- toil/test/wdl/standard_library/read_int_as_command.wdl +17 -0
- toil/test/wdl/standard_library/read_json.json +3 -0
- toil/test/wdl/standard_library/read_json_as_output.wdl +31 -0
- toil/test/wdl/standard_library/read_lines.json +3 -0
- toil/test/wdl/standard_library/read_lines_as_output.wdl +31 -0
- toil/test/wdl/standard_library/read_map.json +3 -0
- toil/test/wdl/standard_library/read_map_as_output.wdl +31 -0
- toil/test/wdl/standard_library/read_string.json +3 -0
- toil/test/wdl/standard_library/read_string_as_command.wdl +17 -0
- toil/test/wdl/standard_library/read_tsv.json +3 -0
- toil/test/wdl/standard_library/read_tsv_as_output.wdl +31 -0
- toil/test/wdl/standard_library/round.json +3 -0
- toil/test/wdl/standard_library/round_as_command.wdl +16 -0
- toil/test/wdl/standard_library/round_as_input.wdl +16 -0
- toil/test/wdl/standard_library/size.json +3 -0
- toil/test/wdl/standard_library/size_as_command.wdl +17 -0
- toil/test/wdl/standard_library/size_as_output.wdl +36 -0
- toil/test/wdl/standard_library/stderr.json +3 -0
- toil/test/wdl/standard_library/stderr_as_output.wdl +30 -0
- toil/test/wdl/standard_library/stdout.json +3 -0
- toil/test/wdl/standard_library/stdout_as_output.wdl +30 -0
- toil/test/wdl/standard_library/sub.json +3 -0
- toil/test/wdl/standard_library/sub_as_input.wdl +17 -0
- toil/test/wdl/standard_library/sub_as_input_with_file.wdl +17 -0
- toil/test/wdl/standard_library/transpose.json +6 -0
- toil/test/wdl/standard_library/transpose_as_input.wdl +18 -0
- toil/test/wdl/standard_library/write_json.json +6 -0
- toil/test/wdl/standard_library/write_json_as_command.wdl +17 -0
- toil/test/wdl/standard_library/write_lines.json +7 -0
- toil/test/wdl/standard_library/write_lines_as_command.wdl +17 -0
- toil/test/wdl/standard_library/write_map.json +6 -0
- toil/test/wdl/standard_library/write_map_as_command.wdl +17 -0
- toil/test/wdl/standard_library/write_tsv.json +6 -0
- toil/test/wdl/standard_library/write_tsv_as_command.wdl +17 -0
- toil/test/wdl/standard_library/zip.json +12 -0
- toil/test/wdl/standard_library/zip_as_input.wdl +19 -0
- toil/test/wdl/test.csv +3 -0
- toil/test/wdl/test.tsv +3 -0
- toil/test/wdl/testfiles/croo.wdl +38 -0
- toil/test/wdl/testfiles/drop_files.wdl +62 -0
- toil/test/wdl/testfiles/drop_files_subworkflow.wdl +13 -0
- toil/test/wdl/testfiles/empty.txt +0 -0
- toil/test/wdl/testfiles/not_enough_outputs.wdl +33 -0
- toil/test/wdl/testfiles/random.wdl +66 -0
- toil/test/wdl/testfiles/string_file_coercion.json +1 -0
- toil/test/wdl/testfiles/string_file_coercion.wdl +35 -0
- toil/test/wdl/testfiles/test.json +4 -0
- toil/test/wdl/testfiles/test_boolean.txt +1 -0
- toil/test/wdl/testfiles/test_float.txt +1 -0
- toil/test/wdl/testfiles/test_int.txt +1 -0
- toil/test/wdl/testfiles/test_lines.txt +5 -0
- toil/test/wdl/testfiles/test_map.txt +2 -0
- toil/test/wdl/testfiles/test_string.txt +1 -0
- toil/test/wdl/testfiles/url_to_file.wdl +13 -0
- toil/test/wdl/testfiles/url_to_optional_file.wdl +13 -0
- toil/test/wdl/testfiles/vocab.json +1 -0
- toil/test/wdl/testfiles/vocab.wdl +66 -0
- toil/test/wdl/testfiles/wait.wdl +34 -0
- toil/test/wdl/wdl_specification/type_pair.json +23 -0
- toil/test/wdl/wdl_specification/type_pair_basic.wdl +36 -0
- toil/test/wdl/wdl_specification/type_pair_with_files.wdl +36 -0
- toil/test/wdl/wdl_specification/v1_spec.json +1 -0
- toil/test/wdl/wdl_specification/v1_spec_declaration.wdl +39 -0
- toil/test/wdl/wdltoil_test.py +681 -408
- toil/test/wdl/wdltoil_test_kubernetes.py +2 -2
- toil/version.py +10 -10
- toil/wdl/wdltoil.py +350 -123
- toil/worker.py +113 -33
- {toil-8.0.0.dist-info → toil-8.2.0.dist-info}/METADATA +13 -7
- toil-8.2.0.dist-info/RECORD +439 -0
- {toil-8.0.0.dist-info → toil-8.2.0.dist-info}/WHEEL +1 -1
- toil/test/lib/test_integration.py +0 -104
- toil-8.0.0.dist-info/RECORD +0 -253
- {toil-8.0.0.dist-info → toil-8.2.0.dist-info}/entry_points.txt +0 -0
- {toil-8.0.0.dist-info → toil-8.2.0.dist-info/licenses}/LICENSE +0 -0
- {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
|
|
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
|
-
|
|
38
|
-
|
|
33
|
+
def create_file(tmp_path: Path, content: str, executable: bool = False) -> Path:
|
|
34
|
+
file_path = tmp_path / str(uuid.uuid4())
|
|
39
35
|
|
|
40
|
-
|
|
41
|
-
|
|
36
|
+
with file_path.open("w") as f:
|
|
37
|
+
f.write(content)
|
|
42
38
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
39
|
+
if executable:
|
|
40
|
+
# Add file owner execute permissions
|
|
41
|
+
file_path.chmod(file_path.stat().st_mode | stat.S_IXUSR)
|
|
46
42
|
|
|
47
|
-
|
|
43
|
+
return file_path
|
|
48
44
|
|
|
49
|
-
|
|
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 =
|
|
53
|
-
|
|
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 =
|
|
60
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
106
|
-
|
|
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(
|
|
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
|
-
|
|
124
|
-
|
|
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 =
|
|
128
|
-
|
|
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
|
|
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 =
|
|
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
|
-
|
|
142
|
-
|
|
143
|
-
|
|
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
|
|
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 =
|
|
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(
|
|
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
|
-
|
|
162
|
+
assert f.read() == "why"
|
|
157
163
|
|
|
158
164
|
|
|
159
165
|
class RestartingJob(Job):
|
|
160
|
-
def __init__(
|
|
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
|
|
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
|
|
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
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
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
|
-
|
|
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()
|