toil 9.1.1__py3-none-any.whl → 9.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 +5 -9
- toil/batchSystems/abstractBatchSystem.py +23 -22
- toil/batchSystems/abstractGridEngineBatchSystem.py +17 -12
- toil/batchSystems/awsBatch.py +8 -8
- toil/batchSystems/cleanup_support.py +4 -4
- toil/batchSystems/contained_executor.py +3 -3
- toil/batchSystems/gridengine.py +3 -4
- toil/batchSystems/htcondor.py +5 -5
- toil/batchSystems/kubernetes.py +65 -63
- toil/batchSystems/local_support.py +2 -3
- toil/batchSystems/lsf.py +6 -7
- toil/batchSystems/mesos/batchSystem.py +11 -7
- toil/batchSystems/mesos/test/__init__.py +1 -2
- toil/batchSystems/options.py +9 -10
- toil/batchSystems/registry.py +3 -7
- toil/batchSystems/singleMachine.py +8 -11
- toil/batchSystems/slurm.py +49 -38
- toil/batchSystems/torque.py +3 -4
- toil/bus.py +36 -34
- toil/common.py +129 -89
- toil/cwl/cwltoil.py +857 -729
- toil/cwl/utils.py +44 -35
- toil/fileStores/__init__.py +3 -1
- toil/fileStores/abstractFileStore.py +28 -30
- toil/fileStores/cachingFileStore.py +8 -8
- toil/fileStores/nonCachingFileStore.py +10 -21
- toil/job.py +159 -158
- toil/jobStores/abstractJobStore.py +68 -69
- toil/jobStores/aws/jobStore.py +249 -213
- toil/jobStores/aws/utils.py +13 -24
- toil/jobStores/fileJobStore.py +28 -22
- toil/jobStores/googleJobStore.py +21 -17
- toil/jobStores/utils.py +3 -7
- toil/leader.py +17 -22
- toil/lib/accelerators.py +6 -4
- toil/lib/aws/__init__.py +9 -10
- toil/lib/aws/ami.py +33 -19
- toil/lib/aws/iam.py +6 -6
- toil/lib/aws/s3.py +259 -157
- toil/lib/aws/session.py +76 -76
- toil/lib/aws/utils.py +51 -43
- toil/lib/checksum.py +19 -15
- toil/lib/compatibility.py +3 -2
- toil/lib/conversions.py +45 -18
- toil/lib/directory.py +29 -26
- toil/lib/docker.py +93 -99
- toil/lib/dockstore.py +77 -50
- toil/lib/ec2.py +39 -38
- toil/lib/ec2nodes.py +11 -4
- toil/lib/exceptions.py +8 -5
- toil/lib/ftp_utils.py +9 -14
- toil/lib/generatedEC2Lists.py +161 -20
- toil/lib/history.py +141 -97
- toil/lib/history_submission.py +163 -72
- toil/lib/io.py +27 -17
- toil/lib/memoize.py +2 -1
- toil/lib/misc.py +15 -11
- toil/lib/pipes.py +40 -25
- toil/lib/plugins.py +12 -8
- toil/lib/resources.py +1 -0
- toil/lib/retry.py +32 -38
- toil/lib/threading.py +12 -12
- toil/lib/throttle.py +1 -2
- toil/lib/trs.py +113 -51
- toil/lib/url.py +14 -23
- toil/lib/web.py +7 -2
- toil/options/common.py +18 -15
- toil/options/cwl.py +2 -2
- toil/options/runner.py +9 -5
- toil/options/wdl.py +1 -3
- toil/provisioners/__init__.py +9 -9
- toil/provisioners/abstractProvisioner.py +22 -20
- toil/provisioners/aws/__init__.py +20 -14
- toil/provisioners/aws/awsProvisioner.py +10 -8
- toil/provisioners/clusterScaler.py +19 -18
- toil/provisioners/gceProvisioner.py +2 -3
- toil/provisioners/node.py +11 -13
- toil/realtimeLogger.py +4 -4
- toil/resource.py +5 -5
- toil/server/app.py +2 -2
- toil/server/cli/wes_cwl_runner.py +11 -11
- toil/server/utils.py +18 -21
- toil/server/wes/abstract_backend.py +9 -8
- toil/server/wes/amazon_wes_utils.py +3 -3
- toil/server/wes/tasks.py +3 -5
- toil/server/wes/toil_backend.py +17 -21
- toil/server/wsgi_app.py +3 -3
- toil/serviceManager.py +3 -4
- toil/statsAndLogging.py +12 -13
- toil/test/__init__.py +33 -24
- toil/test/batchSystems/batchSystemTest.py +12 -11
- toil/test/batchSystems/batch_system_plugin_test.py +3 -5
- toil/test/batchSystems/test_slurm.py +38 -24
- toil/test/cwl/conftest.py +5 -6
- toil/test/cwl/cwlTest.py +194 -78
- toil/test/cwl/download_file_uri.json +6 -0
- toil/test/cwl/download_file_uri_no_hostname.json +6 -0
- toil/test/docs/scripts/tutorial_staging.py +1 -0
- toil/test/jobStores/jobStoreTest.py +9 -7
- toil/test/lib/aws/test_iam.py +1 -3
- toil/test/lib/aws/test_s3.py +1 -1
- toil/test/lib/dockerTest.py +9 -9
- toil/test/lib/test_ec2.py +12 -11
- toil/test/lib/test_history.py +4 -4
- toil/test/lib/test_trs.py +16 -14
- toil/test/lib/test_url.py +7 -6
- toil/test/lib/url_plugin_test.py +12 -18
- toil/test/provisioners/aws/awsProvisionerTest.py +10 -8
- toil/test/provisioners/clusterScalerTest.py +2 -5
- toil/test/provisioners/clusterTest.py +1 -3
- toil/test/server/serverTest.py +13 -4
- toil/test/sort/restart_sort.py +2 -6
- toil/test/sort/sort.py +3 -8
- toil/test/src/deferredFunctionTest.py +7 -7
- toil/test/src/environmentTest.py +1 -2
- toil/test/src/fileStoreTest.py +5 -5
- toil/test/src/importExportFileTest.py +5 -6
- toil/test/src/jobServiceTest.py +22 -14
- toil/test/src/jobTest.py +121 -25
- toil/test/src/miscTests.py +5 -7
- toil/test/src/promisedRequirementTest.py +8 -7
- toil/test/src/regularLogTest.py +2 -3
- toil/test/src/resourceTest.py +5 -8
- toil/test/src/restartDAGTest.py +5 -6
- toil/test/src/resumabilityTest.py +2 -2
- toil/test/src/retainTempDirTest.py +3 -3
- toil/test/src/systemTest.py +3 -3
- toil/test/src/threadingTest.py +1 -1
- toil/test/src/workerTest.py +1 -2
- toil/test/utils/toilDebugTest.py +6 -4
- toil/test/utils/toilKillTest.py +1 -1
- toil/test/utils/utilsTest.py +15 -14
- toil/test/wdl/wdltoil_test.py +247 -124
- toil/test/wdl/wdltoil_test_kubernetes.py +2 -2
- toil/toilState.py +2 -3
- toil/utils/toilDebugFile.py +3 -8
- toil/utils/toilDebugJob.py +1 -2
- toil/utils/toilLaunchCluster.py +1 -2
- toil/utils/toilSshCluster.py +2 -0
- toil/utils/toilStats.py +19 -24
- toil/utils/toilStatus.py +11 -14
- toil/version.py +10 -10
- toil/wdl/wdltoil.py +313 -209
- toil/worker.py +18 -12
- {toil-9.1.1.dist-info → toil-9.2.0.dist-info}/METADATA +11 -14
- {toil-9.1.1.dist-info → toil-9.2.0.dist-info}/RECORD +150 -153
- {toil-9.1.1.dist-info → toil-9.2.0.dist-info}/WHEEL +1 -1
- toil/test/cwl/staging_cat.cwl +0 -27
- toil/test/cwl/staging_make_file.cwl +0 -25
- toil/test/cwl/staging_workflow.cwl +0 -43
- toil/test/cwl/zero_default.cwl +0 -61
- toil/test/utils/ABCWorkflowDebug/ABC.txt +0 -1
- {toil-9.1.1.dist-info → toil-9.2.0.dist-info}/entry_points.txt +0 -0
- {toil-9.1.1.dist-info → toil-9.2.0.dist-info}/licenses/LICENSE +0 -0
- {toil-9.1.1.dist-info → toil-9.2.0.dist-info}/top_level.txt +0 -0
toil/cwl/utils.py
CHANGED
|
@@ -18,27 +18,17 @@ import logging
|
|
|
18
18
|
import os
|
|
19
19
|
import posixpath
|
|
20
20
|
import stat
|
|
21
|
-
from collections.abc import Iterable, MutableMapping, MutableSequence
|
|
21
|
+
from collections.abc import Callable, Iterable, MutableMapping, MutableSequence
|
|
22
22
|
from pathlib import PurePosixPath
|
|
23
|
-
from typing import
|
|
24
|
-
Any,
|
|
25
|
-
Callable,
|
|
26
|
-
TypeVar,
|
|
27
|
-
Union,
|
|
28
|
-
Optional,
|
|
29
|
-
cast,
|
|
30
|
-
MutableSequence,
|
|
31
|
-
MutableMapping,
|
|
32
|
-
TYPE_CHECKING,
|
|
33
|
-
)
|
|
23
|
+
from typing import TYPE_CHECKING, Any, TypeVar, Union, cast
|
|
34
24
|
from urllib.parse import unquote, urlparse
|
|
35
25
|
|
|
36
26
|
if TYPE_CHECKING:
|
|
37
27
|
# This module needs to be importable even if cwltool is not installed.
|
|
38
28
|
from cwltool.utils import CWLObjectType, CWLOutputType
|
|
29
|
+
|
|
39
30
|
from toil.fileStores import FileID
|
|
40
31
|
from toil.fileStores.abstractFileStore import AbstractFileStore
|
|
41
|
-
from toil.jobStores.abstractJobStore import AbstractJobStore
|
|
42
32
|
from toil.lib.url import URLAccess
|
|
43
33
|
|
|
44
34
|
logger = logging.getLogger(__name__)
|
|
@@ -59,9 +49,9 @@ class CWLUnsupportedException(Exception):
|
|
|
59
49
|
try:
|
|
60
50
|
import cwltool.errors
|
|
61
51
|
|
|
62
|
-
CWL_UNSUPPORTED_REQUIREMENT_EXCEPTION:
|
|
63
|
-
type[cwltool.errors.UnsupportedRequirement]
|
|
64
|
-
|
|
52
|
+
CWL_UNSUPPORTED_REQUIREMENT_EXCEPTION: (
|
|
53
|
+
type[cwltool.errors.UnsupportedRequirement] | type[CWLUnsupportedException]
|
|
54
|
+
) = cwltool.errors.UnsupportedRequirement
|
|
65
55
|
except ImportError:
|
|
66
56
|
CWL_UNSUPPORTED_REQUIREMENT_EXCEPTION = CWLUnsupportedException
|
|
67
57
|
|
|
@@ -140,7 +130,7 @@ DirectoryStructure = dict[str, Union[str, "DirectoryStructure"]]
|
|
|
140
130
|
|
|
141
131
|
def get_from_structure(
|
|
142
132
|
dir_dict: DirectoryStructure, path: str
|
|
143
|
-
) ->
|
|
133
|
+
) -> str | DirectoryStructure | None:
|
|
144
134
|
"""
|
|
145
135
|
Given a relative path, follow it in the given directory structure.
|
|
146
136
|
|
|
@@ -154,7 +144,7 @@ def get_from_structure(
|
|
|
154
144
|
return dir_dict
|
|
155
145
|
if parts[0] in ("..", "/"):
|
|
156
146
|
raise RuntimeError(f"Path {path} not resolvable in virtual directory")
|
|
157
|
-
found:
|
|
147
|
+
found: str | DirectoryStructure = dir_dict
|
|
158
148
|
for part in parts:
|
|
159
149
|
# Go down by each path component in turn
|
|
160
150
|
if isinstance(found, str):
|
|
@@ -223,9 +213,7 @@ def download_structure(
|
|
|
223
213
|
)
|
|
224
214
|
else:
|
|
225
215
|
# We need to download from some other kind of URL.
|
|
226
|
-
size, executable = URLAccess.read_from_url(
|
|
227
|
-
value, open(dest_path, "wb")
|
|
228
|
-
)
|
|
216
|
+
size, executable = URLAccess.read_from_url(value, open(dest_path, "wb"))
|
|
229
217
|
if executable:
|
|
230
218
|
# Make the written file executable
|
|
231
219
|
os.chmod(dest_path, os.stat(dest_path).st_mode | stat.S_IXUSR)
|
|
@@ -243,27 +231,34 @@ def trim_mounts_op_down(file_or_directory: "CWLObjectType") -> None:
|
|
|
243
231
|
return
|
|
244
232
|
|
|
245
233
|
|
|
246
|
-
def sniff_location(file_or_directory: "CWLObjectType") ->
|
|
234
|
+
def sniff_location(file_or_directory: "CWLObjectType") -> str | None:
|
|
247
235
|
"""
|
|
248
236
|
Get the local bare path for a CWL file or directory, or None.
|
|
249
237
|
|
|
250
238
|
:return: None if we don't have a local path or file URI
|
|
251
239
|
"""
|
|
252
|
-
if
|
|
240
|
+
if (
|
|
241
|
+
file_or_directory.get("location") is None
|
|
242
|
+
and file_or_directory.get("path") is None
|
|
243
|
+
):
|
|
253
244
|
# file or directory is defined by contents or listing respectively, this is not redundant
|
|
254
245
|
return None
|
|
255
246
|
# Since we only consider mountable paths, if path is not file URI or bare path, don't consider it
|
|
256
|
-
path_or_url = cast(
|
|
247
|
+
path_or_url = cast(
|
|
248
|
+
str, file_or_directory.get("location") or file_or_directory.get("path")
|
|
249
|
+
)
|
|
257
250
|
parsed = urlparse(path_or_url)
|
|
258
|
-
if parsed.scheme ==
|
|
251
|
+
if parsed.scheme == "file":
|
|
259
252
|
return unquote(parsed.path)
|
|
260
|
-
elif parsed.scheme ==
|
|
253
|
+
elif parsed.scheme == "":
|
|
261
254
|
return path_or_url
|
|
262
255
|
else:
|
|
263
256
|
return None
|
|
264
257
|
|
|
265
258
|
|
|
266
|
-
def trim_mounts_op_up(
|
|
259
|
+
def trim_mounts_op_up(
|
|
260
|
+
file_or_directory: "CWLObjectType", op_down_ret: None, child_results: list[bool]
|
|
261
|
+
) -> bool:
|
|
267
262
|
"""
|
|
268
263
|
Remove subtrees of the CWL file or directory object tree that only have redundant stuff in them.
|
|
269
264
|
|
|
@@ -282,40 +277,54 @@ def trim_mounts_op_up(file_or_directory: "CWLObjectType", op_down_ret: None, chi
|
|
|
282
277
|
if own_path is None:
|
|
283
278
|
return True
|
|
284
279
|
# basename should be set as we are the implementation
|
|
285
|
-
own_basename = cast(str, file_or_directory[
|
|
280
|
+
own_basename = cast(str, file_or_directory["basename"])
|
|
286
281
|
|
|
287
282
|
# If the basename does not match the path, then this is nonredundant
|
|
288
283
|
if not own_path.endswith("/" + own_basename):
|
|
289
284
|
return True
|
|
290
285
|
|
|
291
|
-
if file_or_directory[
|
|
286
|
+
if file_or_directory["class"] == "File":
|
|
292
287
|
if any(child_results):
|
|
293
288
|
# one of the children was detected as not redundant
|
|
294
289
|
return True
|
|
295
|
-
for secondary in cast(
|
|
290
|
+
for secondary in cast(
|
|
291
|
+
MutableSequence[MutableMapping[str, "CWLOutputType"]],
|
|
292
|
+
file_or_directory.get("secondaryFiles", []),
|
|
293
|
+
):
|
|
296
294
|
# secondary files should already be flagged nonredundant if they don't have either a path or location
|
|
297
295
|
secondary_path = sniff_location(secondary)
|
|
298
|
-
secondary_basename = cast(str, secondary[
|
|
296
|
+
secondary_basename = cast(str, secondary["basename"])
|
|
299
297
|
# If we swap the secondary basename for the primary basename in the primary path, and they don't match, then they are nonredundant
|
|
300
|
-
if
|
|
298
|
+
if (
|
|
299
|
+
os.path.join(own_path[: -len(own_basename)], secondary_basename)
|
|
300
|
+
!= secondary_path
|
|
301
|
+
):
|
|
301
302
|
return True
|
|
302
303
|
else:
|
|
303
|
-
listings = cast(
|
|
304
|
+
listings = cast(
|
|
305
|
+
MutableSequence[MutableMapping[str, "CWLOutputType"]],
|
|
306
|
+
file_or_directory.get("listing", []),
|
|
307
|
+
)
|
|
304
308
|
if len(listings) == 0:
|
|
305
309
|
return False
|
|
306
310
|
# We assume child_results is in the same order as the directory listing
|
|
307
311
|
# iterate backwards to avoid iteration issues
|
|
308
312
|
for i in range(len(listings) - 1, -1, -1):
|
|
309
313
|
if child_results[i] is False:
|
|
310
|
-
if os.path.join(
|
|
314
|
+
if os.path.join(
|
|
315
|
+
own_path, cast(str, listings[i]["basename"])
|
|
316
|
+
) == sniff_location(listings[i]):
|
|
311
317
|
del listings[i]
|
|
312
318
|
# If one of the listings was nonredundant, then this directory is also nonredundant
|
|
313
319
|
if any(child_results):
|
|
314
320
|
return True
|
|
315
321
|
return False
|
|
316
322
|
|
|
323
|
+
|
|
317
324
|
def remove_redundant_mounts(cwljob: "CWLObjectType") -> None:
|
|
318
325
|
"""
|
|
319
326
|
Remove any redundant mount points from the listing. Modifies the CWL object in place.
|
|
320
327
|
"""
|
|
321
|
-
visit_cwl_class_and_reduce(
|
|
328
|
+
visit_cwl_class_and_reduce(
|
|
329
|
+
cwljob, ["Directory", "File"], trim_mounts_op_down, trim_mounts_op_up
|
|
330
|
+
)
|
toil/fileStores/__init__.py
CHANGED
|
@@ -28,7 +28,9 @@ class FileID(str):
|
|
|
28
28
|
the job store if unavailable in the ID.
|
|
29
29
|
"""
|
|
30
30
|
|
|
31
|
-
def __new__(
|
|
31
|
+
def __new__(
|
|
32
|
+
cls, fileStoreID: str, *args: Any, **kwargs: dict[str, Any]
|
|
33
|
+
) -> "FileID":
|
|
32
34
|
return super().__new__(cls, fileStoreID)
|
|
33
35
|
|
|
34
36
|
def __init__(self, fileStoreID: str, size: int, executable: bool = False) -> None:
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
import logging
|
|
15
15
|
import os
|
|
16
16
|
from abc import ABC, abstractmethod
|
|
17
|
-
from collections.abc import Generator, Iterator
|
|
17
|
+
from collections.abc import Callable, Generator, Iterator
|
|
18
18
|
from contextlib import contextmanager
|
|
19
19
|
from tempfile import mkstemp
|
|
20
20
|
from threading import Event, Semaphore
|
|
@@ -22,10 +22,8 @@ from typing import (
|
|
|
22
22
|
IO,
|
|
23
23
|
TYPE_CHECKING,
|
|
24
24
|
Any,
|
|
25
|
-
Callable,
|
|
26
25
|
ContextManager,
|
|
27
26
|
Literal,
|
|
28
|
-
Optional,
|
|
29
27
|
Union,
|
|
30
28
|
cast,
|
|
31
29
|
overload,
|
|
@@ -118,7 +116,7 @@ class AbstractFileStore(ABC):
|
|
|
118
116
|
)
|
|
119
117
|
self.jobName: str = str(self.jobDesc)
|
|
120
118
|
self.waitForPreviousCommit = waitForPreviousCommit
|
|
121
|
-
self.logging_messages: list[dict[str,
|
|
119
|
+
self.logging_messages: list[dict[str, int | str]] = []
|
|
122
120
|
self.logging_user_streams: list[dict[str, str]] = []
|
|
123
121
|
# Records file IDs of files deleted during the current job. Doesn't get
|
|
124
122
|
# committed back until the job is completely successful, because if the
|
|
@@ -129,7 +127,7 @@ class AbstractFileStore(ABC):
|
|
|
129
127
|
# the accessed files of failed jobs.
|
|
130
128
|
self._accessLog: list[tuple[str, ...]] = []
|
|
131
129
|
# Holds total bytes of observed disk usage for the last job run under open()
|
|
132
|
-
self._job_disk_used:
|
|
130
|
+
self._job_disk_used: int | None = None
|
|
133
131
|
|
|
134
132
|
@staticmethod
|
|
135
133
|
def createFileStore(
|
|
@@ -137,14 +135,14 @@ class AbstractFileStore(ABC):
|
|
|
137
135
|
jobDesc: JobDescription,
|
|
138
136
|
file_store_dir: str,
|
|
139
137
|
waitForPreviousCommit: Callable[[], Any],
|
|
140
|
-
caching:
|
|
138
|
+
caching: bool | None,
|
|
141
139
|
) -> Union["NonCachingFileStore", "CachingFileStore"]:
|
|
142
140
|
"""Create a concreate FileStore."""
|
|
143
141
|
# Defer these imports until runtime, since these classes depend on us
|
|
144
142
|
from toil.fileStores.cachingFileStore import CachingFileStore
|
|
145
143
|
from toil.fileStores.nonCachingFileStore import NonCachingFileStore
|
|
146
144
|
|
|
147
|
-
fileStoreCls:
|
|
145
|
+
fileStoreCls: type["CachingFileStore"] | type["NonCachingFileStore"] = (
|
|
148
146
|
CachingFileStore if caching else NonCachingFileStore
|
|
149
147
|
)
|
|
150
148
|
return fileStoreCls(jobStore, jobDesc, file_store_dir, waitForPreviousCommit)
|
|
@@ -152,8 +150,8 @@ class AbstractFileStore(ABC):
|
|
|
152
150
|
@staticmethod
|
|
153
151
|
def shutdownFileStore(
|
|
154
152
|
workflowID: str,
|
|
155
|
-
config_work_dir:
|
|
156
|
-
config_coordination_dir:
|
|
153
|
+
config_work_dir: str | None,
|
|
154
|
+
config_coordination_dir: str | None,
|
|
157
155
|
) -> None:
|
|
158
156
|
"""
|
|
159
157
|
Carry out any necessary filestore-specific cleanup.
|
|
@@ -230,7 +228,7 @@ class AbstractFileStore(ABC):
|
|
|
230
228
|
else:
|
|
231
229
|
self.log_to_leader(disk_usage, level=logging.DEBUG)
|
|
232
230
|
|
|
233
|
-
def get_disk_usage(self) ->
|
|
231
|
+
def get_disk_usage(self) -> int | None:
|
|
234
232
|
"""
|
|
235
233
|
Get the number of bytes of disk used by the last job run under open().
|
|
236
234
|
|
|
@@ -254,7 +252,7 @@ class AbstractFileStore(ABC):
|
|
|
254
252
|
return os.path.abspath(mkdtemp(dir=self.localTempDir))
|
|
255
253
|
|
|
256
254
|
def getLocalTempFile(
|
|
257
|
-
self, suffix:
|
|
255
|
+
self, suffix: str | None = None, prefix: str | None = None
|
|
258
256
|
) -> str:
|
|
259
257
|
"""
|
|
260
258
|
Get a new local temporary file that will persist for the duration of the job.
|
|
@@ -278,7 +276,7 @@ class AbstractFileStore(ABC):
|
|
|
278
276
|
return os.path.abspath(tmpFile)
|
|
279
277
|
|
|
280
278
|
def getLocalTempFileName(
|
|
281
|
-
self, suffix:
|
|
279
|
+
self, suffix: str | None = None, prefix: str | None = None
|
|
282
280
|
) -> str:
|
|
283
281
|
"""
|
|
284
282
|
Get a valid name for a new local file. Don't actually create a file at the path.
|
|
@@ -330,9 +328,9 @@ class AbstractFileStore(ABC):
|
|
|
330
328
|
def writeGlobalFileStream(
|
|
331
329
|
self,
|
|
332
330
|
cleanup: bool = False,
|
|
333
|
-
basename:
|
|
334
|
-
encoding:
|
|
335
|
-
errors:
|
|
331
|
+
basename: str | None = None,
|
|
332
|
+
encoding: str | None = None,
|
|
333
|
+
errors: str | None = None,
|
|
336
334
|
) -> Iterator[tuple[WriteWatchingStream, FileID]]:
|
|
337
335
|
"""
|
|
338
336
|
Similar to writeGlobalFile, but allows the writing of a stream to the job store.
|
|
@@ -423,7 +421,7 @@ class AbstractFileStore(ABC):
|
|
|
423
421
|
logger.log(log_level, "Streamed file '%s'", *item)
|
|
424
422
|
|
|
425
423
|
def logAccess(
|
|
426
|
-
self, fileStoreID:
|
|
424
|
+
self, fileStoreID: FileID | str, destination: str | None = None
|
|
427
425
|
) -> None:
|
|
428
426
|
"""
|
|
429
427
|
Record that the given file was read by the job.
|
|
@@ -445,7 +443,7 @@ class AbstractFileStore(ABC):
|
|
|
445
443
|
def readGlobalFile(
|
|
446
444
|
self,
|
|
447
445
|
fileStoreID: str,
|
|
448
|
-
userPath:
|
|
446
|
+
userPath: str | None = None,
|
|
449
447
|
cache: bool = True,
|
|
450
448
|
mutable: bool = False,
|
|
451
449
|
symlink: bool = False,
|
|
@@ -486,21 +484,21 @@ class AbstractFileStore(ABC):
|
|
|
486
484
|
self,
|
|
487
485
|
fileStoreID: str,
|
|
488
486
|
encoding: Literal[None] = None,
|
|
489
|
-
errors:
|
|
487
|
+
errors: str | None = None,
|
|
490
488
|
) -> ContextManager[IO[bytes]]: ...
|
|
491
489
|
|
|
492
490
|
@overload
|
|
493
491
|
def readGlobalFileStream(
|
|
494
|
-
self, fileStoreID: str, encoding: str, errors:
|
|
492
|
+
self, fileStoreID: str, encoding: str, errors: str | None = None
|
|
495
493
|
) -> ContextManager[IO[str]]: ...
|
|
496
494
|
|
|
497
495
|
@abstractmethod
|
|
498
496
|
def readGlobalFileStream(
|
|
499
497
|
self,
|
|
500
498
|
fileStoreID: str,
|
|
501
|
-
encoding:
|
|
502
|
-
errors:
|
|
503
|
-
) -> ContextManager[
|
|
499
|
+
encoding: str | None = None,
|
|
500
|
+
errors: str | None = None,
|
|
501
|
+
) -> ContextManager[IO[bytes] | IO[str]]:
|
|
504
502
|
"""
|
|
505
503
|
Read a stream from the job store; similar to readGlobalFile.
|
|
506
504
|
|
|
@@ -519,7 +517,7 @@ class AbstractFileStore(ABC):
|
|
|
519
517
|
"""
|
|
520
518
|
raise NotImplementedError()
|
|
521
519
|
|
|
522
|
-
def getGlobalFileSize(self, fileStoreID:
|
|
520
|
+
def getGlobalFileSize(self, fileStoreID: FileID | str) -> int:
|
|
523
521
|
"""
|
|
524
522
|
Get the size of the file pointed to by the given ID, in bytes.
|
|
525
523
|
|
|
@@ -547,7 +545,7 @@ class AbstractFileStore(ABC):
|
|
|
547
545
|
return cast(int, size)
|
|
548
546
|
|
|
549
547
|
@abstractmethod
|
|
550
|
-
def deleteLocalFile(self, fileStoreID:
|
|
548
|
+
def deleteLocalFile(self, fileStoreID: FileID | str) -> None:
|
|
551
549
|
"""
|
|
552
550
|
Delete local copies of files associated with the provided job store ID.
|
|
553
551
|
|
|
@@ -565,7 +563,7 @@ class AbstractFileStore(ABC):
|
|
|
565
563
|
raise NotImplementedError()
|
|
566
564
|
|
|
567
565
|
@abstractmethod
|
|
568
|
-
def deleteGlobalFile(self, fileStoreID:
|
|
566
|
+
def deleteGlobalFile(self, fileStoreID: FileID | str) -> None:
|
|
569
567
|
"""
|
|
570
568
|
Delete local files and then permanently deletes them from the job store.
|
|
571
569
|
|
|
@@ -580,13 +578,13 @@ class AbstractFileStore(ABC):
|
|
|
580
578
|
# and the job store.
|
|
581
579
|
@deprecated(new_function_name="import_file")
|
|
582
580
|
def importFile(
|
|
583
|
-
self, srcUrl: str, sharedFileName:
|
|
584
|
-
) ->
|
|
581
|
+
self, srcUrl: str, sharedFileName: str | None = None
|
|
582
|
+
) -> FileID | None:
|
|
585
583
|
return self.import_file(srcUrl, sharedFileName)
|
|
586
584
|
|
|
587
585
|
def import_file(
|
|
588
|
-
self, src_uri: str, shared_file_name:
|
|
589
|
-
) ->
|
|
586
|
+
self, src_uri: str, shared_file_name: str | None = None
|
|
587
|
+
) -> FileID | None:
|
|
590
588
|
return self.jobStore.import_file(src_uri, shared_file_name=shared_file_name)
|
|
591
589
|
|
|
592
590
|
@deprecated(new_function_name="export_file")
|
|
@@ -625,7 +623,7 @@ class AbstractFileStore(ABC):
|
|
|
625
623
|
@classmethod
|
|
626
624
|
@abstractmethod
|
|
627
625
|
@contextmanager
|
|
628
|
-
def open(cls, outer:
|
|
626
|
+
def open(cls, outer: Any | None = None) -> Iterator[Any]:
|
|
629
627
|
"""
|
|
630
628
|
This is a context manager that state file and reads it into an object that is returned
|
|
631
629
|
to the user in the yield.
|
|
@@ -22,10 +22,10 @@ import sqlite3
|
|
|
22
22
|
import stat
|
|
23
23
|
import threading
|
|
24
24
|
import time
|
|
25
|
-
from collections.abc import Generator, Iterator, Sequence
|
|
25
|
+
from collections.abc import Callable, Generator, Iterator, Sequence
|
|
26
26
|
from contextlib import contextmanager
|
|
27
27
|
from tempfile import mkstemp
|
|
28
|
-
from typing import Any
|
|
28
|
+
from typing import Any
|
|
29
29
|
|
|
30
30
|
from toil.common import cacheDirName, getFileSystemSize
|
|
31
31
|
from toil.fileStores import FileID
|
|
@@ -221,7 +221,7 @@ class CachingFileStore(AbstractFileStore):
|
|
|
221
221
|
logger.debug("Starting job (%s) with ID (%s).", self.jobName, self.jobID)
|
|
222
222
|
|
|
223
223
|
# When the job actually starts, we will fill this in with the job's disk requirement.
|
|
224
|
-
self.jobDiskBytes:
|
|
224
|
+
self.jobDiskBytes: float | None = None
|
|
225
225
|
|
|
226
226
|
# We need to track what attempt of the workflow we are, to prevent crosstalk between attempts' caches.
|
|
227
227
|
self.workflowAttemptNumber = self.jobStore.config.workflowAttemptNumber
|
|
@@ -386,7 +386,7 @@ class CachingFileStore(AbstractFileStore):
|
|
|
386
386
|
],
|
|
387
387
|
)
|
|
388
388
|
def _static_read(
|
|
389
|
-
cur: sqlite3.Cursor, query: str, args:
|
|
389
|
+
cur: sqlite3.Cursor, query: str, args: Sequence[Any] | None = ()
|
|
390
390
|
) -> Iterator[Any]:
|
|
391
391
|
"""
|
|
392
392
|
Read from the database.
|
|
@@ -398,7 +398,7 @@ class CachingFileStore(AbstractFileStore):
|
|
|
398
398
|
# All the real work is the decorators
|
|
399
399
|
return cur.execute(query, args)
|
|
400
400
|
|
|
401
|
-
def _read(self, query: str, args:
|
|
401
|
+
def _read(self, query: str, args: Sequence[Any] | None = ()) -> Iterator[Any]:
|
|
402
402
|
"""
|
|
403
403
|
Read from the database using the instance's connection.
|
|
404
404
|
|
|
@@ -2010,7 +2010,7 @@ class CachingFileStore(AbstractFileStore):
|
|
|
2010
2010
|
self,
|
|
2011
2011
|
file_store_id: FileID,
|
|
2012
2012
|
reader_id: str,
|
|
2013
|
-
local_file_path:
|
|
2013
|
+
local_file_path: str | None = None,
|
|
2014
2014
|
) -> Generator:
|
|
2015
2015
|
"""
|
|
2016
2016
|
Get a context manager that gives you either the local file path for a
|
|
@@ -2275,7 +2275,7 @@ class CachingFileStore(AbstractFileStore):
|
|
|
2275
2275
|
if len(self.jobDesc.filesToDelete) > 0:
|
|
2276
2276
|
raise RuntimeError("Job is already in the process of being committed!")
|
|
2277
2277
|
|
|
2278
|
-
state_to_commit:
|
|
2278
|
+
state_to_commit: JobDescription | None = None
|
|
2279
2279
|
|
|
2280
2280
|
if jobState:
|
|
2281
2281
|
# Clone the current job description, so that further updates to it
|
|
@@ -2308,7 +2308,7 @@ class CachingFileStore(AbstractFileStore):
|
|
|
2308
2308
|
)
|
|
2309
2309
|
self.commitThread.start()
|
|
2310
2310
|
|
|
2311
|
-
def startCommitThread(self, state_to_commit:
|
|
2311
|
+
def startCommitThread(self, state_to_commit: JobDescription | None):
|
|
2312
2312
|
"""
|
|
2313
2313
|
Run in a thread to actually commit the current job.
|
|
2314
2314
|
"""
|
|
@@ -16,20 +16,9 @@ import logging
|
|
|
16
16
|
import os
|
|
17
17
|
import tempfile
|
|
18
18
|
from collections import defaultdict
|
|
19
|
-
from collections.abc import Generator, Iterator
|
|
19
|
+
from collections.abc import Callable, Generator, Iterator
|
|
20
20
|
from contextlib import contextmanager
|
|
21
|
-
from typing import
|
|
22
|
-
IO,
|
|
23
|
-
Any,
|
|
24
|
-
Callable,
|
|
25
|
-
ContextManager,
|
|
26
|
-
DefaultDict,
|
|
27
|
-
Literal,
|
|
28
|
-
Optional,
|
|
29
|
-
Union,
|
|
30
|
-
cast,
|
|
31
|
-
overload,
|
|
32
|
-
)
|
|
21
|
+
from typing import IO, Any, ContextManager, DefaultDict, Literal, cast, overload
|
|
33
22
|
|
|
34
23
|
import dill
|
|
35
24
|
|
|
@@ -61,13 +50,13 @@ class NonCachingFileStore(AbstractFileStore):
|
|
|
61
50
|
) -> None:
|
|
62
51
|
super().__init__(jobStore, jobDesc, file_store_dir, waitForPreviousCommit)
|
|
63
52
|
# This will be defined in the `open` method.
|
|
64
|
-
self.jobStateFile:
|
|
53
|
+
self.jobStateFile: str | None = None
|
|
65
54
|
self.localFileMap: DefaultDict[str, list[str]] = defaultdict(list)
|
|
66
55
|
|
|
67
56
|
self.check_for_state_corruption()
|
|
68
57
|
|
|
69
58
|
@staticmethod
|
|
70
|
-
def check_for_coordination_corruption(coordination_dir:
|
|
59
|
+
def check_for_coordination_corruption(coordination_dir: str | None) -> None:
|
|
71
60
|
"""
|
|
72
61
|
Make sure the coordination directory hasn't been deleted unexpectedly.
|
|
73
62
|
|
|
@@ -145,7 +134,7 @@ class NonCachingFileStore(AbstractFileStore):
|
|
|
145
134
|
def readGlobalFile(
|
|
146
135
|
self,
|
|
147
136
|
fileStoreID: str,
|
|
148
|
-
userPath:
|
|
137
|
+
userPath: str | None = None,
|
|
149
138
|
cache: bool = True,
|
|
150
139
|
mutable: bool = False,
|
|
151
140
|
symlink: bool = False,
|
|
@@ -169,12 +158,12 @@ class NonCachingFileStore(AbstractFileStore):
|
|
|
169
158
|
self,
|
|
170
159
|
fileStoreID: str,
|
|
171
160
|
encoding: Literal[None] = None,
|
|
172
|
-
errors:
|
|
161
|
+
errors: str | None = None,
|
|
173
162
|
) -> ContextManager[IO[bytes]]: ...
|
|
174
163
|
|
|
175
164
|
@overload
|
|
176
165
|
def readGlobalFileStream(
|
|
177
|
-
self, fileStoreID: str, encoding: str, errors:
|
|
166
|
+
self, fileStoreID: str, encoding: str, errors: str | None = None
|
|
178
167
|
) -> ContextManager[IO[str]]: ...
|
|
179
168
|
|
|
180
169
|
# TODO: This seems to hit https://github.com/python/mypy/issues/11373
|
|
@@ -184,9 +173,9 @@ class NonCachingFileStore(AbstractFileStore):
|
|
|
184
173
|
def readGlobalFileStream(
|
|
185
174
|
self,
|
|
186
175
|
fileStoreID: str,
|
|
187
|
-
encoding:
|
|
188
|
-
errors:
|
|
189
|
-
) -> Iterator[
|
|
176
|
+
encoding: str | None = None,
|
|
177
|
+
errors: str | None = None,
|
|
178
|
+
) -> Iterator[IO[bytes] | IO[str]]:
|
|
190
179
|
with self.jobStore.read_file_stream(
|
|
191
180
|
fileStoreID, encoding=encoding, errors=errors
|
|
192
181
|
) as f:
|