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.
- {richqueue-0.3 → richqueue-0.5}/PKG-INFO +1 -1
- {richqueue-0.3 → richqueue-0.5}/pyproject.toml +1 -1
- {richqueue-0.3 → richqueue-0.5}/richqueue/slurm.py +107 -66
- {richqueue-0.3 → richqueue-0.5}/.gitignore +0 -0
- {richqueue-0.3 → richqueue-0.5}/LICENSE +0 -0
- {richqueue-0.3 → richqueue-0.5}/README.md +0 -0
- {richqueue-0.3 → richqueue-0.5}/richqueue/__init__.py +0 -0
- {richqueue-0.3 → richqueue-0.5}/richqueue/tools.py +0 -0
|
@@ -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]
|
|
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
|
-
|
|
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
|
-
|
|
217
|
-
|
|
218
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
"squeue":[
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
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
|