toil 7.0.0__py3-none-any.whl → 8.1.0b1__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 (197) hide show
  1. toil/__init__.py +124 -86
  2. toil/batchSystems/__init__.py +1 -0
  3. toil/batchSystems/abstractBatchSystem.py +137 -77
  4. toil/batchSystems/abstractGridEngineBatchSystem.py +211 -101
  5. toil/batchSystems/awsBatch.py +237 -128
  6. toil/batchSystems/cleanup_support.py +22 -16
  7. toil/batchSystems/contained_executor.py +30 -26
  8. toil/batchSystems/gridengine.py +85 -49
  9. toil/batchSystems/htcondor.py +164 -87
  10. toil/batchSystems/kubernetes.py +622 -386
  11. toil/batchSystems/local_support.py +17 -12
  12. toil/batchSystems/lsf.py +132 -79
  13. toil/batchSystems/lsfHelper.py +13 -11
  14. toil/batchSystems/mesos/__init__.py +41 -29
  15. toil/batchSystems/mesos/batchSystem.py +288 -149
  16. toil/batchSystems/mesos/executor.py +77 -49
  17. toil/batchSystems/mesos/test/__init__.py +31 -23
  18. toil/batchSystems/options.py +39 -29
  19. toil/batchSystems/registry.py +53 -19
  20. toil/batchSystems/singleMachine.py +293 -123
  21. toil/batchSystems/slurm.py +651 -155
  22. toil/batchSystems/torque.py +46 -32
  23. toil/bus.py +141 -73
  24. toil/common.py +784 -397
  25. toil/cwl/__init__.py +1 -1
  26. toil/cwl/cwltoil.py +1137 -534
  27. toil/cwl/utils.py +17 -22
  28. toil/deferred.py +62 -41
  29. toil/exceptions.py +5 -3
  30. toil/fileStores/__init__.py +5 -5
  31. toil/fileStores/abstractFileStore.py +88 -57
  32. toil/fileStores/cachingFileStore.py +711 -247
  33. toil/fileStores/nonCachingFileStore.py +113 -75
  34. toil/job.py +1031 -349
  35. toil/jobStores/abstractJobStore.py +387 -243
  36. toil/jobStores/aws/jobStore.py +772 -412
  37. toil/jobStores/aws/utils.py +161 -109
  38. toil/jobStores/conftest.py +1 -0
  39. toil/jobStores/fileJobStore.py +289 -151
  40. toil/jobStores/googleJobStore.py +137 -70
  41. toil/jobStores/utils.py +36 -15
  42. toil/leader.py +614 -269
  43. toil/lib/accelerators.py +115 -18
  44. toil/lib/aws/__init__.py +55 -28
  45. toil/lib/aws/ami.py +122 -87
  46. toil/lib/aws/iam.py +284 -108
  47. toil/lib/aws/s3.py +31 -0
  48. toil/lib/aws/session.py +204 -58
  49. toil/lib/aws/utils.py +290 -213
  50. toil/lib/bioio.py +13 -5
  51. toil/lib/compatibility.py +11 -6
  52. toil/lib/conversions.py +83 -49
  53. toil/lib/docker.py +131 -103
  54. toil/lib/dockstore.py +379 -0
  55. toil/lib/ec2.py +322 -209
  56. toil/lib/ec2nodes.py +174 -105
  57. toil/lib/encryption/_dummy.py +5 -3
  58. toil/lib/encryption/_nacl.py +10 -6
  59. toil/lib/encryption/conftest.py +1 -0
  60. toil/lib/exceptions.py +26 -7
  61. toil/lib/expando.py +4 -2
  62. toil/lib/ftp_utils.py +217 -0
  63. toil/lib/generatedEC2Lists.py +127 -19
  64. toil/lib/history.py +1271 -0
  65. toil/lib/history_submission.py +681 -0
  66. toil/lib/humanize.py +6 -2
  67. toil/lib/io.py +121 -12
  68. toil/lib/iterables.py +4 -2
  69. toil/lib/memoize.py +12 -8
  70. toil/lib/misc.py +83 -18
  71. toil/lib/objects.py +2 -2
  72. toil/lib/resources.py +19 -7
  73. toil/lib/retry.py +125 -87
  74. toil/lib/threading.py +282 -80
  75. toil/lib/throttle.py +15 -14
  76. toil/lib/trs.py +390 -0
  77. toil/lib/web.py +38 -0
  78. toil/options/common.py +850 -402
  79. toil/options/cwl.py +185 -90
  80. toil/options/runner.py +50 -0
  81. toil/options/wdl.py +70 -19
  82. toil/provisioners/__init__.py +111 -46
  83. toil/provisioners/abstractProvisioner.py +322 -157
  84. toil/provisioners/aws/__init__.py +62 -30
  85. toil/provisioners/aws/awsProvisioner.py +980 -627
  86. toil/provisioners/clusterScaler.py +541 -279
  87. toil/provisioners/gceProvisioner.py +283 -180
  88. toil/provisioners/node.py +147 -79
  89. toil/realtimeLogger.py +34 -22
  90. toil/resource.py +137 -75
  91. toil/server/app.py +127 -61
  92. toil/server/celery_app.py +3 -1
  93. toil/server/cli/wes_cwl_runner.py +84 -55
  94. toil/server/utils.py +56 -31
  95. toil/server/wes/abstract_backend.py +64 -26
  96. toil/server/wes/amazon_wes_utils.py +21 -15
  97. toil/server/wes/tasks.py +121 -63
  98. toil/server/wes/toil_backend.py +142 -107
  99. toil/server/wsgi_app.py +4 -3
  100. toil/serviceManager.py +58 -22
  101. toil/statsAndLogging.py +183 -65
  102. toil/test/__init__.py +263 -179
  103. toil/test/batchSystems/batchSystemTest.py +438 -195
  104. toil/test/batchSystems/batch_system_plugin_test.py +18 -7
  105. toil/test/batchSystems/test_gridengine.py +173 -0
  106. toil/test/batchSystems/test_lsf_helper.py +67 -58
  107. toil/test/batchSystems/test_slurm.py +265 -49
  108. toil/test/cactus/test_cactus_integration.py +20 -22
  109. toil/test/cwl/conftest.py +39 -0
  110. toil/test/cwl/cwlTest.py +375 -72
  111. toil/test/cwl/measure_default_memory.cwl +12 -0
  112. toil/test/cwl/not_run_required_input.cwl +29 -0
  113. toil/test/cwl/optional-file.cwl +18 -0
  114. toil/test/cwl/scatter_duplicate_outputs.cwl +40 -0
  115. toil/test/docs/scriptsTest.py +60 -34
  116. toil/test/jobStores/jobStoreTest.py +412 -235
  117. toil/test/lib/aws/test_iam.py +116 -48
  118. toil/test/lib/aws/test_s3.py +16 -9
  119. toil/test/lib/aws/test_utils.py +5 -6
  120. toil/test/lib/dockerTest.py +118 -141
  121. toil/test/lib/test_conversions.py +113 -115
  122. toil/test/lib/test_ec2.py +57 -49
  123. toil/test/lib/test_history.py +212 -0
  124. toil/test/lib/test_misc.py +12 -5
  125. toil/test/lib/test_trs.py +161 -0
  126. toil/test/mesos/MesosDataStructuresTest.py +23 -10
  127. toil/test/mesos/helloWorld.py +7 -6
  128. toil/test/mesos/stress.py +25 -20
  129. toil/test/options/options.py +7 -2
  130. toil/test/provisioners/aws/awsProvisionerTest.py +293 -140
  131. toil/test/provisioners/clusterScalerTest.py +440 -250
  132. toil/test/provisioners/clusterTest.py +81 -42
  133. toil/test/provisioners/gceProvisionerTest.py +174 -100
  134. toil/test/provisioners/provisionerTest.py +25 -13
  135. toil/test/provisioners/restartScript.py +5 -4
  136. toil/test/server/serverTest.py +188 -141
  137. toil/test/sort/restart_sort.py +137 -68
  138. toil/test/sort/sort.py +134 -66
  139. toil/test/sort/sortTest.py +91 -49
  140. toil/test/src/autoDeploymentTest.py +140 -100
  141. toil/test/src/busTest.py +20 -18
  142. toil/test/src/checkpointTest.py +8 -2
  143. toil/test/src/deferredFunctionTest.py +49 -35
  144. toil/test/src/dockerCheckTest.py +33 -26
  145. toil/test/src/environmentTest.py +20 -10
  146. toil/test/src/fileStoreTest.py +538 -271
  147. toil/test/src/helloWorldTest.py +7 -4
  148. toil/test/src/importExportFileTest.py +61 -31
  149. toil/test/src/jobDescriptionTest.py +32 -17
  150. toil/test/src/jobEncapsulationTest.py +2 -0
  151. toil/test/src/jobFileStoreTest.py +74 -50
  152. toil/test/src/jobServiceTest.py +187 -73
  153. toil/test/src/jobTest.py +120 -70
  154. toil/test/src/miscTests.py +19 -18
  155. toil/test/src/promisedRequirementTest.py +82 -36
  156. toil/test/src/promisesTest.py +7 -6
  157. toil/test/src/realtimeLoggerTest.py +6 -6
  158. toil/test/src/regularLogTest.py +71 -37
  159. toil/test/src/resourceTest.py +80 -49
  160. toil/test/src/restartDAGTest.py +36 -22
  161. toil/test/src/resumabilityTest.py +9 -2
  162. toil/test/src/retainTempDirTest.py +45 -14
  163. toil/test/src/systemTest.py +12 -8
  164. toil/test/src/threadingTest.py +44 -25
  165. toil/test/src/toilContextManagerTest.py +10 -7
  166. toil/test/src/userDefinedJobArgTypeTest.py +8 -5
  167. toil/test/src/workerTest.py +33 -16
  168. toil/test/utils/toilDebugTest.py +70 -58
  169. toil/test/utils/toilKillTest.py +4 -5
  170. toil/test/utils/utilsTest.py +239 -102
  171. toil/test/wdl/wdltoil_test.py +789 -148
  172. toil/test/wdl/wdltoil_test_kubernetes.py +37 -23
  173. toil/toilState.py +52 -26
  174. toil/utils/toilConfig.py +13 -4
  175. toil/utils/toilDebugFile.py +44 -27
  176. toil/utils/toilDebugJob.py +85 -25
  177. toil/utils/toilDestroyCluster.py +11 -6
  178. toil/utils/toilKill.py +8 -3
  179. toil/utils/toilLaunchCluster.py +251 -145
  180. toil/utils/toilMain.py +37 -16
  181. toil/utils/toilRsyncCluster.py +27 -14
  182. toil/utils/toilSshCluster.py +45 -22
  183. toil/utils/toilStats.py +75 -36
  184. toil/utils/toilStatus.py +226 -119
  185. toil/utils/toilUpdateEC2Instances.py +3 -1
  186. toil/version.py +6 -6
  187. toil/wdl/utils.py +5 -5
  188. toil/wdl/wdltoil.py +3528 -1053
  189. toil/worker.py +370 -149
  190. toil-8.1.0b1.dist-info/METADATA +178 -0
  191. toil-8.1.0b1.dist-info/RECORD +259 -0
  192. {toil-7.0.0.dist-info → toil-8.1.0b1.dist-info}/WHEEL +1 -1
  193. toil-7.0.0.dist-info/METADATA +0 -158
  194. toil-7.0.0.dist-info/RECORD +0 -244
  195. {toil-7.0.0.dist-info → toil-8.1.0b1.dist-info}/LICENSE +0 -0
  196. {toil-7.0.0.dist-info → toil-8.1.0b1.dist-info}/entry_points.txt +0 -0
  197. {toil-7.0.0.dist-info → toil-8.1.0b1.dist-info}/top_level.txt +0 -0
toil/utils/toilStatus.py CHANGED
@@ -15,13 +15,12 @@
15
15
  import logging
16
16
  import os
17
17
  import sys
18
- from typing import Any, Dict, List, Optional, Set
18
+ from typing import Any, Optional
19
19
 
20
20
  from toil.bus import replay_message_bus
21
- from toil.common import Config, Toil, parser_with_common_options
21
+ from toil.common import Toil, parser_with_common_options
22
22
  from toil.job import JobDescription, JobException, ServiceJobDescription
23
- from toil.jobStores.abstractJobStore import (NoSuchFileException,
24
- NoSuchJobStoreException)
23
+ from toil.jobStores.abstractJobStore import NoSuchFileException, NoSuchJobStoreException
25
24
  from toil.statsAndLogging import StatsAndLogging, set_logging_from_options
26
25
 
27
26
  logger = logging.getLogger(__name__)
@@ -30,33 +29,59 @@ logger = logging.getLogger(__name__)
30
29
  class ToilStatus:
31
30
  """Tool for reporting on job status."""
32
31
 
33
- def __init__(self, jobStoreName: str, specifiedJobs: Optional[List[str]] = None):
32
+ def __init__(self, jobStoreName: str, specifiedJobs: Optional[list[str]] = None):
34
33
  self.jobStoreName = jobStoreName
35
34
  self.jobStore = Toil.resumeJobStore(jobStoreName)
36
35
 
37
36
  if specifiedJobs is None:
38
- rootJob = self.fetchRootJob()
39
- logger.info('Traversing the job graph gathering jobs. This may take a couple of minutes.')
40
- self.jobsToReport = self.traverseJobGraph(rootJob)
37
+ try:
38
+ rootJob = self.fetchRootJob()
39
+ logger.info(
40
+ "Traversing the job graph gathering jobs. This may take a couple of minutes."
41
+ )
42
+ self.jobsToReport = self.traverseJobGraph(rootJob)
43
+ except JobException:
44
+ # Root job isn't set.
45
+ logger.warning("Workflow does not have a root job (yet? anymore?). Cannot look for jobs.")
46
+ self.jobsToReport = []
47
+
41
48
  else:
42
49
  self.jobsToReport = self.fetchUserJobs(specifiedJobs)
43
50
 
44
51
  self.message_bus_path = self.jobStore.config.write_messages
52
+
45
53
  def print_dot_chart(self) -> None:
46
54
  """Print a dot output graph representing the workflow."""
47
55
  print("digraph toil_graph {")
48
56
  print("# This graph was created from job-store: %s" % self.jobStoreName)
49
57
 
50
58
  # Make job IDs to node names map
51
- jobsToNodeNames: Dict[str, str] = dict(
52
- map(lambda job: (str(job.jobStoreID), job.jobName), self.jobsToReport)
53
- )
59
+ def id_to_name(job_id: str) -> str:
60
+ """
61
+ Change a job ID into a GraphViz node name.
62
+ """
63
+ replacements = [
64
+ ("_", "_u_"),
65
+ ("/", "_s_"),
66
+ ("-", "_d_")
67
+ ]
68
+ result = job_id
69
+ for char, replacement in replacements:
70
+ result = result.replace(char, replacement)
71
+ return result
72
+ id_strings = [str(job.jobStoreID) for job in self.jobsToReport]
73
+ jobsToNodeNames = {
74
+ s: id_to_name(s) for s in id_strings
75
+ }
54
76
 
55
77
  # Print the nodes
56
78
  for job in set(self.jobsToReport):
57
79
  print(
58
- '{} [label="{} {}"];'.format(
59
- jobsToNodeNames[str(job.jobStoreID)], job.jobName, job.jobStoreID
80
+ '{} [label="{} {}" color="{}"];'.format(
81
+ jobsToNodeNames[str(job.jobStoreID)],
82
+ job.jobName,
83
+ job.displayName,
84
+ "black" if job.has_body() else "green"
60
85
  )
61
86
  )
62
87
 
@@ -82,7 +107,11 @@ class ToilStatus:
82
107
  with job.getLogFileHandle(self.jobStore) as fH:
83
108
  # TODO: This looks intended to be machine-readable, but the format is
84
109
  # unspecified and no escaping is done. But keep these tags around.
85
- print(StatsAndLogging.formatLogStream(fH, stream_name=f"LOG_FILE_OF_JOB:{job} LOG:"))
110
+ print(
111
+ StatsAndLogging.formatLogStream(
112
+ fH, stream_name=f"LOG_FILE_OF_JOB:{job} LOG:"
113
+ )
114
+ )
86
115
  else:
87
116
  print(f"LOG_FILE_OF_JOB: {job} LOG: Job has no log file")
88
117
 
@@ -94,22 +123,33 @@ class ToilStatus:
94
123
  children += "\t(CHILD_JOB:%s,PRECEDENCE:%i)" % (childJob, level)
95
124
  print(children)
96
125
 
97
- def printAggregateJobStats(self, properties: List[Set[str]], childNumber: List[int]) -> None:
126
+ def printAggregateJobStats(
127
+ self, properties: list[set[str]], childNumber: list[int]
128
+ ) -> None:
98
129
  """
99
130
  Prints each job's ID, log file, remaining tries, and other properties.
100
131
 
101
132
  :param properties: A set of string flag names for each job in self.jobsToReport.
102
133
  :param childNumber: A list of child counts for each job in self.jobsToReport.
103
134
  """
104
- for job, job_properties, job_child_number in zip(self.jobsToReport, properties, childNumber):
135
+ for job, job_properties, job_child_number in zip(
136
+ self.jobsToReport, properties, childNumber
137
+ ):
105
138
 
106
139
  def lf(x: str) -> str:
107
140
  return f"{x}:{str(x in job_properties)}"
141
+
108
142
  # We use a sort of not-really-machine-readable key:value TSV format here.
109
143
  # But we only include important keys to help the humans, and flags
110
144
  # don't have a value, just a key.
111
145
  parts = [f"JOB:{job}"]
112
- for flag in ["COMPLETELY_FAILED", "READY_TO_RUN", "IS_ZOMBIE", "HAS_SERVICES", "IS_SERVICE"]:
146
+ for flag in [
147
+ "COMPLETELY_FAILED",
148
+ "READY_TO_RUN",
149
+ "IS_ZOMBIE",
150
+ "HAS_SERVICES",
151
+ "IS_SERVICE",
152
+ ]:
113
153
  if flag in job_properties:
114
154
  parts.append(flag)
115
155
  if job.logJobStoreFileID:
@@ -121,7 +161,7 @@ class ToilStatus:
121
161
 
122
162
  print("\t".join(parts))
123
163
 
124
- def report_on_jobs(self) -> Dict[str, Any]:
164
+ def report_on_jobs(self) -> dict[str, Any]:
125
165
  """
126
166
  Gathers information about jobs such as its child jobs and status.
127
167
 
@@ -132,20 +172,20 @@ class ToilStatus:
132
172
  hasChildren = []
133
173
  readyToRun = []
134
174
  zombies = []
135
- hasLogFile: List[JobDescription] = []
175
+ hasLogFile: list[JobDescription] = []
136
176
  hasServices = []
137
- services: List[ServiceJobDescription] = []
177
+ services: list[ServiceJobDescription] = []
138
178
  completely_failed = []
139
179
 
140
180
  # These are stats for jobs in self.jobsToReport
141
- child_number: List[int] = []
142
- properties: List[Set[str]] = []
181
+ child_number: list[int] = []
182
+ properties: list[set[str]] = []
143
183
 
144
184
  # TODO: This mix of semantics is confusing and made per-job status be
145
185
  # wrong for multiple years because it was not understood. Redesign it!
146
186
 
147
187
  for job in self.jobsToReport:
148
- job_properties: Set[str] = set()
188
+ job_properties: set[str] = set()
149
189
  if job.logJobStoreFileID is not None:
150
190
  hasLogFile.append(job)
151
191
 
@@ -176,16 +216,16 @@ class ToilStatus:
176
216
 
177
217
  jobStats = {
178
218
  # These are lists of the mathcing jobs
179
- 'hasChildren': hasChildren,
180
- 'readyToRun': readyToRun,
181
- 'zombies': zombies,
182
- 'hasServices': hasServices,
183
- 'services': services,
184
- 'hasLogFile': hasLogFile,
185
- 'completelyFailed': completely_failed,
219
+ "hasChildren": hasChildren,
220
+ "readyToRun": readyToRun,
221
+ "zombies": zombies,
222
+ "hasServices": hasServices,
223
+ "services": services,
224
+ "hasLogFile": hasLogFile,
225
+ "completelyFailed": completely_failed,
186
226
  # These are stats for jobs in self.jobsToReport
187
- 'properties': properties,
188
- 'childNumber': child_number
227
+ "properties": properties,
228
+ "childNumber": child_number,
189
229
  }
190
230
  return jobStats
191
231
 
@@ -202,21 +242,21 @@ class ToilStatus:
202
242
  try:
203
243
  jobstore = Toil.resumeJobStore(jobStoreName)
204
244
  except NoSuchJobStoreException:
205
- return 'QUEUED'
245
+ return "QUEUED"
206
246
  except NoSuchFileException:
207
- return 'QUEUED'
247
+ return "QUEUED"
208
248
 
209
249
  try:
210
250
  pid = jobstore.read_leader_pid()
211
251
  try:
212
252
  os.kill(pid, 0) # Does not kill process when 0 is passed.
213
253
  except OSError: # Process not found, must be done.
214
- return 'COMPLETED'
254
+ return "COMPLETED"
215
255
  else:
216
- return 'RUNNING'
256
+ return "RUNNING"
217
257
  except NoSuchFileException:
218
258
  pass
219
- return 'QUEUED'
259
+ return "QUEUED"
220
260
 
221
261
  @staticmethod
222
262
  def getStatus(jobStoreName: str) -> str:
@@ -235,38 +275,45 @@ class ToilStatus:
235
275
  try:
236
276
  jobstore = Toil.resumeJobStore(jobStoreName)
237
277
  except NoSuchJobStoreException:
238
- return 'QUEUED'
278
+ return "QUEUED"
239
279
  except NoSuchFileException:
240
- return 'QUEUED'
280
+ return "QUEUED"
241
281
 
242
282
  try:
243
- with jobstore.read_shared_file_stream('succeeded.log') as successful:
283
+ with jobstore.read_shared_file_stream("succeeded.log") as successful:
244
284
  pass
245
- return 'COMPLETED'
285
+ return "COMPLETED"
246
286
  except NoSuchFileException:
247
287
  try:
248
- with jobstore.read_shared_file_stream('failed.log') as failed:
288
+ with jobstore.read_shared_file_stream("failed.log") as failed:
249
289
  pass
250
- return 'ERROR'
290
+ return "ERROR"
251
291
  except NoSuchFileException:
252
292
  pass
253
- return 'RUNNING'
293
+ return "RUNNING"
254
294
 
255
- def print_bus_messages(self) -> None:
295
+ def print_running_jobs(self) -> None:
256
296
  """
257
- Goes through bus messages, returns a list of tuples which have correspondence between
258
- PID on assigned batch system and
259
-
260
297
  Prints a list of the currently running jobs
261
298
  """
262
299
 
263
300
  print("\nMessage bus path: ", self.message_bus_path)
264
301
  if self.message_bus_path is not None:
265
302
  if os.path.exists(self.message_bus_path):
266
- replayed_messages = replay_message_bus(self.message_bus_path)
267
- for key in replayed_messages:
268
- if replayed_messages[key].exit_code != 0:
269
- print(replayed_messages[key])
303
+ all_job_statuses = replay_message_bus(self.message_bus_path)
304
+
305
+ for job_status in all_job_statuses.values():
306
+ if job_status.is_running():
307
+ status_line = [
308
+ f"Job ID {job_status.job_store_id} with name {job_status.name} is running"
309
+ ]
310
+ if job_status.batch_system != "":
311
+ # batch system exists
312
+ status_line.append(
313
+ f" on {job_status.batch_system} as ID {job_status.external_batch_id}"
314
+ )
315
+ status_line.append(".")
316
+ print("".join(status_line))
270
317
  else:
271
318
  print("Message bus file is missing!")
272
319
 
@@ -287,10 +334,12 @@ class ToilStatus:
287
334
  return self.jobStore.load_root_job()
288
335
  except JobException as e:
289
336
  logger.info(e)
290
- print('Root job is absent. The workflow has may have completed successfully.')
337
+ print(
338
+ "Root job is absent. The workflow has may have completed successfully."
339
+ )
291
340
  raise
292
341
 
293
- def fetchUserJobs(self, jobs: List[str]) -> List[JobDescription]:
342
+ def fetchUserJobs(self, jobs: list[str]) -> list[JobDescription]:
294
343
  """
295
344
  Takes a user input array of jobs, verifies that they are in the jobStore
296
345
  and returns the array of jobsToReport.
@@ -303,16 +352,16 @@ class ToilStatus:
303
352
  try:
304
353
  jobsToReport.append(self.jobStore.load_job(jobID))
305
354
  except JobException:
306
- print('The job %s could not be found.' % jobID, file=sys.stderr)
355
+ print("The job %s could not be found." % jobID, file=sys.stderr)
307
356
  raise
308
357
  return jobsToReport
309
358
 
310
359
  def traverseJobGraph(
311
360
  self,
312
361
  rootJob: JobDescription,
313
- jobsToReport: Optional[List[JobDescription]] = None,
314
- foundJobStoreIDs: Optional[Set[str]] = None,
315
- ) -> List[JobDescription]:
362
+ jobsToReport: Optional[list[JobDescription]] = None,
363
+ foundJobStoreIDs: Optional[set[str]] = None,
364
+ ) -> list[JobDescription]:
316
365
  """
317
366
  Find all current jobs in the jobStore and return them as an Array.
318
367
 
@@ -335,15 +384,24 @@ class ToilStatus:
335
384
  jobsToReport.append(rootJob)
336
385
  # Traverse jobs in stack
337
386
  for successorJobStoreID in rootJob.allSuccessors():
338
- if successorJobStoreID not in foundJobStoreIDs and self.jobStore.job_exists(successorJobStoreID):
339
- self.traverseJobGraph(self.jobStore.load_job(successorJobStoreID), jobsToReport, foundJobStoreIDs)
387
+ if (
388
+ successorJobStoreID not in foundJobStoreIDs
389
+ and self.jobStore.job_exists(successorJobStoreID)
390
+ ):
391
+ self.traverseJobGraph(
392
+ self.jobStore.load_job(successorJobStoreID),
393
+ jobsToReport,
394
+ foundJobStoreIDs,
395
+ )
340
396
 
341
397
  # Traverse service jobs
342
398
  for jobs in rootJob.services:
343
399
  for serviceJobStoreID in jobs:
344
400
  if self.jobStore.job_exists(serviceJobStoreID):
345
401
  if serviceJobStoreID in foundJobStoreIDs:
346
- raise RuntimeError('Service job was unexpectedly found while traversing ')
402
+ raise RuntimeError(
403
+ "Service job was unexpectedly found while traversing "
404
+ )
347
405
  foundJobStoreIDs.add(serviceJobStoreID)
348
406
  jobsToReport.append(self.jobStore.load_job(serviceJobStoreID))
349
407
 
@@ -353,40 +411,80 @@ class ToilStatus:
353
411
  def main() -> None:
354
412
  """Reports the state of a Toil workflow."""
355
413
  parser = parser_with_common_options(prog="toil status")
356
- parser.add_argument("--failIfNotComplete", action="store_true",
357
- help="Return exit value of 1 if toil jobs not all completed. default=%(default)s",
358
- default=False)
359
-
360
- parser.add_argument("--noAggStats", dest="stats", action="store_false",
361
- help="Do not print overall, aggregate status of workflow.",
362
- default=True)
363
-
364
- parser.add_argument("--dot", "--printDot", dest="print_dot", action="store_true",
365
- help="Print dot formatted description of the graph. If using --jobs will "
366
- "restrict to subgraph including only those jobs. default=%(default)s",
367
- default=False)
368
-
369
- parser.add_argument("--jobs", nargs='+',
370
- help="Restrict reporting to the following jobs (allows subsetting of the report).",
371
- default=None)
372
-
373
- parser.add_argument("--perJob", "--printPerJobStats", dest="print_per_job_stats", action="store_true",
374
- help="Print info about each job. default=%(default)s",
375
- default=False)
376
-
377
- parser.add_argument("--logs", "--printLogs", dest="print_logs", action="store_true",
378
- help="Print the log files of jobs (if they exist). default=%(default)s",
379
- default=False)
380
-
381
- parser.add_argument("--children", "--printChildren", dest="print_children", action="store_true",
382
- help="Print children of each job. default=%(default)s",
383
- default=False)
384
-
385
- parser.add_argument("--status", "--printStatus", dest="print_status", action="store_true",
386
- help="Determine which jobs are currently running and the associated batch system ID")
387
-
388
- parser.add_argument("--failed", "--printFailed", dest="print_failed", action="store_true",
389
- help="List jobs which seem to have failed to run")
414
+ parser.add_argument(
415
+ "--failIfNotComplete",
416
+ action="store_true",
417
+ help="Return exit value of 1 if toil jobs not all completed. default=%(default)s",
418
+ default=False,
419
+ )
420
+
421
+ parser.add_argument(
422
+ "--noAggStats",
423
+ dest="stats",
424
+ action="store_false",
425
+ help="Do not print overall, aggregate status of workflow.",
426
+ default=True,
427
+ )
428
+
429
+ parser.add_argument(
430
+ "--dot",
431
+ "--printDot",
432
+ dest="print_dot",
433
+ action="store_true",
434
+ help="Print dot formatted description of the graph. If using --jobs will "
435
+ "restrict to subgraph including only those jobs. default=%(default)s",
436
+ default=False,
437
+ )
438
+
439
+ parser.add_argument(
440
+ "--jobs",
441
+ nargs="+",
442
+ help="Restrict reporting to the following jobs (allows subsetting of the report).",
443
+ default=None,
444
+ )
445
+
446
+ parser.add_argument(
447
+ "--perJob",
448
+ "--printPerJobStats",
449
+ dest="print_per_job_stats",
450
+ action="store_true",
451
+ help="Print info about each job. default=%(default)s",
452
+ default=False,
453
+ )
454
+
455
+ parser.add_argument(
456
+ "--logs",
457
+ "--printLogs",
458
+ dest="print_logs",
459
+ action="store_true",
460
+ help="Print the log files of jobs (if they exist). default=%(default)s",
461
+ default=False,
462
+ )
463
+
464
+ parser.add_argument(
465
+ "--children",
466
+ "--printChildren",
467
+ dest="print_children",
468
+ action="store_true",
469
+ help="Print children of each job. default=%(default)s",
470
+ default=False,
471
+ )
472
+
473
+ parser.add_argument(
474
+ "--status",
475
+ "--printStatus",
476
+ dest="print_status",
477
+ action="store_true",
478
+ help="Determine which jobs are currently running and the associated batch system ID, if any",
479
+ )
480
+
481
+ parser.add_argument(
482
+ "--failed",
483
+ "--printFailed",
484
+ dest="print_failed",
485
+ action="store_true",
486
+ help="List jobs which seem to have failed to run",
487
+ )
390
488
 
391
489
  options = parser.parse_args()
392
490
  set_logging_from_options(options)
@@ -398,7 +496,7 @@ def main() -> None:
398
496
  try:
399
497
  status = ToilStatus(options.jobStore, options.jobs)
400
498
  except NoSuchJobStoreException:
401
- print(f'The job store {options.jobStore} was not found.')
499
+ print(f"The job store {options.jobStore} was not found.")
402
500
  return
403
501
  except JobException: # Workflow likely complete, user informed in ToilStatus()
404
502
  return
@@ -407,16 +505,16 @@ def main() -> None:
407
505
 
408
506
  # Info to be reported.
409
507
  # These are lists of matching jobs.
410
- hasChildren = jobStats['hasChildren']
411
- readyToRun = jobStats['readyToRun']
412
- zombies = jobStats['zombies']
413
- hasServices = jobStats['hasServices']
414
- services = jobStats['services']
415
- hasLogFile = jobStats['hasLogFile']
416
- completely_failed = jobStats['completelyFailed']
508
+ hasChildren = jobStats["hasChildren"]
509
+ readyToRun = jobStats["readyToRun"]
510
+ zombies = jobStats["zombies"]
511
+ hasServices = jobStats["hasServices"]
512
+ services = jobStats["services"]
513
+ hasLogFile = jobStats["hasLogFile"]
514
+ completely_failed = jobStats["completelyFailed"]
417
515
  # These are results for corresponding jobs in status.jobsToReport
418
- properties = jobStats['properties']
419
- childNumber = jobStats['childNumber']
516
+ properties = jobStats["properties"]
517
+ childNumber = jobStats["childNumber"]
420
518
 
421
519
  if options.print_per_job_stats:
422
520
  status.printAggregateJobStats(properties, childNumber)
@@ -431,21 +529,30 @@ def main() -> None:
431
529
  for job in completely_failed:
432
530
  print(job)
433
531
  if options.stats:
434
- print('Of the %i jobs considered, '
435
- 'there are '
436
- '%i completely failed jobs, '
437
- '%i jobs with children, '
438
- '%i jobs ready to run, '
439
- '%i zombie jobs, '
440
- '%i jobs with services, '
441
- '%i services, '
442
- 'and %i jobs with log files currently in %s.' %
443
- (len(status.jobsToReport), len(completely_failed), len(hasChildren),
444
- len(readyToRun), len(zombies), len(hasServices), len(services),
445
- len(hasLogFile), status.jobStore))
532
+ print(
533
+ "Of the %i jobs considered, "
534
+ "there are "
535
+ "%i completely failed jobs, "
536
+ "%i jobs with children, "
537
+ "%i jobs ready to run, "
538
+ "%i zombie jobs, "
539
+ "%i jobs with services, "
540
+ "%i services, "
541
+ "and %i jobs with log files currently in %s."
542
+ % (
543
+ len(status.jobsToReport),
544
+ len(completely_failed),
545
+ len(hasChildren),
546
+ len(readyToRun),
547
+ len(zombies),
548
+ len(hasServices),
549
+ len(services),
550
+ len(hasLogFile),
551
+ status.jobStore,
552
+ )
553
+ )
446
554
  if options.print_status:
447
- status.print_bus_messages()
555
+ status.print_running_jobs()
448
556
  if len(status.jobsToReport) > 0 and options.failIfNotComplete:
449
557
  # Upon workflow completion, all jobs will have been removed from job store
450
558
  exit(1)
451
-
@@ -31,7 +31,9 @@ def internet_connection() -> bool:
31
31
 
32
32
  def main() -> None:
33
33
  if not internet_connection():
34
- raise RuntimeError('No internet. Updating the EC2 Instance list requires internet.')
34
+ raise RuntimeError(
35
+ "No internet. Updating the EC2 Instance list requires internet."
36
+ )
35
37
  updateStaticEC2Instances()
36
38
 
37
39
 
toil/version.py CHANGED
@@ -1,14 +1,14 @@
1
- baseVersion = '7.0.0'
1
+ baseVersion = '8.1.0b1'
2
2
  cgcloudVersion = '1.6.0a1.dev393'
3
- version = '7.0.0-d569ea5711eb310ffd5703803f7250ebf7c19576'
3
+ version = '8.1.0b1-4bb05349c027096ab4785259e39b2648118b5dd7'
4
4
  cacheTag = 'cache-local-py3.9'
5
5
  mainCacheTag = 'cache-master-py3.9'
6
- distVersion = '7.0.0'
6
+ distVersion = '8.1.0b1'
7
7
  exactPython = 'python3.9'
8
8
  python = 'python3.9'
9
- dockerTag = '7.0.0-d569ea5711eb310ffd5703803f7250ebf7c19576-py3.9'
10
- currentCommit = 'd569ea5711eb310ffd5703803f7250ebf7c19576'
9
+ dockerTag = '8.1.0b1-4bb05349c027096ab4785259e39b2648118b5dd7-py3.9'
10
+ currentCommit = '4bb05349c027096ab4785259e39b2648118b5dd7'
11
11
  dockerRegistry = 'quay.io/ucsc_cgl'
12
12
  dockerName = 'toil'
13
13
  dirty = False
14
- cwltool_version = '3.1.20240508115724'
14
+ cwltool_version = '3.1.20250110105449'
toil/wdl/utils.py CHANGED
@@ -11,7 +11,7 @@
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 typing import Iterable
14
+ from collections.abc import Iterable
15
15
 
16
16
 
17
17
  def get_version(iterable: Iterable[str]) -> str:
@@ -22,14 +22,14 @@ def get_version(iterable: Iterable[str]) -> str:
22
22
  :return: The WDL version used in the workflow.
23
23
  """
24
24
  if isinstance(iterable, str):
25
- iterable = iterable.split('\n')
25
+ iterable = iterable.split("\n")
26
26
 
27
27
  for line in iterable:
28
28
  line = line.strip()
29
29
  # check if the first non-empty, non-comment line is the version statement
30
- if line and not line.startswith('#'):
31
- if line.startswith('version '):
30
+ if line and not line.startswith("#"):
31
+ if line.startswith("version "):
32
32
  return line[8:].strip()
33
33
  break
34
34
  # only draft-2 doesn't contain the version declaration
35
- return 'draft-2'
35
+ return "draft-2"