toil 8.1.0b1__py3-none-any.whl → 9.0.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 +0 -35
- 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/registry.py +15 -118
- toil/batchSystems/singleMachine.py +1 -1
- toil/batchSystems/slurm.py +27 -26
- toil/bus.py +5 -3
- toil/common.py +59 -12
- toil/cwl/cwltoil.py +81 -38
- toil/cwl/utils.py +103 -3
- toil/job.py +64 -49
- toil/jobStores/abstractJobStore.py +35 -239
- toil/jobStores/aws/jobStore.py +2 -1
- toil/jobStores/fileJobStore.py +27 -2
- toil/jobStores/googleJobStore.py +110 -33
- toil/leader.py +9 -0
- toil/lib/accelerators.py +4 -2
- toil/lib/aws/utils.py.orig +504 -0
- toil/lib/bioio.py +1 -1
- toil/lib/docker.py +252 -91
- toil/lib/dockstore.py +11 -3
- toil/lib/exceptions.py +5 -3
- toil/lib/generatedEC2Lists.py +81 -19
- toil/lib/history.py +87 -13
- toil/lib/history_submission.py +23 -9
- toil/lib/io.py +34 -22
- toil/lib/misc.py +8 -2
- toil/lib/plugins.py +106 -0
- toil/lib/resources.py +2 -1
- toil/lib/threading.py +11 -10
- toil/lib/url.py +320 -0
- toil/options/common.py +8 -0
- toil/options/cwl.py +13 -1
- toil/options/runner.py +17 -10
- toil/options/wdl.py +22 -0
- toil/provisioners/aws/awsProvisioner.py +25 -2
- toil/server/api_spec/LICENSE +201 -0
- toil/server/api_spec/README.rst +5 -0
- toil/server/app.py +12 -6
- toil/server/cli/wes_cwl_runner.py +3 -2
- toil/server/wes/abstract_backend.py +21 -43
- toil/server/wes/toil_backend.py +2 -2
- toil/test/__init__.py +275 -115
- toil/test/batchSystems/batchSystemTest.py +228 -213
- toil/test/batchSystems/batch_system_plugin_test.py +7 -0
- toil/test/batchSystems/test_slurm.py +27 -0
- 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 +1 -1
- toil/test/cwl/cwlTest.py +1175 -870
- 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/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/docs/scriptsTest.py +2 -1
- toil/test/lib/aws/test_iam.py +3 -1
- toil/test/lib/dockerTest.py +205 -122
- toil/test/lib/test_history.py +101 -77
- toil/test/lib/test_url.py +69 -0
- toil/test/lib/url_plugin_test.py +105 -0
- toil/test/provisioners/aws/awsProvisionerTest.py +13 -10
- toil/test/provisioners/clusterTest.py +17 -4
- toil/test/provisioners/gceProvisionerTest.py +17 -15
- toil/test/server/serverTest.py +78 -36
- 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/read_file.wdl +18 -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 +14 -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 +751 -529
- toil/test/wdl/wdltoil_test_kubernetes.py +2 -2
- toil/utils/toilSshCluster.py +23 -0
- toil/utils/toilUpdateEC2Instances.py +1 -0
- toil/version.py +5 -5
- toil/wdl/wdltoil.py +518 -437
- toil/worker.py +11 -6
- {toil-8.1.0b1.dist-info → toil-9.0.0.dist-info}/METADATA +25 -24
- toil-9.0.0.dist-info/RECORD +444 -0
- {toil-8.1.0b1.dist-info → toil-9.0.0.dist-info}/WHEEL +1 -1
- toil-8.1.0b1.dist-info/RECORD +0 -259
- {toil-8.1.0b1.dist-info → toil-9.0.0.dist-info}/entry_points.txt +0 -0
- {toil-8.1.0b1.dist-info → toil-9.0.0.dist-info/licenses}/LICENSE +0 -0
- {toil-8.1.0b1.dist-info → toil-9.0.0.dist-info}/top_level.txt +0 -0
|
@@ -32,6 +32,7 @@ from typing import (
|
|
|
32
32
|
Union,
|
|
33
33
|
cast,
|
|
34
34
|
overload,
|
|
35
|
+
Type,
|
|
35
36
|
)
|
|
36
37
|
from urllib.error import HTTPError
|
|
37
38
|
from urllib.parse import ParseResult, urlparse
|
|
@@ -52,6 +53,7 @@ from toil.lib.exceptions import UnimplementedURLException
|
|
|
52
53
|
from toil.lib.io import WriteWatchingStream
|
|
53
54
|
from toil.lib.memoize import memoize
|
|
54
55
|
from toil.lib.retry import ErrorCondition, retry
|
|
56
|
+
from toil.lib.url import URLAccess
|
|
55
57
|
|
|
56
58
|
if TYPE_CHECKING:
|
|
57
59
|
from toil.job import TemporaryID
|
|
@@ -354,23 +356,6 @@ class AbstractJobStore(ABC):
|
|
|
354
356
|
jobStoreClasses.append(jobStoreClass)
|
|
355
357
|
return jobStoreClasses
|
|
356
358
|
|
|
357
|
-
@classmethod
|
|
358
|
-
def _findJobStoreForUrl(
|
|
359
|
-
cls, url: ParseResult, export: bool = False
|
|
360
|
-
) -> "AbstractJobStore":
|
|
361
|
-
"""
|
|
362
|
-
Returns the AbstractJobStore subclass that supports the given URL.
|
|
363
|
-
|
|
364
|
-
:param ParseResult url: The given URL
|
|
365
|
-
|
|
366
|
-
:param bool export: Determines if the url is supported for exporting
|
|
367
|
-
|
|
368
|
-
:rtype: toil.jobStore.AbstractJobStore
|
|
369
|
-
"""
|
|
370
|
-
for implementation in cls._get_job_store_classes():
|
|
371
|
-
if implementation._supports_url(url, export):
|
|
372
|
-
return implementation
|
|
373
|
-
raise UnimplementedURLException(url, "export" if export else "import")
|
|
374
359
|
|
|
375
360
|
# Importing a file with a shared file name returns None, but without one it
|
|
376
361
|
# returns a file ID. Explain this to MyPy.
|
|
@@ -464,7 +449,7 @@ class AbstractJobStore(ABC):
|
|
|
464
449
|
# optimizations that circumvent this, the _import_file method should be overridden by
|
|
465
450
|
# subclasses of AbstractJobStore.
|
|
466
451
|
parseResult = urlparse(src_uri)
|
|
467
|
-
otherCls =
|
|
452
|
+
otherCls = URLAccess._find_url_implementation(parseResult)
|
|
468
453
|
logger.info("Importing input %s...", src_uri)
|
|
469
454
|
return self._import_file(
|
|
470
455
|
otherCls,
|
|
@@ -476,7 +461,7 @@ class AbstractJobStore(ABC):
|
|
|
476
461
|
|
|
477
462
|
def _import_file(
|
|
478
463
|
self,
|
|
479
|
-
otherCls: "
|
|
464
|
+
otherCls: Type["URLAccess"],
|
|
480
465
|
uri: ParseResult,
|
|
481
466
|
shared_file_name: Optional[str] = None,
|
|
482
467
|
hardlink: bool = False,
|
|
@@ -490,7 +475,7 @@ class AbstractJobStore(ABC):
|
|
|
490
475
|
|
|
491
476
|
Raises FileNotFoundError if the file does not exist.
|
|
492
477
|
|
|
493
|
-
:param
|
|
478
|
+
:param URLAccess otherCls: The class of URLAccess that supports
|
|
494
479
|
reading from the given URL and getting the file size from the URL.
|
|
495
480
|
|
|
496
481
|
:param ParseResult uri: The location of the file to import.
|
|
@@ -535,16 +520,16 @@ class AbstractJobStore(ABC):
|
|
|
535
520
|
from toil.common import Toil
|
|
536
521
|
dst_uri = Toil.normalize_uri(dst_uri)
|
|
537
522
|
parseResult = urlparse(dst_uri)
|
|
538
|
-
otherCls =
|
|
523
|
+
otherCls = URLAccess._find_url_implementation(parseResult, export=True)
|
|
539
524
|
self._export_file(otherCls, file_id, parseResult)
|
|
540
525
|
|
|
541
526
|
def _export_file(
|
|
542
|
-
self, otherCls: "
|
|
527
|
+
self, otherCls: Type["URLAccess"], jobStoreFileID: FileID, url: ParseResult
|
|
543
528
|
) -> None:
|
|
544
529
|
"""
|
|
545
530
|
Refer to exportFile docstring for information about this method.
|
|
546
531
|
|
|
547
|
-
:param
|
|
532
|
+
:param URLAccess otherCls: The class of URLAccess that supports
|
|
548
533
|
exporting to the given URL. Note that the type annotation here is not completely
|
|
549
534
|
accurate. This is not an instance, it's a class, but there is no way to reflect
|
|
550
535
|
that in :pep:`484` type hints.
|
|
@@ -556,12 +541,12 @@ class AbstractJobStore(ABC):
|
|
|
556
541
|
self._default_export_file(otherCls, jobStoreFileID, url)
|
|
557
542
|
|
|
558
543
|
def _default_export_file(
|
|
559
|
-
self, otherCls: "
|
|
544
|
+
self, otherCls: Type["URLAccess"], jobStoreFileID: FileID, url: ParseResult
|
|
560
545
|
) -> None:
|
|
561
546
|
"""
|
|
562
547
|
Refer to exportFile docstring for information about this method.
|
|
563
548
|
|
|
564
|
-
:param
|
|
549
|
+
:param URLAccess otherCls: The class of URLAccess that supports
|
|
565
550
|
exporting to the given URL. Note that the type annotation here is not completely
|
|
566
551
|
accurate. This is not an instance, it's a class, but there is no way to reflect
|
|
567
552
|
that in :pep:`484` type hints.
|
|
@@ -576,216 +561,6 @@ class AbstractJobStore(ABC):
|
|
|
576
561
|
executable = jobStoreFileID.executable
|
|
577
562
|
otherCls._write_to_url(readable, url, executable)
|
|
578
563
|
|
|
579
|
-
@classmethod
|
|
580
|
-
def url_exists(cls, src_uri: str) -> bool:
|
|
581
|
-
"""
|
|
582
|
-
Return True if the file at the given URI exists, and False otherwise.
|
|
583
|
-
|
|
584
|
-
May raise an error if file existence cannot be determined.
|
|
585
|
-
|
|
586
|
-
:param src_uri: URL that points to a file or object in the storage
|
|
587
|
-
mechanism of a supported URL scheme e.g. a blob in an AWS s3 bucket.
|
|
588
|
-
"""
|
|
589
|
-
parseResult = urlparse(src_uri)
|
|
590
|
-
otherCls = cls._findJobStoreForUrl(parseResult)
|
|
591
|
-
return otherCls._url_exists(parseResult)
|
|
592
|
-
|
|
593
|
-
@classmethod
|
|
594
|
-
def get_size(cls, src_uri: str) -> Optional[int]:
|
|
595
|
-
"""
|
|
596
|
-
Get the size in bytes of the file at the given URL, or None if it cannot be obtained.
|
|
597
|
-
|
|
598
|
-
:param src_uri: URL that points to a file or object in the storage
|
|
599
|
-
mechanism of a supported URL scheme e.g. a blob in an AWS s3 bucket.
|
|
600
|
-
"""
|
|
601
|
-
parseResult = urlparse(src_uri)
|
|
602
|
-
otherCls = cls._findJobStoreForUrl(parseResult)
|
|
603
|
-
return otherCls._get_size(parseResult)
|
|
604
|
-
|
|
605
|
-
@classmethod
|
|
606
|
-
def get_is_directory(cls, src_uri: str) -> bool:
|
|
607
|
-
"""
|
|
608
|
-
Return True if the thing at the given URL is a directory, and False if
|
|
609
|
-
it is a file. The URL may or may not end in '/'.
|
|
610
|
-
"""
|
|
611
|
-
parseResult = urlparse(src_uri)
|
|
612
|
-
otherCls = cls._findJobStoreForUrl(parseResult)
|
|
613
|
-
return otherCls._get_is_directory(parseResult)
|
|
614
|
-
|
|
615
|
-
@classmethod
|
|
616
|
-
def list_url(cls, src_uri: str) -> list[str]:
|
|
617
|
-
"""
|
|
618
|
-
List the directory at the given URL. Returned path components can be
|
|
619
|
-
joined with '/' onto the passed URL to form new URLs. Those that end in
|
|
620
|
-
'/' correspond to directories. The provided URL may or may not end with
|
|
621
|
-
'/'.
|
|
622
|
-
|
|
623
|
-
Currently supported schemes are:
|
|
624
|
-
|
|
625
|
-
- 's3' for objects in Amazon S3
|
|
626
|
-
e.g. s3://bucket/prefix/
|
|
627
|
-
|
|
628
|
-
- 'file' for local files
|
|
629
|
-
e.g. file:///local/dir/path/
|
|
630
|
-
|
|
631
|
-
:param str src_uri: URL that points to a directory or prefix in the storage mechanism of a
|
|
632
|
-
supported URL scheme e.g. a prefix in an AWS s3 bucket.
|
|
633
|
-
|
|
634
|
-
:return: A list of URL components in the given directory, already URL-encoded.
|
|
635
|
-
"""
|
|
636
|
-
parseResult = urlparse(src_uri)
|
|
637
|
-
otherCls = cls._findJobStoreForUrl(parseResult)
|
|
638
|
-
return otherCls._list_url(parseResult)
|
|
639
|
-
|
|
640
|
-
@classmethod
|
|
641
|
-
def read_from_url(cls, src_uri: str, writable: IO[bytes]) -> tuple[int, bool]:
|
|
642
|
-
"""
|
|
643
|
-
Read the given URL and write its content into the given writable stream.
|
|
644
|
-
|
|
645
|
-
Raises FileNotFoundError if the URL doesn't exist.
|
|
646
|
-
|
|
647
|
-
:return: The size of the file in bytes and whether the executable permission bit is set
|
|
648
|
-
"""
|
|
649
|
-
parseResult = urlparse(src_uri)
|
|
650
|
-
otherCls = cls._findJobStoreForUrl(parseResult)
|
|
651
|
-
return otherCls._read_from_url(parseResult, writable)
|
|
652
|
-
|
|
653
|
-
@classmethod
|
|
654
|
-
def open_url(cls, src_uri: str) -> IO[bytes]:
|
|
655
|
-
"""
|
|
656
|
-
Read from the given URI.
|
|
657
|
-
|
|
658
|
-
Raises FileNotFoundError if the URL doesn't exist.
|
|
659
|
-
|
|
660
|
-
Has a readable stream interface, unlike :meth:`read_from_url` which
|
|
661
|
-
takes a writable stream.
|
|
662
|
-
"""
|
|
663
|
-
parseResult = urlparse(src_uri)
|
|
664
|
-
otherCls = cls._findJobStoreForUrl(parseResult)
|
|
665
|
-
return otherCls._open_url(parseResult)
|
|
666
|
-
|
|
667
|
-
@classmethod
|
|
668
|
-
@abstractmethod
|
|
669
|
-
def _url_exists(cls, url: ParseResult) -> bool:
|
|
670
|
-
"""
|
|
671
|
-
Return True if the item at the given URL exists, and Flase otherwise.
|
|
672
|
-
|
|
673
|
-
May raise an error if file existence cannot be determined.
|
|
674
|
-
"""
|
|
675
|
-
raise NotImplementedError(f"No implementation for {url}")
|
|
676
|
-
|
|
677
|
-
@classmethod
|
|
678
|
-
@abstractmethod
|
|
679
|
-
def _get_size(cls, url: ParseResult) -> Optional[int]:
|
|
680
|
-
"""
|
|
681
|
-
Get the size of the object at the given URL, or None if it cannot be obtained.
|
|
682
|
-
"""
|
|
683
|
-
raise NotImplementedError(f"No implementation for {url}")
|
|
684
|
-
|
|
685
|
-
@classmethod
|
|
686
|
-
@abstractmethod
|
|
687
|
-
def _get_is_directory(cls, url: ParseResult) -> bool:
|
|
688
|
-
"""
|
|
689
|
-
Return True if the thing at the given URL is a directory, and False if
|
|
690
|
-
it is a file or it is known not to exist. The URL may or may not end in
|
|
691
|
-
'/'.
|
|
692
|
-
|
|
693
|
-
:param url: URL that points to a file or object, or directory or prefix,
|
|
694
|
-
in the storage mechanism of a supported URL scheme e.g. a blob
|
|
695
|
-
in an AWS s3 bucket.
|
|
696
|
-
"""
|
|
697
|
-
raise NotImplementedError(f"No implementation for {url}")
|
|
698
|
-
|
|
699
|
-
@classmethod
|
|
700
|
-
@abstractmethod
|
|
701
|
-
def _read_from_url(cls, url: ParseResult, writable: IO[bytes]) -> tuple[int, bool]:
|
|
702
|
-
"""
|
|
703
|
-
Reads the contents of the object at the specified location and writes it to the given
|
|
704
|
-
writable stream.
|
|
705
|
-
|
|
706
|
-
Refer to :func:`~AbstractJobStore.importFile` documentation for currently supported URL schemes.
|
|
707
|
-
|
|
708
|
-
Raises FileNotFoundError if the thing at the URL is not found.
|
|
709
|
-
|
|
710
|
-
:param ParseResult url: URL that points to a file or object in the storage
|
|
711
|
-
mechanism of a supported URL scheme e.g. a blob in an AWS s3 bucket.
|
|
712
|
-
|
|
713
|
-
:param IO[bytes] writable: a writable stream
|
|
714
|
-
|
|
715
|
-
:return: The size of the file in bytes and whether the executable permission bit is set
|
|
716
|
-
"""
|
|
717
|
-
raise NotImplementedError(f"No implementation for {url}")
|
|
718
|
-
|
|
719
|
-
@classmethod
|
|
720
|
-
@abstractmethod
|
|
721
|
-
def _list_url(cls, url: ParseResult) -> list[str]:
|
|
722
|
-
"""
|
|
723
|
-
List the contents of the given URL, which may or may not end in '/'
|
|
724
|
-
|
|
725
|
-
Returns a list of URL components. Those that end in '/' are meant to be
|
|
726
|
-
directories, while those that do not are meant to be files.
|
|
727
|
-
|
|
728
|
-
Refer to :func:`~AbstractJobStore.importFile` documentation for currently supported URL schemes.
|
|
729
|
-
|
|
730
|
-
:param ParseResult url: URL that points to a directory or prefix in the
|
|
731
|
-
storage mechanism of a supported URL scheme e.g. a prefix in an AWS s3
|
|
732
|
-
bucket.
|
|
733
|
-
|
|
734
|
-
:return: The children of the given URL, already URL-encoded if
|
|
735
|
-
appropriate. (If the URL is a bare path, no encoding is done.)
|
|
736
|
-
"""
|
|
737
|
-
raise NotImplementedError(f"No implementation for {url}")
|
|
738
|
-
|
|
739
|
-
@classmethod
|
|
740
|
-
@abstractmethod
|
|
741
|
-
def _open_url(cls, url: ParseResult) -> IO[bytes]:
|
|
742
|
-
"""
|
|
743
|
-
Get a stream of the object at the specified location.
|
|
744
|
-
|
|
745
|
-
Refer to :func:`~AbstractJobStore.importFile` documentation for currently supported URL schemes.
|
|
746
|
-
|
|
747
|
-
Raises FileNotFoundError if the thing at the URL is not found.
|
|
748
|
-
"""
|
|
749
|
-
raise NotImplementedError(f"No implementation for {url}")
|
|
750
|
-
|
|
751
|
-
@classmethod
|
|
752
|
-
@abstractmethod
|
|
753
|
-
def _write_to_url(
|
|
754
|
-
cls,
|
|
755
|
-
readable: Union[IO[bytes], IO[str]],
|
|
756
|
-
url: ParseResult,
|
|
757
|
-
executable: bool = False,
|
|
758
|
-
) -> None:
|
|
759
|
-
"""
|
|
760
|
-
Reads the contents of the given readable stream and writes it to the object at the
|
|
761
|
-
specified location. Raises FileNotFoundError if the URL doesn't exist..
|
|
762
|
-
|
|
763
|
-
Refer to AbstractJobStore.importFile documentation for currently supported URL schemes.
|
|
764
|
-
|
|
765
|
-
:param Union[IO[bytes], IO[str]] readable: a readable stream
|
|
766
|
-
|
|
767
|
-
:param ParseResult url: URL that points to a file or object in the storage
|
|
768
|
-
mechanism of a supported URL scheme e.g. a blob in an AWS s3 bucket.
|
|
769
|
-
|
|
770
|
-
:param bool executable: determines if the file has executable permissions
|
|
771
|
-
"""
|
|
772
|
-
raise NotImplementedError(f"No implementation for {url}")
|
|
773
|
-
|
|
774
|
-
@classmethod
|
|
775
|
-
@abstractmethod
|
|
776
|
-
def _supports_url(cls, url: ParseResult, export: bool = False) -> bool:
|
|
777
|
-
"""
|
|
778
|
-
Returns True if the job store supports the URL's scheme.
|
|
779
|
-
|
|
780
|
-
Refer to AbstractJobStore.importFile documentation for currently supported URL schemes.
|
|
781
|
-
|
|
782
|
-
:param ParseResult url: a parsed URL that may be supported
|
|
783
|
-
|
|
784
|
-
:param bool export: Determines if the url is supported for exported
|
|
785
|
-
|
|
786
|
-
:return bool: returns true if the cls supports the URL
|
|
787
|
-
"""
|
|
788
|
-
raise NotImplementedError(f"No implementation for {url}")
|
|
789
564
|
|
|
790
565
|
@abstractmethod
|
|
791
566
|
def destroy(self) -> None:
|
|
@@ -1686,17 +1461,39 @@ class AbstractJobStore(ABC):
|
|
|
1686
1461
|
sharedFileName: str,
|
|
1687
1462
|
encoding: Optional[str] = None,
|
|
1688
1463
|
errors: Optional[str] = None,
|
|
1689
|
-
) -> ContextManager[IO[bytes]]:
|
|
1464
|
+
) -> Union[ContextManager[IO[str]], ContextManager[IO[bytes]]]:
|
|
1690
1465
|
return self.read_shared_file_stream(sharedFileName, encoding, errors)
|
|
1691
1466
|
|
|
1467
|
+
@overload
|
|
1692
1468
|
@abstractmethod
|
|
1693
1469
|
@contextmanager
|
|
1694
1470
|
def read_shared_file_stream(
|
|
1695
1471
|
self,
|
|
1696
1472
|
shared_file_name: str,
|
|
1697
|
-
encoding:
|
|
1473
|
+
encoding: str,
|
|
1474
|
+
errors: Optional[str] = None,
|
|
1475
|
+
) -> Iterator[IO[str]]:
|
|
1476
|
+
"""If encoding is specified, then a text file handle is provided."""
|
|
1477
|
+
|
|
1478
|
+
@overload
|
|
1479
|
+
@abstractmethod
|
|
1480
|
+
@contextmanager
|
|
1481
|
+
def read_shared_file_stream(
|
|
1482
|
+
self,
|
|
1483
|
+
shared_file_name: str,
|
|
1484
|
+
encoding: Literal[None] = None,
|
|
1698
1485
|
errors: Optional[str] = None,
|
|
1699
1486
|
) -> Iterator[IO[bytes]]:
|
|
1487
|
+
"""If no encoding is provided, then a bytest file handle is provided."""
|
|
1488
|
+
|
|
1489
|
+
@abstractmethod
|
|
1490
|
+
@contextmanager
|
|
1491
|
+
def read_shared_file_stream(
|
|
1492
|
+
self,
|
|
1493
|
+
shared_file_name: str,
|
|
1494
|
+
encoding: Optional[str] = None,
|
|
1495
|
+
errors: Optional[str] = None,
|
|
1496
|
+
) -> Union[Iterator[IO[str]], Iterator[IO[bytes]]]:
|
|
1700
1497
|
"""
|
|
1701
1498
|
Returns a context manager yielding a readable file handle to the global file referenced
|
|
1702
1499
|
by the given name.
|
|
@@ -1711,7 +1508,6 @@ class AbstractJobStore(ABC):
|
|
|
1711
1508
|
are the same as for open(). Defaults to 'strict' when an encoding is specified.
|
|
1712
1509
|
|
|
1713
1510
|
:return: a context manager yielding a readable file handle
|
|
1714
|
-
:rtype: Iterator[IO[bytes]]
|
|
1715
1511
|
"""
|
|
1716
1512
|
raise NotImplementedError()
|
|
1717
1513
|
|
|
@@ -1851,7 +1647,7 @@ class AbstractJobStore(ABC):
|
|
|
1851
1647
|
raise ValueError("Not a valid shared file name: '%s'." % sharedFileName)
|
|
1852
1648
|
|
|
1853
1649
|
|
|
1854
|
-
class JobStoreSupport(AbstractJobStore, metaclass=ABCMeta):
|
|
1650
|
+
class JobStoreSupport(AbstractJobStore, URLAccess, metaclass=ABCMeta):
|
|
1855
1651
|
"""
|
|
1856
1652
|
A mostly fake JobStore to access URLs not really associated with real job
|
|
1857
1653
|
stores.
|
toil/jobStores/aws/jobStore.py
CHANGED
|
@@ -75,6 +75,7 @@ from toil.lib.io import AtomicFileCreate
|
|
|
75
75
|
from toil.lib.memoize import strict_bool
|
|
76
76
|
from toil.lib.objects import InnerClass
|
|
77
77
|
from toil.lib.retry import get_error_code, get_error_status, retry
|
|
78
|
+
from toil.lib.url import URLAccess
|
|
78
79
|
|
|
79
80
|
if TYPE_CHECKING:
|
|
80
81
|
from mypy_boto3_sdb.type_defs import (
|
|
@@ -110,7 +111,7 @@ class DomainDoesNotExist(Exception):
|
|
|
110
111
|
super().__init__(f"Expected domain {domain_name} to exist!")
|
|
111
112
|
|
|
112
113
|
|
|
113
|
-
class AWSJobStore(AbstractJobStore):
|
|
114
|
+
class AWSJobStore(AbstractJobStore, URLAccess):
|
|
114
115
|
"""
|
|
115
116
|
A job store that uses Amazon's S3 for file storage and SimpleDB for storing job info and
|
|
116
117
|
enforcing strong consistency on the S3 file storage. There will be SDB domains for jobs and
|
toil/jobStores/fileJobStore.py
CHANGED
|
@@ -42,11 +42,12 @@ from toil.lib.io import (
|
|
|
42
42
|
mkdtemp,
|
|
43
43
|
robust_rmtree,
|
|
44
44
|
)
|
|
45
|
+
from toil.lib.url import URLAccess
|
|
45
46
|
|
|
46
47
|
logger = logging.getLogger(__name__)
|
|
47
48
|
|
|
48
49
|
|
|
49
|
-
class FileJobStore(AbstractJobStore):
|
|
50
|
+
class FileJobStore(AbstractJobStore, URLAccess):
|
|
50
51
|
"""
|
|
51
52
|
A job store that uses a directory on a locally attached file system. To be compatible with
|
|
52
53
|
distributed batch systems, that file system must be shared by all worker nodes.
|
|
@@ -395,6 +396,7 @@ class FileJobStore(AbstractJobStore):
|
|
|
395
396
|
|
|
396
397
|
@classmethod
|
|
397
398
|
def _url_exists(cls, url: ParseResult) -> bool:
|
|
399
|
+
# Note that broken symlinks will not be shown to exist.
|
|
398
400
|
return os.path.exists(cls._extract_path_from_url(url))
|
|
399
401
|
|
|
400
402
|
@classmethod
|
|
@@ -771,8 +773,31 @@ class FileJobStore(AbstractJobStore):
|
|
|
771
773
|
) as f:
|
|
772
774
|
yield f
|
|
773
775
|
|
|
776
|
+
@overload
|
|
774
777
|
@contextmanager
|
|
775
|
-
def read_shared_file_stream(
|
|
778
|
+
def read_shared_file_stream(
|
|
779
|
+
self,
|
|
780
|
+
shared_file_name: str,
|
|
781
|
+
encoding: str,
|
|
782
|
+
errors: Optional[str] = None,
|
|
783
|
+
) -> Iterator[IO[str]]: ...
|
|
784
|
+
|
|
785
|
+
@overload
|
|
786
|
+
@contextmanager
|
|
787
|
+
def read_shared_file_stream(
|
|
788
|
+
self,
|
|
789
|
+
shared_file_name: str,
|
|
790
|
+
encoding: Literal[None] = None,
|
|
791
|
+
errors: Optional[str] = None,
|
|
792
|
+
) -> Iterator[IO[bytes]]: ...
|
|
793
|
+
|
|
794
|
+
@contextmanager
|
|
795
|
+
def read_shared_file_stream(
|
|
796
|
+
self,
|
|
797
|
+
shared_file_name: str,
|
|
798
|
+
encoding: Optional[str] = None,
|
|
799
|
+
errors: Optional[str] = None,
|
|
800
|
+
) -> Union[Iterator[IO[bytes]], Iterator[IO[str]]]:
|
|
776
801
|
self._requireValidSharedFileName(shared_file_name)
|
|
777
802
|
try:
|
|
778
803
|
with open(
|