import os
from multiprocessing import cpu_count as _cpu_count
from powerline.lib.threaded import ThreadedSegment
from powerline.lib import add_divider_highlight_group
from powerline.segments import with_docstring
from powerline.theme import requires_segment_info
cpu_count = None
[docs]def system_load(pl, format='{avg:.1f}', threshold_good=1, threshold_bad=2,
track_cpu_count=False, short=False):
'''Return system load average.
Highlights using ``system_load_good``, ``system_load_bad`` and
``system_load_ugly`` highlighting groups, depending on the thresholds
passed to the function.
:param str format:
format string, receives ``avg`` as an argument
:param float threshold_good:
threshold for gradient level 0: any normalized load average below this
value will have this gradient level.
:param float threshold_bad:
threshold for gradient level 100: any normalized load average above this
value will have this gradient level. Load averages between
``threshold_good`` and ``threshold_bad`` receive gradient level that
indicates relative position in this interval:
(``100 * (cur-good) / (bad-good)``).
Note: both parameters are checked against normalized load averages.
:param bool track_cpu_count:
if True powerline will continuously poll the system to detect changes
in the number of CPUs.
:param bool short:
if True only the sys load over last 1 minute will be displayed.
Divider highlight group used: ``background:divider``.
Highlight groups used: ``system_load_gradient`` (gradient) or ``system_load``.
Click values supplied: ``avg`` (string), ``avg_raw`` (int)
'''
global cpu_count
try:
cpu_num = cpu_count = _cpu_count() if cpu_count is None or track_cpu_count else cpu_count
except NotImplementedError:
pl.warn('Unable to get CPU count: method is not implemented')
return None
ret = []
for avg in os.getloadavg():
normalized = avg / cpu_num
if normalized < threshold_good:
gradient_level = 0
elif normalized < threshold_bad:
gradient_level = (normalized - threshold_good) * 100.0 / (threshold_bad - threshold_good)
else:
gradient_level = 100
ret.append({
'contents': format.format(avg=avg),
'highlight_groups': ['system_load_gradient', 'system_load'],
'divider_highlight_group': 'background:divider',
'gradient_level': gradient_level,
'click_values': {'avg':format.format(avg=avg), 'avg_raw':avg}
})
if short:
return ret
ret[0]['contents'] += ' '
ret[1]['contents'] += ' '
return ret
try:
import psutil
class CPULoadPercentSegment(ThreadedSegment):
interval = 1
def update(self, old_cpu):
return psutil.cpu_percent(interval=None)
def run(self):
while not self.shutdown_event.is_set():
try:
self.update_value = psutil.cpu_percent(interval=self.interval)
except Exception as e:
self.exception('Exception while calculating cpu_percent: {0}', str(e))
def render(self, cpu_percent, format='{0:.0f}%', threshold=None, **kwargs):
if cpu_percent is None or (threshold and cpu_percent < threshold):
return None
return [{
'contents': format.format(cpu_percent),
'gradient_level': cpu_percent,
'highlight_groups': ['cpu_load_percent_gradient', 'cpu_load_percent'],
'click_values': {'cpu_load': format.format(cpu_percent), 'cpu_load_raw': cpu_percent}
}]
except ImportError:
[docs] class CPULoadPercentSegment(ThreadedSegment):
interval = 1
@staticmethod
def startup(**kwargs):
pass
@staticmethod
def start():
pass
@staticmethod
def shutdown():
pass
@staticmethod
def render(cpu_percent, pl, format='{0:.0f}%', threshold=None **kwargs):
pl.warn('Module “psutil” is not installed, thus CPU load is not available')
return None
cpu_load_percent = with_docstring(CPULoadPercentSegment(),
'''Return the average CPU load as a percentage.
Requires the ``psutil`` module.
:param str format:
Output format. Accepts measured CPU load as the first argument.
:param int threshold:
Minimum load to display the segment (in percent)
Highlight groups used: ``cpu_load_percent_gradient`` (gradient) or ``cpu_load_percent``.
Click values supplied: ``cpu_load`` (string), ``cpu_load_raw`` (int)
''')
[docs]@requires_segment_info
def memory_usage(pl, segment_info, format='{percent:.1f}% {absolute:.1f}G/{total:.1f}G', threshold_good=20, threshold_bad=80, short_format='{percent:.1f}%', auto_shrink=False):
'''Return memory usage
Requires the ``psutil`` module
:param str format:
format string, receives ``percent``, ``absolute``, and ``total`` as arguments
:param string short_format:
optional shorter format when the powerline needs to shrink segments
:param bool auto_shrink:
if set to true, this segment will use ``short_format`` per default,
only using ``format`` when any message is present on the ``memory_usage``
message channel.
:param float threshold_good:
threshold for gradient level 0: any memory usage percentage below this
value will have this gradient level.
:param float threshold_bad:
threshold for gradient level 100: any memory usage percentage above this
value will have this gradient level. Load averages between
``threshold_good`` and ``threshold_bad`` receive gradient level that
indicates relative position in this interval:
(``100 * (cur-good) / (bad-good)``).
Highlight groups used: ``memory_usage_gradient`` (gradient) or ``memory_usage``.
Click values supplied: ``memory_usage`` (string), ``percent`` (float), ``absolute`` (float), ``total`` (float)
'''
payload_name = 'memory_usage'
try:
import psutil
except ImportError:
pl.warn('Missing psutil')
return None
info = psutil.virtual_memory()
percentage = info.percent
total_gb = info.total / (1024 * 1024 * 1024)
used_gb = info.used / (1024 * 1024 * 1024)
gradient_level = (max(min(percentage, threshold_bad), threshold_good) - threshold_good) * 100.0 / (threshold_bad - threshold_good)
selected_format = short_format
if not auto_shrink or ('payloads' in segment_info and payload_name in segment_info['payloads'] and segment_info['payloads'][payload_name]):
selected_format = format
text = selected_format.format(percent=percentage, absolute=used_gb, total=total_gb)
return [{
'contents': str(text),
'highlight_groups': ['memory_usage_gradient', 'memory_usage'],
'gradient_level': gradient_level,
'click_values': {'memory_usage': text, 'percent': percentage, 'absolute': used_gb, 'total': total_gb}
}]
if os.path.exists('/proc/uptime'):
def _get_uptime():
with open('/proc/uptime', 'r') as f:
return int(float(f.readline().split()[0]))
elif 'psutil' in globals():
from time import time
if hasattr(psutil, 'boot_time'):
def _get_uptime():
return int(time() - psutil.boot_time())
else:
def _get_uptime():
return int(time() - psutil.BOOT_TIME)
else:
def _get_uptime():
raise NotImplementedError
[docs]@add_divider_highlight_group('background:divider')
def uptime(pl, days_format='{days:d}d', hours_format=' {hours:d}h', minutes_format=' {minutes:d}m',
seconds_format=' {seconds:d}s', format=None, shorten_len=3):
'''Return system uptime.
:param str days_format:
day format string, will be passed ``days`` as the argument
:param str hours_format:
hour format string, will be passed ``hours`` as the argument
:param str minutes_format:
minute format string, will be passed ``minutes`` as the argument
:param str seconds_format:
second format string, will be passed ``seconds`` as the argument
:param int shorten_len:
shorten the amount of units (days, hours, etc.) displayed
Divider highlight group used: ``background:divider``.
'''
try:
seconds = _get_uptime()
except NotImplementedError:
pl.warn('Unable to get uptime. You should install psutil module')
return None
minutes, seconds = divmod(seconds, 60)
hours, minutes = divmod(minutes, 60)
days, hours = divmod(hours, 24)
time_formatted = list(filter(None, [
days_format.format(days=days) if days_format else None,
hours_format.format(hours=hours) if hours_format else None,
minutes_format.format(minutes=minutes) if minutes_format else None,
seconds_format.format(seconds=seconds) if seconds_format else None,
]))
first_non_zero = next((i for i, x in enumerate([days, hours, minutes, seconds]) if x != 0))
time_formatted = time_formatted[first_non_zero:first_non_zero + shorten_len]
return ''.join(time_formatted).strip()
[docs]def temp(pl, format='{:.1f}°C', path="/sys/class/thermal/thermal_zone0/temp", accuracy=0.001, lowtemp=20, hightemp=80):
'''
Returns the temperature
:param string format:
Output format
:param string path:
Path of the file containing the temperature
:param int accuracy:
Accuracy to read
Click values supplied: ``temp`` (string), ``temp_raw`` (int)
'''
with open(path, "r") as f:
temp = int(f.read()) * accuracy
return [{
'contents': format.format(temp),
'highlight_groups': ['temp'],
'gradient_level': 100 * min(1, max(0, (temp-lowtemp) / (hightemp-lowtemp))),
'click_values': {'temp': format.format(temp), 'temp_raw': temp}
}]