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.
Files changed (155) hide show
  1. toil/__init__.py +5 -9
  2. toil/batchSystems/abstractBatchSystem.py +23 -22
  3. toil/batchSystems/abstractGridEngineBatchSystem.py +17 -12
  4. toil/batchSystems/awsBatch.py +8 -8
  5. toil/batchSystems/cleanup_support.py +4 -4
  6. toil/batchSystems/contained_executor.py +3 -3
  7. toil/batchSystems/gridengine.py +3 -4
  8. toil/batchSystems/htcondor.py +5 -5
  9. toil/batchSystems/kubernetes.py +65 -63
  10. toil/batchSystems/local_support.py +2 -3
  11. toil/batchSystems/lsf.py +6 -7
  12. toil/batchSystems/mesos/batchSystem.py +11 -7
  13. toil/batchSystems/mesos/test/__init__.py +1 -2
  14. toil/batchSystems/options.py +9 -10
  15. toil/batchSystems/registry.py +3 -7
  16. toil/batchSystems/singleMachine.py +8 -11
  17. toil/batchSystems/slurm.py +49 -38
  18. toil/batchSystems/torque.py +3 -4
  19. toil/bus.py +36 -34
  20. toil/common.py +129 -89
  21. toil/cwl/cwltoil.py +857 -729
  22. toil/cwl/utils.py +44 -35
  23. toil/fileStores/__init__.py +3 -1
  24. toil/fileStores/abstractFileStore.py +28 -30
  25. toil/fileStores/cachingFileStore.py +8 -8
  26. toil/fileStores/nonCachingFileStore.py +10 -21
  27. toil/job.py +159 -158
  28. toil/jobStores/abstractJobStore.py +68 -69
  29. toil/jobStores/aws/jobStore.py +249 -213
  30. toil/jobStores/aws/utils.py +13 -24
  31. toil/jobStores/fileJobStore.py +28 -22
  32. toil/jobStores/googleJobStore.py +21 -17
  33. toil/jobStores/utils.py +3 -7
  34. toil/leader.py +17 -22
  35. toil/lib/accelerators.py +6 -4
  36. toil/lib/aws/__init__.py +9 -10
  37. toil/lib/aws/ami.py +33 -19
  38. toil/lib/aws/iam.py +6 -6
  39. toil/lib/aws/s3.py +259 -157
  40. toil/lib/aws/session.py +76 -76
  41. toil/lib/aws/utils.py +51 -43
  42. toil/lib/checksum.py +19 -15
  43. toil/lib/compatibility.py +3 -2
  44. toil/lib/conversions.py +45 -18
  45. toil/lib/directory.py +29 -26
  46. toil/lib/docker.py +93 -99
  47. toil/lib/dockstore.py +77 -50
  48. toil/lib/ec2.py +39 -38
  49. toil/lib/ec2nodes.py +11 -4
  50. toil/lib/exceptions.py +8 -5
  51. toil/lib/ftp_utils.py +9 -14
  52. toil/lib/generatedEC2Lists.py +161 -20
  53. toil/lib/history.py +141 -97
  54. toil/lib/history_submission.py +163 -72
  55. toil/lib/io.py +27 -17
  56. toil/lib/memoize.py +2 -1
  57. toil/lib/misc.py +15 -11
  58. toil/lib/pipes.py +40 -25
  59. toil/lib/plugins.py +12 -8
  60. toil/lib/resources.py +1 -0
  61. toil/lib/retry.py +32 -38
  62. toil/lib/threading.py +12 -12
  63. toil/lib/throttle.py +1 -2
  64. toil/lib/trs.py +113 -51
  65. toil/lib/url.py +14 -23
  66. toil/lib/web.py +7 -2
  67. toil/options/common.py +18 -15
  68. toil/options/cwl.py +2 -2
  69. toil/options/runner.py +9 -5
  70. toil/options/wdl.py +1 -3
  71. toil/provisioners/__init__.py +9 -9
  72. toil/provisioners/abstractProvisioner.py +22 -20
  73. toil/provisioners/aws/__init__.py +20 -14
  74. toil/provisioners/aws/awsProvisioner.py +10 -8
  75. toil/provisioners/clusterScaler.py +19 -18
  76. toil/provisioners/gceProvisioner.py +2 -3
  77. toil/provisioners/node.py +11 -13
  78. toil/realtimeLogger.py +4 -4
  79. toil/resource.py +5 -5
  80. toil/server/app.py +2 -2
  81. toil/server/cli/wes_cwl_runner.py +11 -11
  82. toil/server/utils.py +18 -21
  83. toil/server/wes/abstract_backend.py +9 -8
  84. toil/server/wes/amazon_wes_utils.py +3 -3
  85. toil/server/wes/tasks.py +3 -5
  86. toil/server/wes/toil_backend.py +17 -21
  87. toil/server/wsgi_app.py +3 -3
  88. toil/serviceManager.py +3 -4
  89. toil/statsAndLogging.py +12 -13
  90. toil/test/__init__.py +33 -24
  91. toil/test/batchSystems/batchSystemTest.py +12 -11
  92. toil/test/batchSystems/batch_system_plugin_test.py +3 -5
  93. toil/test/batchSystems/test_slurm.py +38 -24
  94. toil/test/cwl/conftest.py +5 -6
  95. toil/test/cwl/cwlTest.py +194 -78
  96. toil/test/cwl/download_file_uri.json +6 -0
  97. toil/test/cwl/download_file_uri_no_hostname.json +6 -0
  98. toil/test/docs/scripts/tutorial_staging.py +1 -0
  99. toil/test/jobStores/jobStoreTest.py +9 -7
  100. toil/test/lib/aws/test_iam.py +1 -3
  101. toil/test/lib/aws/test_s3.py +1 -1
  102. toil/test/lib/dockerTest.py +9 -9
  103. toil/test/lib/test_ec2.py +12 -11
  104. toil/test/lib/test_history.py +4 -4
  105. toil/test/lib/test_trs.py +16 -14
  106. toil/test/lib/test_url.py +7 -6
  107. toil/test/lib/url_plugin_test.py +12 -18
  108. toil/test/provisioners/aws/awsProvisionerTest.py +10 -8
  109. toil/test/provisioners/clusterScalerTest.py +2 -5
  110. toil/test/provisioners/clusterTest.py +1 -3
  111. toil/test/server/serverTest.py +13 -4
  112. toil/test/sort/restart_sort.py +2 -6
  113. toil/test/sort/sort.py +3 -8
  114. toil/test/src/deferredFunctionTest.py +7 -7
  115. toil/test/src/environmentTest.py +1 -2
  116. toil/test/src/fileStoreTest.py +5 -5
  117. toil/test/src/importExportFileTest.py +5 -6
  118. toil/test/src/jobServiceTest.py +22 -14
  119. toil/test/src/jobTest.py +121 -25
  120. toil/test/src/miscTests.py +5 -7
  121. toil/test/src/promisedRequirementTest.py +8 -7
  122. toil/test/src/regularLogTest.py +2 -3
  123. toil/test/src/resourceTest.py +5 -8
  124. toil/test/src/restartDAGTest.py +5 -6
  125. toil/test/src/resumabilityTest.py +2 -2
  126. toil/test/src/retainTempDirTest.py +3 -3
  127. toil/test/src/systemTest.py +3 -3
  128. toil/test/src/threadingTest.py +1 -1
  129. toil/test/src/workerTest.py +1 -2
  130. toil/test/utils/toilDebugTest.py +6 -4
  131. toil/test/utils/toilKillTest.py +1 -1
  132. toil/test/utils/utilsTest.py +15 -14
  133. toil/test/wdl/wdltoil_test.py +247 -124
  134. toil/test/wdl/wdltoil_test_kubernetes.py +2 -2
  135. toil/toilState.py +2 -3
  136. toil/utils/toilDebugFile.py +3 -8
  137. toil/utils/toilDebugJob.py +1 -2
  138. toil/utils/toilLaunchCluster.py +1 -2
  139. toil/utils/toilSshCluster.py +2 -0
  140. toil/utils/toilStats.py +19 -24
  141. toil/utils/toilStatus.py +11 -14
  142. toil/version.py +10 -10
  143. toil/wdl/wdltoil.py +313 -209
  144. toil/worker.py +18 -12
  145. {toil-9.1.1.dist-info → toil-9.2.0.dist-info}/METADATA +11 -14
  146. {toil-9.1.1.dist-info → toil-9.2.0.dist-info}/RECORD +150 -153
  147. {toil-9.1.1.dist-info → toil-9.2.0.dist-info}/WHEEL +1 -1
  148. toil/test/cwl/staging_cat.cwl +0 -27
  149. toil/test/cwl/staging_make_file.cwl +0 -25
  150. toil/test/cwl/staging_workflow.cwl +0 -43
  151. toil/test/cwl/zero_default.cwl +0 -61
  152. toil/test/utils/ABCWorkflowDebug/ABC.txt +0 -1
  153. {toil-9.1.1.dist-info → toil-9.2.0.dist-info}/entry_points.txt +0 -0
  154. {toil-9.1.1.dist-info → toil-9.2.0.dist-info}/licenses/LICENSE +0 -0
  155. {toil-9.1.1.dist-info → toil-9.2.0.dist-info}/top_level.txt +0 -0
toil/statsAndLogging.py CHANGED
@@ -18,9 +18,10 @@ import logging
18
18
  import os
19
19
  import time
20
20
  from argparse import ArgumentParser, Namespace
21
+ from collections.abc import Callable
21
22
  from logging.handlers import RotatingFileHandler
22
23
  from threading import Event, Thread
23
- from typing import IO, TYPE_CHECKING, Any, Callable, Optional, Union
24
+ from typing import IO, TYPE_CHECKING, Any, Union
24
25
 
25
26
  from toil.lib.conversions import strtobool
26
27
  from toil.lib.expando import Expando
@@ -60,9 +61,7 @@ class StatsAndLogging:
60
61
  self._worker.start()
61
62
 
62
63
  @classmethod
63
- def formatLogStream(
64
- cls, stream: Union[IO[str], IO[bytes]], stream_name: str
65
- ) -> str:
64
+ def formatLogStream(cls, stream: IO[str] | IO[bytes], stream_name: str) -> str:
66
65
  """
67
66
  Given a stream of text or bytes, and the job name, job itself, or some
68
67
  other optional stringifyable identity info for the job, return a big
@@ -90,9 +89,9 @@ class StatsAndLogging:
90
89
  def logWithFormatting(
91
90
  cls,
92
91
  stream_name: str,
93
- jobLogs: Union[IO[str], IO[bytes]],
92
+ jobLogs: IO[str] | IO[bytes],
94
93
  method: Callable[[str], None] = logger.debug,
95
- message: Optional[str] = None,
94
+ message: str | None = None,
96
95
  ) -> None:
97
96
  if message is not None:
98
97
  method(message)
@@ -174,7 +173,7 @@ class StatsAndLogging:
174
173
  startTime = time.time()
175
174
  startClock = ResourceMonitor.get_total_cpu_time()
176
175
 
177
- def callback(fileHandle: Union[IO[bytes], IO[str]]) -> None:
176
+ def callback(fileHandle: IO[bytes] | IO[str]) -> None:
178
177
  statsStr = fileHandle.read()
179
178
  if not isinstance(statsStr, str):
180
179
  statsStr = statsStr.decode()
@@ -259,7 +258,7 @@ class StatsAndLogging:
259
258
  cores=float(job.requested_cores),
260
259
  cpu_seconds=float(job.clock),
261
260
  memory_bytes=int(job.memory) * 1024,
262
- disk_bytes=int(job.disk)
261
+ disk_bytes=int(job.disk),
263
262
  )
264
263
  except:
265
264
  logger.exception("Could not record job attempt in history!")
@@ -304,7 +303,7 @@ class StatsAndLogging:
304
303
  # in addition to cleaning on exceptions, onError should clean if there are any failed jobs
305
304
 
306
305
 
307
- def set_log_level(level: str, set_logger: Optional[logging.Logger] = None) -> None:
306
+ def set_log_level(level: str, set_logger: logging.Logger | None = None) -> None:
308
307
  """Sets the root logger level to a given string level (like "INFO")."""
309
308
  level = "CRITICAL" if level.upper() == "OFF" else level.upper()
310
309
  set_logger = set_logger if set_logger else root_logger
@@ -314,7 +313,7 @@ def set_log_level(level: str, set_logger: Optional[logging.Logger] = None) -> No
314
313
  suppress_exotic_logging(__name__)
315
314
 
316
315
 
317
- def install_log_color(set_logger: Optional[logging.Logger] = None) -> None:
316
+ def install_log_color(set_logger: logging.Logger | None = None) -> None:
318
317
  """Make logs colored."""
319
318
  # Most of this code is taken from miniwdl
320
319
  # delayed import
@@ -349,7 +348,7 @@ def install_log_color(set_logger: Optional[logging.Logger] = None) -> None:
349
348
 
350
349
 
351
350
  def add_logging_options(
352
- parser: ArgumentParser, default_level: Optional[int] = None
351
+ parser: ArgumentParser, default_level: int | None = None
353
352
  ) -> None:
354
353
  """
355
354
  Add logging options to set the global log level.
@@ -424,11 +423,11 @@ def configure_root_logger() -> None:
424
423
  root_logger.setLevel(DEFAULT_LOGLEVEL)
425
424
 
426
425
 
427
- def log_to_file(log_file: Optional[str], log_rotation: bool) -> None:
426
+ def log_to_file(log_file: str | None, log_rotation: bool) -> None:
428
427
  if log_file and log_file not in __loggingFiles:
429
428
  logger.debug(f"Logging to file '{log_file}'.")
430
429
  __loggingFiles.append(log_file)
431
- handler: Union[RotatingFileHandler, logging.FileHandler]
430
+ handler: RotatingFileHandler | logging.FileHandler
432
431
  if log_rotation:
433
432
  handler = RotatingFileHandler(log_file, maxBytes=1000000, backupCount=1)
434
433
  else:
toil/test/__init__.py CHANGED
@@ -35,7 +35,8 @@ from pathlib import Path
35
35
  from shutil import which
36
36
  from tempfile import mkstemp
37
37
  from textwrap import dedent
38
- from typing import Any, Callable, Literal, Optional, TypeVar, Union, cast
38
+ from typing import Any, Literal, Optional, TypeVar, Union, cast
39
+ from collections.abc import Callable
39
40
  from unittest.util import strclass
40
41
  from urllib.error import HTTPError, URLError
41
42
  from urllib.request import urlopen
@@ -60,6 +61,7 @@ except ImportError:
60
61
  class ProxyConnectionError(BaseException): # type: ignore[no-redef]
61
62
  ...
62
63
 
64
+
63
65
  logger = logging.getLogger(__name__)
64
66
 
65
67
 
@@ -100,7 +102,7 @@ class ToilTest(unittest.TestCase):
100
102
  """
101
103
 
102
104
  _rootpath: Path
103
- _tempBaseDir: Optional[str] = None
105
+ _tempBaseDir: str | None = None
104
106
  _tempDirs: list[str] = []
105
107
 
106
108
  def setup_method(self, method: Any) -> None:
@@ -179,11 +181,11 @@ class ToilTest(unittest.TestCase):
179
181
  assert region
180
182
  return region.group(1)
181
183
 
182
- def _createTempDir(self, purpose: Optional[str] = None) -> str:
184
+ def _createTempDir(self, purpose: str | None = None) -> str:
183
185
  return self._createTempDirEx(self._testMethodName, purpose)
184
186
 
185
187
  @classmethod
186
- def _createTempDirEx(cls, *names: Optional[str]) -> str:
188
+ def _createTempDirEx(cls, *names: str | None) -> str:
187
189
  classname = strclass(cls)
188
190
  if classname.startswith("toil.test."):
189
191
  classname = classname[len("toil.test.") :]
@@ -207,7 +209,7 @@ class ToilTest(unittest.TestCase):
207
209
  return path
208
210
 
209
211
  @classmethod
210
- def _run(cls, command: str, *args: str, **kwargs: Any) -> Optional[str]:
212
+ def _run(cls, command: str, *args: str, **kwargs: Any) -> str | None:
211
213
  """
212
214
  Run a command.
213
215
 
@@ -265,7 +267,7 @@ else:
265
267
  return cast(MT, getattr(pytest_mark, name)(test_item))
266
268
 
267
269
 
268
- def get_temp_file(suffix: str = "", rootDir: Optional[str] = None) -> str:
270
+ def get_temp_file(suffix: str = "", rootDir: str | None = None) -> str:
269
271
  """Return a string representing a temporary file, that must be manually deleted."""
270
272
  if rootDir is None:
271
273
  handle, tmp_file = mkstemp(suffix)
@@ -282,7 +284,7 @@ def get_temp_file(suffix: str = "", rootDir: Optional[str] = None) -> str:
282
284
  return tmp_file
283
285
 
284
286
 
285
- def needs_env_var(var_name: str, comment: Optional[str] = None) -> Callable[[MT], MT]:
287
+ def needs_env_var(var_name: str, comment: str | None = None) -> Callable[[MT], MT]:
286
288
  """
287
289
  Use as a decorator before test classes or methods to run only if the given
288
290
  environment variable is set.
@@ -369,9 +371,7 @@ def needs_aws_s3(test_item: MT) -> MT:
369
371
  test_item
370
372
  )
371
373
  except ProxyConnectionError as e:
372
- return unittest.skip(f"Proxy error: {e}, skipping this test.")(
373
- test_item
374
- )
374
+ return unittest.skip(f"Proxy error: {e}, skipping this test.")(test_item)
375
375
  from toil.lib.aws import running_on_ec2
376
376
 
377
377
  if not (
@@ -569,6 +569,7 @@ def needs_mesos(test_item: MT) -> MT:
569
569
  )(test_item)
570
570
  try:
571
571
  import psutil # noqa
572
+
572
573
  # If pymesos is installed, because it isn't typed, mypy sees an
573
574
  # import-untyped error here.
574
575
  #
@@ -592,6 +593,9 @@ def _mesos_avail() -> bool:
592
593
  try:
593
594
  import psutil
594
595
  import pymesos
596
+
597
+ str(psutil) # to prevent removal of this import
598
+ str(pymesos) # to prevent removal of this import
595
599
  except ImportError:
596
600
  return False
597
601
  return True
@@ -793,6 +797,8 @@ def needs_cwl(test_item: MT) -> MT:
793
797
  def _cwl_available() -> bool:
794
798
  try:
795
799
  import cwltool
800
+
801
+ str(cwltool) # to prevent removal of this import
796
802
  except ImportError:
797
803
  return False
798
804
  return True
@@ -1038,7 +1044,7 @@ def timeLimit(seconds: int) -> Generator[None, None, None]:
1038
1044
 
1039
1045
  def make_tests(
1040
1046
  generalMethod: Callable[[Any], Any],
1041
- targetClass: Optional[Callable[[Any], Any]],
1047
+ targetClass: Callable[[Any], Any] | None,
1042
1048
  **kwargs: Any,
1043
1049
  ) -> None:
1044
1050
  """
@@ -1185,7 +1191,7 @@ class ApplianceTestSupport(ToilTest):
1185
1191
 
1186
1192
  @contextmanager
1187
1193
  def _applianceCluster(
1188
- self, mounts: dict[str, str], numCores: Optional[int] = None
1194
+ self, mounts: dict[str, str], numCores: int | None = None
1189
1195
  ) -> Generator[
1190
1196
  tuple["ApplianceTestSupport.LeaderThread", "ApplianceTestSupport.WorkerThread"],
1191
1197
  None,
@@ -1244,22 +1250,25 @@ class ApplianceTestSupport(ToilTest):
1244
1250
  self.mounts = mounts
1245
1251
  self.cleanMounts = cleanMounts
1246
1252
  self.containerName = str(uuid.uuid4())
1247
- self.popen: Optional[subprocess.Popen[bytes]] = None
1253
+ self.popen: subprocess.Popen[bytes] | None = None
1248
1254
 
1249
1255
  def __enter__(self) -> Self:
1250
1256
  with self.lock:
1251
1257
  image = applianceSelf()
1252
1258
  # Omitting --rm, it's unreliable, see https://github.com/docker/docker/issues/16575
1253
- args = [
1254
- "docker",
1255
- "run",
1256
- f"--entrypoint={self._entryPoint()}",
1257
- "--net=host",
1258
- "-i",
1259
- f"--name={self.containerName}"] + \
1260
- ["--volume=%s:%s" % mount for mount in self.mounts.items()] + \
1261
- [image] + \
1262
- self._containerCommand()
1259
+ args = (
1260
+ [
1261
+ "docker",
1262
+ "run",
1263
+ f"--entrypoint={self._entryPoint()}",
1264
+ "--net=host",
1265
+ "-i",
1266
+ f"--name={self.containerName}",
1267
+ ]
1268
+ + ["--volume=%s:%s" % mount for mount in self.mounts.items()]
1269
+ + [image]
1270
+ + self._containerCommand()
1271
+ )
1263
1272
  logger.info("Running %r", args)
1264
1273
  self.popen = subprocess.Popen(args)
1265
1274
  self.start()
@@ -1347,7 +1356,7 @@ class ApplianceTestSupport(ToilTest):
1347
1356
  self.runOnAppliance("tee", path, input=contents)
1348
1357
 
1349
1358
  def deployScript(
1350
- self, path: str, packagePath: str, script: Union[str, Callable[..., Any]]
1359
+ self, path: str, packagePath: str, script: str | Callable[..., Any]
1351
1360
  ) -> None:
1352
1361
  """
1353
1362
  Deploy a Python module on the appliance.
@@ -11,22 +11,24 @@
11
11
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
- from collections.abc import Iterable, Generator
15
14
  import argparse
16
15
  import fcntl
17
16
  import itertools
18
17
  import logging
19
18
  import os
20
- from pathlib import Path
21
19
  import subprocess
22
20
  import sys
23
21
  import tempfile
24
22
  import textwrap
25
23
  import time
26
24
  from abc import ABCMeta, abstractmethod
25
+ from collections.abc import Generator
27
26
  from fractions import Fraction
27
+ from pathlib import Path
28
+ from typing import TYPE_CHECKING, Any
28
29
  from unittest import skipIf
29
- from typing import Optional, Any, TYPE_CHECKING
30
+
31
+ import pytest
30
32
 
31
33
  from toil.batchSystems.abstractBatchSystem import (
32
34
  AbstractBatchSystem,
@@ -45,9 +47,9 @@ from toil.batchSystems.registry import (
45
47
  )
46
48
  from toil.batchSystems.singleMachine import SingleMachineBatchSystem
47
49
  from toil.common import Config, Toil
48
- from toil.fileStores.abstractFileStore import AbstractFileStore
49
50
  from toil.job import Job, JobDescription, Requirer, ServiceHostJob
50
51
  from toil.lib.misc import StrPath
52
+ from toil.lib.plugins import remove_plugin
51
53
  from toil.lib.retry import retry_flaky_test
52
54
  from toil.lib.threading import cpu_count
53
55
  from toil.test import (
@@ -63,13 +65,10 @@ from toil.test import (
63
65
  needs_mesos,
64
66
  needs_slurm,
65
67
  needs_torque,
66
- slow,
67
- pslow,
68
68
  pneeds_mesos,
69
+ pslow,
70
+ slow,
69
71
  )
70
- from toil.lib.plugins import remove_plugin
71
-
72
- import pytest
73
72
 
74
73
  if TYPE_CHECKING:
75
74
  from toil.batchSystems.mesos.batchSystem import MesosBatchSystem
@@ -119,6 +118,7 @@ class hidden:
119
118
 
120
119
  http://stackoverflow.com/questions/1323455/python-unit-test-with-base-and-sub-class#answer-25695512
121
120
  """
121
+
122
122
  class AbstractBatchSystemTest(ToilTest, metaclass=ABCMeta):
123
123
  """
124
124
  A base test case with generic tests that every batch system should pass.
@@ -159,7 +159,7 @@ class hidden:
159
159
  return self.createConfig()
160
160
 
161
161
  def _mockJobDescription(
162
- self, jobStoreID: Optional[str] = None, **kwargs: Any
162
+ self, jobStoreID: str | None = None, **kwargs: Any
163
163
  ) -> JobDescription:
164
164
  """
165
165
  Create a mock-up JobDescription with the given ID and other parameters.
@@ -818,7 +818,8 @@ class SingleMachineBatchSystemTest(hidden.AbstractBatchSystemTest):
818
818
  import signal
819
819
  import sys
820
820
  import time
821
- from typing import Any, Iterable
821
+ from collections.abc import Iterable
822
+ from typing import Any
822
823
 
823
824
  def handle_signal(sig: Any, frame: Any) -> None:
824
825
  sys.stderr.write(f"{os.getpid()} ignoring signal {sig}\n")
@@ -12,7 +12,6 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
  import logging
15
- from typing import Optional
16
15
 
17
16
  from configargparse import ArgParser, ArgumentParser
18
17
 
@@ -25,8 +24,8 @@ from toil.batchSystems.options import OptionSetter
25
24
  from toil.batchSystems.registry import add_batch_system_factory
26
25
  from toil.common import Toil, addOptions
27
26
  from toil.job import JobDescription
28
- from toil.test import ToilTest
29
27
  from toil.lib.plugins import remove_plugin
28
+ from toil.test import ToilTest
30
29
 
31
30
  logger = logging.getLogger(__name__)
32
31
 
@@ -40,7 +39,7 @@ class FakeBatchSystem(BatchSystemCleanupSupport):
40
39
  self,
41
40
  command: str,
42
41
  job_desc: JobDescription,
43
- job_environment: Optional[dict[str, str]] = None,
42
+ job_environment: dict[str, str] | None = None,
44
43
  ) -> int:
45
44
  pass
46
45
 
@@ -53,7 +52,7 @@ class FakeBatchSystem(BatchSystemCleanupSupport):
53
52
  def getRunningBatchJobIDs(self) -> dict[int, float]:
54
53
  pass
55
54
 
56
- def getUpdatedBatchJob(self, maxWait: int) -> Optional[UpdatedBatchJobInfo]:
55
+ def getUpdatedBatchJob(self, maxWait: int) -> UpdatedBatchJobInfo | None:
57
56
  pass
58
57
 
59
58
  def shutdown(self) -> None:
@@ -82,7 +81,6 @@ class BatchSystemPluginTest(ToilTest):
82
81
 
83
82
  def fake_batch_system_factory() -> type[AbstractBatchSystem]:
84
83
  return FakeBatchSystem
85
-
86
84
 
87
85
  add_batch_system_factory("fake", fake_batch_system_factory)
88
86
 
@@ -1,12 +1,11 @@
1
1
  import errno
2
+ import logging
3
+ import sys
2
4
  import textwrap
5
+ from datetime import datetime, timedelta
3
6
  from queue import Queue
4
7
 
5
- import logging
6
8
  import pytest
7
- import sys
8
-
9
- from datetime import datetime, timedelta
10
9
 
11
10
  import toil.batchSystems.slurm
12
11
  from toil.batchSystems.abstractBatchSystem import (
@@ -29,6 +28,7 @@ logger = logging.getLogger(__name__)
29
28
  # we hope is not days and days away from the time the tests actually run.
30
29
  JOB_BASE_TIME = datetime.now().astimezone(None) - timedelta(days=5)
31
30
 
31
+
32
32
  def call_either(args, **_) -> str:
33
33
  """
34
34
  Pretend to call either sacct or scontrol as appropriate.
@@ -40,6 +40,7 @@ def call_either(args, **_) -> str:
40
40
  else:
41
41
  raise RuntimeError(f"Cannot fake command call: {args}")
42
42
 
43
+
43
44
  def call_sacct(args, **_) -> str:
44
45
  """
45
46
  The arguments passed to `call_command` when executing `sacct` are something like:
@@ -84,26 +85,24 @@ def call_sacct(args, **_) -> str:
84
85
 
85
86
  # See if they asked for a job list
86
87
  try:
87
- j_index = args.index('-j')
88
+ j_index = args.index("-j")
88
89
  job_ids = [int(job_id) for job_id in args[j_index + 1].split(",")]
89
90
  except ValueError:
90
91
  # We're not restricting to a list of jobs.
91
92
  job_ids = list(sacct_info.keys())
92
93
  # See if they asked for start or end times
93
94
  try:
94
- flag_index = args.index('-S')
95
+ flag_index = args.index("-S")
95
96
  begin_time = datetime.fromisoformat(args[flag_index + 1]).astimezone(None)
96
97
  except ValueError:
97
98
  # By default, Slurm uses today at midnight
98
- begin_time = datetime.now().astimezone(None).replace(
99
- hour=0,
100
- minute=0,
101
- second=0,
102
- microsecond=0,
103
- fold=0
99
+ begin_time = (
100
+ datetime.now()
101
+ .astimezone(None)
102
+ .replace(hour=0, minute=0, second=0, microsecond=0, fold=0)
104
103
  )
105
104
  try:
106
- flag_index = args.index('-E')
105
+ flag_index = args.index("-E")
107
106
  end_time = datetime.fromisoformat(args[flag_index + 1]).astimezone(None)
108
107
  except ValueError:
109
108
  end_time = None
@@ -251,6 +250,7 @@ def call_sacct_raises(*_):
251
250
  1, "sacct: error: Problem talking to the database: " "Connection timed out"
252
251
  )
253
252
 
253
+
254
254
  def call_sinfo(*_) -> str:
255
255
  """
256
256
  Simulate asking for partition info from Slurm
@@ -272,6 +272,7 @@ def call_sinfo(*_) -> str:
272
272
  )
273
273
  return stdout
274
274
 
275
+
275
276
  class FakeBatchSystem(BatchSystemSupport):
276
277
  """
277
278
  Class that implements a minimal Batch System, needed to create a Worker (see below).
@@ -299,13 +300,17 @@ class FakeBatchSystem(BatchSystemSupport):
299
300
 
300
301
  config.workflowID = str(uuid4())
301
302
  config.cleanWorkDir = "always"
302
- toil.batchSystems.slurm.SlurmBatchSystem.setOptions(lambda o: setattr(config, o, None))
303
+ toil.batchSystems.slurm.SlurmBatchSystem.setOptions(
304
+ lambda o: setattr(config, o, None)
305
+ )
303
306
  return config
304
307
 
308
+
305
309
  # Make the mock class not have abstract methods anymore, even though we don't
306
310
  # implement them. See <https://stackoverflow.com/a/17345619>.
307
311
  FakeBatchSystem.__abstractmethods__ = set()
308
312
 
313
+
309
314
  class SlurmTest(ToilTest):
310
315
  """
311
316
  Class for unit-testing SlurmBatchSystem
@@ -373,7 +378,6 @@ class SlurmTest(ToilTest):
373
378
  result = self.worker._getJobDetailsFromSacct(list(expected_result))
374
379
  assert result == expected_result, f"{result} != {expected_result}"
375
380
 
376
-
377
381
  ####
378
382
  #### tests for _getJobDetailsFromScontrol()
379
383
  ####
@@ -524,7 +528,7 @@ class SlurmTest(ToilTest):
524
528
  (130, BatchJobExitReason.FAILED),
525
529
  (0, BatchJobExitReason.FINISHED),
526
530
  (0, BatchJobExitReason.FINISHED),
527
- None
531
+ None,
528
532
  ]
529
533
  result = self.worker.coalesce_job_exit_codes(job_ids)
530
534
  assert result == expected_result, f"{result} != {expected_result}"
@@ -625,13 +629,17 @@ class SlurmTest(ToilTest):
625
629
  assert "--partition=short" in command
626
630
 
627
631
  # With a partition override, we should not. But the override will be rewritten.
628
- self.worker.boss.config.slurm_args = "--something --partition foo --somethingElse"
632
+ self.worker.boss.config.slurm_args = (
633
+ "--something --partition foo --somethingElse"
634
+ )
629
635
  command = self.worker.prepareSbatch(1, 100, 5, "job5", None, None)
630
636
  assert "--partition=short" not in command
631
637
  assert "--partition=foo" in command
632
638
 
633
639
  # All ways of setting partition should work, including =
634
- self.worker.boss.config.slurm_args = "--something --partition=foo --somethingElse"
640
+ self.worker.boss.config.slurm_args = (
641
+ "--something --partition=foo --somethingElse"
642
+ )
635
643
  command = self.worker.prepareSbatch(1, 100, 5, "job5", None, None)
636
644
  assert "--partition=short" not in command
637
645
  assert "--partition=foo" in command
@@ -649,7 +657,9 @@ class SlurmTest(ToilTest):
649
657
  assert "--partition=foobar" in command
650
658
 
651
659
  # But they should be overridden by the argument overrides
652
- self.worker.boss.config.slurm_args = "--something --partition=baz --somethingElse"
660
+ self.worker.boss.config.slurm_args = (
661
+ "--something --partition=baz --somethingElse"
662
+ )
653
663
  command = self.worker.prepareSbatch(1, 100, 5, "job5", None, None)
654
664
  assert "--partition=baz" in command
655
665
 
@@ -669,14 +679,18 @@ class SlurmTest(ToilTest):
669
679
 
670
680
  # With a time override, we should use it, slightly translated, and it
671
681
  # should change the selected partition.
672
- self.worker.boss.config.slurm_args = "--something --time 10:00:00 --somethingElse"
682
+ self.worker.boss.config.slurm_args = (
683
+ "--something --time 10:00:00 --somethingElse"
684
+ )
673
685
  command = self.worker.prepareSbatch(1, 100, 5, "job5", None, None)
674
686
  logger.debug("Command: %s", command)
675
687
  assert "--partition=medium" in command
676
688
  assert "--time=0:36000" in command
677
689
 
678
690
  # All ways of setting time should work, including =
679
- self.worker.boss.config.slurm_args = "--something --time=10:00:00 --somethingElse"
691
+ self.worker.boss.config.slurm_args = (
692
+ "--something --time=10:00:00 --somethingElse"
693
+ )
680
694
  command = self.worker.prepareSbatch(1, 100, 5, "job5", None, None)
681
695
  logger.debug("Command: %s", command)
682
696
  assert "--partition=medium" in command
@@ -724,7 +738,9 @@ class SlurmTest(ToilTest):
724
738
  detector = toil.batchSystems.slurm.any_option_detector([])
725
739
  self.assertFalse(detector("--anything"))
726
740
 
727
- detector = toil.batchSystems.slurm.any_option_detector([("foobar", "f"), "many-bothans", ("bazz-only", "B")])
741
+ detector = toil.batchSystems.slurm.any_option_detector(
742
+ [("foobar", "f"), "many-bothans", ("bazz-only", "B")]
743
+ )
728
744
 
729
745
  self.assertTrue(detector("--foobar"))
730
746
  self.assertTrue(detector("-f"))
@@ -733,5 +749,3 @@ class SlurmTest(ToilTest):
733
749
  self.assertTrue(detector("-B"))
734
750
  self.assertFalse(detector("--no-bazz"))
735
751
  self.assertFalse(detector("--foo-bar=--bazz-only"))
736
-
737
-
toil/test/cwl/conftest.py CHANGED
@@ -17,9 +17,10 @@
17
17
  import json
18
18
  import logging
19
19
  from io import StringIO
20
- from typing import Any, Dict, List, Optional, Tuple
20
+ from typing import Any
21
21
 
22
22
  from cwltest import utils
23
+
23
24
  logger = logging.getLogger(__name__)
24
25
 
25
26
  collect_ignore = ["spec"]
@@ -30,15 +31,13 @@ collect_ignore = ["spec"]
30
31
  # See cwltool's reference implementation:
31
32
  # https://github.com/common-workflow-language/cwltool/blob/05af6c1357c327b3146e9f5da40e7c0aa3e6d976/tests/cwl-conformance/cwltool-conftest.py
32
33
  def pytest_cwl_execute_test(
33
- config: utils.CWLTestConfig,
34
- processfile: str,
35
- jobfile: Optional[str]
36
- ) -> Tuple[int, Optional[Dict[str, Any]]]:
34
+ config: utils.CWLTestConfig, processfile: str, jobfile: str | None
35
+ ) -> tuple[int, dict[str, Any] | None]:
37
36
  """Use Toil to execute CWL tests (equivalent to running toil-cwl-runner)."""
38
37
  from toil.cwl.cwltoil import main
39
38
 
40
39
  stdout = StringIO()
41
- argsl: List[str] = [f"--outdir={config.outdir}"]
40
+ argsl: list[str] = [f"--outdir={config.outdir}"]
42
41
  if config.runner_quiet:
43
42
  argsl.append("--quiet")
44
43
  elif config.verbose: