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
toil/test/__init__.py
CHANGED
|
@@ -28,8 +28,10 @@ import uuid
|
|
|
28
28
|
import zoneinfo
|
|
29
29
|
from abc import ABCMeta, abstractmethod
|
|
30
30
|
from collections.abc import Generator
|
|
31
|
-
from contextlib import contextmanager
|
|
31
|
+
from contextlib import AbstractContextManager, contextmanager
|
|
32
|
+
from importlib.resources import as_file, files
|
|
32
33
|
from inspect import getsource
|
|
34
|
+
from pathlib import Path
|
|
33
35
|
from shutil import which
|
|
34
36
|
from tempfile import mkstemp
|
|
35
37
|
from textwrap import dedent
|
|
@@ -38,7 +40,10 @@ from unittest.util import strclass
|
|
|
38
40
|
from urllib.error import HTTPError, URLError
|
|
39
41
|
from urllib.request import urlopen
|
|
40
42
|
|
|
41
|
-
|
|
43
|
+
import pytest
|
|
44
|
+
from typing_extensions import Self
|
|
45
|
+
|
|
46
|
+
from toil import ApplianceImageNotFound, applianceSelf
|
|
42
47
|
from toil.lib.accelerators import (
|
|
43
48
|
have_working_nvidia_docker_runtime,
|
|
44
49
|
have_working_nvidia_smi,
|
|
@@ -49,14 +54,41 @@ from toil.lib.memoize import memoize
|
|
|
49
54
|
from toil.lib.threading import ExceptionalThread, cpu_count
|
|
50
55
|
from toil.version import distVersion
|
|
51
56
|
|
|
57
|
+
try:
|
|
58
|
+
from botocore.exceptions import ProxyConnectionError
|
|
59
|
+
except ImportError:
|
|
60
|
+
|
|
61
|
+
class ProxyConnectionError(BaseException): # type: ignore[no-redef]
|
|
62
|
+
...
|
|
63
|
+
|
|
52
64
|
logger = logging.getLogger(__name__)
|
|
53
65
|
|
|
54
66
|
|
|
67
|
+
@contextmanager
|
|
68
|
+
def _fallback_get_data(filename: str) -> Generator[Path]:
|
|
69
|
+
try:
|
|
70
|
+
yield Path(os.path.dirname(__file__)) / ".." / ".." / ".." / filename
|
|
71
|
+
finally:
|
|
72
|
+
pass # no cleanup needed
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def get_data(filename: str) -> AbstractContextManager[Path]:
|
|
76
|
+
"""Returns an absolute path for a file from this package."""
|
|
77
|
+
# normalizing path depending on OS or else it will cause problem when joining path
|
|
78
|
+
filename = os.path.normpath(filename)
|
|
79
|
+
try:
|
|
80
|
+
return as_file(files("toil") / filename)
|
|
81
|
+
except ModuleNotFoundError:
|
|
82
|
+
pass
|
|
83
|
+
return _fallback_get_data(filename)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
@pytest.mark.usefixtures("rootpath")
|
|
55
87
|
class ToilTest(unittest.TestCase):
|
|
56
88
|
"""
|
|
57
|
-
|
|
89
|
+
Legacy common base class for Toil tests.
|
|
58
90
|
|
|
59
|
-
|
|
91
|
+
New tests should be made in the 'pytest' style and not use this class.
|
|
60
92
|
|
|
61
93
|
When running tests you may optionally set the TOIL_TEST_TEMP environment variable
|
|
62
94
|
to the path of a directory where you want temporary test files be placed. The
|
|
@@ -68,6 +100,7 @@ class ToilTest(unittest.TestCase):
|
|
|
68
100
|
Otherwise, left-over files will not be removed.
|
|
69
101
|
"""
|
|
70
102
|
|
|
103
|
+
_rootpath: Path
|
|
71
104
|
_tempBaseDir: Optional[str] = None
|
|
72
105
|
_tempDirs: list[str] = []
|
|
73
106
|
|
|
@@ -84,9 +117,7 @@ class ToilTest(unittest.TestCase):
|
|
|
84
117
|
super().setUpClass()
|
|
85
118
|
tempBaseDir = os.environ.get("TOIL_TEST_TEMP", None)
|
|
86
119
|
if tempBaseDir is not None and not os.path.isabs(tempBaseDir):
|
|
87
|
-
tempBaseDir = os.path.abspath(
|
|
88
|
-
os.path.join(cls._projectRootPath(), tempBaseDir)
|
|
89
|
-
)
|
|
120
|
+
tempBaseDir = os.path.abspath(cls._rootpath / tempBaseDir)
|
|
90
121
|
os.makedirs(tempBaseDir, exist_ok=True)
|
|
91
122
|
cls._tempBaseDir = tempBaseDir
|
|
92
123
|
|
|
@@ -149,28 +180,6 @@ class ToilTest(unittest.TestCase):
|
|
|
149
180
|
assert region
|
|
150
181
|
return region.group(1)
|
|
151
182
|
|
|
152
|
-
@classmethod
|
|
153
|
-
def _getUtilScriptPath(cls, script_name: str) -> str:
|
|
154
|
-
return os.path.join(toilPackageDirPath(), "utils", script_name + ".py")
|
|
155
|
-
|
|
156
|
-
@classmethod
|
|
157
|
-
def _projectRootPath(cls) -> str:
|
|
158
|
-
"""
|
|
159
|
-
Return the path to the project root.
|
|
160
|
-
|
|
161
|
-
i.e. the directory that typically contains the .git and src subdirectories.
|
|
162
|
-
This method has limited utility. It only works if in "develop"
|
|
163
|
-
mode, since it assumes the existence of a src subdirectory which, in a regular install
|
|
164
|
-
wouldn't exist. Then again, in that mode project root has no meaning anyways.
|
|
165
|
-
"""
|
|
166
|
-
assert re.search(r"__init__\.pyc?$", __file__)
|
|
167
|
-
projectRootPath = os.path.dirname(os.path.abspath(__file__))
|
|
168
|
-
packageComponents = __name__.split(".")
|
|
169
|
-
expectedSuffix = os.path.join("src", *packageComponents)
|
|
170
|
-
assert projectRootPath.endswith(expectedSuffix)
|
|
171
|
-
projectRootPath = projectRootPath[: -len(expectedSuffix)]
|
|
172
|
-
return projectRootPath
|
|
173
|
-
|
|
174
183
|
def _createTempDir(self, purpose: Optional[str] = None) -> str:
|
|
175
184
|
return self._createTempDirEx(self._testMethodName, purpose)
|
|
176
185
|
|
|
@@ -198,57 +207,6 @@ class ToilTest(unittest.TestCase):
|
|
|
198
207
|
os.rmdir(path)
|
|
199
208
|
return path
|
|
200
209
|
|
|
201
|
-
@classmethod
|
|
202
|
-
def _getSourceDistribution(cls) -> str:
|
|
203
|
-
"""
|
|
204
|
-
Find the sdist tarball for this project and return the path to it.
|
|
205
|
-
|
|
206
|
-
Also assert that the sdist is up-to date
|
|
207
|
-
"""
|
|
208
|
-
sdistPath = os.path.join(
|
|
209
|
-
cls._projectRootPath(), "dist", "toil-%s.tar.gz" % distVersion
|
|
210
|
-
)
|
|
211
|
-
assert os.path.isfile(sdistPath), (
|
|
212
|
-
"Can't find Toil source distribution at %s. Run 'make sdist'." % sdistPath
|
|
213
|
-
)
|
|
214
|
-
excluded = set(
|
|
215
|
-
cast(
|
|
216
|
-
str,
|
|
217
|
-
cls._run(
|
|
218
|
-
"git",
|
|
219
|
-
"ls-files",
|
|
220
|
-
"--others",
|
|
221
|
-
"-i",
|
|
222
|
-
"--exclude-standard",
|
|
223
|
-
capture=True,
|
|
224
|
-
cwd=cls._projectRootPath(),
|
|
225
|
-
),
|
|
226
|
-
).splitlines()
|
|
227
|
-
)
|
|
228
|
-
dirty = cast(
|
|
229
|
-
str,
|
|
230
|
-
cls._run(
|
|
231
|
-
"find",
|
|
232
|
-
"src",
|
|
233
|
-
"-type",
|
|
234
|
-
"f",
|
|
235
|
-
"-newer",
|
|
236
|
-
sdistPath,
|
|
237
|
-
capture=True,
|
|
238
|
-
cwd=cls._projectRootPath(),
|
|
239
|
-
),
|
|
240
|
-
).splitlines()
|
|
241
|
-
assert all(path.startswith("src") for path in dirty)
|
|
242
|
-
dirty_set = set(dirty)
|
|
243
|
-
dirty_set.difference_update(excluded)
|
|
244
|
-
assert (
|
|
245
|
-
not dirty_set
|
|
246
|
-
), "Run 'make clean_sdist sdist'. Files newer than {}: {!r}".format(
|
|
247
|
-
sdistPath,
|
|
248
|
-
list(dirty_set),
|
|
249
|
-
)
|
|
250
|
-
return sdistPath
|
|
251
|
-
|
|
252
210
|
@classmethod
|
|
253
211
|
def _run(cls, command: str, *args: str, **kwargs: Any) -> Optional[str]:
|
|
254
212
|
"""
|
|
@@ -362,6 +320,27 @@ def needs_rsync3(test_item: MT) -> MT:
|
|
|
362
320
|
return test_item
|
|
363
321
|
|
|
364
322
|
|
|
323
|
+
def _has_rsync3() -> bool:
|
|
324
|
+
try:
|
|
325
|
+
versionInfo = subprocess.check_output(["rsync", "--version"]).decode("utf-8")
|
|
326
|
+
if int(versionInfo.split()[2].split(".")[0]) < 3:
|
|
327
|
+
return False
|
|
328
|
+
except subprocess.CalledProcessError:
|
|
329
|
+
return False
|
|
330
|
+
except ValueError:
|
|
331
|
+
# Don't have an int where we looked
|
|
332
|
+
return False
|
|
333
|
+
except IndexError:
|
|
334
|
+
# Don't have the field to look in
|
|
335
|
+
return False
|
|
336
|
+
return True
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
pneeds_rsync3 = pytest.mark.skipif(
|
|
340
|
+
not _has_rsync3(), reason="This test depends on rsync version 3.0.0+."
|
|
341
|
+
)
|
|
342
|
+
|
|
343
|
+
|
|
365
344
|
def needs_online(test_item: MT) -> MT:
|
|
366
345
|
"""Use as a decorator before test classes or methods to run only if we are meant to talk to the Internet."""
|
|
367
346
|
test_item = _mark_test("online", test_item)
|
|
@@ -370,10 +349,17 @@ def needs_online(test_item: MT) -> MT:
|
|
|
370
349
|
return test_item
|
|
371
350
|
|
|
372
351
|
|
|
352
|
+
def _skip_online() -> bool:
|
|
353
|
+
return os.getenv("TOIL_SKIP_ONLINE", "").lower() == "true"
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
pneeds_online = pytest.mark.skipif(_skip_online(), reason="Skipping online test.")
|
|
357
|
+
|
|
358
|
+
|
|
373
359
|
def needs_aws_s3(test_item: MT) -> MT:
|
|
374
360
|
"""Use as a decorator before test classes or methods to run only if AWS S3 is usable."""
|
|
375
361
|
# TODO: we just check for generic access to the AWS account
|
|
376
|
-
test_item = _mark_test("
|
|
362
|
+
test_item = _mark_test("aws_s3", needs_online(test_item))
|
|
377
363
|
try:
|
|
378
364
|
from boto3 import Session
|
|
379
365
|
|
|
@@ -383,6 +369,10 @@ def needs_aws_s3(test_item: MT) -> MT:
|
|
|
383
369
|
return unittest.skip("Install Toil with the 'aws' extra to include this test.")(
|
|
384
370
|
test_item
|
|
385
371
|
)
|
|
372
|
+
except ProxyConnectionError as e:
|
|
373
|
+
return unittest.skip(f"Proxy error: {e}, skipping this test.")(
|
|
374
|
+
test_item
|
|
375
|
+
)
|
|
386
376
|
from toil.lib.aws import running_on_ec2
|
|
387
377
|
|
|
388
378
|
if not (
|
|
@@ -396,23 +386,55 @@ def needs_aws_s3(test_item: MT) -> MT:
|
|
|
396
386
|
return test_item
|
|
397
387
|
|
|
398
388
|
|
|
389
|
+
def _aws_s3_avail() -> bool:
|
|
390
|
+
"""Use as a decorator before test classes or methods to run only if AWS S3 is usable."""
|
|
391
|
+
try:
|
|
392
|
+
from boto3 import Session
|
|
393
|
+
|
|
394
|
+
session = Session()
|
|
395
|
+
boto3_credentials = session.get_credentials()
|
|
396
|
+
except ImportError:
|
|
397
|
+
return False
|
|
398
|
+
from toil.lib.aws import running_on_ec2
|
|
399
|
+
|
|
400
|
+
if not (
|
|
401
|
+
boto3_credentials
|
|
402
|
+
or os.path.exists(os.path.expanduser("~/.aws/credentials"))
|
|
403
|
+
or running_on_ec2()
|
|
404
|
+
):
|
|
405
|
+
return False
|
|
406
|
+
return True
|
|
407
|
+
|
|
408
|
+
|
|
409
|
+
pneeds_aws_s3 = pytest.mark.skipif(
|
|
410
|
+
_skip_online() or not _aws_s3_avail(),
|
|
411
|
+
reason="Install Toil with the 'aws' extra or configure AWS credentials to include this test.",
|
|
412
|
+
)
|
|
413
|
+
|
|
414
|
+
|
|
399
415
|
def needs_aws_ec2(test_item: MT) -> MT:
|
|
400
416
|
"""Use as a decorator before test classes or methods to run only if AWS EC2 is usable."""
|
|
401
417
|
# Assume we need S3 as well as EC2
|
|
402
|
-
test_item = _mark_test("
|
|
418
|
+
test_item = _mark_test("aws_ec2", needs_aws_s3(test_item))
|
|
403
419
|
# In addition to S3 we also need an SSH key to deploy with.
|
|
404
420
|
# TODO: We assume that if this is set we have EC2 access.
|
|
405
421
|
test_item = needs_env_var("TOIL_AWS_KEYNAME", "an AWS-stored SSH key")(test_item)
|
|
406
422
|
return test_item
|
|
407
423
|
|
|
408
424
|
|
|
425
|
+
pneeds_aws_ec2 = pytest.mark.skipif(
|
|
426
|
+
_skip_online() or not _aws_s3_avail() or not os.getenv("TOIL_AWS_KEYNAME"),
|
|
427
|
+
reason="Set 'TOIL_AWS_KEYNAME' to an AWS-stored SSH key to run this test",
|
|
428
|
+
)
|
|
429
|
+
|
|
430
|
+
|
|
409
431
|
def needs_aws_batch(test_item: MT) -> MT:
|
|
410
432
|
"""
|
|
411
433
|
Use as a decorator before test classes or methods to run only if AWS Batch
|
|
412
434
|
is usable.
|
|
413
435
|
"""
|
|
414
436
|
# Assume we need S3 as well as Batch
|
|
415
|
-
test_item = _mark_test("
|
|
437
|
+
test_item = _mark_test("aws_batch", needs_aws_s3(test_item))
|
|
416
438
|
# Assume we have Batch if the user has set these variables.
|
|
417
439
|
test_item = needs_env_var("TOIL_AWS_BATCH_QUEUE", "an AWS Batch queue name or ARN")(
|
|
418
440
|
test_item
|
|
@@ -443,9 +465,9 @@ def needs_google_storage(test_item: MT) -> MT:
|
|
|
443
465
|
Cloud is installed and we ought to be able to access public Google Storage
|
|
444
466
|
URIs.
|
|
445
467
|
"""
|
|
446
|
-
test_item = _mark_test("
|
|
468
|
+
test_item = _mark_test("google_storage", needs_online(test_item))
|
|
447
469
|
try:
|
|
448
|
-
|
|
470
|
+
import google.clould.storage # type: ignore[import-untyped]
|
|
449
471
|
except ImportError:
|
|
450
472
|
return unittest.skip(
|
|
451
473
|
"Install Toil with the 'google' extra to include this test."
|
|
@@ -458,7 +480,7 @@ def needs_google_project(test_item: MT) -> MT:
|
|
|
458
480
|
"""
|
|
459
481
|
Use as a decorator before test classes or methods to run only if we have a Google Cloud project set.
|
|
460
482
|
"""
|
|
461
|
-
test_item = _mark_test("
|
|
483
|
+
test_item = _mark_test("google_project", needs_online(test_item))
|
|
462
484
|
test_item = needs_env_var("TOIL_GOOGLE_PROJECTID", "a Google project ID")(test_item)
|
|
463
485
|
return test_item
|
|
464
486
|
|
|
@@ -471,6 +493,11 @@ def needs_gridengine(test_item: MT) -> MT:
|
|
|
471
493
|
return unittest.skip("Install GridEngine to include this test.")(test_item)
|
|
472
494
|
|
|
473
495
|
|
|
496
|
+
pneeds_gridengine = pytest.mark.skipif(
|
|
497
|
+
not which("qhost"), reason="Install GridEngine to include this test."
|
|
498
|
+
)
|
|
499
|
+
|
|
500
|
+
|
|
474
501
|
def needs_torque(test_item: MT) -> MT:
|
|
475
502
|
"""Use as a decorator before test classes or methods to run only if PBS/Torque is installed."""
|
|
476
503
|
test_item = _mark_test("torque", test_item)
|
|
@@ -479,6 +506,11 @@ def needs_torque(test_item: MT) -> MT:
|
|
|
479
506
|
return unittest.skip("Install PBS/Torque to include this test.")(test_item)
|
|
480
507
|
|
|
481
508
|
|
|
509
|
+
pneeds_torque = pytest.mark.skipif(
|
|
510
|
+
not which("pbsnodes"), reason="Install PBS/Torque to include this test."
|
|
511
|
+
)
|
|
512
|
+
|
|
513
|
+
|
|
482
514
|
def needs_kubernetes_installed(test_item: MT) -> MT:
|
|
483
515
|
"""Use as a decorator before test classes or methods to run only if Kubernetes is installed."""
|
|
484
516
|
test_item = _mark_test("kubernetes", test_item)
|
|
@@ -493,28 +525,40 @@ def needs_kubernetes_installed(test_item: MT) -> MT:
|
|
|
493
525
|
return test_item
|
|
494
526
|
|
|
495
527
|
|
|
496
|
-
def
|
|
497
|
-
"""Use as a decorator before test classes or methods to run only if Kubernetes is installed and configured."""
|
|
498
|
-
test_item = needs_kubernetes_installed(needs_online(test_item))
|
|
528
|
+
def _is_kubernetes_installed_and_configured() -> bool:
|
|
499
529
|
try:
|
|
500
530
|
import kubernetes
|
|
501
531
|
|
|
502
532
|
try:
|
|
503
|
-
kubernetes.config.load_kube_config()
|
|
504
|
-
except kubernetes.config.ConfigException:
|
|
533
|
+
kubernetes.config.load_kube_config() # type: ignore[attr-defined]
|
|
534
|
+
except kubernetes.config.ConfigException: # type: ignore[attr-defined]
|
|
505
535
|
try:
|
|
506
|
-
kubernetes.config.load_incluster_config()
|
|
507
|
-
except kubernetes.config.ConfigException:
|
|
508
|
-
return
|
|
509
|
-
"Configure Kubernetes (~/.kube/config, $KUBECONFIG, "
|
|
510
|
-
"or current pod) to include this test."
|
|
511
|
-
)(test_item)
|
|
536
|
+
kubernetes.config.load_incluster_config() # type: ignore[attr-defined]
|
|
537
|
+
except kubernetes.config.ConfigException: # type: ignore[attr-defined]
|
|
538
|
+
return False
|
|
512
539
|
except ImportError:
|
|
513
|
-
|
|
514
|
-
|
|
540
|
+
return False
|
|
541
|
+
return True
|
|
542
|
+
|
|
543
|
+
|
|
544
|
+
def needs_kubernetes(test_item: MT) -> MT:
|
|
545
|
+
"""Use as a decorator before test classes or methods to run only if Kubernetes is installed and configured."""
|
|
546
|
+
test_item = needs_kubernetes_installed(needs_online(test_item))
|
|
547
|
+
if not _is_kubernetes_installed_and_configured():
|
|
548
|
+
return unittest.skip(
|
|
549
|
+
"Configure Kubernetes (~/.kube/config, $KUBECONFIG, "
|
|
550
|
+
"or current pod) to include this test."
|
|
551
|
+
)(test_item)
|
|
515
552
|
return test_item
|
|
516
553
|
|
|
517
554
|
|
|
555
|
+
pneeds_kubernetes = pytest.mark.skipif(
|
|
556
|
+
_skip_online() or not _is_kubernetes_installed_and_configured(),
|
|
557
|
+
reason="Configure Kubernetes (~/.kube/config, $KUBECONFIG, "
|
|
558
|
+
"or current pod) to include this test.",
|
|
559
|
+
)
|
|
560
|
+
|
|
561
|
+
|
|
518
562
|
def needs_mesos(test_item: MT) -> MT:
|
|
519
563
|
"""Use as a decorator before test classes or methods to run only if Mesos is installed."""
|
|
520
564
|
test_item = _mark_test("mesos", test_item)
|
|
@@ -524,7 +568,16 @@ def needs_mesos(test_item: MT) -> MT:
|
|
|
524
568
|
)(test_item)
|
|
525
569
|
try:
|
|
526
570
|
import psutil # noqa
|
|
527
|
-
|
|
571
|
+
# If pymesos is installed, because it isn't typed, mypy sees an
|
|
572
|
+
# import-untyped error here.
|
|
573
|
+
#
|
|
574
|
+
# If pymesos *isn't* installed, mypy sees an import-not-found error
|
|
575
|
+
# here.
|
|
576
|
+
#
|
|
577
|
+
# If we ignore mypy errors by name, we'll get a mypy error for ignoring
|
|
578
|
+
# whichever one isn't actually occurring on the current system. So we
|
|
579
|
+
# need a blanket ignore here, or a much cleverer mypy.
|
|
580
|
+
import pymesos # type: ignore
|
|
528
581
|
except ImportError:
|
|
529
582
|
return unittest.skip(
|
|
530
583
|
"Install Mesos (and Toil with the 'mesos' extra) to include this test."
|
|
@@ -532,6 +585,23 @@ def needs_mesos(test_item: MT) -> MT:
|
|
|
532
585
|
return test_item
|
|
533
586
|
|
|
534
587
|
|
|
588
|
+
def _mesos_avail() -> bool:
|
|
589
|
+
if not (which("mesos-master") or which("mesos-agent")):
|
|
590
|
+
return False
|
|
591
|
+
try:
|
|
592
|
+
import psutil
|
|
593
|
+
import pymesos
|
|
594
|
+
except ImportError:
|
|
595
|
+
return False
|
|
596
|
+
return True
|
|
597
|
+
|
|
598
|
+
|
|
599
|
+
pneeds_mesos = pytest.mark.skipif(
|
|
600
|
+
not _mesos_avail(),
|
|
601
|
+
reason="Install Mesos (and Toil with the 'mesos' extra) to include this test.",
|
|
602
|
+
)
|
|
603
|
+
|
|
604
|
+
|
|
535
605
|
def needs_slurm(test_item: MT) -> MT:
|
|
536
606
|
"""Use as a decorator before test classes or methods to run only if Slurm is installed."""
|
|
537
607
|
test_item = _mark_test("slurm", test_item)
|
|
@@ -540,11 +610,16 @@ def needs_slurm(test_item: MT) -> MT:
|
|
|
540
610
|
return unittest.skip("Install Slurm to include this test.")(test_item)
|
|
541
611
|
|
|
542
612
|
|
|
613
|
+
pneeds_slurm = pytest.mark.skipif(
|
|
614
|
+
not which("squeue"), reason="Install Slurm to include this test."
|
|
615
|
+
)
|
|
616
|
+
|
|
617
|
+
|
|
543
618
|
def needs_htcondor(test_item: MT) -> MT:
|
|
544
619
|
"""Use a decorator before test classes or methods to run only if the HTCondor is installed."""
|
|
545
620
|
test_item = _mark_test("htcondor", test_item)
|
|
546
621
|
try:
|
|
547
|
-
import htcondor
|
|
622
|
+
import htcondor # type: ignore
|
|
548
623
|
|
|
549
624
|
htcondor.Collector(os.getenv("TOIL_HTCONDOR_COLLECTOR")).query(
|
|
550
625
|
constraint="False"
|
|
@@ -576,6 +651,11 @@ def needs_lsf(test_item: MT) -> MT:
|
|
|
576
651
|
return unittest.skip("Install LSF to include this test.")(test_item)
|
|
577
652
|
|
|
578
653
|
|
|
654
|
+
pneeds_lsf = pytest.mark.skipif(
|
|
655
|
+
not which("bsub"), reason="Install LSF to include this test."
|
|
656
|
+
)
|
|
657
|
+
|
|
658
|
+
|
|
579
659
|
def needs_java(test_item: MT) -> MT:
|
|
580
660
|
"""Use as a test decorator to run only if java is installed."""
|
|
581
661
|
test_item = _mark_test("java", test_item)
|
|
@@ -599,6 +679,14 @@ def needs_docker(test_item: MT) -> MT:
|
|
|
599
679
|
return unittest.skip("Install docker to include this test.")(test_item)
|
|
600
680
|
|
|
601
681
|
|
|
682
|
+
pneeds_docker = pytest.mark.skipif(
|
|
683
|
+
_skip_online()
|
|
684
|
+
or os.getenv("TOIL_SKIP_DOCKER", "").lower() == "true"
|
|
685
|
+
or not which("docker"),
|
|
686
|
+
reason="Requested to skip docker test or docker is not installed.",
|
|
687
|
+
)
|
|
688
|
+
|
|
689
|
+
|
|
602
690
|
def needs_singularity(test_item: MT) -> MT:
|
|
603
691
|
"""
|
|
604
692
|
Use as a decorator before test classes or methods to only run them if
|
|
@@ -641,6 +729,12 @@ def needs_local_cuda(test_item: MT) -> MT:
|
|
|
641
729
|
)(test_item)
|
|
642
730
|
|
|
643
731
|
|
|
732
|
+
pneeds_local_cuda = pytest.mark.skipif(
|
|
733
|
+
not have_working_nvidia_smi(),
|
|
734
|
+
reason="Install nvidia-smi, an nvidia proprietary driver, and a CUDA-capable nvidia GPU to include this test.",
|
|
735
|
+
)
|
|
736
|
+
|
|
737
|
+
|
|
644
738
|
def needs_docker_cuda(test_item: MT) -> MT:
|
|
645
739
|
"""
|
|
646
740
|
Use as a decorator before test classes or methods to only run them if
|
|
@@ -655,6 +749,12 @@ def needs_docker_cuda(test_item: MT) -> MT:
|
|
|
655
749
|
)(test_item)
|
|
656
750
|
|
|
657
751
|
|
|
752
|
+
pneeds_docker_cuda = pytest.mark.skipif(
|
|
753
|
+
_skip_online() or not have_working_nvidia_docker_runtime(),
|
|
754
|
+
reason="Install nvidia-container-runtime on your Docker server and configure an 'nvidia' runtime to include this test.",
|
|
755
|
+
)
|
|
756
|
+
|
|
757
|
+
|
|
658
758
|
def needs_encryption(test_item: MT) -> MT:
|
|
659
759
|
"""
|
|
660
760
|
Use as a decorator before test classes or methods to only run them if PyNaCl is installed
|
|
@@ -689,21 +789,46 @@ def needs_cwl(test_item: MT) -> MT:
|
|
|
689
789
|
return test_item
|
|
690
790
|
|
|
691
791
|
|
|
792
|
+
def _cwl_available() -> bool:
|
|
793
|
+
try:
|
|
794
|
+
import cwltool
|
|
795
|
+
except ImportError:
|
|
796
|
+
return False
|
|
797
|
+
return True
|
|
798
|
+
|
|
799
|
+
|
|
800
|
+
pneeds_cwl = pytest.mark.skipif(
|
|
801
|
+
not _cwl_available(),
|
|
802
|
+
reason="Install Toil with the 'cwl' extra to include this test.",
|
|
803
|
+
)
|
|
804
|
+
|
|
805
|
+
|
|
806
|
+
def _wdl_available() -> bool:
|
|
807
|
+
try:
|
|
808
|
+
# noinspection PyUnresolvedReferences
|
|
809
|
+
import WDL # noqa
|
|
810
|
+
except ImportError:
|
|
811
|
+
return False
|
|
812
|
+
return True
|
|
813
|
+
|
|
814
|
+
|
|
692
815
|
def needs_wdl(test_item: MT) -> MT:
|
|
693
816
|
"""
|
|
694
817
|
Use as a decorator before test classes or methods to only run them if miniwdl is installed
|
|
695
818
|
and configured.
|
|
696
819
|
"""
|
|
697
820
|
test_item = _mark_test("wdl", test_item)
|
|
698
|
-
|
|
699
|
-
# noinspection PyUnresolvedReferences
|
|
700
|
-
import WDL # noqa
|
|
701
|
-
except ImportError:
|
|
702
|
-
return unittest.skip("Install Toil with the 'wdl' extra to include this test.")(
|
|
703
|
-
test_item
|
|
704
|
-
)
|
|
705
|
-
else:
|
|
821
|
+
if _wdl_available():
|
|
706
822
|
return test_item
|
|
823
|
+
return unittest.skip("Install Toil with the 'wdl' extra to include this test.")(
|
|
824
|
+
test_item
|
|
825
|
+
)
|
|
826
|
+
|
|
827
|
+
|
|
828
|
+
pneeds_wdl = pytest.mark.skipif(
|
|
829
|
+
not _wdl_available(),
|
|
830
|
+
reason="Install Toil with the 'wdl' extra to include this test.",
|
|
831
|
+
)
|
|
707
832
|
|
|
708
833
|
|
|
709
834
|
def needs_server(test_item: MT) -> MT:
|
|
@@ -713,7 +838,7 @@ def needs_server(test_item: MT) -> MT:
|
|
|
713
838
|
test_item = _mark_test("server_mode", test_item)
|
|
714
839
|
try:
|
|
715
840
|
# noinspection PyUnresolvedReferences
|
|
716
|
-
import connexion
|
|
841
|
+
import connexion # type: ignore[import-untyped]
|
|
717
842
|
|
|
718
843
|
print(connexion.__file__) # keep this import from being removed.
|
|
719
844
|
except ImportError:
|
|
@@ -756,6 +881,23 @@ def needs_wes_server(test_item: MT) -> MT:
|
|
|
756
881
|
return test_item
|
|
757
882
|
|
|
758
883
|
|
|
884
|
+
def _is_wes_server_avail() -> bool:
|
|
885
|
+
wes_url = os.environ.get("TOIL_WES_ENDPOINT")
|
|
886
|
+
if not wes_url:
|
|
887
|
+
return False
|
|
888
|
+
try:
|
|
889
|
+
urlopen(f"{wes_url}/ga4gh/wes/v1/service-info")
|
|
890
|
+
return True
|
|
891
|
+
except (HTTPError, URLError):
|
|
892
|
+
return False
|
|
893
|
+
|
|
894
|
+
|
|
895
|
+
pneeds_wes_server = pytest.mark.skipif(
|
|
896
|
+
_skip_online() or not _is_wes_server_avail(),
|
|
897
|
+
reason="Set TOIL_WES_ENDPOINT, or run a WES server at that location to include this test.",
|
|
898
|
+
)
|
|
899
|
+
|
|
900
|
+
|
|
759
901
|
def needs_local_appliance(test_item: MT) -> MT:
|
|
760
902
|
"""
|
|
761
903
|
Use as a decorator before test classes or methods to only run them if
|
|
@@ -833,6 +975,13 @@ def integrative(test_item: MT) -> MT:
|
|
|
833
975
|
)(test_item)
|
|
834
976
|
|
|
835
977
|
|
|
978
|
+
pintegrative = pytest.mark.skipif(
|
|
979
|
+
os.getenv("TOIL_TEST_INTEGRATIVE", "").lower() != "true",
|
|
980
|
+
reason="Set TOIL_TEST_INTEGRATIVE=True to include this integration test, "
|
|
981
|
+
"or run `make integration_test_local` to run all integration tests.",
|
|
982
|
+
)
|
|
983
|
+
|
|
984
|
+
|
|
836
985
|
def slow(test_item: MT) -> MT:
|
|
837
986
|
"""
|
|
838
987
|
Use this decorator to identify tests that are slow and not critical.
|
|
@@ -845,6 +994,11 @@ def slow(test_item: MT) -> MT:
|
|
|
845
994
|
return unittest.skip('Skipped because TOIL_TEST_QUICK is "True"')(test_item)
|
|
846
995
|
|
|
847
996
|
|
|
997
|
+
pslow = pytest.mark.skipif(
|
|
998
|
+
os.environ.get("TOIL_TEST_QUICK", "").lower() == "true",
|
|
999
|
+
reason='Skipped because TOIL_TEST_QUICK is "True"',
|
|
1000
|
+
)
|
|
1001
|
+
|
|
848
1002
|
methodNamePartRegex = re.compile("^[a-zA-Z_0-9]+$")
|
|
849
1003
|
|
|
850
1004
|
|
|
@@ -881,7 +1035,11 @@ def timeLimit(seconds: int) -> Generator[None, None, None]:
|
|
|
881
1035
|
signal.alarm(0)
|
|
882
1036
|
|
|
883
1037
|
|
|
884
|
-
def make_tests(
|
|
1038
|
+
def make_tests(
|
|
1039
|
+
generalMethod: Callable[[Any], Any],
|
|
1040
|
+
targetClass: Optional[Callable[[Any], Any]],
|
|
1041
|
+
**kwargs: Any,
|
|
1042
|
+
) -> None:
|
|
885
1043
|
"""
|
|
886
1044
|
This method dynamically generates test methods using the generalMethod as a template. Each
|
|
887
1045
|
generated function is the result of a unique combination of parameters applied to the
|
|
@@ -937,7 +1095,9 @@ def make_tests(generalMethod, targetClass, **kwargs):
|
|
|
937
1095
|
|
|
938
1096
|
"""
|
|
939
1097
|
|
|
940
|
-
def permuteIntoLeft(
|
|
1098
|
+
def permuteIntoLeft(
|
|
1099
|
+
left: dict[str, dict[str, str]], rParamName: str, right: dict[str, str]
|
|
1100
|
+
) -> None:
|
|
941
1101
|
"""
|
|
942
1102
|
Permutes values in right dictionary into each parameter: value dict pair in the left
|
|
943
1103
|
dictionary. Such that the left dictionary will contain a new set of keys each of which is
|
|
@@ -972,10 +1132,10 @@ def make_tests(generalMethod, targetClass, **kwargs):
|
|
|
972
1132
|
left[prmValName + nextPrmVal] = aggDict
|
|
973
1133
|
left.pop(prmValName)
|
|
974
1134
|
|
|
975
|
-
def insertMethodToClass():
|
|
1135
|
+
def insertMethodToClass() -> None:
|
|
976
1136
|
"""Generate and insert test methods."""
|
|
977
1137
|
|
|
978
|
-
def fx(self, prms=prms):
|
|
1138
|
+
def fx(self: Any, prms: Any = prms) -> Any:
|
|
979
1139
|
if prms is not None:
|
|
980
1140
|
return generalMethod(self, **prms)
|
|
981
1141
|
else:
|
|
@@ -1085,7 +1245,7 @@ class ApplianceTestSupport(ToilTest):
|
|
|
1085
1245
|
self.containerName = str(uuid.uuid4())
|
|
1086
1246
|
self.popen: Optional[subprocess.Popen[bytes]] = None
|
|
1087
1247
|
|
|
1088
|
-
def __enter__(self) ->
|
|
1248
|
+
def __enter__(self) -> Self:
|
|
1089
1249
|
with self.lock:
|
|
1090
1250
|
image = applianceSelf()
|
|
1091
1251
|
# Omitting --rm, it's unreliable, see https://github.com/docker/docker/issues/16575
|