toil 9.0.0__py3-none-any.whl → 9.1.1__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/batchSystems/abstractBatchSystem.py +13 -5
- toil/batchSystems/abstractGridEngineBatchSystem.py +17 -5
- toil/batchSystems/kubernetes.py +13 -2
- toil/batchSystems/mesos/batchSystem.py +33 -2
- toil/batchSystems/slurm.py +191 -16
- toil/cwl/cwltoil.py +17 -82
- toil/fileStores/__init__.py +1 -1
- toil/fileStores/abstractFileStore.py +5 -2
- toil/fileStores/cachingFileStore.py +1 -1
- toil/job.py +30 -14
- toil/jobStores/abstractJobStore.py +24 -19
- toil/jobStores/aws/jobStore.py +862 -1963
- toil/jobStores/aws/utils.py +24 -270
- toil/jobStores/googleJobStore.py +25 -9
- toil/jobStores/utils.py +0 -327
- toil/leader.py +27 -22
- toil/lib/aws/config.py +22 -0
- toil/lib/aws/s3.py +477 -9
- toil/lib/aws/utils.py +22 -33
- toil/lib/checksum.py +88 -0
- toil/lib/conversions.py +33 -31
- toil/lib/directory.py +217 -0
- toil/lib/ec2.py +97 -29
- toil/lib/exceptions.py +2 -1
- toil/lib/expando.py +2 -2
- toil/lib/generatedEC2Lists.py +73 -16
- toil/lib/io.py +33 -2
- toil/lib/memoize.py +21 -7
- toil/lib/pipes.py +385 -0
- toil/lib/retry.py +1 -1
- toil/lib/threading.py +1 -1
- toil/lib/web.py +4 -5
- toil/provisioners/__init__.py +5 -2
- toil/provisioners/aws/__init__.py +43 -36
- toil/provisioners/aws/awsProvisioner.py +22 -13
- toil/provisioners/node.py +60 -12
- toil/resource.py +3 -13
- toil/test/__init__.py +14 -16
- toil/test/batchSystems/test_slurm.py +103 -14
- toil/test/cwl/staging_cat.cwl +27 -0
- toil/test/cwl/staging_make_file.cwl +25 -0
- toil/test/cwl/staging_workflow.cwl +43 -0
- toil/test/cwl/zero_default.cwl +61 -0
- toil/test/docs/scripts/tutorial_staging.py +17 -8
- toil/test/jobStores/jobStoreTest.py +23 -133
- toil/test/lib/aws/test_iam.py +7 -7
- toil/test/lib/aws/test_s3.py +30 -33
- toil/test/lib/aws/test_utils.py +9 -9
- toil/test/provisioners/aws/awsProvisionerTest.py +59 -6
- toil/test/src/autoDeploymentTest.py +2 -3
- toil/test/src/fileStoreTest.py +89 -87
- toil/test/utils/ABCWorkflowDebug/ABC.txt +1 -0
- toil/test/utils/ABCWorkflowDebug/debugWorkflow.py +4 -4
- toil/test/utils/toilKillTest.py +35 -28
- toil/test/wdl/md5sum/md5sum.json +1 -1
- toil/test/wdl/testfiles/gather.wdl +52 -0
- toil/test/wdl/wdltoil_test.py +120 -38
- toil/test/wdl/wdltoil_test_kubernetes.py +9 -0
- toil/utils/toilDebugFile.py +6 -3
- toil/utils/toilStats.py +17 -2
- toil/version.py +6 -6
- toil/wdl/wdltoil.py +1038 -549
- toil/worker.py +5 -2
- {toil-9.0.0.dist-info → toil-9.1.1.dist-info}/METADATA +12 -12
- {toil-9.0.0.dist-info → toil-9.1.1.dist-info}/RECORD +69 -61
- toil/lib/iterables.py +0 -112
- toil/test/docs/scripts/stagingExampleFiles/in.txt +0 -1
- {toil-9.0.0.dist-info → toil-9.1.1.dist-info}/WHEEL +0 -0
- {toil-9.0.0.dist-info → toil-9.1.1.dist-info}/entry_points.txt +0 -0
- {toil-9.0.0.dist-info → toil-9.1.1.dist-info}/licenses/LICENSE +0 -0
- {toil-9.0.0.dist-info → toil-9.1.1.dist-info}/top_level.txt +0 -0
|
@@ -671,13 +671,16 @@ class AbstractFileStore(ABC):
|
|
|
671
671
|
Send a logging message to the leader. The message will also be \
|
|
672
672
|
logged by the worker at the same level.
|
|
673
673
|
|
|
674
|
+
Does not depend on the commit system, so this is safe to use during an
|
|
675
|
+
ansynchronous commit, or without a commit afterward.
|
|
676
|
+
|
|
674
677
|
:param text: The string to log.
|
|
675
678
|
:param level: The logging level.
|
|
676
679
|
"""
|
|
677
|
-
logger.log(level=level, msg=("LOG-TO-
|
|
680
|
+
logger.log(level=level, msg=("LOG-TO-LEADER: " + text))
|
|
678
681
|
self.logging_messages.append(dict(text=text, level=level))
|
|
679
682
|
|
|
680
|
-
@deprecated(new_function_name="
|
|
683
|
+
@deprecated(new_function_name="log_to_leader")
|
|
681
684
|
def logToMaster(self, text: str, level: int = logging.INFO) -> None:
|
|
682
685
|
self.log_to_leader(text, level)
|
|
683
686
|
|
|
@@ -1207,7 +1207,7 @@ class CachingFileStore(AbstractFileStore):
|
|
|
1207
1207
|
# its temp dir and database entry.
|
|
1208
1208
|
self._deallocateSpaceForJob()
|
|
1209
1209
|
|
|
1210
|
-
def writeGlobalFile(self, localFileName, cleanup=False
|
|
1210
|
+
def writeGlobalFile(self, localFileName, cleanup=False):
|
|
1211
1211
|
"""
|
|
1212
1212
|
Creates a file in the jobstore and returns a FileID reference.
|
|
1213
1213
|
"""
|
toil/job.py
CHANGED
|
@@ -236,16 +236,16 @@ def parse_accelerator(
|
|
|
236
236
|
{'count': 1, 'kind': 'gpu'}
|
|
237
237
|
|
|
238
238
|
>>> parse_accelerator("nvidia-tesla-k80")
|
|
239
|
-
{'count': 1, 'kind': 'gpu', '
|
|
239
|
+
{'count': 1, 'kind': 'gpu', 'model': 'nvidia-tesla-k80', 'brand': 'nvidia'}
|
|
240
240
|
|
|
241
241
|
>>> parse_accelerator("nvidia-tesla-k80:2")
|
|
242
|
-
{'count': 2, 'kind': 'gpu', '
|
|
242
|
+
{'count': 2, 'kind': 'gpu', 'model': 'nvidia-tesla-k80', 'brand': 'nvidia'}
|
|
243
243
|
|
|
244
244
|
>>> parse_accelerator("gpu")
|
|
245
245
|
{'count': 1, 'kind': 'gpu'}
|
|
246
246
|
|
|
247
247
|
>>> parse_accelerator("cuda:1")
|
|
248
|
-
{'count': 1, 'kind': 'gpu', '
|
|
248
|
+
{'count': 1, 'kind': 'gpu', 'api': 'cuda', 'brand': 'nvidia'}
|
|
249
249
|
|
|
250
250
|
>>> parse_accelerator({"kind": "gpu"})
|
|
251
251
|
{'count': 1, 'kind': 'gpu'}
|
|
@@ -581,8 +581,8 @@ class Requirer:
|
|
|
581
581
|
>>> Requirer._parseResource('cores', 1), Requirer._parseResource('disk', 1), \
|
|
582
582
|
Requirer._parseResource('memory', 1)
|
|
583
583
|
(1, 1, 1)
|
|
584
|
-
>>> Requirer._parseResource('cores', '
|
|
585
|
-
Requirer._parseResource('memory', '
|
|
584
|
+
>>> Requirer._parseResource('cores', '1Gi'), Requirer._parseResource('disk', '1Gi'), \
|
|
585
|
+
Requirer._parseResource('memory', '1Gi')
|
|
586
586
|
(1073741824, 1073741824, 1073741824)
|
|
587
587
|
>>> Requirer._parseResource('cores', 1.1)
|
|
588
588
|
1.1
|
|
@@ -813,7 +813,6 @@ class JobDescription(Requirer):
|
|
|
813
813
|
Subclassed into variants for checkpoint jobs and service jobs that have
|
|
814
814
|
their specific parameters.
|
|
815
815
|
"""
|
|
816
|
-
|
|
817
816
|
def __init__(
|
|
818
817
|
self,
|
|
819
818
|
requirements: Mapping[str, Union[int, str, float, bool, list]],
|
|
@@ -3146,9 +3145,8 @@ class Job:
|
|
|
3146
3145
|
|
|
3147
3146
|
Will modify the job's description with changes that need to be committed back to the JobStore.
|
|
3148
3147
|
"""
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
startClock = ResourceMonitor.get_total_cpu_time()
|
|
3148
|
+
startTime = time.time()
|
|
3149
|
+
startClock = ResourceMonitor.get_total_cpu_time()
|
|
3152
3150
|
baseDir = os.getcwd()
|
|
3153
3151
|
|
|
3154
3152
|
succeeded = False
|
|
@@ -3180,18 +3178,36 @@ class Job:
|
|
|
3180
3178
|
# Change dir back to cwd dir, if changed by job (this is a safety issue)
|
|
3181
3179
|
if os.getcwd() != baseDir:
|
|
3182
3180
|
os.chdir(baseDir)
|
|
3181
|
+
|
|
3182
|
+
totalCpuTime, total_memory_kib = (
|
|
3183
|
+
ResourceMonitor.get_total_cpu_time_and_memory_usage()
|
|
3184
|
+
)
|
|
3185
|
+
job_time = time.time() - startTime
|
|
3186
|
+
job_cpu_time = totalCpuTime - startClock
|
|
3187
|
+
allocated_cpu_time = job_time * self.cores
|
|
3188
|
+
|
|
3189
|
+
if job_cpu_time > allocated_cpu_time and allocated_cpu_time > 0:
|
|
3190
|
+
# Too much CPU was used by this job! Maybe we're using a batch
|
|
3191
|
+
# system that doesn't/can't sandbox us and we started too many
|
|
3192
|
+
# threads. Complain to the user!
|
|
3193
|
+
excess_factor = job_cpu_time / allocated_cpu_time
|
|
3194
|
+
fileStore.log_to_leader(
|
|
3195
|
+
f"Job {self.description} used {excess_factor:.2f}x more "
|
|
3196
|
+
f"CPU than the requested {self.cores} cores. Consider "
|
|
3197
|
+
f"increasing the job's required CPU cores or limiting the "
|
|
3198
|
+
f"number of processes/threads launched.",
|
|
3199
|
+
level=logging.WARNING
|
|
3200
|
+
)
|
|
3201
|
+
|
|
3183
3202
|
# Finish up the stats
|
|
3184
3203
|
if stats is not None:
|
|
3185
|
-
totalCpuTime, total_memory_kib = (
|
|
3186
|
-
ResourceMonitor.get_total_cpu_time_and_memory_usage()
|
|
3187
|
-
)
|
|
3188
3204
|
stats.jobs.append(
|
|
3189
3205
|
# TODO: We represent everything as strings in the stats
|
|
3190
3206
|
# even though the JSON transport can take bools and floats.
|
|
3191
3207
|
Expando(
|
|
3192
3208
|
start=str(startTime),
|
|
3193
|
-
time=str(
|
|
3194
|
-
clock=str(
|
|
3209
|
+
time=str(job_time),
|
|
3210
|
+
clock=str(job_cpu_time),
|
|
3195
3211
|
class_name=self._jobName(),
|
|
3196
3212
|
memory=str(total_memory_kib),
|
|
3197
3213
|
requested_cores=str(self.cores), # TODO: Isn't this really consumed cores?
|
|
@@ -90,7 +90,7 @@ class InvalidImportExportUrlException(Exception):
|
|
|
90
90
|
class NoSuchJobException(Exception):
|
|
91
91
|
"""Indicates that the specified job does not exist."""
|
|
92
92
|
|
|
93
|
-
def __init__(self, jobStoreID: FileID):
|
|
93
|
+
def __init__(self, jobStoreID: Union[FileID, str]):
|
|
94
94
|
"""
|
|
95
95
|
:param str jobStoreID: the jobStoreID that was mistakenly assumed to exist
|
|
96
96
|
"""
|
|
@@ -100,7 +100,7 @@ class NoSuchJobException(Exception):
|
|
|
100
100
|
class ConcurrentFileModificationException(Exception):
|
|
101
101
|
"""Indicates that the file was attempted to be modified by multiple processes at once."""
|
|
102
102
|
|
|
103
|
-
def __init__(self, jobStoreFileID: FileID):
|
|
103
|
+
def __init__(self, jobStoreFileID: Union[FileID, str]):
|
|
104
104
|
"""
|
|
105
105
|
:param jobStoreFileID: the ID of the file that was modified by multiple workers
|
|
106
106
|
or processes concurrently
|
|
@@ -112,7 +112,7 @@ class NoSuchFileException(Exception):
|
|
|
112
112
|
"""Indicates that the specified file does not exist."""
|
|
113
113
|
|
|
114
114
|
def __init__(
|
|
115
|
-
self, jobStoreFileID: FileID, customName: Optional[str] = None, *extra: Any
|
|
115
|
+
self, jobStoreFileID: Union[FileID, str], customName: Optional[str] = None, *extra: Any
|
|
116
116
|
):
|
|
117
117
|
"""
|
|
118
118
|
:param jobStoreFileID: the ID of the file that was mistakenly assumed to exist
|
|
@@ -140,11 +140,12 @@ class NoSuchJobStoreException(LocatorException):
|
|
|
140
140
|
def __init__(self, locator: str, prefix: str):
|
|
141
141
|
"""
|
|
142
142
|
:param str locator: The location of the job store
|
|
143
|
+
:param str prefix: The type of job store
|
|
143
144
|
"""
|
|
144
145
|
super().__init__(
|
|
145
146
|
"The job store '%s' does not exist, so there is nothing to restart.",
|
|
146
147
|
locator,
|
|
147
|
-
prefix
|
|
148
|
+
prefix
|
|
148
149
|
)
|
|
149
150
|
|
|
150
151
|
|
|
@@ -159,7 +160,7 @@ class JobStoreExistsException(LocatorException):
|
|
|
159
160
|
"The job store '%s' already exists. Use --restart to resume the workflow, or remove "
|
|
160
161
|
"the job store with 'toil clean' to start the workflow from scratch.",
|
|
161
162
|
locator,
|
|
162
|
-
prefix
|
|
163
|
+
prefix
|
|
163
164
|
)
|
|
164
165
|
|
|
165
166
|
|
|
@@ -240,7 +241,12 @@ class AbstractJobStore(ABC):
|
|
|
240
241
|
|
|
241
242
|
@property
|
|
242
243
|
def config(self) -> Config:
|
|
243
|
-
"""
|
|
244
|
+
"""
|
|
245
|
+
Return the Toil configuration associated with this job store.
|
|
246
|
+
|
|
247
|
+
:raises AttributeError: if the config has not yet been assigned (i.e.
|
|
248
|
+
during :meth:`resume`).
|
|
249
|
+
"""
|
|
244
250
|
return self.__config
|
|
245
251
|
|
|
246
252
|
@property
|
|
@@ -561,7 +567,6 @@ class AbstractJobStore(ABC):
|
|
|
561
567
|
executable = jobStoreFileID.executable
|
|
562
568
|
otherCls._write_to_url(readable, url, executable)
|
|
563
569
|
|
|
564
|
-
|
|
565
570
|
@abstractmethod
|
|
566
571
|
def destroy(self) -> None:
|
|
567
572
|
"""
|
|
@@ -930,15 +935,6 @@ class AbstractJobStore(ABC):
|
|
|
930
935
|
"""
|
|
931
936
|
raise NotImplementedError()
|
|
932
937
|
|
|
933
|
-
@contextmanager
|
|
934
|
-
def batch(self) -> Iterator[None]:
|
|
935
|
-
"""
|
|
936
|
-
If supported by the batch system, calls to create() with this context
|
|
937
|
-
manager active will be performed in a batch after the context manager
|
|
938
|
-
is released.
|
|
939
|
-
"""
|
|
940
|
-
yield
|
|
941
|
-
|
|
942
938
|
@deprecated(new_function_name="create_job")
|
|
943
939
|
def create(self, jobDescription: JobDescription) -> JobDescription:
|
|
944
940
|
return self.create_job(jobDescription)
|
|
@@ -1036,6 +1032,15 @@ class AbstractJobStore(ABC):
|
|
|
1036
1032
|
def update(self, jobDescription: JobDescription) -> None:
|
|
1037
1033
|
return self.update_job(jobDescription)
|
|
1038
1034
|
|
|
1035
|
+
@contextmanager
|
|
1036
|
+
def batch(self) -> Iterator[None]:
|
|
1037
|
+
"""
|
|
1038
|
+
If supported by the batch system, calls to create() with this context
|
|
1039
|
+
manager active will be performed in a batch after the context manager
|
|
1040
|
+
is released.
|
|
1041
|
+
"""
|
|
1042
|
+
yield
|
|
1043
|
+
|
|
1039
1044
|
@abstractmethod
|
|
1040
1045
|
def update_job(self, job_description: JobDescription) -> None:
|
|
1041
1046
|
"""
|
|
@@ -1206,14 +1211,14 @@ class AbstractJobStore(ABC):
|
|
|
1206
1211
|
Creates an empty file in the job store and returns its ID.
|
|
1207
1212
|
Call to fileExists(getEmptyFileStoreID(jobStoreID)) will return True.
|
|
1208
1213
|
|
|
1209
|
-
:param
|
|
1214
|
+
:param job_id: the id of a job, or None. If specified, the may be associated
|
|
1210
1215
|
with that job in a job-store-specific way. This may influence the returned ID.
|
|
1211
1216
|
|
|
1212
|
-
:param
|
|
1217
|
+
:param cleanup: Whether to attempt to delete the file when the job
|
|
1213
1218
|
whose jobStoreID was given as jobStoreID is deleted with
|
|
1214
1219
|
jobStore.delete(job). If jobStoreID was not given, does nothing.
|
|
1215
1220
|
|
|
1216
|
-
:param
|
|
1221
|
+
:param basename: If supported by the implementation, use the given
|
|
1217
1222
|
file basename so that when searching the job store with a query
|
|
1218
1223
|
matching that basename, the file will be detected.
|
|
1219
1224
|
|