richqueue 0.3__tar.gz → 0.5__tar.gz

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: richqueue
3
- Version: 0.3
3
+ Version: 0.5
4
4
  Summary: RichQueue
5
5
  Project-URL: Homepage, https://github.com/mwinokan/RichQueue/issues
6
6
  Project-URL: Bug Tracker, https://github.com/mwinokan/RichQueue/issues
@@ -3,7 +3,7 @@ requires = ["hatchling"]
3
3
  build-backend = "hatchling.build"
4
4
  [project]
5
5
  name = "richqueue"
6
- version = "0.3"
6
+ version = "0.5"
7
7
  authors = [
8
8
  { name = "Max Winokan", email = "max@winokan.com" },
9
9
  ]
@@ -12,6 +12,7 @@ METADATA = {}
12
12
 
13
13
  app = Typer()
14
14
 
15
+
15
16
  def color_by_state(state):
16
17
 
17
18
  if state == "RUNNING":
@@ -27,10 +28,11 @@ def color_by_state(state):
27
28
  else:
28
29
  return state
29
30
 
31
+
30
32
  def extract_inner(df, key, inner):
31
33
 
32
34
  def _inner(x):
33
- d = x[key]
35
+ d = x[key]
34
36
  if "set" in d:
35
37
  if d["set"]:
36
38
  return d[inner]
@@ -41,11 +43,25 @@ def extract_inner(df, key, inner):
41
43
 
42
44
  df[key] = df.apply(_inner, axis=1)
43
45
 
46
+
44
47
  def extract_time(df, key):
45
48
  df[key] = df.apply(
46
49
  lambda x: datetime.datetime.fromtimestamp(x[key]["number"]), axis=1
47
50
  )
48
51
 
52
+
53
+ def extract_sacct_times(df):
54
+ df["start_time"] = df.apply(
55
+ lambda x: datetime.datetime.fromtimestamp(x["time"]["start"]), axis=1
56
+ )
57
+ df["end_time"] = df.apply(
58
+ lambda x: datetime.datetime.fromtimestamp(x["time"]["end"]), axis=1
59
+ )
60
+ df["submit_time"] = df.apply(
61
+ lambda x: datetime.datetime.fromtimestamp(x["time"]["submission"]), axis=1
62
+ )
63
+
64
+
49
65
  def extract_list(df, key):
50
66
  def inner(x):
51
67
  if len(x[key]) == 1:
@@ -60,6 +76,7 @@ def job_table(
60
76
  df,
61
77
  title: str = "jobs",
62
78
  long: bool = False,
79
+ force_submit_time: bool = False,
63
80
  return_table: bool = False,
64
81
  box: bool = False,
65
82
  panel: bool = True,
@@ -77,6 +94,8 @@ def job_table(
77
94
  num_nodes = "node_count" in df.columns
78
95
  num_cores = "cpus" in df.columns
79
96
  start_time = "start_time" in df.columns
97
+ end_time = "end_time" in df.columns
98
+ submit_time = "submit_time" in df.columns
80
99
 
81
100
  table = Table(title=title, box=box, header_style="")
82
101
 
@@ -95,9 +114,17 @@ def job_table(
95
114
  "[underline magenta]#C", justify="right", style="magenta", no_wrap=True
96
115
  )
97
116
 
117
+ if force_submit_time or long and submit_time:
118
+ table.add_column(
119
+ "[underline dodger_blue2]Submitted",
120
+ justify="right",
121
+ style="dodger_blue2",
122
+ no_wrap=True,
123
+ )
124
+
98
125
  if long and start_time:
99
126
  table.add_column(
100
- "[underline dodger_blue2]Start Time",
127
+ "[underline dodger_blue2]Started",
101
128
  justify="right",
102
129
  style="dodger_blue2",
103
130
  no_wrap=True,
@@ -125,15 +152,20 @@ def job_table(
125
152
  no_wrap=False,
126
153
  )
127
154
 
128
- table.add_column(
129
- "[underline bold]State", justify="left", style=None, no_wrap=True
130
- )
155
+ table.add_column("[underline bold]State", justify="left", style=None, no_wrap=True)
131
156
 
132
157
  for i, row in df.iterrows():
133
158
 
159
+ if submit_time:
160
+ submit_time = human_datetime(row.submit_time)
161
+
134
162
  if start_time:
135
163
  start_time = human_datetime(row.start_time)
136
- run_time = human_timedelta(datetime.datetime.now() - row.start_time)
164
+
165
+ if end_time:
166
+ run_time = human_timedelta(row.end_time - row.start_time)
167
+ else:
168
+ run_time = human_timedelta(datetime.datetime.now() - row.start_time)
137
169
 
138
170
  values = [row.job_id, row["name"]]
139
171
 
@@ -142,6 +174,9 @@ def job_table(
142
174
  if num_cores:
143
175
  values.append(row.cpus)
144
176
 
177
+ if force_submit_time or long and submit_time:
178
+ values.append(submit_time)
179
+
145
180
  if long and start_time:
146
181
  values.append(start_time)
147
182
 
@@ -197,7 +232,6 @@ def parse_squeue_json(payload: dict) -> "DataFrame":
197
232
  extract_inner(df, "cpus_per_task", "number")
198
233
  extract_inner(df, "threads_per_core", "number")
199
234
 
200
- extract_time(df, "end_time")
201
235
  extract_time(df, "start_time")
202
236
  extract_time(df, "submit_time")
203
237
  extract_time(df, "time_limit")
@@ -206,17 +240,20 @@ def parse_squeue_json(payload: dict) -> "DataFrame":
206
240
 
207
241
  return df
208
242
 
243
+
209
244
  def parse_sacct_json(payload: dict) -> "DataFrame":
210
245
 
211
246
  command = "sacct"
212
247
 
213
248
  global METADATA
214
249
 
215
- METADATA.update({
216
- "cluster_name": payload["meta"]["slurm"]["cluster"],
217
- "user": payload["meta"]["client"]["user"],
218
- "group": payload["meta"]["client"]["group"],
219
- })
250
+ METADATA.update(
251
+ {
252
+ "cluster_name": payload["meta"]["slurm"]["cluster"],
253
+ "user": payload["meta"]["client"]["user"],
254
+ "group": payload["meta"]["client"]["group"],
255
+ }
256
+ )
220
257
 
221
258
  # parse payload
222
259
  df = DataFrame(payload["jobs"])
@@ -234,19 +271,11 @@ def parse_sacct_json(payload: dict) -> "DataFrame":
234
271
  if key not in df.columns:
235
272
  raise KeyError(key)
236
273
 
237
- df = df.rename(columns={"user":"user_name", "state":"job_state"})
274
+ df = df.rename(columns={"user": "user_name", "state": "job_state"})
238
275
 
239
276
  extract_inner(df, "job_state", "current")
240
277
 
241
- # extract_number(df, "cpus")
242
- # extract_number(df, "node_count")
243
- # extract_number(df, "cpus_per_task")
244
- # extract_number(df, "threads_per_core")
245
-
246
- # extract_time(df, "end_time")
247
- # extract_time(df, "start_time")
248
- # extract_time(df, "submit_time")
249
- # extract_time(df, "time_limit")
278
+ extract_sacct_times(df)
250
279
 
251
280
  extract_list(df, "job_state")
252
281
 
@@ -254,6 +283,7 @@ def parse_sacct_json(payload: dict) -> "DataFrame":
254
283
 
255
284
  return df
256
285
 
286
+
257
287
  def show_queue(
258
288
  command: str,
259
289
  user: None | str = None,
@@ -296,7 +326,17 @@ def show_queue(
296
326
  else:
297
327
  title = f"[bold]jobs on {cluster}"
298
328
 
299
- return job_table(df, title=title, long=long, return_table=return_table, box=box)
329
+ force_submit_time = command == "sacct"
330
+
331
+ return job_table(
332
+ df,
333
+ title=title,
334
+ long=long,
335
+ force_submit_time=force_submit_time,
336
+ return_table=return_table,
337
+ box=box,
338
+ )
339
+
300
340
 
301
341
  def dual_layout(
302
342
  user: None | str = None,
@@ -313,8 +353,8 @@ def dual_layout(
313
353
  upper = Layout(renderable=panel1, name="upper")
314
354
  lower = Layout(renderable=panel2, name="lower")
315
355
 
316
- upper.size = panel1.renderable.row_count+4
317
- lower.size = panel2.renderable.row_count+4
356
+ upper.size = panel1.renderable.row_count + 4
357
+ lower.size = panel2.renderable.row_count + 4
318
358
 
319
359
  layout.split_column(
320
360
  upper,
@@ -326,6 +366,7 @@ def dual_layout(
326
366
  else:
327
367
  return layout
328
368
 
369
+
329
370
  @app.command()
330
371
  def show(user: None | str = None, long: bool = False):
331
372
 
@@ -355,49 +396,49 @@ def show(user: None | str = None, long: bool = False):
355
396
 
356
397
  def main():
357
398
  app()
358
-
359
- PARSERS = {"squeue":parse_squeue_json, "sacct":parse_sacct_json}
399
+
400
+ PARSERS = {"squeue": parse_squeue_json, "sacct": parse_sacct_json}
360
401
 
361
402
  COLUMNS = {
362
- "sacct":[
363
- "job_id",
364
- "state",
365
- "name",
366
- "nodes",
367
- "partition",
368
- "user",
369
- ],
370
-
371
- "squeue":[
372
- "command",
373
- "cpus_per_task",
374
- "dependency",
375
- "derived_exit_code",
376
- "end_time",
377
- "group_name",
378
- "job_id",
379
- "job_state",
380
- "name",
381
- "nodes",
382
- "node_count",
383
- "cpus",
384
- "tasks",
385
- "partition",
386
- "memory_per_cpu",
387
- "memory_per_node",
388
- "qos",
389
- "restart_cnt",
390
- "requeue",
391
- "exclusive",
392
- "start_time",
393
- "standard_error",
394
- "standard_output",
395
- "submit_time",
396
- "time_limit",
397
- "threads_per_core",
398
- "user_name",
399
- "current_working_directory",
400
- ]}
403
+ "sacct": [
404
+ "job_id",
405
+ "state",
406
+ "name",
407
+ "nodes",
408
+ "partition",
409
+ "user",
410
+ "time",
411
+ ],
412
+ "squeue": [
413
+ "command",
414
+ "cpus_per_task",
415
+ "dependency",
416
+ "derived_exit_code",
417
+ "group_name",
418
+ "job_id",
419
+ "job_state",
420
+ "name",
421
+ "nodes",
422
+ "node_count",
423
+ "cpus",
424
+ "tasks",
425
+ "partition",
426
+ "memory_per_cpu",
427
+ "memory_per_node",
428
+ "qos",
429
+ "restart_cnt",
430
+ "requeue",
431
+ "exclusive",
432
+ "start_time",
433
+ "standard_error",
434
+ "standard_output",
435
+ "submit_time",
436
+ "time_limit",
437
+ "threads_per_core",
438
+ "user_name",
439
+ "current_working_directory",
440
+ ],
441
+ }
401
442
 
402
443
 
403
444
  if __name__ == "__main__":
File without changes
File without changes
File without changes
File without changes
File without changes