toil 9.1.2__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 +14 -14
  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.2.dist-info → toil-9.2.0.dist-info}/METADATA +11 -14
  146. {toil-9.1.2.dist-info → toil-9.2.0.dist-info}/RECORD +150 -153
  147. {toil-9.1.2.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.2.dist-info → toil-9.2.0.dist-info}/entry_points.txt +0 -0
  154. {toil-9.1.2.dist-info → toil-9.2.0.dist-info}/licenses/LICENSE +0 -0
  155. {toil-9.1.2.dist-info → toil-9.2.0.dist-info}/top_level.txt +0 -0
toil/lib/history.py CHANGED
@@ -16,16 +16,16 @@
16
16
  Contains tools for tracking history.
17
17
  """
18
18
 
19
- from contextlib import contextmanager
20
19
  import logging
21
20
  import os
22
21
  import sqlite3
23
22
  import sys
24
- import threading
25
23
  import time
26
24
  import uuid
25
+ from collections.abc import Callable, Iterable, Iterator
26
+ from contextlib import contextmanager
27
27
  from dataclasses import dataclass
28
- from typing import Any, Iterable, Iterator, Optional, TypeVar, Callable
28
+ from typing import TypeVar
29
29
 
30
30
  from toil.lib.conversions import strtobool
31
31
  from toil.lib.io import get_toil_home
@@ -33,12 +33,13 @@ from toil.lib.retry import ErrorCondition, retry
33
33
 
34
34
  logger = logging.getLogger(__name__)
35
35
 
36
+
36
37
  class HistoryDatabaseSchemaTooNewError(RuntimeError):
37
38
  """
38
39
  Raised when we would write to the history database, but its schema is too
39
40
  new for us to understand.
40
41
  """
41
- pass
42
+
42
43
 
43
44
  @dataclass
44
45
  class WorkflowSummary:
@@ -47,25 +48,27 @@ class WorkflowSummary:
47
48
 
48
49
  Represents all the attempts to execute one run of a workflow.
49
50
  """
51
+
50
52
  id: str
51
- name: Optional[str]
53
+ name: str | None
52
54
  job_store: str
53
55
  total_attempts: int
54
56
  total_job_attempts: int
55
57
  succeeded: bool
56
- start_time: Optional[float]
58
+ start_time: float | None
57
59
  """
58
60
  Time when the first workflow attempt started, in seconds since epoch.
59
61
 
60
62
  None if there are no attempts recorded.
61
63
  """
62
- runtime: Optional[float]
64
+ runtime: float | None
63
65
  """
64
66
  Time from the first workflow attempt's start to the last one's end, in seconds.
65
67
 
66
68
  None if there are no attempts recorded.
67
69
  """
68
- trs_spec: Optional[str]
70
+ trs_spec: str | None
71
+
69
72
 
70
73
  @dataclass
71
74
  class WorkflowAttemptSummary:
@@ -74,20 +77,22 @@ class WorkflowAttemptSummary:
74
77
 
75
78
  Helpfully includes the workflow metadata for Dockstore.
76
79
  """
80
+
77
81
  workflow_id: str
78
82
  attempt_number: int
79
83
  succeeded: bool
80
84
  start_time: float
81
85
  runtime: float
82
86
  submitted_to_dockstore: bool
83
- batch_system: Optional[str]
84
- caching: Optional[bool]
85
- toil_version: Optional[str]
86
- python_version: Optional[str]
87
- platform_system: Optional[str]
88
- platform_machine: Optional[str]
87
+ batch_system: str | None
88
+ caching: bool | None
89
+ toil_version: str | None
90
+ python_version: str | None
91
+ platform_system: str | None
92
+ platform_machine: str | None
89
93
  workflow_job_store: str
90
- workflow_trs_spec: Optional[str]
94
+ workflow_trs_spec: str | None
95
+
91
96
 
92
97
  @dataclass
93
98
  class JobAttemptSummary:
@@ -95,20 +100,22 @@ class JobAttemptSummary:
95
100
  Data class holding summary information for a job attempt within a known
96
101
  workflow attempt.
97
102
  """
103
+
98
104
  id: str
99
105
  job_name: str
100
106
  succeeded: bool
101
107
  start_time: float
102
108
  runtime: float
103
109
  submitted_to_dockstore: bool
104
- cores: Optional[float]
105
- cpu_seconds: Optional[float]
106
- memory_bytes: Optional[int]
107
- disk_bytes: Optional[int]
110
+ cores: float | None
111
+ cpu_seconds: float | None
112
+ memory_bytes: int | None
113
+ disk_bytes: int | None
108
114
 
109
115
 
110
116
  RT = TypeVar("RT")
111
117
 
118
+
112
119
  def db_retry(function: Callable[..., RT]) -> Callable[..., RT]:
113
120
  """
114
121
  Decorate a function with the appropriate retries for accessing the database.
@@ -122,6 +129,7 @@ def db_retry(function: Callable[..., RT]) -> Callable[..., RT]:
122
129
  ],
123
130
  )(function)
124
131
 
132
+
125
133
  class HistoryManager:
126
134
  """
127
135
  Class responsible for managing the history of Toil runs.
@@ -134,7 +142,7 @@ class HistoryManager:
134
142
 
135
143
  If False, no access at all shoulf be made to the database.
136
144
  """
137
- return strtobool(os.environ.get("TOIL_HISTORY", 'True'))
145
+ return strtobool(os.environ.get("TOIL_HISTORY", "True"))
138
146
 
139
147
  @classmethod
140
148
  def enabled_job(cls) -> bool:
@@ -146,10 +154,10 @@ class HistoryManager:
146
154
  # TODO: When Dockstore can take job metrics alongside whole-workflow
147
155
  # metrics, and we've tested to make sure history recording doesn't slow
148
156
  # down our leader job processing rate, turn on actual job history logging.
149
- return cls.enabled() and strtobool(os.environ.get("TOIL_JOB_HISTORY", 'False'))
157
+ return cls.enabled() and strtobool(os.environ.get("TOIL_JOB_HISTORY", "False"))
150
158
 
151
159
  # For testing, we can move the database path for the class.
152
- database_path_override: Optional[str] = None
160
+ database_path_override: str | None = None
153
161
 
154
162
  @classmethod
155
163
  def database_path(cls) -> str:
@@ -180,7 +188,9 @@ class HistoryManager:
180
188
  if not cls.enabled():
181
189
  # Make sure we're not missing an enabled check along any codepath
182
190
  # that wants to access the database.
183
- raise RuntimeError("Attempting to connect to database when HistoryManager is disabled!")
191
+ raise RuntimeError(
192
+ "Attempting to connect to database when HistoryManager is disabled!"
193
+ )
184
194
 
185
195
  if not os.path.exists(cls.database_path()):
186
196
  # Make the database and protect it from snoopers and busybodies
@@ -188,10 +198,7 @@ class HistoryManager:
188
198
  del con
189
199
  os.chmod(cls.database_path(), 0o600)
190
200
 
191
- con = sqlite3.connect(
192
- cls.database_path(),
193
- isolation_level="DEFERRED"
194
- )
201
+ con = sqlite3.connect(cls.database_path(), isolation_level="DEFERRED")
195
202
 
196
203
  with cls.no_transaction(con):
197
204
  # Turn on foreign keys.
@@ -203,7 +210,7 @@ class HistoryManager:
203
210
 
204
211
  # Set up the connection to use the Row class so that we can look up row values by column name and not just order.
205
212
  con.row_factory = sqlite3.Row
206
-
213
+
207
214
  return con
208
215
 
209
216
  @classmethod
@@ -215,12 +222,12 @@ class HistoryManager:
215
222
 
216
223
  Commits the current transaction.
217
224
  """
218
-
225
+
219
226
  con.commit()
220
- if hasattr(con, 'autocommit'):
227
+ if hasattr(con, "autocommit"):
221
228
  con.autocommit = True
222
229
  yield
223
- if hasattr(con, 'autocommit'):
230
+ if hasattr(con, "autocommit"):
224
231
  con.autocommit = False
225
232
 
226
233
  @classmethod
@@ -239,12 +246,14 @@ class HistoryManager:
239
246
 
240
247
  # TODO: Do a try-and-fall-back to avoid sending the table schema for
241
248
  # this every time we do anything.
242
- cur.execute("""
249
+ cur.execute(
250
+ """
243
251
  CREATE TABLE IF NOT EXISTS migrations (
244
252
  version INT NOT NULL PRIMARY KEY,
245
253
  description TEXT
246
254
  )
247
- """)
255
+ """
256
+ )
248
257
  db_version = next(cur.execute("SELECT MAX(version) FROM migrations"))[0]
249
258
  if db_version is None:
250
259
  db_version = -1
@@ -317,25 +326,37 @@ class HistoryManager:
317
326
  PRIMARY KEY(workflow_id,attempt_number),
318
327
  FOREIGN KEY(workflow_id) REFERENCES workflows(id)
319
328
  )
320
- """
329
+ """,
321
330
  ],
322
331
  ),
323
332
  ]
324
333
 
325
334
  if db_version + 1 > len(migrations):
326
- raise HistoryDatabaseSchemaTooNewError(f"History database version is {db_version}, but known migrations only go up to {len(migrations) - 1}")
335
+ raise HistoryDatabaseSchemaTooNewError(
336
+ f"History database version is {db_version}, but known migrations only go up to {len(migrations) - 1}"
337
+ )
327
338
 
328
339
  for migration_number in range(db_version + 1, len(migrations)):
329
- for statement_number, statement in enumerate(migrations[migration_number][1]):
340
+ for statement_number, statement in enumerate(
341
+ migrations[migration_number][1]
342
+ ):
330
343
  # Run all the migration commands.
331
344
  # We don't use executescript() because (on old Pythons?) it
332
345
  # commits the current transactrion first.
333
346
  try:
334
347
  cur.execute(statement)
335
348
  except sqlite3.OperationalError:
336
- logger.exception("Could not execute migration %s statement %s: %s", migration_number, statement_number, statement)
349
+ logger.exception(
350
+ "Could not execute migration %s statement %s: %s",
351
+ migration_number,
352
+ statement_number,
353
+ statement,
354
+ )
337
355
  raise
338
- cur.execute("INSERT INTO migrations VALUES (?, ?)", (migration_number, migrations[migration_number][0]))
356
+ cur.execute(
357
+ "INSERT INTO migrations VALUES (?, ?)",
358
+ (migration_number, migrations[migration_number][0]),
359
+ )
339
360
 
340
361
  # If we did have to migrate, leave everything else we do as part of the migration transaction.
341
362
 
@@ -366,13 +387,18 @@ class HistoryManager:
366
387
  if not cls.enabled():
367
388
  return
368
389
 
369
- logger.info("Recording workflow creation of %s in %s", workflow_id, job_store_spec)
390
+ logger.info(
391
+ "Recording workflow creation of %s in %s", workflow_id, job_store_spec
392
+ )
370
393
 
371
394
  con = cls.connection()
372
395
  cur = con.cursor()
373
396
  try:
374
397
  cls.ensure_tables(con, cur)
375
- cur.execute("INSERT INTO workflows VALUES (?, ?, ?, NULL, NULL)", (workflow_id, job_store_spec, time.time()))
398
+ cur.execute(
399
+ "INSERT INTO workflows VALUES (?, ?, ?, NULL, NULL)",
400
+ (workflow_id, job_store_spec, time.time()),
401
+ )
376
402
  except:
377
403
  con.rollback()
378
404
  con.close()
@@ -383,10 +409,11 @@ class HistoryManager:
383
409
 
384
410
  # If we raise out of here the connection goes away and the transaction rolls back.
385
411
 
386
-
387
412
  @classmethod
388
413
  @db_retry
389
- def record_workflow_metadata(cls, workflow_id: str, workflow_name: str, trs_spec: Optional[str] = None) -> None:
414
+ def record_workflow_metadata(
415
+ cls, workflow_id: str, workflow_name: str, trs_spec: str | None = None
416
+ ) -> None:
390
417
  """
391
418
  Associate a name and optionally a TRS ID and version with a workflow run.
392
419
  """
@@ -404,9 +431,15 @@ class HistoryManager:
404
431
  cur = con.cursor()
405
432
  try:
406
433
  cls.ensure_tables(con, cur)
407
- cur.execute("UPDATE workflows SET name = ? WHERE id = ?", (workflow_name, workflow_id))
434
+ cur.execute(
435
+ "UPDATE workflows SET name = ? WHERE id = ?",
436
+ (workflow_name, workflow_id),
437
+ )
408
438
  if trs_spec is not None:
409
- cur.execute("UPDATE workflows SET trs_spec = ? WHERE id = ?", (trs_spec, workflow_id))
439
+ cur.execute(
440
+ "UPDATE workflows SET trs_spec = ? WHERE id = ?",
441
+ (trs_spec, workflow_id),
442
+ )
410
443
  except:
411
444
  con.rollback()
412
445
  con.close()
@@ -418,18 +451,18 @@ class HistoryManager:
418
451
  @classmethod
419
452
  @db_retry
420
453
  def record_job_attempt(
421
- cls,
422
- workflow_id: str,
423
- workflow_attempt_number: int,
424
- job_name: str,
425
- succeeded: bool,
426
- start_time: float,
427
- runtime: float,
428
- cores: Optional[float] = None,
429
- cpu_seconds: Optional[float] = None,
430
- memory_bytes: Optional[int] = None,
431
- disk_bytes: Optional[int] = None
432
- ) -> None:
454
+ cls,
455
+ workflow_id: str,
456
+ workflow_attempt_number: int,
457
+ job_name: str,
458
+ succeeded: bool,
459
+ start_time: float,
460
+ runtime: float,
461
+ cores: float | None = None,
462
+ cpu_seconds: float | None = None,
463
+ memory_bytes: int | None = None,
464
+ disk_bytes: int | None = None,
465
+ ) -> None:
433
466
  """
434
467
  Record that a job ran in a workflow.
435
468
 
@@ -487,7 +520,7 @@ class HistoryManager:
487
520
  cpu_seconds,
488
521
  memory_bytes,
489
522
  disk_bytes,
490
- )
523
+ ),
491
524
  )
492
525
  except:
493
526
  con.rollback()
@@ -506,12 +539,12 @@ class HistoryManager:
506
539
  succeeded: bool,
507
540
  start_time: float,
508
541
  runtime: float,
509
- batch_system: Optional[str] = None,
510
- caching: Optional[bool] = None,
511
- toil_version: Optional[str] = None,
512
- python_version: Optional[str] = None,
513
- platform_system: Optional[str] = None,
514
- platform_machine: Optional[str] = None
542
+ batch_system: str | None = None,
543
+ caching: bool | None = None,
544
+ toil_version: str | None = None,
545
+ python_version: str | None = None,
546
+ platform_system: str | None = None,
547
+ platform_machine: str | None = None,
515
548
  ) -> None:
516
549
  """
517
550
  Record a workflow attempt (start or restart) having finished or failed.
@@ -561,8 +594,8 @@ class HistoryManager:
561
594
  toil_version,
562
595
  python_version,
563
596
  platform_system,
564
- platform_machine
565
- )
597
+ platform_machine,
598
+ ),
566
599
  )
567
600
  except:
568
601
  con.rollback()
@@ -572,7 +605,6 @@ class HistoryManager:
572
605
  con.commit()
573
606
  con.close()
574
607
 
575
-
576
608
  ##
577
609
  # Read methods
578
610
  ##
@@ -630,8 +662,13 @@ class HistoryManager:
630
662
  total_job_attempts=row["total_job_attempts"],
631
663
  succeeded=(row["succeeded"] == 1),
632
664
  start_time=row["start_time"],
633
- runtime=(row["end_time"] - row["start_time"]) if row["start_time"] is not None and row["end_time"] is not None else None,
634
- trs_spec=row["trs_spec"]
665
+ runtime=(
666
+ (row["end_time"] - row["start_time"])
667
+ if row["start_time"] is not None
668
+ and row["end_time"] is not None
669
+ else None
670
+ ),
671
+ trs_spec=row["trs_spec"],
635
672
  )
636
673
  )
637
674
  except:
@@ -646,7 +683,9 @@ class HistoryManager:
646
683
 
647
684
  @classmethod
648
685
  @db_retry
649
- def get_submittable_workflow_attempts(cls, limit: int = sys.maxsize) -> list[WorkflowAttemptSummary]:
686
+ def get_submittable_workflow_attempts(
687
+ cls, limit: int = sys.maxsize
688
+ ) -> list[WorkflowAttemptSummary]:
650
689
  """
651
690
  List all workflow attempts not yet submitted to Dockstore.
652
691
 
@@ -686,7 +725,7 @@ class HistoryManager:
686
725
  ORDER BY start_time DESC
687
726
  LIMIT ?
688
727
  """,
689
- (limit,)
728
+ (limit,),
690
729
  )
691
730
  for row in cur:
692
731
  attempts.append(
@@ -704,7 +743,7 @@ class HistoryManager:
704
743
  platform_machine=row["platform_machine"],
705
744
  submitted_to_dockstore=(row["submitted_to_dockstore"] == 1),
706
745
  workflow_job_store=row["workflow_job_store"],
707
- workflow_trs_spec=row["workflow_trs_spec"]
746
+ workflow_trs_spec=row["workflow_trs_spec"],
708
747
  )
709
748
  )
710
749
  except:
@@ -719,7 +758,9 @@ class HistoryManager:
719
758
 
720
759
  @classmethod
721
760
  @db_retry
722
- def get_workflow_attempts_with_submittable_job_attempts(cls, limit: int = sys.maxsize) -> list[WorkflowAttemptSummary]:
761
+ def get_workflow_attempts_with_submittable_job_attempts(
762
+ cls, limit: int = sys.maxsize
763
+ ) -> list[WorkflowAttemptSummary]:
723
764
  """
724
765
  Get all workflow attempts that have job attempts not yet submitted to
725
766
  Dockstore.
@@ -769,7 +810,7 @@ class HistoryManager:
769
810
  WHERE workflows.trs_spec IS NOT NULL
770
811
  LIMIT ?
771
812
  """,
772
- (limit,)
813
+ (limit,),
773
814
  )
774
815
  for row in cur:
775
816
  # TODO: Unify row to data class conversion
@@ -788,7 +829,7 @@ class HistoryManager:
788
829
  platform_machine=row["platform_machine"],
789
830
  submitted_to_dockstore=(row["submitted_to_dockstore"] == 1),
790
831
  workflow_job_store=row["workflow_job_store"],
791
- workflow_trs_spec=row["workflow_trs_spec"]
832
+ workflow_trs_spec=row["workflow_trs_spec"],
792
833
  )
793
834
  )
794
835
  except:
@@ -803,7 +844,9 @@ class HistoryManager:
803
844
 
804
845
  @classmethod
805
846
  @db_retry
806
- def get_workflow_attempt(cls, workflow_id: str, attempt_number: int) -> Optional[WorkflowAttemptSummary]:
847
+ def get_workflow_attempt(
848
+ cls, workflow_id: str, attempt_number: int
849
+ ) -> WorkflowAttemptSummary | None:
807
850
  """
808
851
  Get a single (not necessarily unsubmitted, not necessarily TRS-ID-having) workflow attempt summary, if present.
809
852
  """
@@ -843,7 +886,7 @@ class HistoryManager:
843
886
  ORDER BY start_time DESC
844
887
  LIMIT 1
845
888
  """,
846
- (workflow_id, attempt_number)
889
+ (workflow_id, attempt_number),
847
890
  )
848
891
  for row in cur:
849
892
  attempts.append(
@@ -861,7 +904,7 @@ class HistoryManager:
861
904
  platform_machine=row["platform_machine"],
862
905
  submitted_to_dockstore=(row["submitted_to_dockstore"] == 1),
863
906
  workflow_job_store=row["workflow_job_store"],
864
- workflow_trs_spec=row["workflow_trs_spec"]
907
+ workflow_trs_spec=row["workflow_trs_spec"],
865
908
  )
866
909
  )
867
910
  except:
@@ -880,7 +923,9 @@ class HistoryManager:
880
923
 
881
924
  @classmethod
882
925
  @db_retry
883
- def get_unsubmitted_job_attempts(cls, workflow_id: str, attempt_number: int) -> list[JobAttemptSummary]:
926
+ def get_unsubmitted_job_attempts(
927
+ cls, workflow_id: str, attempt_number: int
928
+ ) -> list[JobAttemptSummary]:
884
929
  """
885
930
  List all job attempts in the given workflow attempt not yet submitted to Dockstore.
886
931
 
@@ -915,7 +960,7 @@ class HistoryManager:
915
960
  AND submitted_to_dockstore = FALSE
916
961
  ORDER BY start_time DESC
917
962
  """,
918
- (workflow_id, attempt_number)
963
+ (workflow_id, attempt_number),
919
964
  )
920
965
  for row in cur:
921
966
  attempts.append(
@@ -929,7 +974,7 @@ class HistoryManager:
929
974
  cpu_seconds=row["cpu_seconds"],
930
975
  memory_bytes=row["memory_bytes"],
931
976
  disk_bytes=row["disk_bytes"],
932
- submitted_to_dockstore=(row["submitted_to_dockstore"] == 1)
977
+ submitted_to_dockstore=(row["submitted_to_dockstore"] == 1),
933
978
  )
934
979
  )
935
980
  except:
@@ -948,7 +993,9 @@ class HistoryManager:
948
993
 
949
994
  @classmethod
950
995
  @db_retry
951
- def mark_workflow_attempt_submitted(cls, workflow_id: str, attempt_number: int) -> None:
996
+ def mark_workflow_attempt_submitted(
997
+ cls, workflow_id: str, attempt_number: int
998
+ ) -> None:
952
999
  """
953
1000
  Mark a workflow attempt as having been successfully submitted to Dockstore.
954
1001
 
@@ -964,7 +1011,7 @@ class HistoryManager:
964
1011
  cls.ensure_tables(con, cur)
965
1012
  cur.execute(
966
1013
  "UPDATE workflow_attempts SET submitted_to_dockstore = TRUE WHERE workflow_id = ? AND attempt_number = ?",
967
- (workflow_id, attempt_number)
1014
+ (workflow_id, attempt_number),
968
1015
  )
969
1016
  except:
970
1017
  con.rollback()
@@ -992,7 +1039,7 @@ class HistoryManager:
992
1039
  # Do all the marking in one transaction
993
1040
  cur.execute(
994
1041
  "UPDATE job_attempts SET submitted_to_dockstore = TRUE WHERE id = ?",
995
- (job_attempt_id,)
1042
+ (job_attempt_id,),
996
1043
  )
997
1044
  except:
998
1045
  con.rollback()
@@ -1008,7 +1055,7 @@ class HistoryManager:
1008
1055
  """
1009
1056
  Count workflows in the database.
1010
1057
  """
1011
-
1058
+
1012
1059
  if not cls.enabled():
1013
1060
  return 0
1014
1061
 
@@ -1139,7 +1186,7 @@ class HistoryManager:
1139
1186
  ) = 0
1140
1187
  LIMIT ?
1141
1188
  """,
1142
- (limit,)
1189
+ (limit,),
1143
1190
  )
1144
1191
  for row in cur:
1145
1192
  ids.append(row["id"])
@@ -1185,7 +1232,7 @@ class HistoryManager:
1185
1232
  ORDER BY creation_time ASC
1186
1233
  LIMIT ?
1187
1234
  """,
1188
- (limit,)
1235
+ (limit,),
1189
1236
  )
1190
1237
  for row in cur:
1191
1238
  ids.append(row["id"])
@@ -1216,8 +1263,12 @@ class HistoryManager:
1216
1263
  try:
1217
1264
  cls.ensure_tables(con, cur)
1218
1265
 
1219
- cur.execute("DELETE FROM job_attempts WHERE workflow_id = ?", (workflow_id,))
1220
- cur.execute("DELETE FROM workflow_attempts WHERE workflow_id = ?", (workflow_id,))
1266
+ cur.execute(
1267
+ "DELETE FROM job_attempts WHERE workflow_id = ?", (workflow_id,)
1268
+ )
1269
+ cur.execute(
1270
+ "DELETE FROM workflow_attempts WHERE workflow_id = ?", (workflow_id,)
1271
+ )
1221
1272
  cur.execute("DELETE FROM workflows WHERE id = ?", (workflow_id,))
1222
1273
  except:
1223
1274
  con.rollback()
@@ -1269,13 +1320,13 @@ class HistoryManager:
1269
1320
 
1270
1321
  if not cls.enabled():
1271
1322
  return
1272
-
1323
+
1273
1324
  con = cls.connection()
1274
1325
  cur = con.cursor()
1275
1326
 
1276
1327
  # Don't bother making tables; we don't need them for this and they need
1277
1328
  # a transaction.
1278
-
1329
+
1279
1330
  with cls.no_transaction(con):
1280
1331
  # Do the vacuum outside any transaction, and rely on it to
1281
1332
  # synchronize appropriately internally.
@@ -1324,9 +1375,6 @@ class HistoryManager:
1324
1375
  # Re-check the size
1325
1376
  db_size = cls.get_database_byte_size()
1326
1377
 
1327
-
1328
-
1329
-
1330
1378
  @classmethod
1331
1379
  def database_dump_lines(cls) -> Iterable[str]:
1332
1380
  """
@@ -1339,7 +1387,3 @@ class HistoryManager:
1339
1387
  return []
1340
1388
 
1341
1389
  return cls.connection().iterdump()
1342
-
1343
-
1344
-
1345
-