diff --git a/psutil/_pslinux.py b/psutil/_pslinux.py index 1575dad9d..a69b1d664 100644 --- a/psutil/_pslinux.py +++ b/psutil/_pslinux.py @@ -1213,6 +1213,50 @@ def sensors_temperatures(): ret[unit_name].append((label, current, high, critical)) + # Indication that no sensors were detected in /sys/class/hwmon/ + if not basenames: + basenames = glob.glob('/sys/class/thermal/thermal_zone*') + basenames = sorted(set(basenames)) + + for base in basenames: + try: + path = os.path.join(base, 'temp') + current = float(cat(path)) / 1000.0 + path = os.path.join(base, 'type') + unit_name = cat(path, binary=False) + except (IOError, OSError, ValueError) as err: + warnings.warn("ignoring %r for file %r" % (err, path), + RuntimeWarning) + continue + + trip_paths = glob.glob(base + '/trip_point*') + trip_points = set(['_'.join( + os.path.basename(p).split('_')[0:3]) for p in trip_paths]) + critical = None + high = None + for trip_point in trip_points: + path = os.path.join(base, trip_point + "_type") + trip_type = cat(path, fallback='', binary=False) + if trip_type == 'critical': + critical = cat(os.path.join(base, trip_point + "_temp"), + fallback=None) + elif trip_type == 'high': + high = cat(os.path.join(base, trip_point + "_temp"), + fallback=None) + + if high is not None: + try: + high = float(high) / 1000.0 + except ValueError: + high = None + if critical is not None: + try: + critical = float(critical) / 1000.0 + except ValueError: + critical = None + + ret[unit_name].append(('', current, high, critical)) + return ret diff --git a/psutil/tests/test_linux.py b/psutil/tests/test_linux.py index a8e7a5e34..299c110fe 100755 --- a/psutil/tests/test_linux.py +++ b/psutil/tests/test_linux.py @@ -1466,6 +1466,8 @@ def test_emulate_eio_error(self): def open_mock(name, *args, **kwargs): if name.endswith("_input"): raise OSError(errno.EIO, "") + elif name.endswith("temp"): + raise OSError(errno.EIO, "") else: return orig_open(name, *args, **kwargs) @@ -1477,7 +1479,7 @@ def open_mock(name, *args, **kwargs): assert m.called self.assertIn("ignoring", str(ws[0].message)) - def test_emulate_data(self): + def test_emulate_class_hwmon(self): def open_mock(name, *args, **kwargs): if name.endswith('/name'): return io.StringIO(u("name")) @@ -1495,6 +1497,7 @@ def open_mock(name, *args, **kwargs): orig_open = open patch_point = 'builtins.open' if PY3 else '__builtin__.open' with mock.patch(patch_point, side_effect=open_mock): + # Test case with /sys/class/hwmon with mock.patch('glob.glob', return_value=['/sys/class/hwmon/hwmon0/temp1']): temp = psutil.sensors_temperatures()['name'][0] @@ -1503,6 +1506,41 @@ def open_mock(name, *args, **kwargs): self.assertEqual(temp.high, 40.0) self.assertEqual(temp.critical, 50.0) + def test_emulate_class_thermal(self): + def open_mock(name, *args, **kwargs): + if name.endswith('0_temp'): + return io.BytesIO(b"50000") + elif name.endswith('temp'): + return io.BytesIO(b"30000") + elif name.endswith('0_type'): + return io.StringIO(u("critical")) + elif name.endswith('type'): + return io.StringIO(u("name")) + else: + return orig_open(name, *args, **kwargs) + + def glob_mock(path): + if path == '/sys/class/hwmon/hwmon*/temp*_*': + return [] + elif path == '/sys/class/hwmon/hwmon*/device/temp*_*': + return [] + elif path == '/sys/class/thermal/thermal_zone*': + return ['/sys/class/thermal/thermal_zone0'] + elif path == '/sys/class/thermal/thermal_zone0/trip_point*': + return ['/sys/class/thermal/thermal_zone1/trip_point_0_type', + '/sys/class/thermal/thermal_zone1/trip_point_0_temp'] + + orig_open = open + patch_point = 'builtins.open' if PY3 else '__builtin__.open' + with mock.patch(patch_point, side_effect=open_mock): + + with mock.patch('glob.glob', create=True, side_effect=glob_mock): + temp = psutil.sensors_temperatures()['name'][0] + self.assertEqual(temp.label, '') + self.assertEqual(temp.current, 30.0) + self.assertEqual(temp.high, 50.0) + self.assertEqual(temp.critical, 50.0) + @unittest.skipIf(not LINUX, "LINUX only") class TestSensorsFans(unittest.TestCase):