371 temperatures #962

Merged
merged 19 commits into from Feb 1, 2017
Jump to file or symbol
Failed to load files and symbols.
+217 −2
Diff settings

Always

Just for now

View
@@ -181,6 +181,21 @@ Network
{'eth0': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_FULL: 2>, speed=100, mtu=1500),
'lo': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_UNKNOWN: 0>, speed=0, mtu=65536)}
+Sensors (Linux only)
+====================
+
+.. code-block:: python
+
+ >>> import psutil
+ >>> psutil.sensors_temperatures()
+ {'acpitz': [shwtemp(label='', current=47.0, high=103.0, critical=103.0)],
+ 'asus': [shwtemp(label='', current=47.0, high=None, critical=None)],
+ 'coretemp': [shwtemp(label='Physical id 0', current=52.0, high=100.0, critical=100.0),
+ shwtemp(label='Core 0', current=45.0, high=100.0, critical=100.0),
+ shwtemp(label='Core 1', current=52.0, high=100.0, critical=100.0),
+ shwtemp(label='Core 2', current=45.0, high=100.0, critical=100.0),
+ shwtemp(label='Core 3', current=47.0, high=100.0, critical=100.0)]}
+
Other system info
=================
View
@@ -617,6 +617,41 @@ Network
.. versionadded:: 3.0.0
+Sensors
+-------
+
+.. function:: sensors_temperatures(fahrenheit=False)
+
+ Return hardware temperatures. Each entry is a namedtuple representing a
+ certain hardware sensor (it may be a CPU, an hard disk or something
+ else, depending on the OS and its configuration).
+ All temperatures are expressed in celsius unless *fahrenheit* is set to
+ ``True``. Example::
+
+ >>> import psutil
+ >>> psutil.sensors_temperatures()
+ {'acpitz': [shwtemp(label='', current=47.0, high=103.0, critical=103.0)],
+ 'asus': [shwtemp(label='', current=47.0, high=None, critical=None)],
+ 'coretemp': [shwtemp(label='Physical id 0', current=52.0, high=100.0, critical=100.0),
+ shwtemp(label='Core 0', current=45.0, high=100.0, critical=100.0),
+ shwtemp(label='Core 1', current=52.0, high=100.0, critical=100.0),
+ shwtemp(label='Core 2', current=45.0, high=100.0, critical=100.0),
+ shwtemp(label='Core 3', current=47.0, high=100.0, critical=100.0)]}
+
+ See also `sensors.py <https://github.com/giampaolo/psutil/blob/master/scripts/sensors.py>`__
+ for an example application.
+
+ .. warning::
+
+ This API is experimental. Backwards incompatible changes may occur if
+ deemed necessary.
+
+ Availability: Linux
+
+ .. versionadded:: 5.1.0
+
+
+
Other system info
-----------------
View
@@ -185,6 +185,7 @@
"net_io_counters", "net_connections", "net_if_addrs", # network
"net_if_stats",
"disk_io_counters", "disk_partitions", "disk_usage", # disk
+ # "sensors_temperatures", # sensors
"users", "boot_time", # others
]
__all__.extend(_psplatform.__extra__all__)
@@ -2180,6 +2181,50 @@ def net_if_stats():
return _psplatform.net_if_stats()
+# =====================================================================
+# --- sensors
+# =====================================================================
+
+
+if hasattr(_psplatform, "sensors_temperatures"):
+
+ def sensors_temperatures(fahrenheit=False):
+ """Return hardware temperatures. Each entry is a namedtuple
+ representing a certain hardware sensor (it may be a CPU, an
+ hard disk or something else, depending on the OS and its
+ configuration).
+ All temperatures are expressed in celsius unless *fahrenheit*
+ is set to True.
+ """
+ def to_fahrenheit(n):
+ return (float(n) * 9 / 5) + 32
+
+ ret = collections.defaultdict(list)
+ rawdict = _psplatform.sensors_temperatures()
+
+ for name, values in rawdict.items():
+ while values:
+ label, current, high, critical = values.pop(0)
+ if fahrenheit:
+ current = to_fahrenheit(current)
+ if high is not None:
+ high = to_fahrenheit(high)
+ if critical is not None:
+ critical = to_fahrenheit(critical)
+
+ if high and not critical:
+ critical = high
+ elif critical and not high:
+ high = critical
+
+ ret[name].append(
+ _common.shwtemp(label, current, high, critical))
+
+ return dict(ret)
+
+ __all__.append("sensors_temperatures")
+
+
# =====================================================================
# --- other system related functions
# =====================================================================
View
@@ -158,6 +158,9 @@ class NicDuplex(enum.IntEnum):
'scpustats', ['ctx_switches', 'interrupts', 'soft_interrupts', 'syscalls'])
# psutil.cpu_freq()
scpufreq = namedtuple('scpufreq', ['current', 'min', 'max'])
+# psutil.sensors_temperatures()
+shwtemp = namedtuple(
+ 'shwtemp', ['label', 'current', 'high', 'critical'])
# --- for Process methods
View
@@ -7,6 +7,7 @@
from __future__ import division
import base64
+import collections
import errno
import functools
import glob
@@ -64,6 +65,7 @@
HAS_SMAPS = os.path.exists('/proc/%s/smaps' % os.getpid())
HAS_PRLIMIT = hasattr(cext, "linux_prlimit")
+_DEFAULT = object()
# RLIMIT_* constants, not guaranteed to be present on all kernels
if HAS_PRLIMIT:
@@ -1059,6 +1061,47 @@ def disk_partitions(all=False):
return retlist
+# =====================================================================
+# --- sensors
+# =====================================================================
+
+
+if os.path.exists('/sys/class/hwmon'):
+
+ def sensors_temperatures():
+ """Return hardware (CPU and others) temperatures as a dict
+ including hardware name, label, current, max and critical
+ temperatures.
+
+ Implementation notes:
+ - /sys/class/hwmon looks like the most recent interface to
+ retrieve this info, and this implementation relies on it
+ only (old distros will probably use something else)
+ - lm-sensors on Ubuntu 16.04 relies on /sys/class/hwmon
+ - /sys/class/thermal/thermal_zone* is another one but it's more
+ difficult to parse
+ """
+ ret = collections.defaultdict(list)
+ basenames = sorted(set(
+ [x.split('_')[0] for x in
+ glob.glob('/sys/class/hwmon/hwmon*/temp*_*')]))
+ for base in basenames:
+ unit_name = cat(os.path.join(os.path.dirname(base), 'name'))
+ label = cat(base + '_label', fallback='')
+ current = float(cat(base + '_input')) / 1000.0
+ high = cat(base + '_max', fallback=None)
+ critical = cat(base + '_crit', fallback=None)
+
+ if high is not None:
+ high = float(high) / 1000.0
+ if critical is not None:
+ critical = float(critical) / 1000.0
+
+ ret[unit_name].append((label, current, high, critical))
+
+ return ret
+
+
# =====================================================================
# --- other system functions
# =====================================================================
@@ -382,6 +382,12 @@ psutil_winservice_query_descr(PyObject *self, PyObject *args) {
bytesNeeded = 0;
QueryServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION, NULL, 0,
&bytesNeeded);
+ if (GetLastError() == ERROR_MUI_FILE_NOT_FOUND) {
+ // Also services.msc fails in the same manner, so we return an
+ // empty string.
+ CloseServiceHandle(hService);
+ return Py_BuildValue("s", "");
+ }
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
PyErr_SetFromWindowsErr(0);
goto error;
@@ -388,7 +388,7 @@ def assert_syntax(self, exe, args=None):
src = f.read()
ast.parse(src)
- def test_check_presence(self):
+ def test_coverage(self):
# make sure all example scripts have a test method defined
meths = dir(self)
for name in os.listdir(SCRIPTS_DIR):
@@ -469,6 +469,12 @@ def test_winservices(self):
def test_cpu_distribution(self):
self.assert_syntax('cpu_distribution.py')
+ def test_sensors(self):
+ if hasattr(psutil, "sensors_temperatures"):
+ self.assert_stdout('sensors.py')
+ else:
+ self.assert_syntax('sensors.py')
+
# ===================================================================
# --- Unit tests for test utilities.
@@ -1808,10 +1808,10 @@ def cwd(self, ret, proc):
try:
st = os.stat(ret)
except OSError as err:
- # directory has been removed in mean time
if WINDOWS and err.errno in \
psutil._psplatform.ACCESS_DENIED_SET:
pass
+ # directory has been removed in mean time
elif err.errno != errno.ENOENT:
raise
else:
@@ -29,6 +29,7 @@
from psutil import SUNOS
from psutil import WINDOWS
from psutil._compat import long
+from psutil._compat import unicode
from psutil.tests import AF_INET6
from psutil.tests import APPVEYOR
from psutil.tests import check_net_address
@@ -755,6 +756,21 @@ def test_os_constants(self):
for name in names:
self.assertIs(getattr(psutil, name), False, msg=name)
+ @unittest.skipUnless(hasattr(psutil, "sensors_temperatures"),
+ "platform not suported")
+ def test_sensors_temperatures(self):
+ temps = psutil.sensors_temperatures()
+ for name, entries in temps.items():
+ self.assertIsInstance(name, (str, unicode))
+ for entry in entries:
+ self.assertIsInstance(entry.label, (str, unicode))
+ if entry.current is not None:
+ self.assertGreaterEqual(entry.current, 0)
+ if entry.high is not None:
+ self.assertGreaterEqual(entry.high, 0)
+ if entry.critical is not None:
+ self.assertGreaterEqual(entry.critical, 0)
+
if __name__ == '__main__':
run_test_module_by_name(__file__)
View
@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+A clone of 'sensors' utility on Linux printing hardware temperatures.
+
+$ python scripts/sensors.py
+asus
+ asus 47.0 °C (high = None °C, critical = None °C)
+
+acpitz
+ acpitz 47.0 °C (high = 103.0 °C, critical = 103.0 °C)
+
+coretemp
+ Physical id 0 54.0 °C (high = 100.0 °C, critical = 100.0 °C)
+ Core 0 47.0 °C (high = 100.0 °C, critical = 100.0 °C)
+ Core 1 48.0 °C (high = 100.0 °C, critical = 100.0 °C)
+ Core 2 47.0 °C (high = 100.0 °C, critical = 100.0 °C)
+ Core 3 54.0 °C (high = 100.0 °C, critical = 100.0 °C)
+"""
+
+from __future__ import print_function
+import sys
+
+import psutil
+
+
+def main():
+ if not hasattr(psutil, "sensors_temperatures"):
+ sys.exit("platform not supported")
+ temps = psutil.sensors_temperatures()
+ for name, entries in temps.items():
+ print(name)
+ for entry in entries:
+ print(" %-20s %s °C (high = %s °C, critical = %s °C)" % (
+ entry.label or name, entry.current, entry.high,
+ entry.critical))
+ print()
+
+
+if __name__ == '__main__':
+ main()