2 # _*_ coding: utf-8 _*_
5 A psutil-based command to display customizable system usage info in a single line, intended for Tint2 executors
8 e-mail: nwg.piotr@gmail.com
10 Project: https://github.com/nwg-piotr/psuinfo
13 Inspired by https://github.com/tknomanzr/scripts/blob/master/tint2/executors/cpu.py by William Bradley (@tknomanzr)
29 home
= os
.getenv("HOME")
32 pcpu
, avg
, speed
, freqs
, temp
, fans
, b_time
, memory
, swap
, disks_usage
, which
, ul
, dl
, xfer_start
, xfer_finish
, \
33 path_to_icon
, c_name
= None, None, None, None, None, None, None, None, None, None, None, None, None, None, \
36 for i
in range(1, len(sys
.argv
)):
37 if sys
.argv
[i
] == "-h" or sys
.argv
[i
] == "--help":
41 if sys
.argv
[i
] == "-F":
44 if sys
.argv
[i
] == "-N":
47 if sys
.argv
[i
] == "-T":
50 if sys
.argv
[i
].startswith("-C"):
51 components
= sys
.argv
[i
][2::]
53 if sys
.argv
[i
].startswith("-S"):
56 spacing
= int(sys
.argv
[i
][2::])
57 separator
= " " * spacing
60 separator
= sys
.argv
[i
][2::]
62 if sys
.argv
[i
].startswith("-W"):
64 which
= int(sys
.argv
[i
][2::])
68 if sys
.argv
[i
].upper() == "-ALL":
69 components
= "gpaQStfMcWDUk"
73 if sys
.argv
[i
].startswith("-I"):
75 # We can only have one icon per executor, so let's strip components to the first one
76 components
= sys
.argv
[i
][2]
77 # exception for UL/DL speed; to assign an icon to it we need to calculate speeds first
79 path_to_icon
= icon_path(home
, components
)
81 if sys
.argv
[i
].startswith("-M"):
82 # We can only have a custom name for a single component
83 components
= components
[0]
85 c_name
= sys
.argv
[i
][2::]
88 time_start
= int(round(time
.time() * 1000))
92 # Prepare ONLY requested data, ONLY once
93 if "g" or "p" in components
:
95 pcpu
= psutil
.cpu_percent(interval
=1, percpu
=True)
101 avg
= str(psutil
.cpu_percent(interval
=1))
107 if "s" or "S" in components
:
109 speed
= psutil
.cpu_freq(False)
113 if "q" or "Q" in components
:
115 freqs
= psutil
.cpu_freq(True)
121 if "t" in components
:
123 temp
= psutil
.sensors_temperatures(fahrenheit
)
127 if "f" in components
:
129 fans
= psutil
.sensors_fans()
133 if "m" or "M" or "z" or "Z" in components
:
135 memory
= psutil
.virtual_memory()
139 if "w" or "W" or "x" in components
:
141 swap
= psutil
.swap_memory()
145 if "k" in components
:
147 xfer_start
= psutil
.net_io_counters()
149 xfer_finish
= psutil
.net_io_counters()
150 ul
= (xfer_finish
[0] - xfer_start
[0]) / 1024
151 dl
= (xfer_finish
[1] - xfer_start
[1]) / 1024
152 # We've not selected an icon previously. Now we have enough data.
154 path_to_icon
= net_icon(home
, ul
, dl
)
159 # Find drive names, mountpoints
160 if "d" or "D" or "n" or "N" in components
:
162 d
= psutil
.disk_partitions()
163 # This will store name, mountpoint
165 n
= entry
[0].split("/")
168 drive
= name
, entry
[1]
173 if "d" or "D" in components
:
177 # Search drives by path
178 data
= psutil
.disk_usage(drive
[1])
179 # Store name, used, total, percent
180 essential
= drive
[0].upper(), data
[1], data
[0], data
[3]
181 disks_usage
.append(essential
)
185 if "n" in components
or "N" in components
:
189 # Search drives by path
190 data
= psutil
.disk_usage(drive
[1])
191 # Store mountpoint, used, total, percent
192 essential
= drive
[1], data
[1], data
[0], data
[3]
193 disks_usage
.append(essential
)
197 if "u" or "U" in components
:
199 b_time
= psutil
.boot_time()
203 # Build output component after component
206 for char
in components
:
207 if char
== "g" and pcpu
is not None:
210 output
+= graph_per_cpu(pcpu
) + separator
212 if char
== "p" and pcpu
is not None:
214 output
+= c_name
if c_name
else "CPU: "
215 output
+= per_cpu(pcpu
) + separator
217 if char
== "a" and avg
is not None:
219 output
+= c_name
if c_name
else "avCPU: "
220 output
+= avg
+ "%" + separator
222 if char
== "q" and freqs
is not None:
224 output
+= c_name
if c_name
else "CPU: "
225 output
+= freq_per_cpu(freqs
)[0][:-1] + " GHz" + separator
227 if char
== "Q" and freqs
is not None:
229 output
+= c_name
if c_name
else "CPU: "
230 result
= freq_per_cpu(freqs
)
231 output
+= result
[0][:-1] + "/" + str(result
[1]) + " GHz" + separator
233 if char
== "s" and speed
is not None:
235 output
+= c_name
if c_name
else "SPD: "
236 output
+= str(round(speed
[0] / 1000, 1)) + " GHz" + separator
238 if char
== "S" and speed
is not None:
240 output
+= c_name
if c_name
else "avSPD: "
241 output
+= str(round(speed
[0] / 1000, 1)) + "/" + str(round(speed
[2] / 1000, 1)) + " GHz" + separator
243 if char
== "t" and temp
is not None and len(temp
) > 0:
245 output
+= c_name
if c_name
else "CORE: "
246 if "k10temp" in temp
.keys():
247 # ryzen, multiple Die temperatures for threadripper/Epyc
248 ryzen_die_temps
= [sensor
.current
for sensor
in temp
["k10temp"] if sensor
.label
== 'Tdie']
249 output
+= str(int(max(ryzen_die_temps
)))
250 if "coretemp" in temp
.keys():
252 output
+= str(int(temp
["coretemp"][0][1]))
253 output
+= "℉" if fahrenheit
else "℃"
256 if char
== "f" and fans
is not None and len(fans
) > 0:
258 output
+= c_name
if c_name
else "FAN: "
259 fan0
= next(iter(fans
.values()))
260 output
+= str(fan0
[0][1]) + "/m" + separator
262 if char
== 'm' and memory
is not None:
264 output
+= c_name
if c_name
else "MEM: "
265 output
+= str(round((memory
[0] - memory
[1]) / 1073741824, 1)) + " GB" + separator
267 if char
== 'M' and memory
is not None:
269 output
+= c_name
if c_name
else "MEM: "
270 output
+= str(round((memory
[3]) / 1073741824, 1)) + "/" + str(
271 round(memory
[0] / 1073741824, 1)) + " GB" + separator
273 if char
== 'c' and memory
is not None:
275 output
+= c_name
if c_name
else "MEM: "
276 output
+= str(memory
[2]) + "%" + separator
278 if char
== 'C' and memory
is not None:
280 output
+= c_name
if c_name
else "MEM: "
281 output
+= str(100 - memory
[2]) + "%" + separator
283 if char
== 'u' and b_time
is not None:
284 up_time
= int(time
.time()) - b_time
285 m
, s
= divmod(up_time
, 60)
288 output
+= c_name
if c_name
else "UP: "
289 output
+= "%d:%02d" % (h
, m
) + separator
291 if char
== 'U' and b_time
is not None:
292 up_time
= int(time
.time()) - b_time
293 m
, s
= divmod(up_time
, 60)
296 output
+= c_name
if c_name
else "UP: "
297 output
+= "%d:%02d:%02d" % (h
, m
, s
) + separator
299 if char
== "w" and swap
is not None:
301 output
+= c_name
if c_name
else "SWAP: "
302 output
+= str(round(swap
[1] / 1073741824, 1)) + " GB" + separator
304 if char
== "W" and swap
is not None:
306 output
+= c_name
if c_name
else "SWAP: "
307 output
+= str(round(swap
[1] / 1073741824, 1)) + "/"
308 output
+= str(round(swap
[0] / 1073741824, 1)) + " GB" + separator
310 if char
== "x" and swap
is not None:
312 output
+= c_name
if c_name
else "SWAP: "
313 output
+= str(swap
[3]) + "%" + separator
315 if char
== "d" or char
== "n" and disks_usage
is not None:
316 if which
is not None:
318 entry
= disks_usage
[which
]
319 output
+= entry
[0] + ": "
320 output
+= str(entry
[3]) + "%" + separator
324 for entry
in disks_usage
:
325 output
+= entry
[0] + ": "
326 output
+= str(entry
[3]) + "%" + separator
328 if char
== "D" or char
== "N" and disks_usage
is not None:
331 if which
is not None:
333 entry
= disks_usage
[which
]
334 output
+= entry
[0] + ": "
335 output
+= str(round(entry
[1] / 1073741824, 1)) + "/"
336 output
+= str(round(entry
[2] / 1073741824, 1)) + " GB" + separator
340 for entry
in disks_usage
:
341 output
+= entry
[0] + ": "
342 output
+= str(round(entry
[1] / 1073741824, 1)) + "/"
343 output
+= str(round(entry
[2] / 1073741824, 1)) + " GB" + separator
346 if names
and xfer_start
is not None and xfer_finish
is not None:
347 output
+= c_name
if c_name
else "Net: "
348 output
+= '{:0.2f}'.format((xfer_finish
[0] - xfer_start
[0]) / 1024) + ' {:0.2f} kB/s'.format(
349 (xfer_finish
[1] - xfer_start
[1]) / 1024) + separator
352 output
+= "[" + str(int((round(time
.time() * 1000)) - time_start
) / 1000) + "s]" + separator
354 # remove leading and trailing separator
357 output
= output
[l
:-l
]
368 proc
= str(int(round(val
, 1)))
371 string
+= proc
+ "% "
375 def freq_per_cpu(result
):
379 freq
= str(round(val
[0] / 1000, 1))
381 max_freq
= str(round(val
[2] / 1000, 1))
383 return string
, max_freq
386 def graph_per_cpu(result
):
387 graph
= "_▁▂▃▄▅▆▇███"
391 proc
= int(round(val
/ 10, 0))
392 string
+= graph
[proc
]
398 print("\npsuinfo [-C{components}] | [-I{component}] [-F] [-N] [-S<number>] | [-S<string>] [-T] [-W{number}] [-all] [-h] [--help]")
400 print("\n-C defines multiple components. -I defines a single component. If none given, -CgStfM argument will be used by default.\n")
401 print(" g - (g)raphical CPU load bar")
402 print(" p - (p)ercentage for each core (text)")
403 print(" a - (a)verage CPU load (text)")
404 print(" q - fre(q)ency for each thread")
405 print(" Q - fre(Q)ency for each thread/max frequency")
406 print(" s - current CPU (s)peed")
407 print(" S - current/max CPU (S)peed")
408 print(" t - CPU (t)emperature")
409 print(" f - (f)an speed")
410 print(" m - (m)emory in use")
411 print(" M - (M)emory in use/total")
412 print(" c - used memory per(c)entage")
413 print(" C - free memory per(C)entage")
414 print(" w - s(w)ap memory in use")
415 print(" W - s(W)ap memory in use/total")
416 print(" x - swap usage in %")
417 print(" d - (d)rives as names usage in %")
418 print(" D - (D)rives as names used/total")
419 print(" n - drives as mou(n)tpoints usage in %")
420 print(" N - drives as mou(N)tpoints used/total")
421 print(" u - (u)ptime HH:MM")
422 print(" U - (U)ptime HH:MM:SS")
423 print(" k - current networ(k) traffic as upload/download in kB/s")
425 print("\n-F - use Fahrenheit instead of ℃")
426 print("-N - display field names (except for (g)raphical CPU load bar)")
427 print("-S<number> - number of spaces between components (-S2 if none given)")
428 print("-S<string> for custom separator (use \' | \' to include spaces)")
429 print("-M<string> for custom component name (\'My custom name: \')")
430 print("-T - test execution time")
431 print("-all - display all possible data (for use in terminal)\n")
433 print("-I<component> - show an icon before text; 1 component per executor allowed")
434 print("-W<number> - select 0 to n-th element from multiple output (drives, mountpoints)\n")
437 def icon_path(home
, component
):
447 'm': 'network-card.svg',
448 'M': 'network-card.svg',
449 'c': 'network-card.svg',
450 'C': 'network-card.svg',
454 'd': 'drive-harddisk.svg',
455 'D': 'drive-harddisk.svg',
456 'n': 'drive-harddisk.svg',
457 'N': 'drive-harddisk.svg',
461 f_name
= icons
[component
]
465 return icon_to_use(home
, f_name
)
468 def net_icon(home
, ul
, dl
):
469 f_name
= "knemo-monitor-transmit.svg"
470 return icon_to_use(home
, f_name
)
473 def icon_to_use(home
, f_name
):
474 icon_custom
= home
+ '/.local/share/psuinfo/' + f_name
475 icon_default
= "/usr/share/icons/MB-Mango-Suru-GLOW/devices/16/" + f_name
476 if os
.path
.isfile(icon_custom
):
482 if __name__
== "__main__":