richqueue 0.9__tar.gz → 1.1__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.9
3
+ Version: 1.1
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.9"
6
+ version = "1.1"
7
7
  authors = [
8
8
  { name = "Max Winokan", email = "max@winokan.com" },
9
9
  ]
@@ -31,3 +31,4 @@ include = [
31
31
 
32
32
  [project.scripts]
33
33
  rq = "richqueue.main:main"
34
+ confucius = "richqueue.wisdom:main"
@@ -0,0 +1,142 @@
1
+ from typer import Typer, Option
2
+ from typing import Optional
3
+ from typing_extensions import Annotated
4
+ from .layout import dual_layout
5
+ from rich.live import Live
6
+ import time
7
+ from .console import console
8
+ from .tools import curry
9
+ from .slurm import (
10
+ get_layout_pair,
11
+ get_node_layout,
12
+ get_hist_layout,
13
+ get_job_layout,
14
+ NotOnClusterError,
15
+ )
16
+
17
+ # set up singletons
18
+ app = Typer()
19
+
20
+
21
+ # main CLI command
22
+ @app.callback(invoke_without_command=True)
23
+ def show(
24
+ user: Annotated[
25
+ str,
26
+ Option(
27
+ "-u",
28
+ "--user",
29
+ help="Query jobs for this user. Use 'all' to see all jobs",
30
+ ),
31
+ ] = None,
32
+ long: Annotated[bool, Option("-v", "--long", help="More detailed output")] = False,
33
+ idle: Annotated[bool, Option("-i", "--idle", help="Show available nodes")] = False,
34
+ loop: Annotated[
35
+ bool, Option("-l", "--loop", help="Show a live-updating screen")
36
+ ] = True,
37
+ hist: Annotated[
38
+ int, Option("-h", "--hist", help="Show historical jobs from the last X weeks")
39
+ ] = None,
40
+ hist_unit: Annotated[
41
+ str,
42
+ Option("-hu", "--hist-unit", help="Show historical jobs from the last X weeks"),
43
+ ] = "weeks",
44
+ job: Annotated[
45
+ int, Option("-j", "--job", help="Show details for a specific job")
46
+ ] = None,
47
+ wisdom: Annotated[
48
+ bool, Option("-w", "--wisdom", help="Show a confucius quote on exit")
49
+ ] = False,
50
+ ):
51
+
52
+ screen = True
53
+ disappear = not screen
54
+
55
+ kwargs = {
56
+ "user": user,
57
+ "long": long,
58
+ "idle": idle,
59
+ "loop": loop,
60
+ "hist": hist,
61
+ "hist_unit": hist_unit,
62
+ "screen": screen,
63
+ "disappear": disappear,
64
+ "job": job,
65
+ }
66
+
67
+ # console.print(kwargs)
68
+
69
+ match (bool(idle), bool(hist), bool(job)):
70
+ case (True, False, False):
71
+ loop = False
72
+ layout_func = get_node_layout
73
+ case (False, True, False):
74
+ loop = False
75
+ layout_func = get_hist_layout
76
+ case (False, False, True):
77
+ layout_func = get_job_layout
78
+ case (False, False, False):
79
+ layout_func = curry(dual_layout, get_layout_pair)
80
+ case _:
81
+ raise Exception("Unsupported CLI options")
82
+
83
+ try:
84
+
85
+ # live updating layout
86
+ if loop:
87
+
88
+ layout = layout_func(**kwargs)
89
+
90
+ with Live(
91
+ layout,
92
+ refresh_per_second=4,
93
+ screen=screen,
94
+ transient=disappear,
95
+ vertical_overflow="visible",
96
+ ) as live:
97
+
98
+ try:
99
+ while True:
100
+ layout = layout_func(**kwargs)
101
+ live.update(layout)
102
+ time.sleep(1)
103
+ except KeyboardInterrupt:
104
+ live.stop()
105
+ if wisdom:
106
+ from .wisdom import print_random_quote
107
+
108
+ print_random_quote()
109
+
110
+ # static layout
111
+ else:
112
+
113
+ layout = layout_func(**kwargs)
114
+ console.print(layout)
115
+
116
+ except NotOnClusterError as e:
117
+ console.print(f"[red bold]{e}[reset]")
118
+
119
+
120
+ @app.command()
121
+ def log(job: Annotated[int, Option(help="Show logs from a specific job")]):
122
+ raise NotImplementedError
123
+
124
+
125
+ @app.command()
126
+ def dir(job: Annotated[int, Option(help="Get job directory")]):
127
+ raise NotImplementedError
128
+
129
+
130
+ @app.command()
131
+ def nickname():
132
+ raise NotImplementedError
133
+
134
+
135
+ # start Typer app
136
+ def main():
137
+ app()
138
+
139
+
140
+ # start Typer app
141
+ if __name__ == "__main__":
142
+ app()
@@ -161,16 +161,7 @@ def get_squeue(
161
161
  payload = json.loads(output[0])
162
162
 
163
163
  except json.JSONDecodeError:
164
- # console.print('[orange1 bold]Warning: using example data')
165
-
166
- if job:
167
- example = "squeue_job.json"
168
- else:
169
- example = "squeue_long.json"
170
-
171
- payload = json.load(
172
- open(Path(__file__).parent.parent / "example_data" / example, "rt")
173
- )
164
+ raise NotOnClusterError("Could not get sinfo JSON. Not on a SLURM cluster?")
174
165
 
175
166
  global METADATA
176
167
 
@@ -237,15 +228,17 @@ def get_sacct(
237
228
  output = process.communicate()
238
229
  payload = json.loads(output[0])
239
230
  except json.JSONDecodeError:
231
+ raise NotOnClusterError("Could not get sacct JSON. Not on a SLURM cluster?")
232
+
240
233
  # console.print('[orange1 bold]Warning: using example data')
241
- if job:
242
- example = "sacct_job.json"
243
- else:
244
- example = "sacct.json"
234
+ # if job:
235
+ # example = "sacct_job.json"
236
+ # else:
237
+ # example = "sacct.json"
245
238
 
246
- payload = json.load(
247
- open(Path(__file__).parent.parent / "example_data" / example, "rt")
248
- )
239
+ # payload = json.load(
240
+ # open(Path(__file__).parent.parent / "example_data" / example, "rt")
241
+ # )
249
242
 
250
243
  global METADATA
251
244
 
@@ -295,9 +288,7 @@ def get_sinfo(**kwargs) -> "pandas.DataFrame":
295
288
  output = process.communicate()
296
289
  payload = json.loads(output[0])
297
290
  except json.JSONDecodeError:
298
- payload = json.load(
299
- open(Path(__file__).parent.parent / "example_data" / "sinfo_N.json", "rt")
300
- )
291
+ raise NotOnClusterError("Could not get sinfo JSON. Not on a SLURM cluster?")
301
292
 
302
293
  global METADATA
303
294
 
@@ -476,3 +467,6 @@ COLUMNS = {
476
467
  "current_working_directory",
477
468
  ],
478
469
  }
470
+
471
+
472
+ class NotOnClusterError(Exception): ...
@@ -317,6 +317,7 @@ RUNNING_JOB_COLUMNS = {
317
317
  "submit_time",
318
318
  "start_time",
319
319
  "run_time",
320
+ "time_limit",
320
321
  "partition",
321
322
  "nodes",
322
323
  "job_state",
@@ -328,6 +329,7 @@ RUNNING_JOB_COLUMNS = {
328
329
  "cpus",
329
330
  "start_time",
330
331
  "run_time",
332
+ "time_limit",
331
333
  "job_state",
332
334
  ],
333
335
  }
@@ -498,7 +500,7 @@ COLUMNS = {
498
500
  "requeue": {"header": "Requeue?", "style": "green_yellow"},
499
501
  "exclusive": {"header": "Exclusive?", "style": "green_yellow"},
500
502
  "time_limit": {
501
- "header": "[underline dodger_blue2]Time Limit",
503
+ "header": "[underline dodger_blue2]Limit",
502
504
  "justify": "right",
503
505
  "style": "dodger_blue2",
504
506
  "no_wrap": True,
@@ -12,6 +12,9 @@ def human_timedelta(delta):
12
12
 
13
13
  bits = []
14
14
 
15
+ if delta.days < 0 or delta.seconds < 0:
16
+ return ""
17
+
15
18
  days = delta.days
16
19
 
17
20
  s = delta.seconds
@@ -0,0 +1,336 @@
1
+ from random import sample
2
+ from .console import console
3
+ from rich.table import Table
4
+ from rich.text import Text
5
+ from rich.panel import Panel
6
+ from rich.layout import Layout
7
+ from rich.padding import Padding
8
+ from typer import Typer
9
+
10
+ import textwrap
11
+
12
+ app = Typer()
13
+
14
+
15
+ @app.callback(invoke_without_command=True)
16
+ def print_random_quote():
17
+
18
+ width = console.size.width
19
+
20
+ if width < 12 + PADDING * 2:
21
+ return
22
+
23
+ quote = sample(QUOTES, 1)[0]
24
+ index = QUOTES.index(quote)
25
+
26
+ lines = [""]
27
+
28
+ paragraphs = [""]
29
+ for c in quote:
30
+ if c == "\n":
31
+ paragraphs.append("")
32
+ else:
33
+ paragraphs[-1] += c
34
+
35
+ for i, paragraph in enumerate(paragraphs):
36
+
37
+ if len(paragraph) == 0:
38
+ lines.append("")
39
+ continue
40
+
41
+ if i == 0:
42
+ first_padding = " " * PADDING
43
+ else:
44
+ first_padding = " " * (PADDING + 1)
45
+
46
+ subsequent_padding = " " * (PADDING + 1)
47
+
48
+ if i == 0:
49
+ paragraph = f'"{paragraph}'
50
+
51
+ if i + 1 == len(paragraphs):
52
+ paragraph = f'{paragraph}"'
53
+
54
+ lines += textwrap.wrap(
55
+ paragraph,
56
+ width=width - PADDING,
57
+ replace_whitespace=False,
58
+ initial_indent=first_padding,
59
+ subsequent_indent=subsequent_padding,
60
+ )
61
+
62
+ lines.append("")
63
+
64
+ longest = max(len(l) for l in lines)
65
+ signoff = f"-CONFUCIUS #{index+1}"
66
+ lines.append(" " * (longest - len(signoff)) + f"[italic]{signoff}[reset]")
67
+
68
+ lines.append("")
69
+
70
+ for line in lines:
71
+ console.print(line, highlight=False)
72
+
73
+
74
+ PADDING = 6
75
+
76
+ QUOTES = [
77
+ "DO IT TOMORROW",
78
+ "DO DFT TOMORROW",
79
+ "HOW 'BOUT NAH",
80
+ "STYLE OVER SUBSTANCE",
81
+ "I'M NOT CHINESE",
82
+ "TO DRIVE A TANK SIMPLY USE DRUIDRY TO TRANSFORM INTO A TANK DRIVER",
83
+ "IF THE GAUSSIAN FAILS TWICE CONSECUTIVELY, GIVE UP",
84
+ "THE FEWER HOURS YOU WORK ON A FIXED SALARY THE HIGHER YOUR HOURLY PAY", # MW
85
+ "COMP. CHEM IS TEMPORARY. CONFUCIUS IS FOREVER",
86
+ "BETTER TO ASK FOR FORGIVENESS THAN PERMISSION",
87
+ "DO YOU THINK I WANT TO BE HERE?",
88
+ "READ THE FUCKING MANUAL",
89
+ "NEVER GIVE A COW FREE MILK",
90
+ "FOR BETTER OR FOR WORSE I'LL ALWAYS HAVE ANOTHER COFFEE", # MW
91
+ "I'M A BIG PROPONENT FOR HAVING FUN", # MW
92
+ "I WOULDN'T BET MY LIFE ON IT",
93
+ "DEATH DOES NOT PROTECT YOU FROM CRITICISM",
94
+ "SOMETIMES YOU HAVE TO SPEND MONEY TO MAKE MONEY.\n\nSOMETIMES YOU HAVE TO SPEND MONEY TO LOSE MONEY.\n\nONE THING'S FOR SURE, YOU HAVE TO SPEND MONEY.", # Rust Valley Restorers
95
+ "PREMATURE JOB FAILURE IS NOTHING TO BE ASHAMED OF",
96
+ "LOUIE TOLD ME WHAT TO DO AND I DID MY BEST TO FUCK IT UP",
97
+ "IT IS IMPOSSIBLE TO REVERSE THE CREATION OF A CAKE",
98
+ "CAKE CAN BE CREATED AND DESTROYED",
99
+ "I CAN HEAR BUT I CAN'T LISTEN",
100
+ "I'M BETTER THAN THE MANUAL",
101
+ "BEFORE TRYING, CONSULT ME",
102
+ "CODE FIRST, THINK LATER",
103
+ "WHEN IN DOUBT, CROSS PRODUCT",
104
+ "CHEMIS[bold]DO[/bold] OR CHEMIS[bold]DON'T[/bold] THERE IS NO CHEMIS[bold]TRY[/bold]",
105
+ "I HATE IT HERE",
106
+ "I DIDN'T SIGN UP FOR THIS",
107
+ "I DON'T UNDERSTAND WHY PEOPLE WOULD CHOOSE TO BE A BIOLOGIST",
108
+ "I HATE PAST ME",
109
+ "SOUNDS LIKE A FUTURE ME PROBLEM",
110
+ "I STRUGGLE TO FIND PEACE",
111
+ "I HEREBY CLASSIFY THIS AS A ROYAL BALL ACHE",
112
+ "I'M ALL OUT OF PASSION",
113
+ "WHAT IS A DECIMAL PLACE BETWEEN FRIENDS?",
114
+ "[bold italic]OF COURSE",
115
+ "[dodger_blue2 bold] 🇬🇷 OF COURSE [/bold /dodger_blue2]",
116
+ "ΩΦ KΩΥΡΣΕ",
117
+ "FRENCH? SO YOU'RE EASY TO SATISFY",
118
+ "YOU DON'T WANT TO FINISH TOO EARLY",
119
+ "BOLD AND UNPROVEN",
120
+ "WHERE IS MY GIRAFFE??", # CV
121
+ "THIS IS A HIPPOPOTAMUS",
122
+ "MONOGAMOUS ENTANGLEMENT",
123
+ "INVEST IN A STRAP-ON",
124
+ "[bold italic]FRIZZ OFF", # AC
125
+ "I'M FRIZZED OFF", # AC
126
+ "I'M GONNA GO TO THAT BUS STATION TOMORROW AND KICK MIKE'S ASS",
127
+ "STRUGGLING FROM SUCCESS",
128
+ "I'D SHOW YOU MINE; BUT I DON'T THINK YOU'D LIKE IT",
129
+ "I'M SEVERAL RAKI'S DEEP",
130
+ "DON'T ASK ME QUESTIONS THAT COULD HAVE CONSEQUENCES",
131
+ "ENORMOUS DRAGON OF FAECES, DANCING INSIDE ME", # FB
132
+ "I HAD A CRISIS OF FAITH IN MY RESEARCH, BUT THEN I REALISED THAT IT'S FINE",
133
+ "IT DEPENDS",
134
+ "KIND OF A PROOF",
135
+ "THE DEAD CAT CAN BE A RESOURCE",
136
+ "WITH A TALK LIKE THAT YOU CAN EXPECT TO MEET A PERSON\nWHO TOTALLY DISAGREES WITH EVERYTHING YOU SAID.\nYOU WILL FIND THAT PERSON IN ME", # Moritz @ QuEBS 2022
137
+ "MIDNIGHT MEAT",
138
+ "EXISTENCE IS CANCER",
139
+ "IT'S A PITY THEY FOUND A CURE FOR LEPROSY", # QuEBS 2022 Excursion
140
+ "[bold italic]MEOW", # RG
141
+ "DON’T KNOW DON’T CARE",
142
+ "INTERESTING TRANSFER DOWN THESE RODS",
143
+ # "DISSEMINATE THROUGHOUT THE UK",
144
+ "DUMPING MY PUMP ON",
145
+ "KINDA TOXIC, BUT DON’T WORRY ABOUT THAT",
146
+ "WHACKING GREAT ABSORBER", # AM
147
+ "I KNOW YOU’RE THEORISTS, AND THIS IS VERY MUDDY",
148
+ "I HAVE A PROPENSITY FOR THE DENSITY", # AB @ QuEBS 2022
149
+ "OH MY [bold]GOODNESS[/bold]", # GF
150
+ "YOU ARE UNDERMINING MY AUTHORITY", # unknown @ QuEBS 2022
151
+ "TO BE WEAK, IS ACTUALLY AN ADVANTAGE ",
152
+ "SPEEDY BOARDING",
153
+ "THE PHILOSOPHICAL SIGNIFICANCE OF POO",
154
+ "THE CAFFEINE IS A MATTER OF LIFE AND DEATH ",
155
+ "IT’S ALMOST CERTAINLY WRONG, BUT FUN",
156
+ "THAT WOULD HAVE BEEN WISE, HOWEVER, I AM NOT A WISE MAN",
157
+ "THAT MAKES YOU THINK SOFT",
158
+ "I WOULD ARGUE THAT BARE LEGS IS BETTER",
159
+ "ANYTHING IS MICROSCOPIC IF IT’S FAR AWAY ENOUGH",
160
+ "AN ERROR OCCURRED, HOW IS THAT EVEN SCIENTIFICALLY POSSIBLE",
161
+ "YOU HEAR THAT? THAT’S A TARDIGRADE",
162
+ "I SEEM TO HAVE LOST CONTROL [OF MY MOUSE]",
163
+ "THERE’S NO ANSWER, BY THE WAY",
164
+ "BECAUSE OF SOME PHYSICS ",
165
+ "PSEUDO-WEAK",
166
+ "THESE BALLS ARE JUST REGULAR SHINY", # MW
167
+ "THE LAST COUP KIND OF FIZZLED OUT",
168
+ "I THINK IT’S STRAIGHT SO IT MUST BE ERADICATED",
169
+ "KOBE BEEF IS ALSO FAMOUSLY DEAD COW",
170
+ "I’VE ALSO DECIDED I AM NOT A MORAL PERSON",
171
+ "IT WAS ONLY AN EMPTY THREAT", # JJMF
172
+ "THREATS ARE A PART OF WORKING LIFE", # JJMF
173
+ "WELL THE THREAT WORKED!", # JJMF
174
+ "AN EMPTY THREAT IS STILL A THREAT",
175
+ "WHAT DO YOU THINK I’M SOME SORT OF PEPSI CRACK WHORE?",
176
+ "LOW IMPACT FACTOR? I WANT LOW IMPACT ON MY LIFE!",
177
+ "NOT F*CK YO MAMA F*CK YO-YO MA!",
178
+ "I FORGOT ABOUT THE PASSAGE OF TIME",
179
+ "EVERYTHING IS JUST A BIG WEIRD LIGAND",
180
+ "IT NEEDS TO TASTE GOOD, AND KILL YOU", # CV
181
+ "MY ABILITY TO SEE FUNKINESS REQUIRES EXPERIENCE", # ISQBP 2022
182
+ "HISTIDINE IS A PROBLEM",
183
+ "I HATE THE FACT THAT THEY SPENT SO MUCH TIME ON THESE QUOTES, INSTEAD OF IMPROVING THEIR SIMULATION SOFTWARE", # Gromacs
184
+ "BUTTER MUSS SEIN",
185
+ "I DON’T NEED A CONTROL BECAUSE I DON’T HAVE ANY RESULTS",
186
+ "LET THE ANIMAL EAT FIBRE, AND THEN EAT THE ANIMAL",
187
+ "THAT’S NOT A SHOT MATE!!",
188
+ "FUCK AROUND AND FIND OUT",
189
+ "♫♬♪[bold]OH MON BEBE[/bold]", # Les Kaira
190
+ "WHY DID TOM CHEATHAM KILL US LAST NIGHT?", # ISQBP 2022
191
+ "NOSE-HOOVER? SO LIKE A COCAINE ADDICT?",
192
+ "YOU CAN SLEEP ON A BANANA",
193
+ "AMBER AND I BROKE UP", # MW
194
+ "WE WENT TOO FAR",
195
+ "THEY GOT JIGGLY PHYSICS?",
196
+ "DO YOU WANT TO SEE MY STUFF JIGGLING?",
197
+ "WE DON’T SEE COLOURS HERE, WE JUST SEE BALLS",
198
+ "IN MY OPINION THIS IS EXACTLY WHAT IS WRONG WITH SCIENCE",
199
+ "I DIDN’T REALISE YOU WERE A NONCE",
200
+ "I HEARD YOU LIKE FINISHING EARLY",
201
+ "JOIN THE QUANTUM BIOLOGY DISCORD SERVER! #GAMERSRISEUP",
202
+ "WE SHOULD GET SOMETHING VENOMOUS LIKE A PLATYPUS",
203
+ "THERE IS TOO MUCH ON YOUTUBE ABOUT PLATYPUS CUSTARD",
204
+ "I DON'T BELIEVE IN GRANDCHILDREN",
205
+ "WINNING IS NEVER AN OPTION, ONLY REVENGE",
206
+ "FEDERICO’S ALLEYWAY BOUQUET", # MW
207
+ "SENT FROM MY GALAXY",
208
+ " _______\n / 12 \\ \n| | |\n|9 | 3|\n| \\ |\n| |\n \\___6___/\n\nGOOD HEAVENS, LOOK AT THE TIME!",
209
+ # "Har🌳-Frick ✝️ ",
210
+ "BRANEURISM\n\nSymptoms:\tlight-headed, delirium, dyslexic, autism, chicken sounds, flowcharts",
211
+ f" LISTEN TO PHAT BRAHMS\n | \\\n V \\\n EAT KATSU \\ IS IT FRIDAY? ----> WAIT\n | \\ | Yes ^ No |\n V \\ V L-----------\n SPIN MESMERISING SPIN ORB | IS HILLSIDE OPEN? ---> KATSU\n | | | \n V ^ V \n [bold]BRANEURYSM[/bold] | IS YOUNG'S OPEN ---> KATSU\n / \\ | | \n /YES \\ | V\n L NO------->--------| IS MAX IN THE OFFICE?\nKATSU COMA | | Yes \\ No\n ----<---- \\\n END THE DAY\n",
212
+ "I WOULDN’T PAY £100 FOR A WET DREAM,\nFOR £100 I CAN GET A WET REALITY",
213
+ "I KNOW YOUR FUTURE… BUT I’LL TELL YOU AFTER I GO TO THE LOO",
214
+ "YOU ARE HEADING FOR A SMACK",
215
+ "[bold]F*CK!!! WHY ARE THESE GUYS SUCH *$#@'S?![/bold]\n\n...\n\nI NEED ANOTHER COFFEE, I'M NOT ON EDGE ENOUGH.", # MW
216
+ "RESULTS ARE A SOCIAL CONSTRUCT",
217
+ "AUTISOMANCY",
218
+ "IS A HANGING MAN STANDING ON A BOX THAT HE IS HOLDING BENEATH HIS FEET A PERPETUAL MOTION MACHINE?",
219
+ "HAVE YOU READ KARL MARX'S LATEST TWEET?",
220
+ "WE NEED MORE GAY SCIENCE",
221
+ "IF WE OVERCOME THIS I WILL JERK FROM NOW UNTIL THE NEXT YEAR", # FB
222
+ "DO LOOK A THIEVING STUFFED DOUGHNUT IN THE ASS",
223
+ "YOU'RE NOT HUMAN UNTIL YOU'VE BEEN CITED", # LS
224
+ "TRUE [bold]AND[/bold] FALSE",
225
+ "EINSTEIN? LARGELY A B*TCH",
226
+ "I’M SCARED TO GO TO TEXAS, PEOPLE JUST SHOOTING ME", # MS
227
+ "YOU’RE WRONG WITH THAT, YOU’RE ABSOLUTELY WRONG WITH THAT", # MS, supervisory meeting
228
+ "WE SHOULD GET AN OFFICE DILDO",
229
+ "AIDS SALIVA IS A-OK, SO YOU CAN GIVE THAT WHISTLE A SUCK",
230
+ "NO ONE EVER SAID NOT TO EAT YELLOW RICE",
231
+ "WALRUSES RAPING PENGUINS FOR REASONS THAT ARE NOT YET CLEAR",
232
+ "THEY NEVER SAID DON'T EAT YELLOW RICE",
233
+ "RUINING PEOPLE'S CAREERS BY KEEPING THEM IN THE SAME PLACE JUST BECAUSE I DID", # JAK
234
+ "WHEN I FIRST STARTED LECTURING I DID A LOT OF BUM WIGGLING", # JAK
235
+ "I DON'T UNDERSTAND HAVING VALUES",
236
+ "PISS",
237
+ "THAT'S THE ONLY REASON I'M NOT EATING YOUR FACE OFF RIGHT NOW",
238
+ "DOUBLE-TEAMED BY GERIATRICS",
239
+ "LIMPINGCHAN",
240
+ "LET'S HAVE A QUICK CHAT? I NEED TO VENT SOME ANGER!",
241
+ "THE FRENCHMAN BURNS EASILY",
242
+ "WHY IS THE BROWN ALWAYS CAUSING PROBLEMS",
243
+ "QUANTUM NATIONALISM",
244
+ "THERE IS NO SUCH THING AS TIME",
245
+ "IS OUR BANANA CORRECT?",
246
+ "WOULD YOU RATHER:\n\nWALLACE HAMMERING FOR AN HOUR\n\nOR\n\nA BRIEF AL-QAEDA MOMENT?",
247
+ "THE CONSPIRACY GROWS",
248
+ "YOU'RE LOOKING GUILTIER BY THE SECOND",
249
+ "I HAD TO MAKE SOMETHING, BUT I ONLY DESTROY",
250
+ "QUANTUM CRY FOR HELP",
251
+ "QB SOS",
252
+ "UNFORUNATELY THE JAVA VERSION ON EUREKA IS TOO OLD TO RUN MINECRAFT", # MW
253
+ "NOBODY CARES, ESPECIALLY ME",
254
+ "GEOGRAPHICALLY-CHALLENGED",
255
+ "I GUESS THAT'S ONE GOOD THING ABOUT FASCISTS",
256
+ "TESTICLES HAVE SO MUCH POTENTIAL",
257
+ "WHENEVER IN DOUBT, GIVE LOUIE A SHOUT",
258
+ "IF IN MOGADISHU, TELL LOUIE 'I MISS YOU'",
259
+ "IF YOU'RE IN A PICKLE, GIVE LOUIE A TICKLE",
260
+ "DOORS - UNLIKE PEOPLE - CAN BE UNFUCKED", # MW
261
+ "ARE YOU GOING TO GO TO HIS OFFICE, LIFT HIS ARMS UP AND GET YOUR FINGERS IN THERE?",
262
+ "I CANNOT RIPEN MY OWN BANANA",
263
+ "I DO BELIEVE!",
264
+ "GREAT MINDS THINK THE SAME JUNK",
265
+ """HI EVERYONE. HOW DO YOU KEEP WORKING WITH A COLLABORATOR IF YOUR LAST MEETING ENDED WITH YOU SAYING "SPARE ME THIS USELESS AND AGGRESSIVE RHETORIC, 'CAUSE I DON'T NEED IT, OR CARE ABOUT IT"?""",
266
+ "LUCKILY SCIENCE AND DFT CALCULATIONS, DO NOT CARE ABOUT YOUR IMPRESSION OF THEM", # FB
267
+ "I WAS ONLY DOING AN IMPRESSION OF A NONCE!",
268
+ "I GUESS WE ALL LEAVE AS FLESH",
269
+ "SHOULD I BUY AN END OF LIFE PLANNER FOR MY PHD?", # EN
270
+ "WE NEED MORE MONEY TO MAKE STUDENTS SUFFER",
271
+ "I WON'T TELL YOU WHAT TO DO, I'LL JUST JUDGE YOU",
272
+ "NO, YOU DO NOT NEED TO STAY IN QB.\nAND YOU MIGHT NOT WANT TO DO SO",
273
+ "SHIT CODE IS THE FIRST STEP TO NOT SHIT CODE", # MW
274
+ "GRANTS MAKE IT RAIN!",
275
+ "YOU CAN'T GET DRUNK ON PISS",
276
+ "CAN'T GET CANCELLED IF YOU'RE NOT FAMOUS",
277
+ "I'M STARTING TO BELIEVE THESE ARE NOT REAL CONFUCIUS QUOTES", # MS
278
+ "WOULD YOU RATHER MAKE LOVE TO AN EYE OR A FOOT?", # unknown @ MMC 2023
279
+ "QUANTUM PHYSICS MEANS THAT ANYTHING CAN HAPPEN AT ANY TIME, FOR NO REASON", # Futurama
280
+ "I WOULD BE SCHLOBBIN ON SOMEONE'S KNOB FOR THAT", # LS
281
+ "THERE IS NO GREAT LOVE, WITHOUT GREAT JEALOUSY", # Futurama
282
+ "THE BAD BOYS WON'T WAIT ALL NIGHT", # MW @ ABC 2023
283
+ "YOU WON'T BELIEVE WHAT THIS OLD ITALIAN MAN PUT IN MY MIND",
284
+ "THERE'S NOTHING NATURAL ABOUT AVERAGING COORDINATES", # ABC 2023
285
+ "ONIONS DON'T HURT ME",
286
+ "THAT WAS BEFORE I DISCOVERED TURKISH MEN", # RG @ ABC 2023
287
+ "ALL COSTS ARE SUBSTANTIAL",
288
+ "ALWAYS A GOOD IDEA TO BLAME THE FRENCH",
289
+ "CHEESE, SEX AND ALIENS", # about a museum in Basel
290
+ "YOU HAVE TO ACCEPT YOUR MISERY",
291
+ "COSTA RICA WAS A SIMULATION WITH THE WRONG FORCE FIELD", # Leandro @ ABC 2023
292
+ "LOW ENTROPY REGION OF NERDS",
293
+ "THANK YOU FOR BEING WILLING", # MW @ ABC 2023
294
+ "HELLO STALKERS, COME TO ME",
295
+ "YOU'RE ALWAYS ON THE RECEIVING END OF THE MOOSE SHAFTING",
296
+ "IT'S A COCKTAIL OF SHIT",
297
+ "F*CK HIM, CARVE YOUR OWN PATH", # LS about Löwdin
298
+ "I AM A STRAIGHT WHITE WHALE",
299
+ "TO KILL A MONKEYBIRD",
300
+ "LAZINESS LEADS TO THE ULTIMATE CREATIVITY",
301
+ "DO YOU KNOW HOW TO READ [bold]FACIAL[/bold] LIPS?",
302
+ "THERE'S TOO MANY BALD BASTARDS",
303
+ "MAYBE YOU'RE THE D&D CHARACTER OF SOMEONE ELSE, AND THEY ARE DOING A REALLY BAD JOB",
304
+ "THIS IS NOT AN ACT OF GOD, IT IS PITY",
305
+ "FREUD'S THEORY ON GRAPEFRUITING YOUR DAD",
306
+ "NORMALLY IT'S SHIT. BUT TODAY, IT'S [bold]EXCEPTIONALLY[/bold] SHIT",
307
+ "WHAT ARE THESE REVOLUTIONARY LOOKING FIGURES? AH YES, HEXAGONS",
308
+ "IF YOU ABUSE THEM, THEY'LL MOVE",
309
+ "IT'S NOT SEXUAL HARASSMENT, IT'S A COMPLIMENT",
310
+ "NOT A GOOD CRAZY",
311
+ "EVENTUALLY YOU HAVE TO CARE ABOUT [bold]SOMETHING[/bold]",
312
+ "DON'T PUSH THE RIVER", # MW
313
+ "THE DILDO OF CONSEQUENCES RARELY ARRIVES PRE-LUBED", # REDDIT
314
+ "IT'S ALL UNDER CONTROL", # TH
315
+ "THERE IS NO FUN WITHOUT VIOLENCE", # GF
316
+ "AN UBER IS TRANSIENT BUT SWIM TRUNKS ARE FOREVER", # MW
317
+ "IT'S NOT STEALING IF YOU PIONEER SOMETHING", # MW
318
+ "THE SUFFERING IS OPTIONAL",
319
+ "THAT'S THANKS TO LOUIE, AIMEE, AND - IT PAINS ME TO SAY IT - GEORGE", # alex jones @ QuEBS 2023
320
+ "HOME IS WHERE YOUR CHEEKS IMPRESS", # MW
321
+ "YOUR NUTS ARE DOING A REAL JOB ON MY THROAT", # MW
322
+ "VICIOUS CIRCLE OF BOLLOCKING", # RL, XChem, Aug 2023
323
+ "CROWDS GATHER TO WITNESS THE FIRST PANINI ARRIVE IN IRELAND", # Waterford Whispers News
324
+ "BLESSED ARE THE TOASTED SANDWICH MAKERS", # Waterford Whispers News
325
+ "BEEF JESUS DIED FOR OUR SINS", # MW
326
+ "I'M NOT IN A PICKLE, I'M IN A POTENTIAL WELL",
327
+ "THE ELECTRON IDENTITY CRISIS",
328
+ "TOY STORY IS A SOCIAL COMMENTARY ON THE MEASUREMENT PROBLEM",
329
+ "DO YOU THINK SOME STUDENTS JUST AREN'T INTELLIGENT ENOUGH?",
330
+ "YOU DON'T NEED A DEBUGGER. YOU NEED A PRIEST", # MW
331
+ "IF THE PAPER YOU WANT TO READ DOESN'T EXIST, WRITE IT", # MW
332
+ "THE WORLD IS YOUR HOSTAGE", #
333
+ ]
334
+
335
+ if __name__ == "__main__":
336
+ app()
@@ -1,94 +0,0 @@
1
- from typer import Typer
2
- from .layout import dual_layout
3
- from rich.live import Live
4
- import time
5
- from .console import console
6
- from .tools import curry
7
- from .slurm import get_layout_pair, get_node_layout, get_hist_layout, get_job_layout
8
-
9
- # set up singletons
10
- app = Typer()
11
-
12
- # main CLI command
13
-
14
-
15
- @app.command()
16
- def show(
17
- user: None | str = None,
18
- long: bool = False,
19
- idle: bool = False,
20
- loop: bool = True,
21
- hist: int | None = None,
22
- hist_unit: str = "weeks",
23
- job: int | None = None,
24
- # screen: bool = True,
25
- # disappear: bool = True,
26
- ):
27
-
28
- screen = True
29
- disappear = not screen
30
-
31
- kwargs = {
32
- "user": user,
33
- "long": long,
34
- "idle": idle,
35
- "loop": loop,
36
- "hist": hist,
37
- "hist_unit": hist_unit,
38
- "screen": screen,
39
- "disappear": disappear,
40
- "job": job,
41
- }
42
-
43
- # console.print(kwargs)
44
-
45
- match (bool(idle), bool(hist), bool(job)):
46
- case (True, False, False):
47
- loop = False
48
- layout_func = get_node_layout
49
- case (False, True, False):
50
- loop = False
51
- layout_func = get_hist_layout
52
- case (False, False, True):
53
- layout_func = get_job_layout
54
- case (False, False, False):
55
- layout_func = curry(dual_layout, get_layout_pair)
56
- case _:
57
- raise Exception("Unsupported CLI options")
58
-
59
- # live updating layout
60
- if loop:
61
-
62
- layout = layout_func(**kwargs)
63
-
64
- with Live(
65
- layout,
66
- refresh_per_second=4,
67
- screen=screen,
68
- transient=disappear,
69
- vertical_overflow="visible",
70
- ) as live:
71
-
72
- try:
73
- while True:
74
- layout = layout_func(**kwargs)
75
- live.update(layout)
76
- time.sleep(1)
77
- except KeyboardInterrupt:
78
- live.stop()
79
-
80
- # static layout
81
- else:
82
-
83
- layout = layout_func(**kwargs)
84
- console.print(layout)
85
-
86
-
87
- # start Typer app
88
- def main():
89
- app()
90
-
91
-
92
- # start Typer app
93
- if __name__ == "__main__":
94
- app()
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes