summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGiampaolo Rodola <g.rodola@gmail.com>2016-02-24 09:31:48 -0800
committerGiampaolo Rodola <g.rodola@gmail.com>2016-02-24 09:31:48 -0800
commita8c97637fa64c6e08f235396686d1512a2c0ed42 (patch)
tree9178b7b0f29a186dfed323858374c62b6d8dfef7
parent38652a6d5d6a205fb6ddeac255a76c0345a9c026 (diff)
parent4470230e440c9df4a21707163d1837c2ec607318 (diff)
downloadpsutil-a8c97637fa64c6e08f235396686d1512a2c0ed42.tar.gz
Merge branch 'master' of github.com:giampaolo/psutil
-rw-r--r--.coveragerc12
-rw-r--r--CREDITS4
-rw-r--r--HISTORY.rst9
-rw-r--r--TODO25
-rw-r--r--docs/index.rst31
-rw-r--r--psutil/__init__.py46
-rw-r--r--psutil/_common.py24
-rw-r--r--psutil/_psposix.py2
-rw-r--r--psutil/_psutil_linux.c4
-rw-r--r--psutil/tests/test_linux.py25
-rw-r--r--psutil/tests/test_misc.py23
-rw-r--r--psutil/tests/test_posix.py2
-rw-r--r--psutil/tests/test_process.py6
-rw-r--r--psutil/tests/test_system.py13
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:
diff --git a/CREDITS b/CREDITS
index 4753d3e5..2d46e440 100644
--- a/CREDITS
+++ b/CREDITS
@@ -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
==================
diff --git a/TODO b/TODO
index 211b1b8d..ed96b0f8 100644
--- a/TODO
+++ b/TODO
@@ -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")