diff options
author | Giampaolo Rodola <g.rodola@gmail.com> | 2016-02-24 09:31:48 -0800 |
---|---|---|
committer | Giampaolo Rodola <g.rodola@gmail.com> | 2016-02-24 09:31:48 -0800 |
commit | a8c97637fa64c6e08f235396686d1512a2c0ed42 (patch) | |
tree | 9178b7b0f29a186dfed323858374c62b6d8dfef7 | |
parent | 38652a6d5d6a205fb6ddeac255a76c0345a9c026 (diff) | |
parent | 4470230e440c9df4a21707163d1837c2ec607318 (diff) | |
download | psutil-a8c97637fa64c6e08f235396686d1512a2c0ed42.tar.gz |
Merge branch 'master' of github.com:giampaolo/psutil
-rw-r--r-- | .coveragerc | 12 | ||||
-rw-r--r-- | CREDITS | 4 | ||||
-rw-r--r-- | HISTORY.rst | 9 | ||||
-rw-r--r-- | TODO | 25 | ||||
-rw-r--r-- | docs/index.rst | 31 | ||||
-rw-r--r-- | psutil/__init__.py | 46 | ||||
-rw-r--r-- | psutil/_common.py | 24 | ||||
-rw-r--r-- | psutil/_psposix.py | 2 | ||||
-rw-r--r-- | psutil/_psutil_linux.c | 4 | ||||
-rw-r--r-- | psutil/tests/test_linux.py | 25 | ||||
-rw-r--r-- | psutil/tests/test_misc.py | 23 | ||||
-rw-r--r-- | psutil/tests/test_posix.py | 2 | ||||
-rw-r--r-- | psutil/tests/test_process.py | 6 | ||||
-rw-r--r-- | psutil/tests/test_system.py | 13 |
14 files changed, 131 insertions, 95 deletions
diff --git a/.coveragerc b/.coveragerc index 4801ba65..6b6309b9 100644 --- a/.coveragerc +++ b/.coveragerc @@ -10,6 +10,7 @@ omit = exclude_lines = pragma: no cover + if PY3: if __name__ == .__main__.: if sys.platform.startswith if _WINDOWS: @@ -17,5 +18,16 @@ exclude_lines = if enum is not None: if enum is None: if has_enums: + if LITTLE_ENDIAN: enum.IntEnum except ImportError: + raise NotImplementedError + if WINDOWS + if OSX + if BSD + if FREEBSD + if OPENBSD + if NETBSD + if SUNOS + if LINUX + if ppid_map is None: @@ -378,3 +378,7 @@ I: 660 N: Mozilla Foundation D: sample code for process USS memory. + +N: wxwright +W: https://github.com/wxwright +I: 776 diff --git a/HISTORY.rst b/HISTORY.rst index e3c54cff..296dc85f 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -1,5 +1,14 @@ Bug tracker at https://github.com/giampaolo/psutil/issues +4.1.0 - XXXX-XX-XX +================== + +**Bug fixes** + +- #776: [Linux] Process.cpu_affinity() may erroneously raise NoSuchProcess. + (patch by wxwright) + + 4.0.0 - 2016-02-17 ================== @@ -9,8 +9,6 @@ https://github.com/giampaolo/psutil/issues PLATFORMS ========= - * #429 (patch): NetBSD - * #355 (patch): Android * #605 (branch): AIX @@ -19,6 +17,8 @@ PLATFORMS * DragonFlyBSD + * HP-UX + HIGHER PRIORITY =============== @@ -26,8 +26,8 @@ HIGHER PRIORITY * #371: CPU temperature (apparently OSX and Linux only; on Linux it requires lm-sensors lib). - * #269: expose network ifaces RX/TW queues. This should probably go into - net_if_stats(). Figure out on what platforms this is supported: + * #269: NIC rx/tx queue. This should probably go into net_if_stats(). + Figure out on what platforms this is supported: Linux: yes Others: ? @@ -44,8 +44,6 @@ HIGHER PRIORITY * #604: emulate os.getloadavg() on Windows - * #269: NIC rx/tx queue. - LOWER PRIORITY ============== @@ -89,8 +87,6 @@ DEBATABLE limiting per-process network IO resources though, which is great). Needs further reading. - * Should we expose OS constants (psutil.WINDOWS, psutil.OSX etc.)? - * Python 3.3. exposed different sched.h functions: http://docs.python.org/dev/whatsnew/3.3.html#os http://bugs.python.org/issue12655 @@ -152,19 +148,6 @@ DEBATABLE * Have psutil.Process().cpu_affinity([]) be an alias for "all CPUs"? -COMPATIBILITY BREAKAGE -====================== - -Removals (will likely happen in 2.2): - - * (S) psutil.Process.nice (deprecated in 0.5.0) - * (S) get_process_list (deprecated in 0.5.0) - * (S) psutil.*mem* functions (deprecated in 0.3.0 and 0.6.0) - * (M) psutil.network_io_counters (deprecated in 1.0.0) - * (M) local_address and remote_address Process.connection() namedtuple fields - (deprecated in 1.0.0) - - REJECTED IDEAS ============== diff --git a/docs/index.rst b/docs/index.rst index 9ac4b976..286f8a6a 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -267,38 +267,15 @@ Disks Return system-wide disk I/O statistics as a namedtuple including the following fields. - - +--------------------+-------------+-------------+-------------+-------------+-------------+-------------+ - | Linux | OSX | Solaris | Windows | FreeBSD | OpenBSD | NetBSD | - +====================+=============+=============+=============+=============+=============+=============+ - | read_count | read_count | read_count | read_count | read_count | read_count | read_count | - +--------------------+-------------+-------------+-------------+-------------+-------------+-------------+ - | write_count | write_count | write_count | write_count | write_count | write_count | write_count | - +--------------------+-------------+-------------+-------------+-------------+-------------+-------------+ - | read_bytes | read_bytes | read_bytes | read_bytes | read_bytes | read_bytes | read_bytes | - +--------------------+-------------+-------------+-------------+-------------+-------------+-------------+ - | write_bytes | write_bytes | write_bytes | write_bytes | write_bytes | write_bytes | write_bytes | - +--------------------+-------------+-------------+-------------+-------------+-------------+-------------+ - | read_time | read_time | read_time | read_time | read_time | read_time | | - +--------------------+-------------+-------------+-------------+-------------+-------------+-------------+ - | write_time | write_time | write_time | write_time | write_time | write_time | | - +--------------------+-------------+-------------+-------------+-------------+-------------+-------------+ - | read_merged_count | | | | busy_time | | | - +--------------------+-------------+-------------+-------------+-------------+-------------+-------------+ - | write_merged_count | | | | | | | - +--------------------+-------------+-------------+-------------+-------------+-------------+-------------+ - | busy_time | | | | | | | - +--------------------+-------------+-------------+-------------+-------------+-------------+-------------+ - - **read_count**: number of reads - **write_count**: number of writes - **read_bytes**: number of bytes read - **write_bytes**: number of bytes written - - **read_time**: time spent reading from disk (in milliseconds) - - **write_time**: time spent writing to disk (in milliseconds) + - **read_time**: (all except NetBSD and OpenBSD) time spent reading from disk (in milliseconds) + - **write_time**: (all except NetBSD and OpenBSD) time spent writing to disk (in milliseconds) - **busy_time**: (Linux, FreeBSD) time spent doing actual I/Os (in milliseconds) - **read_merged_count** (Linux): number of merged reads (see `iostat doc <https://www.kernel.org/doc/Documentation/iostats.txt>`__) - - **write_merged_count** (Linux): number of merged writes (see `iostat doc <https://www.kernel.org/doc/Documentation/iostats.txt>`__) + - **write_merged_count** (Linux): number of merged writes (see `iostats doc <https://www.kernel.org/doc/Documentation/iostats.txt>`__) If *perdisk* is ``True`` return the same information for every physical disk installed on the system as a dictionary with partition names as the keys and @@ -1101,6 +1078,8 @@ Process class It does so by passing through the whole process address. As such it usually requires higher user privileges than :meth:`memory_info` and is considerably slower. + On platforms where extra fields are not implented this simply returns the + same metrics as :meth:`memory_info`. - **uss**: (Linux, OSX, Windows) aka "Unique Set Size", this is the memory which is unique to a process and which would be freed if the process was terminated right now. diff --git a/psutil/__init__.py b/psutil/__init__.py index 1e3b43f2..8594e4b9 100644 --- a/psutil/__init__.py +++ b/psutil/__init__.py @@ -839,7 +839,7 @@ class Process(object): ret.append(p) except (NoSuchProcess, ZombieProcess): pass - else: + else: # pragma: no cover # Windows only (faster) for pid, ppid in ppid_map.items(): if ppid == self.pid: @@ -861,7 +861,7 @@ class Process(object): table[p.ppid()].append(p) except (NoSuchProcess, ZombieProcess): pass - else: + else: # pragma: no cover for pid, ppid in ppid_map.items(): try: p = Process(pid) @@ -1006,30 +1006,26 @@ class Process(object): >>> psutil.Process().memory_info()._fields ('rss', 'vms', 'shared', 'text', 'lib', 'data', 'dirty', 'uss', 'pss') """ - if memtype in ('uss', 'pss', 'swap'): - if not hasattr(self, "memory_full_info"): - fields = _psplatform.pmem._fields - raise ValueError( - "invalid memtype %r; valid types are %r" % ( - memtype, fields)) - fun = self.memory_full_info - fields = _psplatform.pfullmem._fields - else: - fields = _psplatform.pmem._fields - fun = self.memory_info - - if memtype not in fields: + valid_types = list(_psplatform.pfullmem._fields) + if hasattr(_psplatform, "pfullmem"): + valid_types.extend(list(_psplatform.pfullmem._fields)) + if memtype not in valid_types: raise ValueError("invalid memtype %r; valid types are %r" % ( - memtype, fields)) + memtype, tuple(valid_types))) + fun = self.memory_full_info if memtype in ('uss', 'pss', 'swap') else \ + self.memory_info metrics = fun() value = getattr(metrics, memtype) # use cached value if available total_phymem = _TOTAL_PHYMEM or virtual_memory().total - try: - return (value / float(total_phymem)) * 100 - except ZeroDivisionError: - return 0.0 + if not total_phymem > 0: + # we should never get here + raise ValueError( + "can't calculate process memory percent because " + "total physical system memory is not positive (%r)" + % total_phymem) + return (value / float(total_phymem)) * 100 if hasattr(_psplatform.Process, "memory_maps"): # Available everywhere except OpenBSD and NetBSD. @@ -1121,7 +1117,7 @@ class Process(object): """ if POSIX: self._send_signal(sig) - else: + else: # pragma: no cover if sig == signal.SIGTERM: self._proc.kill() # py >= 2.7 @@ -1141,7 +1137,7 @@ class Process(object): """ if POSIX: self._send_signal(signal.SIGSTOP) - else: + else: # pragma: no cover self._proc.suspend() @_assert_pid_not_reused @@ -1152,7 +1148,7 @@ class Process(object): """ if POSIX: self._send_signal(signal.SIGCONT) - else: + else: # pragma: no cover self._proc.resume() @_assert_pid_not_reused @@ -1163,7 +1159,7 @@ class Process(object): """ if POSIX: self._send_signal(signal.SIGTERM) - else: + else: # pragma: no cover self._proc.kill() @_assert_pid_not_reused @@ -1173,7 +1169,7 @@ class Process(object): """ if POSIX: self._send_signal(signal.SIGKILL) - else: + else: # pragma: no cover self._proc.kill() def wait(self, timeout=None): diff --git a/psutil/_common.py b/psutil/_common.py index 92b3b5e1..c90b0ba5 100644 --- a/psutil/_common.py +++ b/psutil/_common.py @@ -92,7 +92,7 @@ def usage_percent(used, total, _round=None): try: ret = (used / total) * 100 except ZeroDivisionError: - ret = 0 + ret = 0.0 if isinstance(used, float) or isinstance(total, float) else 0 if _round is not None: return round(ret, _round) else: @@ -187,6 +187,8 @@ def parse_environ_block(data): ret = {} pos = 0 + # localize global variable to speed up access. + WINDOWS_ = WINDOWS while True: next_pos = data.find("\0", pos) # nul byte at the beginning or double nul byte means finish @@ -198,7 +200,7 @@ def parse_environ_block(data): key = data[pos:equal_pos] value = data[equal_pos+1:next_pos] # Windows expects environment variables to be uppercase only - if os.name == "nt": + if WINDOWS_: key = key.upper() ret[key] = value pos = next_pos + 1 @@ -212,10 +214,11 @@ def sockfam_to_enum(num): """ if enum is None: return num - try: - return socket.AddressFamily(num) - except (ValueError, AttributeError): - return num + else: + try: + return socket.AddressFamily(num) + except (ValueError, AttributeError): + return num def socktype_to_enum(num): @@ -224,10 +227,11 @@ def socktype_to_enum(num): """ if enum is None: return num - try: - return socket.AddressType(num) - except (ValueError, AttributeError): - return num + else: + try: + return socket.AddressType(num) + except (ValueError, AttributeError): + return num def deprecated_method(replacement): diff --git a/psutil/_psposix.py b/psutil/_psposix.py index 02bbfcec..88aed919 100644 --- a/psutil/_psposix.py +++ b/psutil/_psposix.py @@ -113,7 +113,7 @@ def wait_pid(pid, timeout=None): return os.WEXITSTATUS(status) else: # should never happen - raise RuntimeError("unknown process exit status") + raise ValueError("unknown process exit status %r" % status) def disk_usage(path): diff --git a/psutil/_psutil_linux.c b/psutil/_psutil_linux.c index 2cf2a7db..78a5408d 100644 --- a/psutil/_psutil_linux.c +++ b/psutil/_psutil_linux.c @@ -275,7 +275,7 @@ psutil_proc_cpu_affinity_get(PyObject *self, PyObject *args) { cpu_set_t *mask = NULL; PyObject *py_list = NULL; - if (!PyArg_ParseTuple(args, "i", &pid)) + if (!PyArg_ParseTuple(args, "l", &pid)) return NULL; ncpus = NCPUS_START; while (1) { @@ -342,7 +342,7 @@ psutil_proc_cpu_affinity_get(PyObject *self, PyObject *args) { PyObject* py_retlist = NULL; PyObject *py_cpu_num = NULL; - if (!PyArg_ParseTuple(args, "i", &pid)) + if (!PyArg_ParseTuple(args, "l", &pid)) return NULL; CPU_ZERO(&cpuset); if (sched_getaffinity(pid, len, &cpuset) < 0) diff --git a/psutil/tests/test_linux.py b/psutil/tests/test_linux.py index 44c09862..7bf753b2 100644 --- a/psutil/tests/test_linux.py +++ b/psutil/tests/test_linux.py @@ -686,6 +686,31 @@ class TestMisc(unittest.TestCase): psutil.PROCFS_PATH = "/proc" os.rmdir(tdir) + def test_sector_size_mock(self): + # Test SECTOR_SIZE fallback in case 'hw_sector_size' file + # does not exist. + def open_mock(name, *args, **kwargs): + if PY3 and isinstance(name, bytes): + name = name.decode() + if name.startswith("/sys/block/sda/queue/hw_sector_size"): + flag.append(None) + raise IOError(errno.ENOENT, '') + else: + return orig_open(name, *args, **kwargs) + + flag = [] + orig_open = open + patch_point = 'builtins.open' if PY3 else '__builtin__.open' + try: + with mock.patch(patch_point, side_effect=open_mock): + importlib.reload(psutil._pslinux) + importlib.reload(psutil) + self.assertEqual(flag, [None]) + self.assertEqual(psutil._pslinux.SECTOR_SIZE, 512) + finally: + importlib.reload(psutil._pslinux) + importlib.reload(psutil) + # ===================================================================== # test process diff --git a/psutil/tests/test_misc.py b/psutil/tests/test_misc.py index f0a24234..c35e0d35 100644 --- a/psutil/tests/test_misc.py +++ b/psutil/tests/test_misc.py @@ -313,6 +313,29 @@ class TestMisc(unittest.TestCase): def test_psutil_is_reloadable(self): importlib.reload(psutil) + def test_sanity_version_check(self): + # see: https://github.com/giampaolo/psutil/issues/564 + try: + with mock.patch( + "psutil._psplatform.cext.version", return_value="0.0.0"): + with self.assertRaises(ImportError) as cm: + importlib.reload(psutil) + self.assertIn("version conflict", str(cm.exception).lower()) + finally: + importlib.reload(psutil) + + # https://travis-ci.org/giampaolo/psutil/jobs/111419416 + @unittest.skipIf(TRAVIS and LINUX, "skipped on travis") + def test_memory_percent_0_division(self): + import collections + try: + retval = collections.namedtuple("mem", "total")(0) + with mock.patch( + "psutil._psplatform.virtual_memory", return_value=retval): + self.assertRaises(ValueError, psutil.Process().memory_percent) + finally: + importlib.reload(psutil) + # =================================================================== # --- Example script tests diff --git a/psutil/tests/test_posix.py b/psutil/tests/test_posix.py index 6184ea6a..83125426 100644 --- a/psutil/tests/test_posix.py +++ b/psutil/tests/test_posix.py @@ -1,4 +1,5 @@ #!/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 @@ -275,6 +276,5 @@ class TestSystemAPIs(unittest.TestCase): self.assertTrue(u.name in users, u.name) self.assertTrue(u.terminal in terminals, u.terminal) - if __name__ == '__main__': run_test_module_by_name(__file__) diff --git a/psutil/tests/test_process.py b/psutil/tests/test_process.py index ecf99723..0fc27940 100644 --- a/psutil/tests/test_process.py +++ b/psutil/tests/test_process.py @@ -154,6 +154,12 @@ class TestProcess(unittest.TestCase): with self.assertRaises(psutil.AccessDenied): psutil.Process().send_signal(sig) assert fun.called + # Sending a signal to process with PID 0 is not allowed as + # it would affect every process in the process group of + # the calling process (os.getpid()) instead of PID 0"). + if 0 in psutil.pids(): + p = psutil.Process(0) + self.assertRaises(ValueError, p.send_signal, signal.SIGTERM) def test_wait(self): # check exit code signal diff --git a/psutil/tests/test_system.py b/psutil/tests/test_system.py index 48a2bed7..4f73e181 100644 --- a/psutil/tests/test_system.py +++ b/psutil/tests/test_system.py @@ -419,15 +419,10 @@ class TestSystemAPIs(unittest.TestCase): "os.statvfs() function not available on this platform") def test_disk_usage_unicode(self): # see: https://github.com/giampaolo/psutil/issues/416 - # XXX this test is not really reliable as it always fails on - # Python 3.X (2.X is fine) - try: - safe_rmdir(TESTFN_UNICODE) - os.mkdir(TESTFN_UNICODE) - psutil.disk_usage(TESTFN_UNICODE) - safe_rmdir(TESTFN_UNICODE) - except UnicodeEncodeError: - pass + safe_rmdir(TESTFN_UNICODE) + self.addCleanup(safe_rmdir, TESTFN_UNICODE) + os.mkdir(TESTFN_UNICODE) + psutil.disk_usage(TESTFN_UNICODE) @unittest.skipIf(POSIX and not hasattr(os, 'statvfs'), "os.statvfs() function not available on this platform") |