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
@@ -15,48 +15,71 @@
15
15
  import argparse
16
16
  import logging
17
17
  import sys
18
- from typing import List
19
18
 
20
19
  from toil.common import parser_with_common_options
21
- from toil.provisioners import cluster_factory, NoSuchClusterException
20
+ from toil.provisioners import NoSuchClusterException, cluster_factory
22
21
  from toil.statsAndLogging import set_logging_from_options
23
22
 
24
23
  logger = logging.getLogger(__name__)
25
24
 
26
25
 
27
26
  def main() -> None:
28
- parser = parser_with_common_options(provisioner_options=True, jobstore_option=False, prog="toil ssh-cluster")
29
- parser.add_argument("--insecure", action='store_true',
30
- help="Temporarily disable strict host key checking.")
31
- parser.add_argument("--sshOption", dest='sshOptions', default=[], action='append',
32
- help="Pass an additional option to the SSH command.")
33
- parser.add_argument("--grafana_port", dest='grafana_port', default=3000,
34
- help="Assign a local port to be used for the Grafana dashboard.")
35
- parser.add_argument('args', nargs=argparse.REMAINDER)
27
+ parser = parser_with_common_options(
28
+ provisioner_options=True, jobstore_option=False, prog="toil ssh-cluster"
29
+ )
30
+ parser.add_argument(
31
+ "--insecure",
32
+ action="store_true",
33
+ help="Temporarily disable strict host key checking.",
34
+ )
35
+ parser.add_argument(
36
+ "--sshOption",
37
+ dest="sshOptions",
38
+ default=[],
39
+ action="append",
40
+ help="Pass an additional option to the SSH command.",
41
+ )
42
+ parser.add_argument(
43
+ "--grafana_port",
44
+ dest="grafana_port",
45
+ default=3000,
46
+ help="Assign a local port to be used for the Grafana dashboard.",
47
+ )
48
+ parser.add_argument("args", nargs=argparse.REMAINDER)
36
49
  options = parser.parse_args()
37
50
  set_logging_from_options(options)
38
51
 
39
52
  # Since we collect all the remaining arguments at the end for a command to
40
53
  # run, it's easy to lose options.
41
- if len(options.args) > 0 and options.args[0].startswith('-'):
42
- logger.warning('Argument \'%s\' interpreted as a command to run '
43
- 'despite looking like an option.', options.args[0])
54
+ if len(options.args) > 0 and options.args[0].startswith("-"):
55
+ logger.warning(
56
+ "Argument '%s' interpreted as a command to run "
57
+ "despite looking like an option.",
58
+ options.args[0],
59
+ )
44
60
 
45
- cluster = cluster_factory(provisioner=options.provisioner,
46
- clusterName=options.clusterName,
47
- zone=options.zone)
48
- command = options.args if options.args else ['bash']
49
- sshOptions: List[str] = options.sshOptions
61
+ cluster = cluster_factory(
62
+ provisioner=options.provisioner,
63
+ clusterName=options.clusterName,
64
+ zone=options.zone,
65
+ )
66
+ command = options.args if options.args else ["bash"]
67
+ sshOptions: list[str] = options.sshOptions
50
68
 
51
69
  # Forward ports:
52
70
  # 3000 for Grafana dashboard
53
71
  # 9090 for Prometheus dashboard
54
- sshOptions.extend(['-L', f'{options.grafana_port}:localhost:3000',
55
- '-L', '9090:localhost:9090'])
72
+ sshOptions.extend(
73
+ ["-L", f"{options.grafana_port}:localhost:3000", "-L", "9090:localhost:9090"]
74
+ )
56
75
 
57
76
  try:
58
- cluster.getLeader().sshAppliance(*command, strict=not options.insecure, tty=sys.stdin.isatty(),
59
- sshOptions=sshOptions)
77
+ cluster.getLeader().sshAppliance(
78
+ *command,
79
+ strict=not options.insecure,
80
+ tty=sys.stdin.isatty(),
81
+ sshOptions=sshOptions,
82
+ )
60
83
  except NoSuchClusterException as e:
61
84
  logger.error(e)
62
85
  sys.exit(1)
toil/utils/toilStats.py CHANGED
@@ -18,7 +18,7 @@ import math
18
18
  import sys
19
19
  from argparse import ArgumentParser, Namespace
20
20
  from functools import partial
21
- from typing import Any, Callable, Dict, List, Optional, TextIO, Union
21
+ from typing import Any, Callable, Optional, TextIO, Union
22
22
 
23
23
  from toil.common import Config, Toil, parser_with_common_options
24
24
  from toil.job import Job
@@ -37,7 +37,7 @@ CATEGORY_UNITS = {
37
37
  "clock": "core-s",
38
38
  "wait": "core-s",
39
39
  "memory": "KiB",
40
- "disk": "B"
40
+ "disk": "B",
41
41
  }
42
42
  # These are what we call them to the user
43
43
  TITLES = {
@@ -45,7 +45,7 @@ TITLES = {
45
45
  "clock": "CPU Time",
46
46
  "wait": "CPU Wait",
47
47
  "memory": "Memory",
48
- "disk": "Disk"
48
+ "disk": "Disk",
49
49
  }
50
50
 
51
51
  # Of those, these are in time
@@ -65,6 +65,7 @@ LONG_FORMS = {
65
65
  "max": "max",
66
66
  }
67
67
 
68
+
68
69
  class ColumnWidths:
69
70
  """
70
71
  Convenience object that stores the width of columns for printing. Helps make things pretty.
@@ -74,7 +75,7 @@ class ColumnWidths:
74
75
  self.categories = CATEGORIES
75
76
  self.fields_count = ["count", "min", "med", "ave", "max", "total"]
76
77
  self.fields = ["min", "med", "ave", "max", "total"]
77
- self.data: Dict[str, int] = {}
78
+ self.data: dict[str, int] = {}
78
79
  for category in self.categories:
79
80
  for field in self.fields_count:
80
81
  self.set_width(category, field, 8)
@@ -110,21 +111,27 @@ def pretty_space(k: float, field: Optional[int] = None, alone: bool = False) ->
110
111
  # If we don't have a header to say bytes, include the B.
111
112
  trailer = "B" if alone else ""
112
113
  if k < 1024:
113
- return pad_str("%gKi%s" % (k, trailer), field)
114
+ return pad_str("{:g}Ki{}".format(k, trailer), field)
114
115
  if k < (1024 * 1024):
115
- return pad_str("%.1fMi%s" % (k / 1024.0, trailer), field)
116
+ return pad_str("{:.1f}Mi{}".format(k / 1024.0, trailer), field)
116
117
  if k < (1024 * 1024 * 1024):
117
- return pad_str("%.1fGi%s" % (k / 1024.0 / 1024.0, trailer), field)
118
+ return pad_str("{:.1f}Gi{}".format(k / 1024.0 / 1024.0, trailer), field)
118
119
  if k < (1024 * 1024 * 1024 * 1024):
119
- return pad_str("%.1fTi%s" % (k / 1024.0 / 1024.0 / 1024.0, trailer), field)
120
+ return pad_str(
121
+ "{:.1f}Ti{}".format(k / 1024.0 / 1024.0 / 1024.0, trailer), field
122
+ )
120
123
  if k < (1024 * 1024 * 1024 * 1024 * 1024):
121
- return pad_str("%.1fPi%s" % (k / 1024.0 / 1024.0 / 1024.0 / 1024.0, trailer), field)
124
+ return pad_str(
125
+ "{:.1f}Pi{}".format(k / 1024.0 / 1024.0 / 1024.0 / 1024.0, trailer), field
126
+ )
122
127
 
123
128
  # due to https://stackoverflow.com/questions/47149154
124
129
  assert False
125
130
 
126
131
 
127
- def pretty_time(t: float, field: Optional[int] = None, unit: str = "s", alone: bool = False) -> str:
132
+ def pretty_time(
133
+ t: float, field: Optional[int] = None, unit: str = "s", alone: bool = False
134
+ ) -> str:
128
135
  """
129
136
  Given input t as seconds, return a nicely formatted string.
130
137
  """
@@ -170,7 +177,10 @@ def pretty_time(t: float, field: Optional[int] = None, unit: str = "s", alone: b
170
177
  s = t % 60
171
178
  wPlural = pluralDict[w > 1]
172
179
  dPlural = pluralDict[d > 1]
173
- return pad_str("%dweek%s%dday%s%dh%dm%d%s" % (w, wPlural, d, dPlural, h, m, s, unit_str), field)
180
+ return pad_str(
181
+ "%dweek%s%dday%s%dh%dm%d%s" % (w, wPlural, d, dPlural, h, m, s, unit_str), field
182
+ )
183
+
174
184
 
175
185
  def report_unit(unit: str) -> str:
176
186
  """
@@ -180,7 +190,14 @@ def report_unit(unit: str) -> str:
180
190
  return "core·s"
181
191
  return unit
182
192
 
183
- def report_time(t: float, options: Namespace, field: Optional[int] = None, unit: str = "s", alone: bool = False) -> str:
193
+
194
+ def report_time(
195
+ t: float,
196
+ options: Namespace,
197
+ field: Optional[int] = None,
198
+ unit: str = "s",
199
+ alone: bool = False,
200
+ ) -> str:
184
201
  """Given t seconds, report back the correct format as string."""
185
202
  assert unit in ("s", "core-s")
186
203
  if options.pretty:
@@ -189,11 +206,15 @@ def report_time(t: float, options: Namespace, field: Optional[int] = None, unit:
189
206
  if field is not None:
190
207
  assert field >= len(unit_text)
191
208
  return "%*.2f%s" % (field - len(unit_text), t, unit_text)
192
- return "%.2f%s" % (t, unit_text)
209
+ return "{:.2f}{}".format(t, unit_text)
193
210
 
194
211
 
195
212
  def report_space(
196
- k: float, options: Namespace, field: Optional[int] = None, unit: str = "KiB", alone: bool = False
213
+ k: float,
214
+ options: Namespace,
215
+ field: Optional[int] = None,
216
+ unit: str = "KiB",
217
+ alone: bool = False,
197
218
  ) -> str:
198
219
  """
199
220
  Given k kibibytes, report back the correct format as string.
@@ -216,10 +237,12 @@ def report_space(
216
237
  return "%d%s" % (int(k), trailer)
217
238
 
218
239
 
219
- def report_number(n: Union[int, float, None], field: Optional[int] = None, nan_value: str = "NaN") -> str:
240
+ def report_number(
241
+ n: Union[int, float, None], field: Optional[int] = None, nan_value: str = "NaN"
242
+ ) -> str:
220
243
  """
221
244
  Given a number, report back the correct format as string.
222
-
245
+
223
246
  If it is a NaN or None, use nan_value to represent it instead.
224
247
  """
225
248
  if n is None or math.isnan(n):
@@ -229,7 +252,14 @@ def report_number(n: Union[int, float, None], field: Optional[int] = None, nan_v
229
252
  # leave room for . and the spacing to the previous field.
230
253
  return "%*.*g" % (field, field - 2, n) if field else "%g" % n
231
254
 
232
- def report(v: float, category: str, options: Namespace, field: Optional[int] = None, alone=False) -> str:
255
+
256
+ def report(
257
+ v: float,
258
+ category: str,
259
+ options: Namespace,
260
+ field: Optional[int] = None,
261
+ alone=False,
262
+ ) -> str:
233
263
  """
234
264
  Report a value of the given category formatted as a string.
235
265
 
@@ -248,6 +278,7 @@ def report(v: float, category: str, options: Namespace, field: Optional[int] = N
248
278
  else:
249
279
  raise ValueError(f"Unimplemented unit {unit} for category {category}")
250
280
 
281
+
251
282
  def sprint_tag(
252
283
  key: str,
253
284
  tag: Expando,
@@ -365,15 +396,15 @@ def get(tree: Expando, name: str) -> float:
365
396
  return float("nan")
366
397
 
367
398
 
368
- def sort_jobs(jobTypes: List[Any], options: Namespace) -> List[Any]:
399
+ def sort_jobs(jobTypes: list[Any], options: Namespace) -> list[Any]:
369
400
  """Return a jobTypes all sorted."""
370
401
  sortField = LONG_FORMS[options.sortField]
371
- if (
372
- options.sortCategory in CATEGORIES
373
- ):
402
+ if options.sortCategory in CATEGORIES:
374
403
  return sorted(
375
404
  jobTypes,
376
- key=lambda tag: getattr(tag, "%s_%s" % (sortField, options.sortCategory)),
405
+ key=lambda tag: getattr(
406
+ tag, "{}_{}".format(sortField, options.sortCategory)
407
+ ),
377
408
  reverse=options.sort == "decending",
378
409
  )
379
410
  elif options.sortCategory == "alpha":
@@ -397,7 +428,7 @@ def report_pretty_data(
397
428
  root: Expando,
398
429
  worker: Expando,
399
430
  job: Expando,
400
- job_types: List[Any],
431
+ job_types: list[Any],
401
432
  options: Namespace,
402
433
  ) -> str:
403
434
  """Print the important bits out."""
@@ -426,7 +457,7 @@ def report_pretty_data(
426
457
 
427
458
 
428
459
  def compute_column_widths(
429
- job_types: List[Any], worker: Expando, job: Expando, options: Namespace
460
+ job_types: list[Any], worker: Expando, job: Expando, options: Namespace
430
461
  ) -> ColumnWidths:
431
462
  """Return a ColumnWidths() object with the correct max widths."""
432
463
  cw = ColumnWidths()
@@ -451,12 +482,14 @@ def update_column_widths(tag: Expando, cw: ColumnWidths, options: Namespace) ->
451
482
  cw.set_width(category, field, len(s) + 1)
452
483
 
453
484
 
454
- def build_element(element: Expando, items: List[Job], item_name: str, defaults: Dict[str, float]) -> Expando:
485
+ def build_element(
486
+ element: Expando, items: list[Job], item_name: str, defaults: dict[str, float]
487
+ ) -> Expando:
455
488
  """Create an element for output."""
456
489
 
457
490
  def assertNonnegative(i: float, name: str) -> float:
458
491
  if i < 0:
459
- raise RuntimeError("Negative value %s reported for %s" % (i, name))
492
+ raise RuntimeError("Negative value {} reported for {}".format(i, name))
460
493
  else:
461
494
  return float(i)
462
495
 
@@ -470,12 +503,17 @@ def build_element(element: Expando, items: List[Job], item_name: str, defaults:
470
503
  if category in COMPUTED_CATEGORIES:
471
504
  continue
472
505
  category_key = category if category != "cores" else "requested_cores"
473
- category_value = assertNonnegative(float(item.get(category_key, defaults[category])), category)
506
+ category_value = assertNonnegative(
507
+ float(item.get(category_key, defaults[category])), category
508
+ )
474
509
  values.append(category_value)
475
510
 
476
511
  for index in range(0, len(item_values[CATEGORIES[0]])):
477
512
  # For each item, compute the computed categories
478
- item_values["wait"].append(item_values["time"][index] * item_values["cores"][index] - item_values["clock"][index])
513
+ item_values["wait"].append(
514
+ item_values["time"][index] * item_values["cores"][index]
515
+ - item_values["clock"][index]
516
+ )
479
517
 
480
518
  for category, values in item_values.items():
481
519
  values.sort()
@@ -485,10 +523,7 @@ def build_element(element: Expando, items: List[Job], item_name: str, defaults:
485
523
  for k, v in item_values.items():
486
524
  v.append(0)
487
525
 
488
- item_element = Expando(
489
- total_number=float(len(items)),
490
- name=item_name
491
- )
526
+ item_element = Expando(total_number=float(len(items)), name=item_name)
492
527
 
493
528
  for category, values in item_values.items():
494
529
  item_element["total_" + category] = float(sum(values))
@@ -504,7 +539,7 @@ def build_element(element: Expando, items: List[Job], item_name: str, defaults:
504
539
 
505
540
  def create_summary(
506
541
  element: Expando,
507
- containingItems: List[Expando],
542
+ containingItems: list[Expando],
508
543
  containingItemName: str,
509
544
  count_contained: Callable[[Expando], int],
510
545
  ) -> None:
@@ -599,7 +634,7 @@ def process_data(config: Config, stats: Expando) -> Expando:
599
634
  build_element(collatedStatsTag, jobs, "jobs", defaults),
600
635
  getattr(stats, "workers", []),
601
636
  "worker",
602
- lambda worker: getattr(worker, "jobs_run", 0)
637
+ lambda worker: getattr(worker, "jobs_run", 0),
603
638
  )
604
639
  # Get info for each job
605
640
  jobNames = set()
@@ -684,7 +719,9 @@ def main() -> None:
684
719
 
685
720
  for c in options.categories.split(","):
686
721
  if c.strip().lower() not in CATEGORIES:
687
- logger.critical("Cannot use category %s, options are: %s", c.strip().lower(), CATEGORIES)
722
+ logger.critical(
723
+ "Cannot use category %s, options are: %s", c.strip().lower(), CATEGORIES
724
+ )
688
725
  sys.exit(1)
689
726
  options.categories = [x.strip().lower() for x in options.categories.split(",")]
690
727
 
@@ -696,7 +733,9 @@ def main() -> None:
696
733
  except NoSuchJobStoreException:
697
734
  logger.critical("The job store %s does not exist", config.jobStore)
698
735
  sys.exit(1)
699
- logger.info('Gathering stats from jobstore... depending on the number of jobs, this may take a while (e.g. 10 jobs ~= 3 seconds; 100,000 jobs ~= 3,000 seconds or 50 minutes).')
736
+ logger.info(
737
+ "Gathering stats from jobstore... depending on the number of jobs, this may take a while (e.g. 10 jobs ~= 3 seconds; 100,000 jobs ~= 3,000 seconds or 50 minutes)."
738
+ )
700
739
  stats = get_stats(jobStore)
701
740
  collatedStatsTag = process_data(jobStore.config, stats)
702
741
  report_data(collatedStatsTag, options)