toil 6.1.0a1__py3-none-any.whl → 7.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.
Files changed (104) hide show
  1. toil/__init__.py +1 -232
  2. toil/batchSystems/abstractBatchSystem.py +41 -17
  3. toil/batchSystems/abstractGridEngineBatchSystem.py +79 -65
  4. toil/batchSystems/awsBatch.py +8 -8
  5. toil/batchSystems/cleanup_support.py +7 -3
  6. toil/batchSystems/contained_executor.py +4 -5
  7. toil/batchSystems/gridengine.py +1 -1
  8. toil/batchSystems/htcondor.py +5 -5
  9. toil/batchSystems/kubernetes.py +25 -11
  10. toil/batchSystems/local_support.py +3 -3
  11. toil/batchSystems/lsf.py +9 -9
  12. toil/batchSystems/mesos/batchSystem.py +4 -4
  13. toil/batchSystems/mesos/executor.py +3 -2
  14. toil/batchSystems/options.py +9 -0
  15. toil/batchSystems/singleMachine.py +11 -10
  16. toil/batchSystems/slurm.py +129 -16
  17. toil/batchSystems/torque.py +1 -1
  18. toil/bus.py +45 -3
  19. toil/common.py +56 -31
  20. toil/cwl/cwltoil.py +442 -371
  21. toil/deferred.py +1 -1
  22. toil/exceptions.py +1 -1
  23. toil/fileStores/abstractFileStore.py +69 -20
  24. toil/fileStores/cachingFileStore.py +6 -22
  25. toil/fileStores/nonCachingFileStore.py +6 -15
  26. toil/job.py +270 -86
  27. toil/jobStores/abstractJobStore.py +37 -31
  28. toil/jobStores/aws/jobStore.py +280 -218
  29. toil/jobStores/aws/utils.py +60 -31
  30. toil/jobStores/conftest.py +2 -2
  31. toil/jobStores/fileJobStore.py +3 -3
  32. toil/jobStores/googleJobStore.py +3 -4
  33. toil/leader.py +89 -38
  34. toil/lib/aws/__init__.py +26 -10
  35. toil/lib/aws/iam.py +2 -2
  36. toil/lib/aws/session.py +62 -22
  37. toil/lib/aws/utils.py +73 -37
  38. toil/lib/conversions.py +24 -1
  39. toil/lib/ec2.py +118 -69
  40. toil/lib/expando.py +1 -1
  41. toil/lib/generatedEC2Lists.py +8 -8
  42. toil/lib/io.py +42 -4
  43. toil/lib/misc.py +1 -3
  44. toil/lib/resources.py +57 -16
  45. toil/lib/retry.py +12 -5
  46. toil/lib/threading.py +29 -14
  47. toil/lib/throttle.py +1 -1
  48. toil/options/common.py +31 -30
  49. toil/options/wdl.py +5 -0
  50. toil/provisioners/__init__.py +9 -3
  51. toil/provisioners/abstractProvisioner.py +12 -2
  52. toil/provisioners/aws/__init__.py +20 -15
  53. toil/provisioners/aws/awsProvisioner.py +406 -329
  54. toil/provisioners/gceProvisioner.py +2 -2
  55. toil/provisioners/node.py +13 -5
  56. toil/server/app.py +1 -1
  57. toil/statsAndLogging.py +93 -23
  58. toil/test/__init__.py +27 -12
  59. toil/test/batchSystems/batchSystemTest.py +40 -33
  60. toil/test/batchSystems/batch_system_plugin_test.py +79 -0
  61. toil/test/batchSystems/test_slurm.py +22 -7
  62. toil/test/cactus/__init__.py +0 -0
  63. toil/test/cactus/test_cactus_integration.py +58 -0
  64. toil/test/cwl/cwlTest.py +245 -236
  65. toil/test/cwl/seqtk_seq.cwl +1 -1
  66. toil/test/docs/scriptsTest.py +11 -14
  67. toil/test/jobStores/jobStoreTest.py +40 -54
  68. toil/test/lib/aws/test_iam.py +2 -2
  69. toil/test/lib/test_ec2.py +1 -1
  70. toil/test/options/__init__.py +13 -0
  71. toil/test/options/options.py +37 -0
  72. toil/test/provisioners/aws/awsProvisionerTest.py +51 -34
  73. toil/test/provisioners/clusterTest.py +99 -16
  74. toil/test/server/serverTest.py +2 -2
  75. toil/test/src/autoDeploymentTest.py +1 -1
  76. toil/test/src/dockerCheckTest.py +2 -1
  77. toil/test/src/environmentTest.py +125 -0
  78. toil/test/src/fileStoreTest.py +1 -1
  79. toil/test/src/jobDescriptionTest.py +18 -8
  80. toil/test/src/jobTest.py +1 -1
  81. toil/test/src/realtimeLoggerTest.py +4 -0
  82. toil/test/src/workerTest.py +52 -19
  83. toil/test/utils/toilDebugTest.py +62 -4
  84. toil/test/utils/utilsTest.py +23 -21
  85. toil/test/wdl/wdltoil_test.py +49 -21
  86. toil/test/wdl/wdltoil_test_kubernetes.py +77 -0
  87. toil/toilState.py +68 -9
  88. toil/utils/toilDebugFile.py +1 -1
  89. toil/utils/toilDebugJob.py +153 -26
  90. toil/utils/toilLaunchCluster.py +12 -2
  91. toil/utils/toilRsyncCluster.py +7 -2
  92. toil/utils/toilSshCluster.py +7 -3
  93. toil/utils/toilStats.py +310 -266
  94. toil/utils/toilStatus.py +98 -52
  95. toil/version.py +11 -11
  96. toil/wdl/wdltoil.py +644 -225
  97. toil/worker.py +125 -83
  98. {toil-6.1.0a1.dist-info → toil-7.0.0.dist-info}/LICENSE +25 -0
  99. toil-7.0.0.dist-info/METADATA +158 -0
  100. {toil-6.1.0a1.dist-info → toil-7.0.0.dist-info}/RECORD +103 -96
  101. {toil-6.1.0a1.dist-info → toil-7.0.0.dist-info}/WHEEL +1 -1
  102. toil-6.1.0a1.dist-info/METADATA +0 -125
  103. {toil-6.1.0a1.dist-info → toil-7.0.0.dist-info}/entry_points.txt +0 -0
  104. {toil-6.1.0a1.dist-info → toil-7.0.0.dist-info}/top_level.txt +0 -0
toil/test/cwl/cwlTest.py CHANGED
@@ -23,13 +23,22 @@ import sys
23
23
  import unittest
24
24
  import uuid
25
25
  import zipfile
26
+
26
27
  from functools import partial
27
28
  from io import StringIO
28
29
  from pathlib import Path
29
- from typing import Dict, List, MutableMapping, Optional
30
+ from typing import (TYPE_CHECKING,
31
+ Callable,
32
+ Dict,
33
+ List,
34
+ Optional,
35
+ cast)
30
36
  from unittest.mock import Mock, call
31
37
  from urllib.request import urlretrieve
32
38
 
39
+ if TYPE_CHECKING:
40
+ from cwltool.utils import CWLObjectType
41
+
33
42
  import pytest
34
43
 
35
44
  pkg_root = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) # noqa
@@ -37,10 +46,10 @@ sys.path.insert(0, pkg_root) # noqa
37
46
 
38
47
  from schema_salad.exceptions import ValidationException
39
48
 
40
- from toil.cwl.utils import (download_structure,
49
+ from toil.cwl.utils import (DirectoryStructure,
50
+ download_structure,
41
51
  visit_cwl_class_and_reduce,
42
52
  visit_top_cwl_class)
43
- from toil.exceptions import FailedJobsException
44
53
  from toil.fileStores import FileID
45
54
  from toil.fileStores.abstractFileStore import AbstractFileStore
46
55
  from toil.lib.threading import cpu_count
@@ -63,7 +72,6 @@ from toil.test import (ToilTest,
63
72
  needs_torque,
64
73
  needs_wes_server,
65
74
  slow)
66
- from toil.test.provisioners.clusterTest import AbstractClusterTest
67
75
 
68
76
  log = logging.getLogger(__name__)
69
77
  CONFORMANCE_TEST_TIMEOUT = 10000
@@ -74,14 +82,14 @@ def run_conformance_tests(
74
82
  yml: str,
75
83
  runner: Optional[str] = None,
76
84
  caching: bool = False,
77
- batchSystem: str = None,
78
- selected_tests: str = None,
79
- selected_tags: str = None,
80
- skipped_tests: str = None,
85
+ batchSystem: Optional[str] = None,
86
+ selected_tests: Optional[str] = None,
87
+ selected_tags: Optional[str] = None,
88
+ skipped_tests: Optional[str] = None,
81
89
  extra_args: Optional[List[str]] = None,
82
90
  must_support_all_features: bool = False,
83
91
  junit_file: Optional[str] = None,
84
- ):
92
+ ) -> None:
85
93
  """
86
94
  Run the CWL conformance tests.
87
95
 
@@ -199,6 +207,8 @@ def run_conformance_tests(
199
207
  raise e
200
208
 
201
209
 
210
+ TesterFuncType = Callable[[str, str, "CWLObjectType"], None]
211
+
202
212
  @needs_cwl
203
213
  class CWLWorkflowTest(ToilTest):
204
214
  """
@@ -207,19 +217,19 @@ class CWLWorkflowTest(ToilTest):
207
217
  inputs.
208
218
  """
209
219
 
210
- def setUp(self):
220
+ def setUp(self) -> None:
211
221
  """Runs anew before each test to create farm fresh temp dirs."""
212
222
  self.outDir = f"/tmp/toil-cwl-test-{str(uuid.uuid4())}"
213
223
  os.makedirs(self.outDir)
214
224
  self.rootDir = self._projectRootPath()
215
225
 
216
- def tearDown(self):
226
+ def tearDown(self) -> None:
217
227
  """Clean up outputs."""
218
228
  if os.path.exists(self.outDir):
219
229
  shutil.rmtree(self.outDir)
220
230
  unittest.TestCase.tearDown(self)
221
231
 
222
- def test_cwl_cmdline_input(self):
232
+ def test_cwl_cmdline_input(self) -> None:
223
233
  """
224
234
  Test that running a CWL workflow with inputs specified on the command line passes.
225
235
  """
@@ -230,7 +240,15 @@ class CWLWorkflowTest(ToilTest):
230
240
  # If the workflow runs, it must have had options
231
241
  cwltoil.main(args, stdout=st)
232
242
 
233
- def _tester(self, cwlfile, jobfile, expect, main_args=[], out_name="output", output_here=False):
243
+ def _tester(
244
+ self,
245
+ cwlfile: str,
246
+ jobfile: str,
247
+ expect: "CWLObjectType",
248
+ main_args: List[str] = [],
249
+ out_name: str = "output",
250
+ output_here: bool = False,
251
+ ) -> None:
234
252
  from toil.cwl import cwltoil
235
253
 
236
254
  st = StringIO()
@@ -264,7 +282,9 @@ class CWLWorkflowTest(ToilTest):
264
282
  self.assertTrue(os.path.exists(v["path"]))
265
283
  self.assertFalse(os.stat(v["path"]).st_mode & stat.S_IXUSR)
266
284
 
267
- def _debug_worker_tester(self, cwlfile, jobfile, expect):
285
+ def _debug_worker_tester(
286
+ self, cwlfile: str, jobfile: str, expect: "CWLObjectType"
287
+ ) -> None:
268
288
  from toil.cwl import cwltoil
269
289
 
270
290
  st = StringIO()
@@ -284,21 +304,21 @@ class CWLWorkflowTest(ToilTest):
284
304
  out["output"].pop("nameroot", None)
285
305
  self.assertEqual(out, expect)
286
306
 
287
- def revsort(self, cwl_filename, tester_fn):
307
+ def revsort(self, cwl_filename: str, tester_fn: TesterFuncType) -> None:
288
308
  tester_fn(
289
309
  "src/toil/test/cwl/" + cwl_filename,
290
310
  "src/toil/test/cwl/revsort-job.json",
291
311
  self._expected_revsort_output(self.outDir),
292
312
  )
293
313
 
294
- def revsort_no_checksum(self, cwl_filename, tester_fn):
314
+ def revsort_no_checksum(self, cwl_filename: str, tester_fn: TesterFuncType) -> None:
295
315
  tester_fn(
296
316
  "src/toil/test/cwl/" + cwl_filename,
297
317
  "src/toil/test/cwl/revsort-job.json",
298
318
  self._expected_revsort_nochecksum_output(self.outDir),
299
319
  )
300
320
 
301
- def download(self, inputs, tester_fn):
321
+ def download(self, inputs: str, tester_fn: TesterFuncType) -> None:
302
322
  input_location = os.path.join("src/toil/test/cwl", inputs)
303
323
  tester_fn(
304
324
  "src/toil/test/cwl/download.cwl",
@@ -306,7 +326,7 @@ class CWLWorkflowTest(ToilTest):
306
326
  self._expected_download_output(self.outDir),
307
327
  )
308
328
 
309
- def load_contents(self, inputs, tester_fn):
329
+ def load_contents(self, inputs: str, tester_fn: TesterFuncType) -> None:
310
330
  input_location = os.path.join("src/toil/test/cwl", inputs)
311
331
  tester_fn(
312
332
  "src/toil/test/cwl/load_contents.cwl",
@@ -314,7 +334,7 @@ class CWLWorkflowTest(ToilTest):
314
334
  self._expected_load_contents_output(self.outDir),
315
335
  )
316
336
 
317
- def download_directory(self, inputs, tester_fn):
337
+ def download_directory(self, inputs: str, tester_fn: TesterFuncType) -> None:
318
338
  input_location = os.path.join("src/toil/test/cwl", inputs)
319
339
  tester_fn(
320
340
  "src/toil/test/cwl/download_directory.cwl",
@@ -322,7 +342,7 @@ class CWLWorkflowTest(ToilTest):
322
342
  self._expected_download_output(self.outDir),
323
343
  )
324
344
 
325
- def download_subdirectory(self, inputs, tester_fn):
345
+ def download_subdirectory(self, inputs: str, tester_fn: TesterFuncType) -> None:
326
346
  input_location = os.path.join("src/toil/test/cwl", inputs)
327
347
  tester_fn(
328
348
  "src/toil/test/cwl/download_subdirectory.cwl",
@@ -330,7 +350,7 @@ class CWLWorkflowTest(ToilTest):
330
350
  self._expected_download_output(self.outDir),
331
351
  )
332
352
 
333
- def test_mpi(self):
353
+ def test_mpi(self) -> None:
334
354
  from toil.cwl import cwltoil
335
355
 
336
356
  stdout = StringIO()
@@ -355,7 +375,7 @@ class CWLWorkflowTest(ToilTest):
355
375
  self.assertTrue(isinstance(two_pids[1], int))
356
376
 
357
377
  @needs_aws_s3
358
- def test_s3_as_secondary_file(self):
378
+ def test_s3_as_secondary_file(self) -> None:
359
379
  from toil.cwl import cwltoil
360
380
 
361
381
  stdout = StringIO()
@@ -374,21 +394,21 @@ class CWLWorkflowTest(ToilTest):
374
394
  with open(out["output"]["location"][len("file://") :]) as f:
375
395
  self.assertEqual(f.read().strip(), "When is s4 coming out?")
376
396
 
377
- def test_run_revsort(self):
397
+ def test_run_revsort(self) -> None:
378
398
  self.revsort("revsort.cwl", self._tester)
379
399
 
380
- def test_run_revsort_nochecksum(self):
400
+ def test_run_revsort_nochecksum(self) -> None:
381
401
  self.revsort_no_checksum(
382
402
  "revsort.cwl", partial(self._tester, main_args=["--no-compute-checksum"])
383
403
  )
384
404
 
385
- def test_run_revsort2(self):
405
+ def test_run_revsort2(self) -> None:
386
406
  self.revsort("revsort2.cwl", self._tester)
387
407
 
388
- def test_run_revsort_debug_worker(self):
408
+ def test_run_revsort_debug_worker(self) -> None:
389
409
  self.revsort("revsort.cwl", self._debug_worker_tester)
390
410
 
391
- def test_run_colon_output(self):
411
+ def test_run_colon_output(self) -> None:
392
412
  self._tester(
393
413
  "src/toil/test/cwl/colon_test_output.cwl",
394
414
  "src/toil/test/cwl/colon_test_output_job.yaml",
@@ -396,7 +416,7 @@ class CWLWorkflowTest(ToilTest):
396
416
  out_name="result",
397
417
  )
398
418
 
399
- def test_glob_dir_bypass_file_store(self):
419
+ def test_glob_dir_bypass_file_store(self) -> None:
400
420
  self.maxDiff = 1000
401
421
  try:
402
422
  # We need to output to the current directory to make sure that
@@ -416,58 +436,58 @@ class CWLWorkflowTest(ToilTest):
416
436
  pass
417
437
 
418
438
  @needs_aws_s3
419
- def test_download_s3(self):
439
+ def test_download_s3(self) -> None:
420
440
  self.download("download_s3.json", self._tester)
421
441
 
422
- def test_download_http(self):
442
+ def test_download_http(self) -> None:
423
443
  self.download("download_http.json", self._tester)
424
444
 
425
- def test_download_https(self):
445
+ def test_download_https(self) -> None:
426
446
  self.download("download_https.json", self._tester)
427
447
 
428
- def test_download_https_reference(self):
448
+ def test_download_https_reference(self) -> None:
429
449
  self.download("download_https.json", partial(self._tester, main_args=["--reference-inputs"]))
430
450
 
431
- def test_download_file(self):
451
+ def test_download_file(self) -> None:
432
452
  self.download("download_file.json", self._tester)
433
453
 
434
454
  @needs_aws_s3
435
- def test_download_directory_s3(self):
455
+ def test_download_directory_s3(self) -> None:
436
456
  self.download_directory("download_directory_s3.json", self._tester)
437
457
 
438
458
  @needs_aws_s3
439
- def test_download_directory_s3_reference(self):
459
+ def test_download_directory_s3_reference(self) -> None:
440
460
  self.download_directory("download_directory_s3.json", partial(self._tester, main_args=["--reference-inputs"]))
441
461
 
442
- def test_download_directory_file(self):
462
+ def test_download_directory_file(self) -> None:
443
463
  self.download_directory("download_directory_file.json", self._tester)
444
464
 
445
465
  @needs_aws_s3
446
- def test_download_subdirectory_s3(self):
466
+ def test_download_subdirectory_s3(self) -> None:
447
467
  self.download_subdirectory("download_subdirectory_s3.json", self._tester)
448
468
 
449
- def test_download_subdirectory_file(self):
469
+ def test_download_subdirectory_file(self) -> None:
450
470
  self.download_subdirectory("download_subdirectory_file.json", self._tester)
451
471
 
452
472
  # We also want to make sure we can run a bare tool with loadContents on the inputs, which requires accessing the input data early in the leader.
453
473
 
454
474
  @needs_aws_s3
455
- def test_load_contents_s3(self):
475
+ def test_load_contents_s3(self) -> None:
456
476
  self.load_contents("download_s3.json", self._tester)
457
477
 
458
- def test_load_contents_http(self):
478
+ def test_load_contents_http(self) -> None:
459
479
  self.load_contents("download_http.json", self._tester)
460
480
 
461
- def test_load_contents_https(self):
481
+ def test_load_contents_https(self) -> None:
462
482
  self.load_contents("download_https.json", self._tester)
463
483
 
464
- def test_load_contents_file(self):
484
+ def test_load_contents_file(self) -> None:
465
485
  self.load_contents("download_file.json", self._tester)
466
486
 
467
487
  @slow
468
488
  @pytest.mark.integrative
469
- @unittest.skip
470
- def test_bioconda(self):
489
+ @unittest.skip("Fails too often due to remote service")
490
+ def test_bioconda(self) -> None:
471
491
  self._tester(
472
492
  "src/toil/test/cwl/seqtk_seq.cwl",
473
493
  "src/toil/test/cwl/seqtk_seq_job.json",
@@ -476,10 +496,20 @@ class CWLWorkflowTest(ToilTest):
476
496
  out_name="output1",
477
497
  )
478
498
 
499
+ @needs_docker
500
+ def test_default_args(self) -> None:
501
+ self._tester(
502
+ "src/toil/test/cwl/seqtk_seq.cwl",
503
+ "src/toil/test/cwl/seqtk_seq_job.json",
504
+ self._expected_seqtk_output(self.outDir),
505
+ main_args=["--default-container", "quay.io/biocontainers/seqtk:1.4--he4a0461_1"],
506
+ out_name="output1",
507
+ )
508
+
479
509
  @needs_docker
480
510
  @pytest.mark.integrative
481
- @unittest.skip
482
- def test_biocontainers(self):
511
+ @unittest.skip("Fails too often due to remote service")
512
+ def test_biocontainers(self) -> None:
483
513
  self._tester(
484
514
  "src/toil/test/cwl/seqtk_seq.cwl",
485
515
  "src/toil/test/cwl/seqtk_seq_job.json",
@@ -491,7 +521,7 @@ class CWLWorkflowTest(ToilTest):
491
521
  @needs_docker
492
522
  @needs_docker_cuda
493
523
  @needs_local_cuda
494
- def test_cuda(self):
524
+ def test_cuda(self) -> None:
495
525
  self._tester(
496
526
  "src/toil/test/cwl/nvidia_smi.cwl",
497
527
  "src/toil/test/cwl/empty.json",
@@ -500,14 +530,13 @@ class CWLWorkflowTest(ToilTest):
500
530
  )
501
531
 
502
532
  @slow
503
- def test_restart(self):
533
+ def test_restart(self) -> None:
504
534
  """
505
535
  Enable restarts with toil-cwl-runner -- run failing test, re-run correct test.
506
536
  Only implemented for single machine.
507
537
  """
508
538
  log.info("Running CWL Test Restart. Expecting failure, then success.")
509
539
  from toil.cwl import cwltoil
510
- from toil.jobStores.abstractJobStore import NoSuchJobStoreException
511
540
 
512
541
  outDir = self._createTempDir()
513
542
  cwlDir = os.path.join(self._projectRootPath(), "src", "toil", "test", "cwl")
@@ -529,7 +558,7 @@ class CWLWorkflowTest(ToilTest):
529
558
  ][-1]
530
559
  os.symlink(os.path.join(cal_path, "date"), f'{os.path.join(outDir, "rev")}')
531
560
 
532
- def path_with_bogus_rev():
561
+ def path_with_bogus_rev() -> str:
533
562
  # append to the front of the PATH so that we check there first
534
563
  return f"{outDir}:" + os.environ["PATH"]
535
564
 
@@ -537,22 +566,23 @@ class CWLWorkflowTest(ToilTest):
537
566
  # Force a failure by trying to use an incorrect version of `rev` from the PATH
538
567
  os.environ["PATH"] = path_with_bogus_rev()
539
568
  try:
540
- cwltoil.main(cmd)
569
+ subprocess.check_output(["toil-cwl-runner"] + cmd, env=os.environ.copy(), stderr=subprocess.STDOUT)
541
570
  self.fail("Expected problem job with incorrect PATH did not fail")
542
- except FailedJobsException:
571
+ except subprocess.CalledProcessError:
543
572
  pass
544
573
  # Finish the job with a correct PATH
545
574
  os.environ["PATH"] = orig_path
546
- cwltoil.main(["--restart"] + cmd)
575
+ cmd.insert(0, "--restart")
576
+ cwltoil.main(cmd)
547
577
  # Should fail because previous job completed successfully
548
578
  try:
549
- cwltoil.main(["--restart"] + cmd)
579
+ subprocess.check_output(["toil-cwl-runner"] + cmd, env=os.environ.copy(), stderr=subprocess.STDOUT)
550
580
  self.fail("Restart with missing directory did not fail")
551
- except NoSuchJobStoreException:
581
+ except subprocess.CalledProcessError:
552
582
  pass
553
583
 
554
584
  @needs_aws_s3
555
- def test_streamable(self, extra_args: List[str] = None):
585
+ def test_streamable(self, extra_args: Optional[List[str]] = None) -> None:
556
586
  """
557
587
  Test that a file with 'streamable'=True is a named pipe.
558
588
  This is a CWL1.2 feature.
@@ -585,13 +615,13 @@ class CWLWorkflowTest(ToilTest):
585
615
  self.assertEqual(f.read().strip(), "When is s4 coming out?")
586
616
 
587
617
  @needs_aws_s3
588
- def test_streamable_reference(self):
618
+ def test_streamable_reference(self) -> None:
589
619
  """
590
620
  Test that a streamable file is a stream even when passed around by URI.
591
621
  """
592
622
  self.test_streamable(extra_args=["--reference-inputs"])
593
623
 
594
- def test_preemptible(self):
624
+ def test_preemptible(self) -> None:
595
625
  """
596
626
  Tests that the http://arvados.org/cwl#UsePreemptible extension is supported.
597
627
  """
@@ -615,7 +645,7 @@ class CWLWorkflowTest(ToilTest):
615
645
  with open(out[out_name]["location"][len("file://") :]) as f:
616
646
  self.assertEqual(f.read().strip(), "hello")
617
647
 
618
- def test_preemptible_expression(self):
648
+ def test_preemptible_expression(self) -> None:
619
649
  """
620
650
  Tests that the http://arvados.org/cwl#UsePreemptible extension is validated.
621
651
  """
@@ -639,7 +669,7 @@ class CWLWorkflowTest(ToilTest):
639
669
 
640
670
 
641
671
  @staticmethod
642
- def _expected_seqtk_output(outDir):
672
+ def _expected_seqtk_output(outDir: str) -> "CWLObjectType":
643
673
  path = os.path.join(outDir, "out")
644
674
  loc = "file://" + path
645
675
  return {
@@ -654,7 +684,7 @@ class CWLWorkflowTest(ToilTest):
654
684
  }
655
685
 
656
686
  @staticmethod
657
- def _expected_revsort_output(outDir):
687
+ def _expected_revsort_output(outDir: str) -> "CWLObjectType":
658
688
  path = os.path.join(outDir, "output.txt")
659
689
  loc = "file://" + path
660
690
  return {
@@ -669,7 +699,7 @@ class CWLWorkflowTest(ToilTest):
669
699
  }
670
700
 
671
701
  @staticmethod
672
- def _expected_revsort_nochecksum_output(outDir):
702
+ def _expected_revsort_nochecksum_output(outDir: str) -> "CWLObjectType":
673
703
  path = os.path.join(outDir, "output.txt")
674
704
  loc = "file://" + path
675
705
  return {
@@ -683,7 +713,7 @@ class CWLWorkflowTest(ToilTest):
683
713
  }
684
714
 
685
715
  @staticmethod
686
- def _expected_download_output(outDir):
716
+ def _expected_download_output(outDir: str) -> "CWLObjectType":
687
717
  path = os.path.join(outDir, "output.txt")
688
718
  loc = "file://" + path
689
719
  return {
@@ -698,7 +728,7 @@ class CWLWorkflowTest(ToilTest):
698
728
  }
699
729
 
700
730
  @staticmethod
701
- def _expected_glob_dir_output(out_dir):
731
+ def _expected_glob_dir_output(out_dir: str) -> "CWLObjectType":
702
732
  dir_path = os.path.join(out_dir, "shouldmake")
703
733
  dir_loc = "file://" + dir_path
704
734
  file_path = os.path.join(dir_path, "test.txt")
@@ -727,7 +757,7 @@ class CWLWorkflowTest(ToilTest):
727
757
  }
728
758
 
729
759
  @classmethod
730
- def _expected_load_contents_output(cls, out_dir):
760
+ def _expected_load_contents_output(cls, out_dir: str) -> "CWLObjectType":
731
761
  """
732
762
  Generate the putput we expect from load_contents.cwl, when sending
733
763
  output files to the given directory.
@@ -737,7 +767,7 @@ class CWLWorkflowTest(ToilTest):
737
767
  return expected
738
768
 
739
769
  @staticmethod
740
- def _expected_colon_output(outDir):
770
+ def _expected_colon_output(outDir: str) -> "CWLObjectType":
741
771
  path = os.path.join(outDir, "A:Gln2Cys_result")
742
772
  loc = "file://" + os.path.join(outDir, "A%3AGln2Cys_result")
743
773
  return {
@@ -761,7 +791,7 @@ class CWLWorkflowTest(ToilTest):
761
791
  }
762
792
  }
763
793
 
764
- def _expected_streaming_output(self, outDir):
794
+ def _expected_streaming_output(self, outDir: str) -> "CWLObjectType":
765
795
  path = os.path.join(outDir, "output.txt")
766
796
  loc = "file://" + path
767
797
  return {
@@ -783,7 +813,7 @@ class CWLv10Test(ToilTest):
783
813
  Run the CWL 1.0 conformance tests in various environments.
784
814
  """
785
815
 
786
- def setUp(self):
816
+ def setUp(self) -> None:
787
817
  """Runs anew before each test to create farm fresh temp dirs."""
788
818
  self.outDir = f"/tmp/toil-cwl-test-{str(uuid.uuid4())}"
789
819
  os.makedirs(self.outDir)
@@ -804,7 +834,7 @@ class CWLv10Test(ToilTest):
804
834
  shutil.move("common-workflow-language-%s" % testhash, self.cwlSpec)
805
835
  os.remove("spec.zip")
806
836
 
807
- def tearDown(self):
837
+ def tearDown(self) -> None:
808
838
  """Clean up outputs."""
809
839
  if os.path.exists(self.outDir):
810
840
  shutil.rmtree(self.outDir)
@@ -812,99 +842,106 @@ class CWLv10Test(ToilTest):
812
842
 
813
843
  @slow
814
844
  @pytest.mark.timeout(CONFORMANCE_TEST_TIMEOUT)
815
- def test_run_conformance_with_caching(self):
845
+ def test_run_conformance_with_caching(self) -> None:
816
846
  self.test_run_conformance(caching=True)
817
847
 
818
848
  @slow
819
849
  @pytest.mark.timeout(CONFORMANCE_TEST_TIMEOUT)
820
850
  def test_run_conformance(
821
- self, batchSystem=None, caching=False, selected_tests=None
822
- ):
851
+ self,
852
+ batchSystem: Optional[str] = None,
853
+ caching: bool = False,
854
+ selected_tests: Optional[str] = None,
855
+ skipped_tests: Optional[str] = None,
856
+ extra_args: Optional[List[str]] = None,
857
+ ) -> None:
823
858
  run_conformance_tests(
824
859
  workDir=self.workDir,
825
860
  yml="conformance_test_v1.0.yaml",
826
861
  caching=caching,
827
862
  batchSystem=batchSystem,
828
863
  selected_tests=selected_tests,
864
+ skipped_tests=skipped_tests,
865
+ extra_args=extra_args,
829
866
  )
830
867
 
831
868
  @slow
832
869
  @needs_lsf
833
- @unittest.skip
834
- def test_lsf_cwl_conformance(self, **kwargs):
835
- return self.test_run_conformance(batchSystem="lsf", **kwargs)
870
+ @unittest.skip("Not run")
871
+ def test_lsf_cwl_conformance(self, caching: bool = False) -> None:
872
+ self.test_run_conformance(batchSystem="lsf", caching=caching)
836
873
 
837
874
  @slow
838
875
  @needs_slurm
839
- @unittest.skip
840
- def test_slurm_cwl_conformance(self, **kwargs):
841
- return self.test_run_conformance(batchSystem="slurm", **kwargs)
876
+ @unittest.skip("Not run")
877
+ def test_slurm_cwl_conformance(self, caching: bool = False) -> None:
878
+ self.test_run_conformance(batchSystem="slurm", caching=caching)
842
879
 
843
880
  @slow
844
881
  @needs_torque
845
- @unittest.skip
846
- def test_torque_cwl_conformance(self, **kwargs):
847
- return self.test_run_conformance(batchSystem="torque", **kwargs)
882
+ @unittest.skip("Not run")
883
+ def test_torque_cwl_conformance(self, caching: bool = False) -> None:
884
+ self.test_run_conformance(batchSystem="torque", caching=caching)
848
885
 
849
886
  @slow
850
887
  @needs_gridengine
851
- @unittest.skip
852
- def test_gridengine_cwl_conformance(self, **kwargs):
853
- return self.test_run_conformance(batchSystem="grid_engine", **kwargs)
888
+ @unittest.skip("Not run")
889
+ def test_gridengine_cwl_conformance(self, caching: bool = False) -> None:
890
+ self.test_run_conformance(batchSystem="grid_engine", caching=caching)
854
891
 
855
892
  @slow
856
893
  @needs_mesos
857
- @unittest.skip
858
- def test_mesos_cwl_conformance(self, **kwargs):
859
- return self.test_run_conformance(batchSystem="mesos", **kwargs)
894
+ @unittest.skip("Not run")
895
+ def test_mesos_cwl_conformance(self, caching: bool = False) -> None:
896
+ self.test_run_conformance(batchSystem="mesos", caching=caching)
860
897
 
861
898
  @slow
862
899
  @needs_kubernetes
863
- def test_kubernetes_cwl_conformance(self, **kwargs):
864
- return self.test_run_conformance(
900
+ def test_kubernetes_cwl_conformance(self, caching: bool = False) -> None:
901
+ self.test_run_conformance(
902
+ caching=caching,
865
903
  batchSystem="kubernetes",
866
904
  extra_args=["--retryCount=3"],
867
905
  # This test doesn't work with
868
906
  # Singularity; see
869
907
  # https://github.com/common-workflow-language/cwltool/blob/7094ede917c2d5b16d11f9231fe0c05260b51be6/conformance-test.sh#L99-L117
870
908
  skipped_tests="docker_entrypoint",
871
- **kwargs,
872
909
  )
873
910
 
874
911
  @slow
875
912
  @needs_lsf
876
- @unittest.skip
877
- def test_lsf_cwl_conformance_with_caching(self):
878
- return self.test_lsf_cwl_conformance(caching=True)
913
+ @unittest.skip("Not run")
914
+ def test_lsf_cwl_conformance_with_caching(self) -> None:
915
+ self.test_lsf_cwl_conformance(caching=True)
879
916
 
880
917
  @slow
881
918
  @needs_slurm
882
- @unittest.skip
883
- def test_slurm_cwl_conformance_with_caching(self):
884
- return self.test_slurm_cwl_conformance(caching=True)
919
+ @unittest.skip("Not run")
920
+ def test_slurm_cwl_conformance_with_caching(self) -> None:
921
+ self.test_slurm_cwl_conformance(caching=True)
885
922
 
886
923
  @slow
887
924
  @needs_torque
888
- @unittest.skip
889
- def test_torque_cwl_conformance_with_caching(self):
890
- return self.test_torque_cwl_conformance(caching=True)
925
+ @unittest.skip("Not run")
926
+ def test_torque_cwl_conformance_with_caching(self) -> None:
927
+ self.test_torque_cwl_conformance(caching=True)
891
928
 
892
929
  @slow
893
930
  @needs_gridengine
894
- @unittest.skip
895
- def test_gridengine_cwl_conformance_with_caching(self):
896
- return self.test_gridengine_cwl_conformance(caching=True)
931
+ @unittest.skip("Not run")
932
+ def test_gridengine_cwl_conformance_with_caching(self) -> None:
933
+ self.test_gridengine_cwl_conformance(caching=True)
897
934
 
898
935
  @slow
899
936
  @needs_mesos
900
- @unittest.skip
901
- def test_mesos_cwl_conformance_with_caching(self):
902
- return self.test_mesos_cwl_conformance(caching=True)
937
+ @unittest.skip("Not run")
938
+ def test_mesos_cwl_conformance_with_caching(self) -> None:
939
+ self.test_mesos_cwl_conformance(caching=True)
903
940
 
904
941
  @slow
905
942
  @needs_kubernetes
906
- def test_kubernetes_cwl_conformance_with_caching(self):
907
- return self.test_kubernetes_cwl_conformance(caching=True)
943
+ def test_kubernetes_cwl_conformance_with_caching(self) -> None:
944
+ self.test_kubernetes_cwl_conformance(caching=True)
908
945
 
909
946
 
910
947
  @needs_cwl
@@ -914,8 +951,12 @@ class CWLv11Test(ToilTest):
914
951
  Run the CWL 1.1 conformance tests in various environments.
915
952
  """
916
953
 
954
+ rootDir: str
955
+ cwlSpec: str
956
+ test_yaml: str
957
+
917
958
  @classmethod
918
- def setUpClass(cls):
959
+ def setUpClass(cls) -> None:
919
960
  """Runs anew before each test."""
920
961
  cls.rootDir = cls._projectRootPath()
921
962
  cls.cwlSpec = os.path.join(cls.rootDir, "src/toil/test/cwl/spec_v11")
@@ -929,37 +970,50 @@ class CWLv11Test(ToilTest):
929
970
  )
930
971
  p.communicate()
931
972
 
932
- def tearDown(self):
973
+ def tearDown(self) -> None:
933
974
  """Clean up outputs."""
934
975
  unittest.TestCase.tearDown(self)
935
976
 
936
977
  @slow
937
978
  @pytest.mark.timeout(CONFORMANCE_TEST_TIMEOUT)
938
- def test_run_conformance(self, **kwargs):
939
- run_conformance_tests(workDir=self.cwlSpec, yml=self.test_yaml, **kwargs)
979
+ def test_run_conformance(
980
+ self,
981
+ caching: bool = False,
982
+ batchSystem: Optional[str] = None,
983
+ skipped_tests: Optional[str] = None,
984
+ extra_args: Optional[List[str]] = None,
985
+ ) -> None:
986
+ run_conformance_tests(
987
+ workDir=self.cwlSpec,
988
+ yml=self.test_yaml,
989
+ caching=caching,
990
+ batchSystem=batchSystem,
991
+ skipped_tests=skipped_tests,
992
+ extra_args=extra_args,
993
+ )
940
994
 
941
995
  @slow
942
996
  @pytest.mark.timeout(CONFORMANCE_TEST_TIMEOUT)
943
- def test_run_conformance_with_caching(self):
997
+ def test_run_conformance_with_caching(self) -> None:
944
998
  self.test_run_conformance(caching=True)
945
999
 
946
1000
  @slow
947
1001
  @needs_kubernetes
948
- def test_kubernetes_cwl_conformance(self, **kwargs):
949
- return self.test_run_conformance(
1002
+ def test_kubernetes_cwl_conformance(self, caching: bool = False) -> None:
1003
+ self.test_run_conformance(
950
1004
  batchSystem="kubernetes",
951
1005
  extra_args=["--retryCount=3"],
952
1006
  # These tests don't work with
953
1007
  # Singularity; see
954
1008
  # https://github.com/common-workflow-language/cwltool/blob/7094ede917c2d5b16d11f9231fe0c05260b51be6/conformance-test.sh#L99-L117
955
1009
  skipped_tests="docker_entrypoint,stdin_shorcut",
956
- **kwargs,
1010
+ caching=caching,
957
1011
  )
958
1012
 
959
1013
  @slow
960
1014
  @needs_kubernetes
961
- def test_kubernetes_cwl_conformance_with_caching(self):
962
- return self.test_kubernetes_cwl_conformance(caching=True)
1015
+ def test_kubernetes_cwl_conformance_with_caching(self) -> None:
1016
+ self.test_kubernetes_cwl_conformance(caching=True)
963
1017
 
964
1018
 
965
1019
  @needs_cwl
@@ -969,8 +1023,12 @@ class CWLv12Test(ToilTest):
969
1023
  Run the CWL 1.2 conformance tests in various environments.
970
1024
  """
971
1025
 
1026
+ rootDir: str
1027
+ cwlSpec: str
1028
+ test_yaml: str
1029
+
972
1030
  @classmethod
973
- def setUpClass(cls):
1031
+ def setUpClass(cls) -> None:
974
1032
  """Runs anew before each test."""
975
1033
  cls.rootDir = cls._projectRootPath()
976
1034
  cls.cwlSpec = os.path.join(cls.rootDir, "src/toil/test/cwl/spec_v12")
@@ -984,22 +1042,41 @@ class CWLv12Test(ToilTest):
984
1042
  )
985
1043
  p.communicate()
986
1044
 
987
- def tearDown(self):
1045
+ def tearDown(self) -> None:
988
1046
  """Clean up outputs."""
989
1047
  unittest.TestCase.tearDown(self)
990
1048
 
991
1049
  @slow
992
1050
  @pytest.mark.timeout(CONFORMANCE_TEST_TIMEOUT)
993
- def test_run_conformance(self, **kwargs):
994
- if "junit_file" not in kwargs:
995
- kwargs["junit_file"] = os.path.join(
996
- self.rootDir, "conformance-1.2.junit.xml"
997
- )
998
- run_conformance_tests(workDir=self.cwlSpec, yml=self.test_yaml, **kwargs)
1051
+ def test_run_conformance(
1052
+ self,
1053
+ runner: Optional[str] = None,
1054
+ caching: bool = False,
1055
+ batchSystem: Optional[str] = None,
1056
+ selected_tests: Optional[str] = None,
1057
+ skipped_tests: Optional[str] = None,
1058
+ extra_args: Optional[List[str]] = None,
1059
+ must_support_all_features: bool = False,
1060
+ junit_file: Optional[str] = None,
1061
+ ) -> None:
1062
+ if junit_file is None:
1063
+ junit_file = os.path.join(self.rootDir, "conformance-1.2.junit.xml")
1064
+ run_conformance_tests(
1065
+ workDir=self.cwlSpec,
1066
+ yml=self.test_yaml,
1067
+ runner=runner,
1068
+ caching=caching,
1069
+ batchSystem=batchSystem,
1070
+ selected_tests=selected_tests,
1071
+ skipped_tests=skipped_tests,
1072
+ extra_args=extra_args,
1073
+ must_support_all_features=must_support_all_features,
1074
+ junit_file=junit_file,
1075
+ )
999
1076
 
1000
1077
  @slow
1001
1078
  @pytest.mark.timeout(CONFORMANCE_TEST_TIMEOUT)
1002
- def test_run_conformance_with_caching(self):
1079
+ def test_run_conformance_with_caching(self) -> None:
1003
1080
  self.test_run_conformance(
1004
1081
  caching=True,
1005
1082
  junit_file = os.path.join(
@@ -1009,7 +1086,7 @@ class CWLv12Test(ToilTest):
1009
1086
 
1010
1087
  @slow
1011
1088
  @pytest.mark.timeout(CONFORMANCE_TEST_TIMEOUT)
1012
- def test_run_conformance_with_in_place_update(self):
1089
+ def test_run_conformance_with_in_place_update(self) -> None:
1013
1090
  """
1014
1091
  Make sure that with --bypass-file-store we properly support in place
1015
1092
  update on a single node, and that this doesn't break any other
@@ -1024,12 +1101,15 @@ class CWLv12Test(ToilTest):
1024
1101
 
1025
1102
  @slow
1026
1103
  @needs_kubernetes
1027
- def test_kubernetes_cwl_conformance(self, **kwargs):
1028
- if "junit_file" not in kwargs:
1029
- kwargs["junit_file"] = os.path.join(
1104
+ def test_kubernetes_cwl_conformance(
1105
+ self, caching: bool = False, junit_file: Optional[str] = None
1106
+ ) -> None:
1107
+ if junit_file is None:
1108
+ junit_file = os.path.join(
1030
1109
  self.rootDir, "kubernetes-conformance-1.2.junit.xml"
1031
1110
  )
1032
- return self.test_run_conformance(
1111
+ self.test_run_conformance(
1112
+ caching=caching,
1033
1113
  batchSystem="kubernetes",
1034
1114
  extra_args=["--retryCount=3"],
1035
1115
  # This test doesn't work with
@@ -1038,13 +1118,13 @@ class CWLv12Test(ToilTest):
1038
1118
  # and
1039
1119
  # https://github.com/common-workflow-language/cwltool/issues/1441#issuecomment-826747975
1040
1120
  skipped_tests="docker_entrypoint",
1041
- **kwargs,
1121
+ junit_file=junit_file,
1042
1122
  )
1043
1123
 
1044
1124
  @slow
1045
1125
  @needs_kubernetes
1046
- def test_kubernetes_cwl_conformance_with_caching(self):
1047
- return self.test_kubernetes_cwl_conformance(
1126
+ def test_kubernetes_cwl_conformance_with_caching(self) -> None:
1127
+ self.test_kubernetes_cwl_conformance(
1048
1128
  caching=True,
1049
1129
  junit_file=os.path.join(
1050
1130
  self.rootDir, "kubernetes-caching-conformance-1.2.junit.xml"
@@ -1053,7 +1133,7 @@ class CWLv12Test(ToilTest):
1053
1133
 
1054
1134
  @slow
1055
1135
  @needs_wes_server
1056
- def test_wes_server_cwl_conformance(self):
1136
+ def test_wes_server_cwl_conformance(self) -> None:
1057
1137
  """
1058
1138
  Run the CWL conformance tests via WES. TOIL_WES_ENDPOINT must be
1059
1139
  specified. If the WES server requires authentication, set TOIL_WES_USER
@@ -1078,96 +1158,16 @@ class CWLv12Test(ToilTest):
1078
1158
  # 1. `cwltool --print-deps` doesn't seem to include secondary files from the default
1079
1159
  # e.g.: https://github.com/common-workflow-language/cwl-v1.2/blob/1.2.1_proposed/tests/mixed-versions/wf-v10.cwl#L4-L10
1080
1160
 
1081
- return self.test_run_conformance(
1161
+ self.test_run_conformance(
1082
1162
  runner="toil-wes-cwl-runner",
1083
1163
  selected_tests="1-309,313-337",
1084
1164
  extra_args=extra_args,
1085
1165
  )
1086
1166
 
1087
1167
 
1088
- @needs_aws_ec2
1089
- @needs_fetchable_appliance
1090
- @slow
1091
- class CWLOnARMTest(AbstractClusterTest):
1092
- """
1093
- Run the CWL 1.2 conformance tests on ARM specifically.
1094
- """
1095
-
1096
- def __init__(self, methodName):
1097
- super().__init__(methodName=methodName)
1098
- self.clusterName = "cwl-test-" + str(uuid.uuid4())
1099
- self.leaderNodeType = "t4g.2xlarge"
1100
- self.clusterType = "kubernetes"
1101
- # We need to be running in a directory which Flatcar and the Toil Appliance both have
1102
- self.cwl_test_dir = "/tmp/toil/cwlTests"
1103
-
1104
- def setUp(self):
1105
- super().setUp()
1106
- self.jobStore = f"aws:{self.awsRegion()}:cluster-{uuid.uuid4()}"
1107
-
1108
- @needs_env_var("CI_COMMIT_SHA", "a git commit sha")
1109
- def test_cwl_on_arm(self):
1110
- # Make a cluster
1111
- self.launchCluster()
1112
- # get the leader so we know the IP address - we don't need to wait since create cluster
1113
- # already ensures the leader is running
1114
- self.cluster = cluster_factory(
1115
- provisioner="aws", zone=self.zone, clusterName=self.clusterName
1116
- )
1117
- self.leader = self.cluster.getLeader()
1118
-
1119
- commit = os.environ["CI_COMMIT_SHA"]
1120
- self.sshUtil(
1121
- [
1122
- "bash",
1123
- "-c",
1124
- f"mkdir -p {self.cwl_test_dir} && cd {self.cwl_test_dir} && git clone https://github.com/DataBiosphere/toil.git",
1125
- ]
1126
- )
1127
-
1128
- # We use CI_COMMIT_SHA to retrieve the Toil version needed to run the CWL tests
1129
- self.sshUtil(
1130
- ["bash", "-c", f"cd {self.cwl_test_dir}/toil && git checkout {commit}"]
1131
- )
1132
-
1133
- # --never-download prevents silent upgrades to pip, wheel and setuptools
1134
- self.sshUtil(
1135
- [
1136
- "bash",
1137
- "-c",
1138
- f"virtualenv --system-site-packages --never-download {self.venvDir}",
1139
- ]
1140
- )
1141
- self.sshUtil(
1142
- [
1143
- "bash",
1144
- "-c",
1145
- f". .{self.venvDir}/bin/activate && cd {self.cwl_test_dir}/toil && make prepare && make develop extras=[all]",
1146
- ]
1147
- )
1148
-
1149
- # Runs the CWLv12Test on an ARM instance
1150
- self.sshUtil(
1151
- [
1152
- "bash",
1153
- "-c",
1154
- f". .{self.venvDir}/bin/activate && cd {self.cwl_test_dir}/toil && pytest --log-cli-level DEBUG -r s src/toil/test/cwl/cwlTest.py::CWLv12Test::test_run_conformance",
1155
- ]
1156
- )
1157
-
1158
- # We know if it succeeds it should save a junit XML for us to read.
1159
- # Bring it back to be an artifact.
1160
- self.rsync_util(
1161
- f":{self.cwl_test_dir}/toil/conformance-1.2.junit.xml",
1162
- os.path.join(
1163
- self._projectRootPath(),
1164
- "arm-conformance-1.2.junit.xml"
1165
- )
1166
- )
1167
-
1168
1168
  @needs_cwl
1169
1169
  @pytest.mark.cwl_small_log_dir
1170
- def test_workflow_echo_string_scatter_stderr_log_dir(tmp_path: Path):
1170
+ def test_workflow_echo_string_scatter_stderr_log_dir(tmp_path: Path) -> None:
1171
1171
  log_dir = tmp_path / "cwl-logs"
1172
1172
  job_store = "test_workflow_echo_string_scatter_stderr_log_dir"
1173
1173
  toil = "toil-cwl-runner"
@@ -1274,7 +1274,7 @@ def test_log_dir_echo_stderr(tmp_path: Path) -> None:
1274
1274
 
1275
1275
  @needs_cwl
1276
1276
  @pytest.mark.cwl_small_log_dir
1277
- def test_filename_conflict_resolution(tmp_path: Path):
1277
+ def test_filename_conflict_resolution(tmp_path: Path) -> None:
1278
1278
  out_dir = tmp_path / "cwl-out-dir"
1279
1279
  toil = "toil-cwl-runner"
1280
1280
  options = [
@@ -1297,7 +1297,7 @@ def test_filename_conflict_resolution(tmp_path: Path):
1297
1297
  @needs_cwl
1298
1298
  @needs_docker
1299
1299
  @pytest.mark.cwl_small_log_dir
1300
- def test_filename_conflict_detection(tmp_path: Path):
1300
+ def test_filename_conflict_detection(tmp_path: Path) -> None:
1301
1301
  """
1302
1302
  Make sure we don't just stage files over each other when using a container.
1303
1303
  """
@@ -1319,7 +1319,7 @@ def test_filename_conflict_detection(tmp_path: Path):
1319
1319
  @needs_cwl
1320
1320
  @needs_docker
1321
1321
  @pytest.mark.cwl_small_log_dir
1322
- def test_filename_conflict_detection_at_root(tmp_path: Path):
1322
+ def test_filename_conflict_detection_at_root(tmp_path: Path) -> None:
1323
1323
  """
1324
1324
  Make sure we don't just stage files over each other.
1325
1325
 
@@ -1343,7 +1343,7 @@ def test_filename_conflict_detection_at_root(tmp_path: Path):
1343
1343
 
1344
1344
  @needs_cwl
1345
1345
  @pytest.mark.cwl_small
1346
- def test_pick_value_with_one_null_value(caplog):
1346
+ def test_pick_value_with_one_null_value(caplog: pytest.LogCaptureFixture) -> None:
1347
1347
  """
1348
1348
  Make sure toil-cwl-runner does not false log a warning when pickValue is
1349
1349
  used but outputSource only contains one null value. See: #3991.
@@ -1362,7 +1362,7 @@ def test_pick_value_with_one_null_value(caplog):
1362
1362
 
1363
1363
  @needs_cwl
1364
1364
  @pytest.mark.cwl_small
1365
- def test_workflow_echo_string():
1365
+ def test_workflow_echo_string() -> None:
1366
1366
  toil = "toil-cwl-runner"
1367
1367
  jobstore = f"--jobStore=file:explicit-local-jobstore-{uuid.uuid4()}"
1368
1368
  option_1 = "--strict-memory-limit"
@@ -1372,14 +1372,18 @@ def test_workflow_echo_string():
1372
1372
  cmd = [toil, jobstore, option_1, option_2, option_3, cwl]
1373
1373
  p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
1374
1374
  stdout, stderr = p.communicate()
1375
- assert stdout.decode("utf-8").strip() == "{}", f"Got wrong output: {stdout}\nWith error: {stderr}"
1376
- assert b"Finished toil run successfully" in stderr
1375
+ stdout2 = stdout.decode("utf-8")
1376
+ stderr2 = stderr.decode("utf-8")
1377
+ assert (
1378
+ stdout2.strip() == "{}"
1379
+ ), f"Got wrong output: {stdout2}\nWith error: {stderr2}"
1380
+ assert "Finished toil run successfully" in stderr2
1377
1381
  assert p.returncode == 0
1378
1382
 
1379
1383
 
1380
1384
  @needs_cwl
1381
1385
  @pytest.mark.cwl_small
1382
- def test_workflow_echo_string_scatter_capture_stdout():
1386
+ def test_workflow_echo_string_scatter_capture_stdout() -> None:
1383
1387
  toil = "toil-cwl-runner"
1384
1388
  jobstore = f"--jobStore=file:explicit-local-jobstore-{uuid.uuid4()}"
1385
1389
  option_1 = "--strict-memory-limit"
@@ -1412,7 +1416,7 @@ def test_workflow_echo_string_scatter_capture_stdout():
1412
1416
 
1413
1417
  @needs_cwl
1414
1418
  @pytest.mark.cwl_small
1415
- def test_visit_top_cwl_class():
1419
+ def test_visit_top_cwl_class() -> None:
1416
1420
  structure = {
1417
1421
  "class": "Directory",
1418
1422
  "listing": [
@@ -1438,7 +1442,7 @@ def test_visit_top_cwl_class():
1438
1442
 
1439
1443
  counter = 0
1440
1444
 
1441
- def increment(thing: Dict) -> None:
1445
+ def increment(thing: "CWLObjectType") -> None:
1442
1446
  """
1443
1447
  Make sure we are at something CWL object like, and count it.
1444
1448
  """
@@ -1463,7 +1467,7 @@ def test_visit_top_cwl_class():
1463
1467
 
1464
1468
  @needs_cwl
1465
1469
  @pytest.mark.cwl_small
1466
- def test_visit_cwl_class_and_reduce():
1470
+ def test_visit_cwl_class_and_reduce() -> None:
1467
1471
  structure = {
1468
1472
  "class": "Directory",
1469
1473
  "listing": [
@@ -1489,7 +1493,7 @@ def test_visit_cwl_class_and_reduce():
1489
1493
 
1490
1494
  down_count = 0
1491
1495
 
1492
- def op_down(thing: MutableMapping) -> int:
1496
+ def op_down(thing: "CWLObjectType") -> int:
1493
1497
  """
1494
1498
  Grab the ID of the thing we are at, and count what we visit going
1495
1499
  down.
@@ -1501,7 +1505,7 @@ def test_visit_cwl_class_and_reduce():
1501
1505
  up_count = 0
1502
1506
  up_child_count = 0
1503
1507
 
1504
- def op_up(thing: MutableMapping, down_value: int, child_results: List[str]) -> str:
1508
+ def op_up(thing: "CWLObjectType", down_value: int, child_results: List[str]) -> str:
1505
1509
  """
1506
1510
  Check the down return value and the up return values, and count
1507
1511
  what we visit going up and what child relationships we have.
@@ -1524,7 +1528,7 @@ def test_visit_cwl_class_and_reduce():
1524
1528
 
1525
1529
  @needs_cwl
1526
1530
  @pytest.mark.cwl_small
1527
- def test_download_structure(tmp_path) -> None:
1531
+ def test_download_structure(tmp_path: Path) -> None:
1528
1532
  """
1529
1533
  Make sure that download_structure makes the right calls to what it thinks is the file store.
1530
1534
  """
@@ -1534,7 +1538,7 @@ def test_download_structure(tmp_path) -> None:
1534
1538
  fid2 = FileID("adifferentfile", 1000, True)
1535
1539
 
1536
1540
  # And what directory structure it would be in
1537
- structure = {
1541
+ structure: DirectoryStructure = {
1538
1542
  "dir1": {
1539
1543
  "dir2": {
1540
1544
  "f1": "toilfile:" + fid1.pack(),
@@ -1555,9 +1559,9 @@ def test_download_structure(tmp_path) -> None:
1555
1559
  # These will be populated.
1556
1560
  # TODO: This cache seems unused. Remove it?
1557
1561
  # This maps filesystem path to CWL URI
1558
- index = {}
1562
+ index: Dict[str, str] = {}
1559
1563
  # This maps CWL URI to filesystem path
1560
- existing = {}
1564
+ existing: Dict[str, str] = {}
1561
1565
 
1562
1566
  # Do the download
1563
1567
  download_structure(file_store, index, existing, structure, to_dir)
@@ -1573,11 +1577,16 @@ def test_download_structure(tmp_path) -> None:
1573
1577
  assert os.path.join(to_dir, "dir1/dir2/f1again") in index
1574
1578
  assert os.path.join(to_dir, "anotherfile") in index
1575
1579
  assert (
1576
- index[os.path.join(to_dir, "dir1/dir2/f1")] == structure["dir1"]["dir2"]["f1"]
1580
+ index[os.path.join(to_dir, "dir1/dir2/f1")]
1581
+ == cast(
1582
+ DirectoryStructure, cast(DirectoryStructure, structure["dir1"])["dir2"]
1583
+ )["f1"]
1577
1584
  )
1578
1585
  assert (
1579
1586
  index[os.path.join(to_dir, "dir1/dir2/f1again")]
1580
- == structure["dir1"]["dir2"]["f1again"]
1587
+ == cast(
1588
+ DirectoryStructure, cast(DirectoryStructure, structure["dir1"])["dir2"]
1589
+ )["f1again"]
1581
1590
  )
1582
1591
  assert index[os.path.join(to_dir, "anotherfile")] == structure["anotherfile"]
1583
1592