toil 5.12.0__py3-none-any.whl → 6.1.0a1__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 +18 -13
- toil/batchSystems/abstractBatchSystem.py +21 -10
- toil/batchSystems/abstractGridEngineBatchSystem.py +2 -2
- toil/batchSystems/awsBatch.py +14 -14
- toil/batchSystems/contained_executor.py +3 -3
- toil/batchSystems/htcondor.py +0 -1
- toil/batchSystems/kubernetes.py +34 -31
- toil/batchSystems/local_support.py +3 -1
- toil/batchSystems/mesos/batchSystem.py +7 -7
- toil/batchSystems/options.py +32 -83
- toil/batchSystems/registry.py +104 -23
- toil/batchSystems/singleMachine.py +16 -13
- toil/batchSystems/slurm.py +3 -3
- toil/batchSystems/torque.py +0 -1
- toil/bus.py +6 -8
- toil/common.py +532 -743
- toil/cwl/__init__.py +28 -32
- toil/cwl/cwltoil.py +523 -520
- toil/cwl/utils.py +55 -10
- toil/fileStores/__init__.py +2 -2
- toil/fileStores/abstractFileStore.py +36 -11
- toil/fileStores/cachingFileStore.py +607 -530
- toil/fileStores/nonCachingFileStore.py +43 -10
- toil/job.py +140 -75
- toil/jobStores/abstractJobStore.py +147 -79
- toil/jobStores/aws/jobStore.py +23 -9
- toil/jobStores/aws/utils.py +1 -2
- toil/jobStores/fileJobStore.py +117 -19
- toil/jobStores/googleJobStore.py +16 -7
- toil/jobStores/utils.py +5 -6
- toil/leader.py +71 -43
- toil/lib/accelerators.py +10 -5
- toil/lib/aws/__init__.py +3 -14
- toil/lib/aws/ami.py +22 -9
- toil/lib/aws/iam.py +21 -13
- toil/lib/aws/session.py +2 -16
- toil/lib/aws/utils.py +4 -5
- toil/lib/compatibility.py +1 -1
- toil/lib/conversions.py +7 -3
- toil/lib/docker.py +22 -23
- toil/lib/ec2.py +10 -6
- toil/lib/ec2nodes.py +106 -100
- toil/lib/encryption/_nacl.py +2 -1
- toil/lib/generatedEC2Lists.py +325 -18
- toil/lib/io.py +21 -0
- toil/lib/misc.py +1 -1
- toil/lib/resources.py +1 -1
- toil/lib/threading.py +74 -26
- toil/options/common.py +738 -0
- toil/options/cwl.py +336 -0
- toil/options/wdl.py +32 -0
- toil/provisioners/abstractProvisioner.py +1 -4
- toil/provisioners/aws/__init__.py +3 -6
- toil/provisioners/aws/awsProvisioner.py +6 -0
- toil/provisioners/clusterScaler.py +3 -2
- toil/provisioners/gceProvisioner.py +2 -2
- toil/realtimeLogger.py +2 -1
- toil/resource.py +24 -18
- toil/server/app.py +2 -3
- toil/server/cli/wes_cwl_runner.py +4 -4
- toil/server/utils.py +1 -1
- toil/server/wes/abstract_backend.py +3 -2
- toil/server/wes/amazon_wes_utils.py +5 -4
- toil/server/wes/tasks.py +2 -3
- toil/server/wes/toil_backend.py +2 -10
- toil/server/wsgi_app.py +2 -0
- toil/serviceManager.py +12 -10
- toil/statsAndLogging.py +5 -1
- toil/test/__init__.py +29 -54
- toil/test/batchSystems/batchSystemTest.py +11 -111
- toil/test/batchSystems/test_slurm.py +3 -2
- toil/test/cwl/cwlTest.py +213 -90
- toil/test/cwl/glob_dir.cwl +15 -0
- toil/test/cwl/preemptible.cwl +21 -0
- toil/test/cwl/preemptible_expression.cwl +28 -0
- toil/test/cwl/revsort.cwl +1 -1
- toil/test/cwl/revsort2.cwl +1 -1
- toil/test/docs/scriptsTest.py +0 -1
- toil/test/jobStores/jobStoreTest.py +27 -16
- toil/test/lib/aws/test_iam.py +4 -14
- toil/test/lib/aws/test_utils.py +0 -3
- toil/test/lib/dockerTest.py +4 -4
- toil/test/lib/test_ec2.py +11 -16
- toil/test/mesos/helloWorld.py +4 -5
- toil/test/mesos/stress.py +1 -1
- toil/test/provisioners/aws/awsProvisionerTest.py +9 -5
- toil/test/provisioners/clusterScalerTest.py +6 -4
- toil/test/provisioners/clusterTest.py +14 -3
- toil/test/provisioners/gceProvisionerTest.py +0 -6
- toil/test/provisioners/restartScript.py +3 -2
- toil/test/server/serverTest.py +1 -1
- toil/test/sort/restart_sort.py +2 -1
- toil/test/sort/sort.py +2 -1
- toil/test/sort/sortTest.py +2 -13
- toil/test/src/autoDeploymentTest.py +45 -45
- toil/test/src/busTest.py +5 -5
- toil/test/src/checkpointTest.py +2 -2
- toil/test/src/deferredFunctionTest.py +1 -1
- toil/test/src/fileStoreTest.py +32 -16
- toil/test/src/helloWorldTest.py +1 -1
- toil/test/src/importExportFileTest.py +1 -1
- toil/test/src/jobDescriptionTest.py +2 -1
- toil/test/src/jobServiceTest.py +1 -1
- toil/test/src/jobTest.py +18 -18
- toil/test/src/miscTests.py +5 -3
- toil/test/src/promisedRequirementTest.py +3 -3
- toil/test/src/realtimeLoggerTest.py +1 -1
- toil/test/src/resourceTest.py +2 -2
- toil/test/src/restartDAGTest.py +1 -1
- toil/test/src/resumabilityTest.py +36 -2
- toil/test/src/retainTempDirTest.py +1 -1
- toil/test/src/systemTest.py +2 -2
- toil/test/src/toilContextManagerTest.py +2 -2
- toil/test/src/userDefinedJobArgTypeTest.py +1 -1
- toil/test/utils/toilDebugTest.py +98 -32
- toil/test/utils/toilKillTest.py +2 -2
- toil/test/utils/utilsTest.py +20 -0
- toil/test/wdl/wdltoil_test.py +148 -45
- toil/toilState.py +7 -6
- toil/utils/toilClean.py +1 -1
- toil/utils/toilConfig.py +36 -0
- toil/utils/toilDebugFile.py +60 -33
- toil/utils/toilDebugJob.py +39 -12
- toil/utils/toilDestroyCluster.py +1 -1
- toil/utils/toilKill.py +1 -1
- toil/utils/toilLaunchCluster.py +13 -2
- toil/utils/toilMain.py +3 -2
- toil/utils/toilRsyncCluster.py +1 -1
- toil/utils/toilSshCluster.py +1 -1
- toil/utils/toilStats.py +240 -143
- toil/utils/toilStatus.py +1 -4
- toil/version.py +11 -11
- toil/wdl/utils.py +2 -122
- toil/wdl/wdltoil.py +999 -386
- toil/worker.py +25 -31
- {toil-5.12.0.dist-info → toil-6.1.0a1.dist-info}/METADATA +60 -53
- toil-6.1.0a1.dist-info/RECORD +237 -0
- {toil-5.12.0.dist-info → toil-6.1.0a1.dist-info}/WHEEL +1 -1
- {toil-5.12.0.dist-info → toil-6.1.0a1.dist-info}/entry_points.txt +0 -1
- toil/batchSystems/parasol.py +0 -379
- toil/batchSystems/tes.py +0 -459
- toil/test/batchSystems/parasolTestSupport.py +0 -117
- toil/test/wdl/builtinTest.py +0 -506
- toil/test/wdl/conftest.py +0 -23
- toil/test/wdl/toilwdlTest.py +0 -522
- toil/wdl/toilwdl.py +0 -141
- toil/wdl/versions/dev.py +0 -107
- toil/wdl/versions/draft2.py +0 -980
- toil/wdl/versions/v1.py +0 -794
- toil/wdl/wdl_analysis.py +0 -116
- toil/wdl/wdl_functions.py +0 -997
- toil/wdl/wdl_synthesis.py +0 -1011
- toil/wdl/wdl_types.py +0 -243
- toil-5.12.0.dist-info/RECORD +0 -244
- /toil/{wdl/versions → options}/__init__.py +0 -0
- {toil-5.12.0.dist-info → toil-6.1.0a1.dist-info}/LICENSE +0 -0
- {toil-5.12.0.dist-info → toil-6.1.0a1.dist-info}/top_level.txt +0 -0
toil/cwl/utils.py
CHANGED
|
@@ -16,6 +16,9 @@
|
|
|
16
16
|
|
|
17
17
|
import logging
|
|
18
18
|
import os
|
|
19
|
+
from pathlib import PurePosixPath
|
|
20
|
+
import posixpath
|
|
21
|
+
import stat
|
|
19
22
|
from typing import (
|
|
20
23
|
Any,
|
|
21
24
|
Callable,
|
|
@@ -24,7 +27,6 @@ from typing import (
|
|
|
24
27
|
List,
|
|
25
28
|
MutableMapping,
|
|
26
29
|
MutableSequence,
|
|
27
|
-
Tuple,
|
|
28
30
|
Type,
|
|
29
31
|
TypeVar,
|
|
30
32
|
Union,
|
|
@@ -32,6 +34,7 @@ from typing import (
|
|
|
32
34
|
|
|
33
35
|
from toil.fileStores import FileID
|
|
34
36
|
from toil.fileStores.abstractFileStore import AbstractFileStore
|
|
37
|
+
from toil.jobStores.abstractJobStore import AbstractJobStore
|
|
35
38
|
|
|
36
39
|
logger = logging.getLogger(__name__)
|
|
37
40
|
|
|
@@ -129,6 +132,32 @@ def visit_cwl_class_and_reduce(
|
|
|
129
132
|
|
|
130
133
|
DirectoryStructure = Dict[str, Union[str, "DirectoryStructure"]]
|
|
131
134
|
|
|
135
|
+
def get_from_structure(dir_dict: DirectoryStructure, path: str) -> Union[str, DirectoryStructure, None]:
|
|
136
|
+
"""
|
|
137
|
+
Given a relative path, follow it in the given directory structure.
|
|
138
|
+
|
|
139
|
+
Return the string URI for files, the directory dict for
|
|
140
|
+
subdirectories, or None for nonexistent things.
|
|
141
|
+
"""
|
|
142
|
+
|
|
143
|
+
# Resolve .. and split into path components
|
|
144
|
+
parts = PurePosixPath(posixpath.normpath(path)).parts
|
|
145
|
+
if len(parts) == 0:
|
|
146
|
+
return dir_dict
|
|
147
|
+
if parts[0] in ('..', '/'):
|
|
148
|
+
raise RuntimeError(f"Path {path} not resolvable in virtual directory")
|
|
149
|
+
found: Union[str, DirectoryStructure] = dir_dict
|
|
150
|
+
for part in parts:
|
|
151
|
+
# Go down by each path component in turn
|
|
152
|
+
if isinstance(found, str):
|
|
153
|
+
# Looking for a subdirectory of a file, which doesn't exist
|
|
154
|
+
return None
|
|
155
|
+
if part not in found:
|
|
156
|
+
return None
|
|
157
|
+
found = found[part]
|
|
158
|
+
# Now we're at the place we want to be.
|
|
159
|
+
return found
|
|
160
|
+
|
|
132
161
|
|
|
133
162
|
def download_structure(
|
|
134
163
|
file_store: AbstractFileStore,
|
|
@@ -140,17 +169,21 @@ def download_structure(
|
|
|
140
169
|
"""
|
|
141
170
|
Download nested dictionary from the Toil file store to a local path.
|
|
142
171
|
|
|
172
|
+
Guaranteed to fill the structure with real files, and not symlinks out of
|
|
173
|
+
it to elsewhere. File URIs may be toilfile: URIs or any other URI that
|
|
174
|
+
Toil's job store system can read.
|
|
175
|
+
|
|
143
176
|
:param file_store: The Toil file store to download from.
|
|
144
177
|
|
|
145
|
-
:param index: Maps from downloaded file path back to input
|
|
178
|
+
:param index: Maps from downloaded file path back to input URI.
|
|
146
179
|
|
|
147
180
|
:param existing: Maps from file_store_id URI to downloaded file path.
|
|
148
181
|
|
|
149
182
|
:param dir_dict: a dict from string to string (for files) or dict (for
|
|
150
|
-
|
|
183
|
+
subdirectories) describing a directory structure.
|
|
151
184
|
|
|
152
185
|
:param into_dir: The directory to download the top-level dict's files
|
|
153
|
-
|
|
186
|
+
into.
|
|
154
187
|
"""
|
|
155
188
|
logger.debug("Downloading directory with %s items", len(dir_dict))
|
|
156
189
|
|
|
@@ -167,14 +200,26 @@ def download_structure(
|
|
|
167
200
|
download_structure(file_store, index, existing, value, subdir)
|
|
168
201
|
else:
|
|
169
202
|
# This must be a file path uploaded to Toil.
|
|
170
|
-
|
|
171
|
-
|
|
203
|
+
if not isinstance(value, str):
|
|
204
|
+
raise RuntimeError(f"Did not find a file at {value}.")
|
|
205
|
+
|
|
172
206
|
logger.debug("Downloading contained file '%s'", name)
|
|
173
207
|
dest_path = os.path.join(into_dir, name)
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
208
|
+
|
|
209
|
+
if value.startswith("toilfile:"):
|
|
210
|
+
# So download the file into place.
|
|
211
|
+
# Make sure to get a real copy of the file because we may need to
|
|
212
|
+
# mount the directory into a container as a whole.
|
|
213
|
+
file_store.readGlobalFile(
|
|
214
|
+
FileID.unpack(value[len("toilfile:") :]), dest_path, symlink=False
|
|
215
|
+
)
|
|
216
|
+
else:
|
|
217
|
+
# We need to download from some other kind of URL.
|
|
218
|
+
size, executable = AbstractJobStore.read_from_url(value, open(dest_path, 'wb'))
|
|
219
|
+
if executable:
|
|
220
|
+
# Make the written file executable
|
|
221
|
+
os.chmod(dest_path, os.stat(dest_path).st_mode | stat.S_IXUSR)
|
|
222
|
+
|
|
178
223
|
# Update the index dicts
|
|
179
224
|
# TODO: why?
|
|
180
225
|
index[dest_path] = value
|
toil/fileStores/__init__.py
CHANGED
|
@@ -40,7 +40,7 @@ class FileID(str):
|
|
|
40
40
|
|
|
41
41
|
def pack(self) -> str:
|
|
42
42
|
"""Pack the FileID into a string so it can be passed through external code."""
|
|
43
|
-
return f'{self.size}:{
|
|
43
|
+
return f'{self.size}:{"1" if self.executable else "0"}:{self}'
|
|
44
44
|
|
|
45
45
|
@classmethod
|
|
46
46
|
def forPath(cls, fileStoreID: str, filePath: str) -> 'FileID':
|
|
@@ -54,7 +54,7 @@ class FileID(str):
|
|
|
54
54
|
vals = packedFileStoreID.split(':', 2)
|
|
55
55
|
# Break up the packed value
|
|
56
56
|
size = int(vals[0])
|
|
57
|
-
executable =
|
|
57
|
+
executable = (vals[1] == "1")
|
|
58
58
|
value = vals[2]
|
|
59
59
|
# Create the FileID
|
|
60
60
|
return cls(value, size, executable)
|
|
@@ -13,9 +13,9 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
import logging
|
|
15
15
|
import os
|
|
16
|
-
import tempfile
|
|
17
16
|
from abc import ABC, abstractmethod
|
|
18
17
|
from contextlib import contextmanager
|
|
18
|
+
from tempfile import mkstemp
|
|
19
19
|
from threading import Event, Semaphore
|
|
20
20
|
from typing import (IO,
|
|
21
21
|
TYPE_CHECKING,
|
|
@@ -26,12 +26,14 @@ from typing import (IO,
|
|
|
26
26
|
Generator,
|
|
27
27
|
Iterator,
|
|
28
28
|
List,
|
|
29
|
+
Literal,
|
|
29
30
|
Optional,
|
|
30
31
|
Set,
|
|
31
32
|
Tuple,
|
|
32
33
|
Type,
|
|
33
34
|
Union,
|
|
34
|
-
cast
|
|
35
|
+
cast,
|
|
36
|
+
overload)
|
|
35
37
|
|
|
36
38
|
import dill
|
|
37
39
|
|
|
@@ -40,7 +42,7 @@ from toil.fileStores import FileID
|
|
|
40
42
|
from toil.job import Job, JobDescription
|
|
41
43
|
from toil.jobStores.abstractJobStore import AbstractJobStore
|
|
42
44
|
from toil.lib.compatibility import deprecated
|
|
43
|
-
from toil.lib.io import WriteWatchingStream
|
|
45
|
+
from toil.lib.io import WriteWatchingStream, mkdtemp
|
|
44
46
|
|
|
45
47
|
logger = logging.getLogger(__name__)
|
|
46
48
|
|
|
@@ -120,10 +122,6 @@ class AbstractFileStore(ABC):
|
|
|
120
122
|
# job is re-run it will need to be able to re-delete these files.
|
|
121
123
|
# This is a set of str objects, not FileIDs.
|
|
122
124
|
self.filesToDelete: Set[str] = set()
|
|
123
|
-
# Records IDs of jobs that need to be deleted when the currently
|
|
124
|
-
# running job is cleaned up.
|
|
125
|
-
# May be modified by the worker to actually delete jobs!
|
|
126
|
-
self.jobsToDelete: Set[str] = set()
|
|
127
125
|
# Holds records of file ID, or file ID and local path, for reporting
|
|
128
126
|
# the accessed files of failed jobs.
|
|
129
127
|
self._accessLog: List[Tuple[str, ...]] = []
|
|
@@ -211,7 +209,7 @@ class AbstractFileStore(ABC):
|
|
|
211
209
|
to be deleted once the job terminates, removing all files it
|
|
212
210
|
contains recursively.
|
|
213
211
|
"""
|
|
214
|
-
return os.path.abspath(
|
|
212
|
+
return os.path.abspath(mkdtemp(dir=self.localTempDir))
|
|
215
213
|
|
|
216
214
|
def getLocalTempFile(self, suffix: Optional[str] = None, prefix: Optional[str] = None) -> str:
|
|
217
215
|
"""
|
|
@@ -227,7 +225,7 @@ class AbstractFileStore(ABC):
|
|
|
227
225
|
for the duration of the job only, and is guaranteed to be deleted
|
|
228
226
|
once the job terminates.
|
|
229
227
|
"""
|
|
230
|
-
handle, tmpFile =
|
|
228
|
+
handle, tmpFile = mkstemp(
|
|
231
229
|
suffix=".tmp" if suffix is None else suffix,
|
|
232
230
|
prefix="tmp" if prefix is None else prefix,
|
|
233
231
|
dir=self.localTempDir
|
|
@@ -417,6 +415,21 @@ class AbstractFileStore(ABC):
|
|
|
417
415
|
"""
|
|
418
416
|
raise NotImplementedError()
|
|
419
417
|
|
|
418
|
+
@overload
|
|
419
|
+
def readGlobalFileStream(
|
|
420
|
+
self,
|
|
421
|
+
fileStoreID: str,
|
|
422
|
+
encoding: Literal[None] = None,
|
|
423
|
+
errors: Optional[str] = None,
|
|
424
|
+
) -> ContextManager[IO[bytes]]:
|
|
425
|
+
...
|
|
426
|
+
|
|
427
|
+
@overload
|
|
428
|
+
def readGlobalFileStream(
|
|
429
|
+
self, fileStoreID: str, encoding: str, errors: Optional[str] = None
|
|
430
|
+
) -> ContextManager[IO[str]]:
|
|
431
|
+
...
|
|
432
|
+
|
|
420
433
|
@abstractmethod
|
|
421
434
|
def readGlobalFileStream(
|
|
422
435
|
self,
|
|
@@ -589,7 +602,7 @@ class AbstractFileStore(ABC):
|
|
|
589
602
|
os.rename(fileName + '.tmp', fileName)
|
|
590
603
|
|
|
591
604
|
# Functions related to logging
|
|
592
|
-
def
|
|
605
|
+
def log_to_leader(self, text: str, level: int = logging.INFO) -> None:
|
|
593
606
|
"""
|
|
594
607
|
Send a logging message to the leader. The message will also be \
|
|
595
608
|
logged by the worker at the same level.
|
|
@@ -600,13 +613,25 @@ class AbstractFileStore(ABC):
|
|
|
600
613
|
logger.log(level=level, msg=("LOG-TO-MASTER: " + text))
|
|
601
614
|
self.loggingMessages.append(dict(text=text, level=level))
|
|
602
615
|
|
|
616
|
+
|
|
617
|
+
@deprecated(new_function_name='export_file')
|
|
618
|
+
def logToMaster(self, text: str, level: int = logging.INFO) -> None:
|
|
619
|
+
self.log_to_leader(text, level)
|
|
620
|
+
|
|
621
|
+
|
|
603
622
|
# Functions run after the completion of the job.
|
|
604
623
|
@abstractmethod
|
|
605
624
|
def startCommit(self, jobState: bool = False) -> None:
|
|
606
625
|
"""
|
|
607
626
|
Update the status of the job on the disk.
|
|
608
627
|
|
|
609
|
-
May
|
|
628
|
+
May bump the version number of the job.
|
|
629
|
+
|
|
630
|
+
May start an asynchronous process. Call waitForCommit() to wait on that
|
|
631
|
+
process. You must waitForCommit() before committing any further updates
|
|
632
|
+
to the job. During the asynchronous process, it is safe to modify the
|
|
633
|
+
job; modifications after this call will not be committed until the next
|
|
634
|
+
call.
|
|
610
635
|
|
|
611
636
|
:param jobState: If True, commit the state of the FileStore's job,
|
|
612
637
|
and file deletes. Otherwise, commit only file creates/updates.
|