summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGiampaolo Rodola <g.rodola@gmail.com>2015-11-06 17:14:18 +0100
committerGiampaolo Rodola <g.rodola@gmail.com>2015-11-06 17:14:18 +0100
commit4cffa4ce9cc900cb3a5f547deb06f46101d0a90b (patch)
tree9cc6d63c8a1ad3d0a1b6c0cb20e5e7f1b600d87a
parentc83bca37349952a5d5c0d437d1649afb78c9a0ca (diff)
parentafd4e5b0957b27c2121a8c37a893fdd9d40bae1c (diff)
downloadpsutil-4cffa4ce9cc900cb3a5f547deb06f46101d0a90b.tar.gz
merge from master
-rwxr-xr-x.git-pre-commit2
-rw-r--r--.travis.yml4
-rw-r--r--CREDITS8
-rw-r--r--HISTORY.rst21
-rw-r--r--README.rst1
-rw-r--r--TODO28
-rw-r--r--docs/index.rst28
-rwxr-xr-xexamples/top.py5
-rw-r--r--make.bat5
-rw-r--r--psutil/__init__.py48
-rw-r--r--psutil/_common.py22
-rw-r--r--psutil/_compat.py6
-rw-r--r--psutil/_psbsd.py4
-rw-r--r--psutil/_pslinux.py171
-rw-r--r--psutil/_psosx.py7
-rw-r--r--psutil/_psposix.py7
-rw-r--r--psutil/_pssunos.py12
-rw-r--r--psutil/_psutil_bsd.c10
-rw-r--r--psutil/_psutil_sunos.c8
-rw-r--r--psutil/_pswindows.py24
-rw-r--r--psutil/arch/windows/ntextapi.h7
-rw-r--r--test/_freebsd.py11
-rw-r--r--test/_linux.py75
-rw-r--r--test/_osx.py11
-rw-r--r--test/_posix.py20
-rw-r--r--test/_sunos.py4
-rw-r--r--test/_windows.py15
-rw-r--r--test/test_memory_leaks.py21
-rw-r--r--test/test_psutil.py52
29 files changed, 431 insertions, 206 deletions
diff --git a/.git-pre-commit b/.git-pre-commit
index 3a6161f4..0b838d48 100755
--- a/.git-pre-commit
+++ b/.git-pre-commit
@@ -38,7 +38,7 @@ def main():
# flake8
failed = False
for path in files:
- ret = subprocess.call("flake8 %s" % path, shell=True)
+ ret = subprocess.call("python -m flake8 %s" % path, shell=True)
if ret != 0:
failed = True
if failed:
diff --git a/.travis.yml b/.travis.yml
index d883c653..6ec09d37 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -4,7 +4,6 @@ matrix:
include:
- python: 2.6
- python: 2.7
- - python: 3.2
- python: 3.3
- python: 3.4
- language: generic
@@ -15,9 +14,6 @@ matrix:
env: PYVER=py27
- language: generic
os: osx
- env: PYVER=py32
- - language: generic
- os: osx
env: PYVER=py33
- language: generic
os: osx
diff --git a/CREDITS b/CREDITS
index baff88c4..ef4f432c 100644
--- a/CREDITS
+++ b/CREDITS
@@ -329,3 +329,11 @@ I: 659
N: wiggin15
W: https://github.com/wiggin15
I: 517, 607, 610
+
+N: dasumin
+W: https://github.com/dasumin
+I: 541
+
+N: Mike Sarahan
+W: https://github.com/msarahan
+I: 688
diff --git a/HISTORY.rst b/HISTORY.rst
index 52566b44..639c9d91 100644
--- a/HISTORY.rst
+++ b/HISTORY.rst
@@ -1,14 +1,33 @@
Bug tracker at https://github.com/giampaolo/psutil/issues
-3.2.2 - XXXX-XX-XX
+3.2.3 - XXXX-XX-XX
+==================
+
+**Enhancements**
+
+- #558: [Linux] exposed psutil.PROCFS_PATH constant to change the default
+ location of /proc filesystem.
+
+**Bug fixes**
+
+- #692: [UNIX] Process.name() is no longer cached as it may change.
+
+
+3.2.2 - 2015-10-04
==================
**Bug fixes**
- #517: [SunOS] net_io_counters failed to detect network interfaces
correctly on Solaris 10
+- #541: [FreeBSD] disk_io_counters r/w times were expressed in seconds instead
+ of milliseconds. (patch by dasumin)
- #610: [SunOS] fix build and tests on Solaris 10
+- #623: [Linux] process or system connections raises ValueError if IPv6 is not
+ supported by the system.
- #678: [Linux] can't install psutil due to bug in setup.py.
+- #688: [Windows] compilation fails with MSVC 2015, Python 3.5. (patch by
+ Mike Sarahan)
3.2.1 - 2015-09-03
diff --git a/README.rst b/README.rst
index 6517810a..5df3e8b0 100644
--- a/README.rst
+++ b/README.rst
@@ -350,6 +350,7 @@ http://groups.google.com/group/psutil/
Timeline
========
+- 2015-10-04: `psutil-3.2.2.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-3.2.2.tar.gz>`_
- 2015-09-03: `psutil-3.2.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-3.2.1.tar.gz>`_
- 2015-09-02: `psutil-3.2.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-3.2.0.tar.gz>`_
- 2015-07-15: `psutil-3.1.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-3.1.1.tar.gz>`_
diff --git a/TODO b/TODO
index a5df809d..a428da18 100644
--- a/TODO
+++ b/TODO
@@ -6,11 +6,25 @@ A collection of ideas and notes about stuff to implement in future versions.
https://github.com/giampaolo/psutil/issues
+PLATFORMS
+=========
+
+ * #615 (PR): OpenBSD
+
+ * #355 (patch): Android
+
+ * #429 (patch): NetBSD
+
+ * #605 (branch): AIX
+
+ * #276: GNU/Hurd
+
+ * DragonFlyBSD
+
+
HIGHER PRIORITY
===============
- * OpenBSD support.
-
* #371: CPU temperature (apparently OSX and Linux only; on Linux it requires
lm-sensors lib).
@@ -36,16 +50,6 @@ HIGHER PRIORITY
LOWER PRIORITY
==============
- * #355: Android support.
-
- * #276: GNU/Hurd support.
-
- * #429: NetBSD support.
-
- * DragonFlyBSD support?
-
- * AIX support?
-
* examples/taskmgr-gui.py (using tk).
* system-wide number of open file descriptors:
diff --git a/docs/index.rst b/docs/index.rst
index e8998390..31ba1fc3 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -455,9 +455,9 @@ Network
.. note:: *netmask*, *broadcast* and *ptp* are not supported on Windows and
are set to ``None``.
- *New in 3.0.0*
+ .. versionadded:: 3.0.0
- *Changed in 3.2.0:* *ptp* field was added.
+ .. versionchanged:: 3.2.0 *ptp* field was added.
.. function:: net_if_stats()
@@ -484,7 +484,7 @@ 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)}
- *New in 3.0.0*
+ .. versionadded:: 3.0.0
Other system info
@@ -615,7 +615,7 @@ Exceptions
interested in retrieving zombies (e.g. when using :func:`process_iter()`)
you can ignore this exception and just catch :class:`NoSuchProcess`.
- *New in 3.0.0*
+ .. versionadded:: 3.0.0
.. class:: AccessDenied(pid=None, name=None, msg=None)
@@ -679,7 +679,7 @@ Process class
.. method:: name()
- The process name. The return value is cached after first call.
+ The process name.
.. method:: exe()
@@ -1188,8 +1188,8 @@ Process class
signals are supported and **SIGTERM** is treated as an alias for
:meth:`kill()`.
- *Changed in 3.2.0:* support for CTRL_C_EVENT and CTRL_BREAK_EVENT signals
- was added.
+ .. versionchanged:: 3.2.0 support for CTRL_C_EVENT and CTRL_BREAK_EVENT
+ signals was added.
.. method:: suspend()
@@ -1280,6 +1280,16 @@ Constants
=========
.. _const-pstatus:
+.. data:: PROCFS_PATH
+
+ The path of the /proc filesystem on Linux (defaults to "/proc"). You may want
+ to re-set this in case /proc is mounted elsewhere.
+
+ Availability: Linux
+
+ .. versionadded:: 3.2.3
+
+.. _const-pstatus:
.. data:: STATUS_RUNNING
STATUS_SLEEPING
STATUS_DISK_SLEEP
@@ -1394,7 +1404,7 @@ Constants
Constant which identifies a MAC address associated with a network interface.
To be used in conjunction with :func:`psutil.net_if_addrs()`.
- *New in 3.0.0*
+ .. versionadded:: 3.0.0
.. _const-duplex:
.. data:: NIC_DUPLEX_FULL
@@ -1407,7 +1417,7 @@ Constants
receive data at a time.
To be used in conjunction with :func:`psutil.net_if_stats()`.
- *New in 3.0.0*
+ .. versionadded:: 3.0.0
Development guide
=================
diff --git a/examples/top.py b/examples/top.py
index 7aebef1d..4807439c 100755
--- a/examples/top.py
+++ b/examples/top.py
@@ -34,11 +34,12 @@ PID USER NI VIRT RES CPU% MEM% TIME+ NAME
...
"""
-from datetime import datetime, timedelta
+from datetime import datetime
+from datetime import timedelta
import atexit
import os
-import time
import sys
+import time
try:
import curses
except ImportError:
diff --git a/make.bat b/make.bat
index 56cdbfc4..8f0cb1b7 100644
--- a/make.bat
+++ b/make.bat
@@ -30,12 +30,14 @@ set PYTHON26=C:\Python26\python.exe
set PYTHON27=C:\Python27\python.exe
set PYTHON33=C:\Python33\python.exe
set PYTHON34=C:\Python34\python.exe
+set PYTHON35=C:\Python35\python.exe
set PYTHON26-64=C:\Python26-64\python.exe
set PYTHON27-64=C:\Python27-64\python.exe
set PYTHON33-64=C:\Python33-64\python.exe
set PYTHON34-64=C:\Python34-64\python.exe
+set PYTHON35-64=C:\Python35-64\python.exe
-set ALL_PYTHONS=%PYTHON26% %PYTHON27% %PYTHON33% %PYTHON34% %PYTHON26-64% %PYTHON27-64% %PYTHON33-64% %PYTHON34-64%
+set ALL_PYTHONS=%PYTHON26% %PYTHON27% %PYTHON33% %PYTHON34% %PYTHON35% %PYTHON26-64% %PYTHON27-64% %PYTHON33-64% %PYTHON34-64% %PYTHON35-64%
rem Needed to locate the .pypirc file and upload exes on PYPI.
set HOME=%USERPROFILE%
@@ -64,7 +66,6 @@ if "%1" == "clean" (
for /r %%R in (__pycache__) do if exist %%R (rmdir /S /Q %%R)
for /r %%R in (*.pyc) do if exist %%R (del /s %%R)
for /r %%R in (*.pyd) do if exist %%R (del /s %%R)
- for /r %%R in (*.obj) do if exist %%R (del /s %%R)
for /r %%R in (*.orig) do if exist %%R (del /s %%R)
for /r %%R in (*.bak) do if exist %%R (del /s %%R)
for /r %%R in (*.rej) do if exist %%R (del /s %%R)
diff --git a/psutil/__init__.py b/psutil/__init__.py
index 636bf5a8..048ac527 100644
--- a/psutil/__init__.py
+++ b/psutil/__init__.py
@@ -61,6 +61,10 @@ from ._common import (NIC_DUPLEX_FULL, # NOQA
if sys.platform.startswith("linux"):
from . import _pslinux as _psplatform
+ # This is public API and it will be retrieved from _pslinux.py
+ # via sys.modules.
+ PROCFS_PATH = "/proc"
+
from ._pslinux import (IOPRIO_CLASS_NONE, # NOQA
IOPRIO_CLASS_RT,
IOPRIO_CLASS_BE,
@@ -157,7 +161,7 @@ __all__ = [
]
__all__.extend(_psplatform.__extra__all__)
__author__ = "Giampaolo Rodola'"
-__version__ = "3.2.2"
+__version__ = "3.2.3"
version_info = tuple([int(num) for num in __version__.split('.')])
AF_LINK = _psplatform.AF_LINK
_TOTAL_PHYMEM = None
@@ -519,25 +523,29 @@ class Process(object):
def name(self):
"""The process name. The return value is cached after first call."""
- if self._name is None:
- name = self._proc.name()
- if _POSIX and len(name) >= 15:
- # On UNIX the name gets truncated to the first 15 characters.
- # If it matches the first part of the cmdline we return that
- # one instead because it's usually more explicative.
- # Examples are "gnome-keyring-d" vs. "gnome-keyring-daemon".
- try:
- cmdline = self.cmdline()
- except AccessDenied:
- pass
- else:
- if cmdline:
- extended_name = os.path.basename(cmdline[0])
- if extended_name.startswith(name):
- name = extended_name
- self._proc._name = name
- self._name = name
- return self._name
+ # Process name is only cached on Windows as on POSIX it may
+ # change, see:
+ # https://github.com/giampaolo/psutil/issues/692
+ if _WINDOWS and self._name is not None:
+ return self._name
+ name = self._proc.name()
+ if _POSIX and len(name) >= 15:
+ # On UNIX the name gets truncated to the first 15 characters.
+ # If it matches the first part of the cmdline we return that
+ # one instead because it's usually more explicative.
+ # Examples are "gnome-keyring-d" vs. "gnome-keyring-daemon".
+ try:
+ cmdline = self.cmdline()
+ except AccessDenied:
+ pass
+ else:
+ if cmdline:
+ extended_name = os.path.basename(cmdline[0])
+ if extended_name.startswith(name):
+ name = extended_name
+ self._name = name
+ self._proc._name = name
+ return name
def exe(self):
"""The process executable as an absolute path.
diff --git a/psutil/_common.py b/psutil/_common.py
index 9f5c06f2..29acfb8d 100644
--- a/psutil/_common.py
+++ b/psutil/_common.py
@@ -1,5 +1,3 @@
-# /usr/bin/env python
-
# 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.
@@ -7,6 +5,8 @@
"""Common objects shared by all _ps* modules."""
from __future__ import division
+
+import contextlib
import errno
import functools
import os
@@ -14,7 +14,10 @@ import socket
import stat
import sys
from collections import namedtuple
-from socket import AF_INET, SOCK_STREAM, SOCK_DGRAM
+from socket import AF_INET
+from socket import SOCK_DGRAM
+from socket import SOCK_STREAM
+
try:
import threading
except ImportError:
@@ -140,6 +143,19 @@ def isfile_strict(path):
return stat.S_ISREG(st.st_mode)
+def supports_ipv6():
+ """Return True if IPv6 is supported on this platform."""
+ if not socket.has_ipv6 or not hasattr(socket, "AF_INET6"):
+ return False
+ try:
+ sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
+ with contextlib.closing(sock):
+ sock.bind(("::1", 0))
+ return True
+ except socket.error:
+ return False
+
+
def sockfam_to_enum(num):
"""Convert a numeric socket family value to an IntEnum member.
If it's not a known member, return the numeric value itself.
diff --git a/psutil/_compat.py b/psutil/_compat.py
index 3d984998..f79af3ac 100644
--- a/psutil/_compat.py
+++ b/psutil/_compat.py
@@ -20,6 +20,9 @@ if PY3:
def u(s):
return s
+
+ def b(s):
+ return s.encode("latin-1")
else:
long = long
xrange = xrange
@@ -28,6 +31,9 @@ else:
def u(s):
return unicode(s, "unicode_escape")
+ def b(s):
+ return s
+
# removed in 3.0, reintroduced in 3.2
try:
diff --git a/psutil/_psbsd.py b/psutil/_psbsd.py
index 1c147033..a381ef39 100644
--- a/psutil/_psbsd.py
+++ b/psutil/_psbsd.py
@@ -15,8 +15,10 @@ from . import _common
from . import _psposix
from . import _psutil_bsd as cext
from . import _psutil_posix as cext_posix
-from ._common import conn_tmap, usage_percent, sockfam_to_enum
+from ._common import conn_tmap
+from ._common import sockfam_to_enum
from ._common import socktype_to_enum
+from ._common import usage_percent
from ._compat import which
diff --git a/psutil/_pslinux.py b/psutil/_pslinux.py
index 54a2f916..5731851b 100644
--- a/psutil/_pslinux.py
+++ b/psutil/_pslinux.py
@@ -15,15 +15,22 @@ import socket
import struct
import sys
import warnings
-from collections import namedtuple, defaultdict
+from collections import defaultdict
+from collections import namedtuple
from . import _common
from . import _psposix
from . import _psutil_linux as cext
from . import _psutil_posix as cext_posix
-from ._common import isfile_strict, usage_percent
-from ._common import NIC_DUPLEX_FULL, NIC_DUPLEX_HALF, NIC_DUPLEX_UNKNOWN
-from ._compat import PY3, long
+from ._common import isfile_strict
+from ._common import NIC_DUPLEX_FULL
+from ._common import NIC_DUPLEX_HALF
+from ._common import NIC_DUPLEX_UNKNOWN
+from ._common import supports_ipv6
+from ._common import usage_percent
+from ._compat import b
+from ._compat import long
+from ._compat import PY3
if sys.version_info >= (3, 4):
import enum
@@ -32,6 +39,8 @@ else:
__extra__all__ = [
+ #
+ 'PROCFS_PATH',
# io prio constants
"IOPRIO_CLASS_NONE", "IOPRIO_CLASS_RT", "IOPRIO_CLASS_BE",
"IOPRIO_CLASS_IDLE",
@@ -124,15 +133,20 @@ def open_text(fname):
return open(fname, "rt", **kw)
+def get_procfs_path():
+ return sys.modules['psutil'].PROCFS_PATH
+
+
# --- named tuples
-def _get_cputimes_fields():
+def set_scputimes_ntuple(procfs_path):
"""Return a namedtuple of variable fields depending on the
CPU times available on this Linux kernel version which may be:
(user, nice, system, idle, iowait, irq, softirq, [steal, [guest,
[guest_nice]]])
"""
- with open('/proc/stat', 'rb') as f:
+ global scputimes
+ with open('%s/stat' % procfs_path, 'rb') as f:
values = f.readline().split()[1:]
fields = ['user', 'nice', 'system', 'idle', 'iowait', 'irq', 'softirq']
vlen = len(values)
@@ -145,10 +159,11 @@ def _get_cputimes_fields():
if vlen >= 10:
# Linux >= 3.2.0
fields.append('guest_nice')
- return fields
+ scputimes = namedtuple('scputimes', fields)
+ return scputimes
-scputimes = namedtuple('scputimes', _get_cputimes_fields())
+scputimes = set_scputimes_ntuple('/proc')
svmem = namedtuple(
'svmem', ['total', 'available', 'percent', 'used', 'free',
@@ -170,7 +185,7 @@ pmmap_ext = namedtuple(
def virtual_memory():
total, free, buffers, shared, _, _ = cext.linux_sysinfo()
cached = active = inactive = None
- with open('/proc/meminfo', 'rb') as f:
+ with open('%s/meminfo' % get_procfs_path(), 'rb') as f:
for line in f:
if line.startswith(b"Cached:"):
cached = int(line.split()[1]) * 1024
@@ -201,7 +216,7 @@ def swap_memory():
used = total - free
percent = usage_percent(used, total, _round=1)
# get pgin/pgouts
- with open("/proc/vmstat", "rb") as f:
+ with open("%s/vmstat" % get_procfs_path(), "rb") as f:
sin = sout = None
for line in f:
# values are expressed in 4 kilo bytes, we want bytes instead
@@ -230,7 +245,9 @@ def cpu_times():
[guest_nice]]])
Last 3 fields may not be available on all Linux kernel versions.
"""
- with open('/proc/stat', 'rb') as f:
+ procfs_path = get_procfs_path()
+ set_scputimes_ntuple(procfs_path)
+ with open('%s/stat' % procfs_path, 'rb') as f:
values = f.readline().split()
fields = values[1:len(scputimes._fields) + 1]
fields = [float(x) / CLOCK_TICKS for x in fields]
@@ -241,8 +258,10 @@ def per_cpu_times():
"""Return a list of namedtuple representing the CPU times
for every CPU available on the system.
"""
+ procfs_path = get_procfs_path()
+ set_scputimes_ntuple(procfs_path)
cpus = []
- with open('/proc/stat', 'rb') as f:
+ with open('%s/stat' % procfs_path, 'rb') as f:
# get rid of the first line which refers to system wide CPU stats
f.readline()
for line in f:
@@ -262,7 +281,7 @@ def cpu_count_logical():
except ValueError:
# as a second fallback we try to parse /proc/cpuinfo
num = 0
- with open('/proc/cpuinfo', 'rb') as f:
+ with open('%s/cpuinfo' % get_procfs_path(), 'rb') as f:
for line in f:
if line.lower().startswith(b'processor'):
num += 1
@@ -272,7 +291,7 @@ def cpu_count_logical():
# try to parse /proc/stat as a last resort
if num == 0:
search = re.compile('cpu\d')
- with open_text('/proc/stat') as f:
+ with open_text('%s/stat' % get_procfs_path()) as f:
for line in f:
line = line.split(' ')[0]
if search.match(line):
@@ -288,7 +307,7 @@ def cpu_count_physical():
"""Return the number of physical cores in the system."""
mapping = {}
current_info = {}
- with open('/proc/cpuinfo', 'rb') as f:
+ with open('%s/cpuinfo' % get_procfs_path(), 'rb') as f:
for line in f:
line = line.strip().lower()
if not line:
@@ -332,20 +351,21 @@ def users():
def boot_time():
"""Return the system boot time expressed in seconds since the epoch."""
global BOOT_TIME
- with open('/proc/stat', 'rb') as f:
+ with open('%s/stat' % get_procfs_path(), 'rb') as f:
for line in f:
if line.startswith(b'btime'):
ret = float(line.strip().split()[1])
BOOT_TIME = ret
return ret
- raise RuntimeError("line 'btime' not found in /proc/stat")
+ raise RuntimeError(
+ "line 'btime' not found in %s/stat" % get_procfs_path())
# --- processes
def pids():
"""Returns a list of PIDs currently running on the system."""
- return [int(x) for x in os.listdir(b'/proc') if x.isdigit()]
+ return [int(x) for x in os.listdir(b(get_procfs_path())) if x.isdigit()]
def pid_exists(pid):
@@ -355,6 +375,10 @@ def pid_exists(pid):
# --- network
+class _Ipv6UnsupportedError(Exception):
+ pass
+
+
class Connections:
"""A wrapper on top of /proc/net/* files, retrieving per-process
and system-wide open connections (TCP, UDP, UNIX) similarly to
@@ -386,12 +410,14 @@ class Connections:
"inet4": (tcp4, udp4),
"inet6": (tcp6, udp6),
}
+ self._procfs_path = None
def get_proc_inodes(self, pid):
inodes = defaultdict(list)
- for fd in os.listdir("/proc/%s/fd" % pid):
+ for fd in os.listdir("%s/%s/fd" % (self._procfs_path, pid)):
try:
- inode = os.readlink("/proc/%s/fd/%s" % (pid, fd))
+ inode = os.readlink("%s/%s/fd/%s" % (
+ self._procfs_path, pid, fd))
except OSError as err:
# ENOENT == file which is gone in the meantime;
# os.stat('/proc/%s' % self.pid) will be done later
@@ -464,15 +490,22 @@ class Connections:
# return socket.inet_ntop(socket.AF_INET6,
# ''.join(ip[i:i+4][::-1] for i in xrange(0, 16, 4)))
ip = base64.b16decode(ip)
- # see: https://github.com/giampaolo/psutil/issues/201
- if sys.byteorder == 'little':
- ip = socket.inet_ntop(
- socket.AF_INET6,
- struct.pack('>4I', *struct.unpack('<4I', ip)))
- else:
- ip = socket.inet_ntop(
- socket.AF_INET6,
- struct.pack('<4I', *struct.unpack('<4I', ip)))
+ try:
+ # see: https://github.com/giampaolo/psutil/issues/201
+ if sys.byteorder == 'little':
+ ip = socket.inet_ntop(
+ socket.AF_INET6,
+ struct.pack('>4I', *struct.unpack('<4I', ip)))
+ else:
+ ip = socket.inet_ntop(
+ socket.AF_INET6,
+ struct.pack('<4I', *struct.unpack('<4I', ip)))
+ except ValueError:
+ # see: https://github.com/giampaolo/psutil/issues/623
+ if not supports_ipv6():
+ raise _Ipv6UnsupportedError
+ else:
+ raise
return (ip, port)
def process_inet(self, file, family, type_, inodes, filter_pid=None):
@@ -507,8 +540,11 @@ class Connections:
status = TCP_STATUSES[status]
else:
status = _common.CONN_NONE
- laddr = self.decode_address(laddr, family)
- raddr = self.decode_address(raddr, family)
+ try:
+ laddr = self.decode_address(laddr, family)
+ raddr = self.decode_address(raddr, family)
+ except _Ipv6UnsupportedError:
+ continue
yield (fd, family, type_, laddr, raddr, status, pid)
def process_unix(self, file, family, inodes, filter_pid=None):
@@ -548,6 +584,7 @@ class Connections:
if kind not in self.tmap:
raise ValueError("invalid %r kind argument; choose between %s"
% (kind, ', '.join([repr(x) for x in self.tmap])))
+ self._procfs_path = get_procfs_path()
if pid is not None:
inodes = self.get_proc_inodes(pid)
if not inodes:
@@ -559,10 +596,12 @@ class Connections:
for f, family, type_ in self.tmap[kind]:
if family in (socket.AF_INET, socket.AF_INET6):
ls = self.process_inet(
- "/proc/net/%s" % f, family, type_, inodes, filter_pid=pid)
+ "%s/net/%s" % (self._procfs_path, f),
+ family, type_, inodes, filter_pid=pid)
else:
ls = self.process_unix(
- "/proc/net/%s" % f, family, inodes, filter_pid=pid)
+ "%s/net/%s" % (self._procfs_path, f),
+ family, inodes, filter_pid=pid)
for fd, family, type_, laddr, raddr, status, bound_pid in ls:
if pid:
conn = _common.pconn(fd, family, type_, laddr, raddr,
@@ -586,7 +625,7 @@ def net_io_counters():
"""Return network I/O statistics for every network interface
installed on the system as a dict of raw tuples.
"""
- with open_text("/proc/net/dev") as f:
+ with open_text("%s/net/dev" % get_procfs_path()) as f:
lines = f.readlines()
retdict = {}
for line in lines[2:]:
@@ -637,7 +676,7 @@ def disk_io_counters():
# determine partitions we want to look for
partitions = []
- with open_text("/proc/partitions") as f:
+ with open_text("%s/partitions" % get_procfs_path()) as f:
lines = f.readlines()[2:]
for line in reversed(lines):
_, _, _, name = line.split()
@@ -654,7 +693,7 @@ def disk_io_counters():
partitions.append(name)
#
retdict = {}
- with open_text("/proc/diskstats") as f:
+ with open_text("%s/diskstats" % get_procfs_path()) as f:
lines = f.readlines()
for line in lines:
# http://www.mjmwired.net/kernel/Documentation/iostats.txt
@@ -680,7 +719,7 @@ def disk_io_counters():
def disk_partitions(all=False):
"""Return mounted disk partitions as a list of namedtuples"""
fstypes = set()
- with open_text("/proc/filesystems") as f:
+ with open_text("%s/filesystems" % get_procfs_path()) as f:
for line in f:
line = line.strip()
if not line.startswith("nodev"):
@@ -750,29 +789,30 @@ def wrap_exceptions_w_zombie(fun):
class Process(object):
"""Linux process implementation."""
- __slots__ = ["pid", "_name", "_ppid"]
+ __slots__ = ["pid", "_name", "_ppid", "_procfs_path"]
def __init__(self, pid):
self.pid = pid
self._name = None
self._ppid = None
+ self._procfs_path = get_procfs_path()
@wrap_exceptions
def name(self):
- with open_text("/proc/%s/stat" % self.pid) as f:
+ with open_text("%s/%s/stat" % (self._procfs_path, self.pid)) as f:
data = f.read()
# XXX - gets changed later and probably needs refactoring
return data[data.find('(') + 1:data.rfind(')')]
def exe(self):
try:
- exe = os.readlink("/proc/%s/exe" % self.pid)
+ exe = os.readlink("%s/%s/exe" % (self._procfs_path, self.pid))
except OSError as err:
if err.errno in (errno.ENOENT, errno.ESRCH):
# no such file error; might be raised also if the
# path actually exists for system processes with
# low pids (about 0-20)
- if os.path.lexists("/proc/%s" % self.pid):
+ if os.path.lexists("%s/%s" % (self._procfs_path, self.pid)):
return ""
else:
if not pid_exists(self.pid):
@@ -795,7 +835,7 @@ class Process(object):
@wrap_exceptions
def cmdline(self):
- with open_text("/proc/%s/cmdline" % self.pid) as f:
+ with open_text("%s/%s/cmdline" % (self._procfs_path, self.pid)) as f:
data = f.read()
if data.endswith('\x00'):
data = data[:-1]
@@ -804,7 +844,7 @@ class Process(object):
@wrap_exceptions
def terminal(self):
tmap = _psposix._get_terminal_map()
- with open("/proc/%s/stat" % self.pid, 'rb') as f:
+ with open("%s/%s/stat" % (self._procfs_path, self.pid), 'rb') as f:
tty_nr = int(f.read().split(b' ')[6])
try:
return tmap[tty_nr]
@@ -814,7 +854,7 @@ class Process(object):
if os.path.exists('/proc/%s/io' % os.getpid()):
@wrap_exceptions
def io_counters(self):
- fname = "/proc/%s/io" % self.pid
+ fname = "%s/%s/io" % (self._procfs_path, self.pid)
with open(fname, 'rb') as f:
rcount = wcount = rbytes = wbytes = None
for line in f:
@@ -838,7 +878,7 @@ class Process(object):
@wrap_exceptions
def cpu_times(self):
- with open("/proc/%s/stat" % self.pid, 'rb') as f:
+ with open("%s/%s/stat" % (self._procfs_path, self.pid), 'rb') as f:
st = f.read().strip()
# ignore the first two values ("pid (exe)")
st = st[st.find(b')') + 2:]
@@ -859,7 +899,7 @@ class Process(object):
@wrap_exceptions
def create_time(self):
- with open("/proc/%s/stat" % self.pid, 'rb') as f:
+ with open("%s/%s/stat" % (self._procfs_path, self.pid), 'rb') as f:
st = f.read().strip()
# ignore the first two values ("pid (exe)")
st = st[st.rfind(b')') + 2:]
@@ -874,7 +914,7 @@ class Process(object):
@wrap_exceptions
def memory_info(self):
- with open("/proc/%s/statm" % self.pid, 'rb') as f:
+ with open("%s/%s/statm" % (self._procfs_path, self.pid), 'rb') as f:
vms, rss = f.readline().split()[:2]
return _common.pmem(int(rss) * PAGESIZE,
int(vms) * PAGESIZE)
@@ -892,7 +932,7 @@ class Process(object):
# | data | data + stack | drs | DATA |
# | dirty | dirty pages (unused in Linux 2.6) | dt | |
# ============================================================
- with open("/proc/%s/statm" % self.pid, "rb") as f:
+ with open("%s/%s/statm" % (self._procfs_path, self.pid), "rb") as f:
vms, rss, shared, text, lib, data, dirty = \
[int(x) * PAGESIZE for x in f.readline().split()[:7]]
return pextmem(rss, vms, shared, text, lib, data, dirty)
@@ -905,7 +945,7 @@ class Process(object):
Fields are explained in 'man proc'; here is an updated (Apr 2012)
version: http://goo.gl/fmebo
"""
- with open_text("/proc/%s/smaps" % self.pid) as f:
+ with open_text("%s/%s/smaps" % (self._procfs_path, self.pid)) as f:
first_line = f.readline()
current_block = [first_line]
@@ -969,13 +1009,13 @@ class Process(object):
# readlink() might return paths containing null bytes causing
# problems when used with other fs-related functions (os.*,
# open(), ...)
- path = os.readlink("/proc/%s/cwd" % self.pid)
+ path = os.readlink("%s/%s/cwd" % (self._procfs_path, self.pid))
return path.replace('\x00', '')
@wrap_exceptions
def num_ctx_switches(self):
vol = unvol = None
- with open("/proc/%s/status" % self.pid, "rb") as f:
+ with open("%s/%s/status" % (self._procfs_path, self.pid), "rb") as f:
for line in f:
if line.startswith(b"voluntary_ctxt_switches"):
vol = int(line.split()[1])
@@ -990,7 +1030,7 @@ class Process(object):
@wrap_exceptions
def num_threads(self):
- with open("/proc/%s/status" % self.pid, "rb") as f:
+ with open("%s/%s/status" % (self._procfs_path, self.pid), "rb") as f:
for line in f:
if line.startswith(b"Threads:"):
return int(line.split()[1])
@@ -998,12 +1038,13 @@ class Process(object):
@wrap_exceptions
def threads(self):
- thread_ids = os.listdir("/proc/%s/task" % self.pid)
+ thread_ids = os.listdir("%s/%s/task" % (self._procfs_path, self.pid))
thread_ids.sort()
retlist = []
hit_enoent = False
for thread_id in thread_ids:
- fname = "/proc/%s/task/%s/stat" % (self.pid, thread_id)
+ fname = "%s/%s/task/%s/stat" % (
+ self._procfs_path, self.pid, thread_id)
try:
with open(fname, 'rb') as f:
st = f.read().strip()
@@ -1023,12 +1064,12 @@ class Process(object):
retlist.append(ntuple)
if hit_enoent:
# raise NSP if the process disappeared on us
- os.stat('/proc/%s' % self.pid)
+ os.stat('%s/%s' % (self._procfs_path, self.pid))
return retlist
@wrap_exceptions
def nice_get(self):
- # with open_text('/proc/%s/stat' % self.pid) as f:
+ # with open_text('%s/%s/stat' % (self._procfs_path, self.pid)) as f:
# data = f.read()
# return int(data.split()[18])
@@ -1129,7 +1170,7 @@ class Process(object):
@wrap_exceptions
def status(self):
- with open("/proc/%s/status" % self.pid, 'rb') as f:
+ with open("%s/%s/status" % (self._procfs_path, self.pid), 'rb') as f:
for line in f:
if line.startswith(b"State:"):
letter = line.split()[1]
@@ -1142,10 +1183,10 @@ class Process(object):
@wrap_exceptions
def open_files(self):
retlist = []
- files = os.listdir("/proc/%s/fd" % self.pid)
+ files = os.listdir("%s/%s/fd" % (self._procfs_path, self.pid))
hit_enoent = False
for fd in files:
- file = "/proc/%s/fd/%s" % (self.pid, fd)
+ file = "%s/%s/fd/%s" % (self._procfs_path, self.pid, fd)
try:
file = os.readlink(file)
except OSError as err:
@@ -1168,23 +1209,23 @@ class Process(object):
retlist.append(ntuple)
if hit_enoent:
# raise NSP if the process disappeared on us
- os.stat('/proc/%s' % self.pid)
+ os.stat('%s/%s' % (self._procfs_path, self.pid))
return retlist
@wrap_exceptions
def connections(self, kind='inet'):
ret = _connections.retrieve(kind, self.pid)
# raise NSP if the process disappeared on us
- os.stat('/proc/%s' % self.pid)
+ os.stat('%s/%s' % (self._procfs_path, self.pid))
return ret
@wrap_exceptions
def num_fds(self):
- return len(os.listdir("/proc/%s/fd" % self.pid))
+ return len(os.listdir("%s/%s/fd" % (self._procfs_path, self.pid)))
@wrap_exceptions
def ppid(self):
- fpath = "/proc/%s/status" % self.pid
+ fpath = "%s/%s/status" % (self._procfs_path, self.pid)
with open(fpath, 'rb') as f:
for line in f:
if line.startswith(b"PPid:"):
@@ -1194,7 +1235,7 @@ class Process(object):
@wrap_exceptions
def uids(self):
- fpath = "/proc/%s/status" % self.pid
+ fpath = "%s/%s/status" % (self._procfs_path, self.pid)
with open(fpath, 'rb') as f:
for line in f:
if line.startswith(b'Uid:'):
@@ -1204,7 +1245,7 @@ class Process(object):
@wrap_exceptions
def gids(self):
- fpath = "/proc/%s/status" % self.pid
+ fpath = "%s/%s/status" % (self._procfs_path, self.pid)
with open(fpath, 'rb') as f:
for line in f:
if line.startswith(b'Gid:'):
diff --git a/psutil/_psosx.py b/psutil/_psosx.py
index b44acb23..0e770b80 100644
--- a/psutil/_psosx.py
+++ b/psutil/_psosx.py
@@ -13,8 +13,11 @@ from . import _common
from . import _psposix
from . import _psutil_osx as cext
from . import _psutil_posix as cext_posix
-from ._common import conn_tmap, usage_percent, isfile_strict
-from ._common import sockfam_to_enum, socktype_to_enum
+from ._common import conn_tmap
+from ._common import isfile_strict
+from ._common import sockfam_to_enum
+from ._common import socktype_to_enum
+from ._common import usage_percent
__extra__all__ = []
diff --git a/psutil/_psposix.py b/psutil/_psposix.py
index 046a75f0..02bbfcec 100644
--- a/psutil/_psposix.py
+++ b/psutil/_psposix.py
@@ -10,8 +10,11 @@ import os
import sys
import time
-from ._common import sdiskusage, usage_percent, memoize
-from ._compat import PY3, unicode
+from ._common import memoize
+from ._common import sdiskusage
+from ._common import usage_percent
+from ._compat import PY3
+from ._compat import unicode
class TimeoutExpired(Exception):
diff --git a/psutil/_pssunos.py b/psutil/_pssunos.py
index 10e439a4..c1574096 100644
--- a/psutil/_pssunos.py
+++ b/psutil/_pssunos.py
@@ -15,7 +15,9 @@ from . import _common
from . import _psposix
from . import _psutil_posix as cext_posix
from . import _psutil_sunos as cext
-from ._common import isfile_strict, socktype_to_enum, sockfam_to_enum
+from ._common import isfile_strict
+from ._common import sockfam_to_enum
+from ._common import socktype_to_enum
from ._common import usage_percent
from ._compat import PY3
@@ -211,7 +213,7 @@ def net_connections(kind, _pid=-1):
raise ValueError("invalid %r kind argument; choose between %s"
% (kind, ', '.join([repr(x) for x in cmap])))
families, types = _common.conn_tmap[kind]
- rawlist = cext.net_connections(_pid, families, types)
+ rawlist = cext.net_connections(_pid)
ret = set()
for item in rawlist:
fd, fam, type_, laddr, raddr, status, pid = item
@@ -284,7 +286,11 @@ class Process(object):
@wrap_exceptions
def exe(self):
- # Will be guess later from cmdline but we want to explicitly
+ try:
+ return os.readlink("/proc/%s/path/a.out" % self.pid)
+ except OSError:
+ pass # continue and guess the exe name from the cmdline
+ # Will be guessed later from cmdline but we want to explicitly
# invoke cmdline here in order to get an AccessDenied
# exception if the user has not enough privileges.
self.cmdline()
diff --git a/psutil/_psutil_bsd.c b/psutil/_psutil_bsd.c
index 16bb351f..f9a366d3 100644
--- a/psutil/_psutil_bsd.c
+++ b/psutil/_psutil_bsd.c
@@ -63,7 +63,8 @@
// convert a timeval struct to a double
#define TV2DOUBLE(t) ((t).tv_sec + (t).tv_usec / 1000000.0)
-
+// convert a bintime struct to milliseconds
+#define BT2MSEC(bt) (bt.sec * 1000 + ( ( (uint64_t) 1000000000 * (uint32_t) (bt.frac >> 32) ) >> 32 ) / 1000000)
/*
* Utility function which fills a kinfo_proc struct based on process pid
@@ -1555,10 +1556,9 @@ psutil_disk_io_counters(PyObject *self, PyObject *args) {
current.operations[DEVSTAT_WRITE], // no writes
current.bytes[DEVSTAT_READ], // bytes read
current.bytes[DEVSTAT_WRITE], // bytes written
- (long long)devstat_compute_etime(
- &current.duration[DEVSTAT_READ], NULL), // r time
- (long long)devstat_compute_etime(
- &current.duration[DEVSTAT_WRITE], NULL)); // w time
+ (long long) BT2MSEC(current.duration[DEVSTAT_READ]), // r time
+ (long long) BT2MSEC(current.duration[DEVSTAT_WRITE]) // w time
+ ); // finished transactions
if (!py_disk_info)
goto error;
if (PyDict_SetItemString(py_retdict, disk_name, py_disk_info))
diff --git a/psutil/_psutil_sunos.c b/psutil/_psutil_sunos.c
index 5910eb59..0a235d22 100644
--- a/psutil/_psutil_sunos.c
+++ b/psutil/_psutil_sunos.c
@@ -827,17 +827,11 @@ psutil_net_connections(PyObject *self, PyObject *args) {
PyObject *py_tuple = NULL;
PyObject *py_laddr = NULL;
PyObject *py_raddr = NULL;
- PyObject *py_af_filter = NULL;
- PyObject *py_type_filter = NULL;
if (py_retlist == NULL)
return NULL;
- if (! PyArg_ParseTuple(args, "lOO", &pid, &py_af_filter, &py_type_filter))
+ if (! PyArg_ParseTuple(args, "l", &pid))
goto error;
- if (!PySequence_Check(py_af_filter) || !PySequence_Check(py_type_filter)) {
- PyErr_SetString(PyExc_TypeError, "arg 2 or 3 is not a sequence");
- goto error;
- }
sd = open("/dev/arp", O_RDWR);
if (sd == -1) {
diff --git a/psutil/_pswindows.py b/psutil/_pswindows.py
index 5df17272..83f88765 100644
--- a/psutil/_pswindows.py
+++ b/psutil/_pswindows.py
@@ -12,15 +12,21 @@ from collections import namedtuple
from . import _common
from . import _psutil_windows as cext
-from ._common import conn_tmap, usage_percent, isfile_strict
-from ._common import sockfam_to_enum, socktype_to_enum
-from ._compat import PY3, xrange, lru_cache, long
-from ._psutil_windows import (ABOVE_NORMAL_PRIORITY_CLASS,
- BELOW_NORMAL_PRIORITY_CLASS,
- HIGH_PRIORITY_CLASS,
- IDLE_PRIORITY_CLASS,
- NORMAL_PRIORITY_CLASS,
- REALTIME_PRIORITY_CLASS)
+from ._common import conn_tmap
+from ._common import isfile_strict
+from ._common import sockfam_to_enum
+from ._common import socktype_to_enum
+from ._common import usage_percent
+from ._compat import long
+from ._compat import lru_cache
+from ._compat import PY3
+from ._compat import xrange
+from ._psutil_windows import ABOVE_NORMAL_PRIORITY_CLASS
+from ._psutil_windows import BELOW_NORMAL_PRIORITY_CLASS
+from ._psutil_windows import HIGH_PRIORITY_CLASS
+from ._psutil_windows import IDLE_PRIORITY_CLASS
+from ._psutil_windows import NORMAL_PRIORITY_CLASS
+from ._psutil_windows import REALTIME_PRIORITY_CLASS
if sys.version_info >= (3, 4):
import enum
diff --git a/psutil/arch/windows/ntextapi.h b/psutil/arch/windows/ntextapi.h
index 7f86c57a..4f843e02 100644
--- a/psutil/arch/windows/ntextapi.h
+++ b/psutil/arch/windows/ntextapi.h
@@ -177,7 +177,6 @@ typedef NTSTATUS (NTAPI *_NtSetInformationProcess)(
DWORD ProcessInformationLength
);
-
typedef enum _PROCESSINFOCLASS2 {
_ProcessBasicInformation,
ProcessQuotaLimits,
@@ -209,8 +208,12 @@ typedef enum _PROCESSINFOCLASS2 {
/* added after XP+ */
_ProcessImageFileName,
ProcessLUIDDeviceMapsEnabled,
+// MSVC 2015 starts forcing C++11 standard, which does not allow duplicate
+// unscoped enumerations. It doesn't matter that this is C code, MSVC is a C++ compiler.
+#if _MSC_VER < 1900
ProcessBreakOnTermination,
- ProcessDebugObjectHandle,
+#endif
+ ProcessDebugObjectHandle=ProcessLUIDDeviceMapsEnabled+2,
ProcessDebugFlags,
ProcessHandleTracing,
ProcessIoPriority,
diff --git a/test/_freebsd.py b/test/_freebsd.py
index 8726c908..1aac6213 100644
--- a/test/_freebsd.py
+++ b/test/_freebsd.py
@@ -14,10 +14,15 @@ import sys
import time
import psutil
-
from psutil._compat import PY3
-from test_psutil import (MEMORY_TOLERANCE, FREEBSD, sh, get_test_subprocess,
- which, retry_before_failing, reap_children, unittest)
+from test_psutil import FREEBSD
+from test_psutil import get_test_subprocess
+from test_psutil import MEMORY_TOLERANCE
+from test_psutil import reap_children
+from test_psutil import retry_before_failing
+from test_psutil import sh
+from test_psutil import unittest
+from test_psutil import which
PAGESIZE = os.sysconf("SC_PAGE_SIZE")
diff --git a/test/_linux.py b/test/_linux.py
index c9e04a53..661a2c87 100644
--- a/test/_linux.py
+++ b/test/_linux.py
@@ -7,6 +7,7 @@
"""Linux specific tests. These are implicitly run by test_psutil.py."""
from __future__ import division
+
import contextlib
import errno
import fcntl
@@ -26,15 +27,27 @@ try:
except ImportError:
import mock # requires "pip install mock"
-from test_psutil import POSIX, MEMORY_TOLERANCE, TRAVIS, LINUX
-from test_psutil import (skip_on_not_implemented, sh, get_test_subprocess,
- retry_before_failing, get_kernel_version, unittest,
- which, call_until)
-
import psutil
import psutil._pslinux
-from psutil._compat import PY3, u
-
+from psutil._compat import PY3
+from psutil._compat import u
+from test_psutil import call_until
+from test_psutil import get_kernel_version
+from test_psutil import get_test_subprocess
+from test_psutil import LINUX
+from test_psutil import MEMORY_TOLERANCE
+from test_psutil import POSIX
+from test_psutil import retry_before_failing
+from test_psutil import sh
+from test_psutil import skip_on_not_implemented
+from test_psutil import TRAVIS
+from test_psutil import unittest
+from test_psutil import which
+
+
+# procps-ng 3.3.10 changed the output format of free
+# and removed the 'buffers/cache line'
+OLD_PROCPS_NG_VERSION = 'buffers/cache' in sh('free')
SIOCGIFADDR = 0x8915
SIOCGIFCONF = 0x8912
@@ -129,7 +142,9 @@ class LinuxSpecificTestCase(unittest.TestCase):
@retry_before_failing()
def test_vmem_used(self):
lines = sh('free').split('\n')[1:]
- used = int(lines[0].split()[2]) * 1024
+ total = int(lines[0].split()[1])
+ free = int(lines[0].split()[3])
+ used = (total - free) * 1024
self.assertAlmostEqual(used, psutil.virtual_memory().used,
delta=MEMORY_TOLERANCE)
@@ -142,34 +157,32 @@ class LinuxSpecificTestCase(unittest.TestCase):
@retry_before_failing()
def test_vmem_buffers(self):
- lines = sh('free').split('\n')[1:]
- buffers = int(lines[0].split()[5]) * 1024
+ buffers = int(sh('vmstat').split('\n')[2].split()[4]) * 1024
self.assertAlmostEqual(buffers, psutil.virtual_memory().buffers,
delta=MEMORY_TOLERANCE)
@retry_before_failing()
def test_vmem_cached(self):
- lines = sh('free').split('\n')[1:]
- cached = int(lines[0].split()[6]) * 1024
+ cached = int(sh('vmstat').split('\n')[2].split()[5]) * 1024
self.assertAlmostEqual(cached, psutil.virtual_memory().cached,
delta=MEMORY_TOLERANCE)
def test_swapmem_total(self):
lines = sh('free').split('\n')[1:]
- total = int(lines[2].split()[1]) * 1024
+ total = int(lines[2 if OLD_PROCPS_NG_VERSION else 1].split()[1]) * 1024
self.assertEqual(total, psutil.swap_memory().total)
@retry_before_failing()
def test_swapmem_used(self):
lines = sh('free').split('\n')[1:]
- used = int(lines[2].split()[2]) * 1024
+ used = int(lines[2 if OLD_PROCPS_NG_VERSION else 1].split()[2]) * 1024
self.assertAlmostEqual(used, psutil.swap_memory().used,
delta=MEMORY_TOLERANCE)
@retry_before_failing()
def test_swapmem_free(self):
lines = sh('free').split('\n')[1:]
- free = int(lines[2].split()[3]) * 1024
+ free = int(lines[2 if OLD_PROCPS_NG_VERSION else 1].split()[1]) * 1024
self.assertAlmostEqual(free, psutil.swap_memory().free,
delta=MEMORY_TOLERANCE)
@@ -426,6 +439,38 @@ class LinuxSpecificTestCase(unittest.TestCase):
assert ret
self.assertEqual(ret[0].fstype, 'zfs')
+ @mock.patch('psutil._pslinux.socket.inet_ntop', side_effect=ValueError)
+ @mock.patch('psutil._pslinux.supports_ipv6', return_value=False)
+ def test_connections_ipv6_not_supported(self, supports_ipv6, inet_ntop):
+ # see: https://github.com/giampaolo/psutil/issues/623
+ try:
+ s = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
+ self.addCleanup(s.close)
+ s.bind(("::1", 0))
+ except socket.error:
+ pass
+ psutil.net_connections(kind='inet6')
+
+ def test_procfs_path(self):
+ tdir = tempfile.mkdtemp()
+ try:
+ psutil.PROCFS_PATH = tdir
+ self.assertRaises(IOError, psutil.virtual_memory)
+ self.assertRaises(IOError, psutil.swap_memory)
+ self.assertRaises(IOError, psutil.cpu_times)
+ self.assertRaises(IOError, psutil.cpu_times, percpu=True)
+ self.assertRaises(IOError, psutil.boot_time)
+ # self.assertRaises(IOError, psutil.pids)
+ self.assertRaises(IOError, psutil.net_connections)
+ self.assertRaises(IOError, psutil.net_io_counters)
+ self.assertRaises(IOError, psutil.net_if_stats)
+ self.assertRaises(IOError, psutil.disk_io_counters)
+ self.assertRaises(IOError, psutil.disk_partitions)
+ self.assertRaises(psutil.NoSuchProcess, psutil.Process)
+ finally:
+ psutil.PROCFS_PATH = "/proc"
+ os.rmdir(tdir)
+
# --- tests for specific kernel versions
@unittest.skipUnless(
diff --git a/test/_osx.py b/test/_osx.py
index 2375a483..cfa16c1f 100644
--- a/test/_osx.py
+++ b/test/_osx.py
@@ -15,9 +15,14 @@ import time
import psutil
from psutil._compat import PY3
-from test_psutil import (MEMORY_TOLERANCE, OSX, sh, get_test_subprocess,
- reap_children, retry_before_failing, unittest,
- TRAVIS)
+from test_psutil import get_test_subprocess
+from test_psutil import MEMORY_TOLERANCE
+from test_psutil import OSX
+from test_psutil import reap_children
+from test_psutil import retry_before_failing
+from test_psutil import sh
+from test_psutil import TRAVIS
+from test_psutil import unittest
PAGESIZE = os.sysconf("SC_PAGE_SIZE")
diff --git a/test/_posix.py b/test/_posix.py
index 63db0d7e..c5f26f78 100644
--- a/test/_posix.py
+++ b/test/_posix.py
@@ -13,12 +13,22 @@ import sys
import time
import psutil
-
from psutil._compat import PY3, callable
-from test_psutil import LINUX, SUNOS, OSX, BSD, PYTHON, POSIX, TRAVIS
-from test_psutil import (get_test_subprocess, skip_on_access_denied,
- retry_before_failing, reap_children, sh, unittest,
- get_kernel_version, wait_for_pid)
+from test_psutil import BSD
+from test_psutil import get_kernel_version
+from test_psutil import get_test_subprocess
+from test_psutil import LINUX
+from test_psutil import OSX
+from test_psutil import POSIX
+from test_psutil import PYTHON
+from test_psutil import reap_children
+from test_psutil import retry_before_failing
+from test_psutil import sh
+from test_psutil import skip_on_access_denied
+from test_psutil import SUNOS
+from test_psutil import TRAVIS
+from test_psutil import unittest
+from test_psutil import wait_for_pid
def ps(cmd):
diff --git a/test/_sunos.py b/test/_sunos.py
index 7520afc2..58050b1e 100644
--- a/test/_sunos.py
+++ b/test/_sunos.py
@@ -9,8 +9,10 @@
import sys
import os
-from test_psutil import SUNOS, sh, unittest
import psutil
+from test_psutil import sh
+from test_psutil import SUNOS
+from test_psutil import unittest
@unittest.skipUnless(SUNOS, "not a SunOS system")
diff --git a/test/_windows.py b/test/_windows.py
index 827cc449..d1e3935e 100644
--- a/test/_windows.py
+++ b/test/_windows.py
@@ -16,10 +16,8 @@ import sys
import time
import traceback
-from test_psutil import APPVEYOR, WINDOWS
-from test_psutil import get_test_subprocess, reap_children, unittest
-
import mock
+
try:
import wmi
except ImportError:
@@ -30,8 +28,16 @@ try:
except ImportError:
win32api = win32con = None
-from psutil._compat import PY3, callable, long
import psutil
+from psutil._compat import callable
+from psutil._compat import long
+from psutil._compat import PY3
+from test_psutil import APPVEYOR
+from test_psutil import get_test_subprocess
+from test_psutil import reap_children
+from test_psutil import retry_before_failing
+from test_psutil import unittest
+from test_psutil import WINDOWS
cext = psutil._psplatform.cext
@@ -207,6 +213,7 @@ class WindowsSpecificTestCase(unittest.TestCase):
self.assertEqual(wmi_pids, psutil_pids)
@unittest.skipIf(wmi is None, "wmi module is not installed")
+ @retry_before_failing()
def test_disks(self):
ps_parts = psutil.disk_partitions(all=True)
wmi_parts = wmi.WMI().Win32_LogicalDisk()
diff --git a/test/test_memory_leaks.py b/test/test_memory_leaks.py
index 89167fdc..d7588b0c 100644
--- a/test/test_memory_leaks.py
+++ b/test/test_memory_leaks.py
@@ -20,12 +20,21 @@ import time
import psutil
import psutil._common
-
-from psutil._compat import xrange, callable
-from test_psutil import (WINDOWS, POSIX, OSX, LINUX, SUNOS, BSD, TESTFN,
- RLIMIT_SUPPORT, TRAVIS)
-from test_psutil import (reap_children, supports_ipv6, safe_remove,
- get_test_subprocess)
+from psutil._compat import callable
+from psutil._compat import xrange
+from test_psutil import BSD
+from test_psutil import get_test_subprocess
+from test_psutil import LINUX
+from test_psutil import OSX
+from test_psutil import POSIX
+from test_psutil import reap_children
+from test_psutil import RLIMIT_SUPPORT
+from test_psutil import safe_remove
+from test_psutil import SUNOS
+from test_psutil import supports_ipv6
+from test_psutil import TESTFN
+from test_psutil import TRAVIS
+from test_psutil import WINDOWS
if sys.version_info < (2, 7):
import unittest2 as unittest # https://pypi.python.org/pypi/unittest2
diff --git a/test/test_psutil.py b/test/test_psutil.py
index 5c173990..bbaeecb9 100644
--- a/test/test_psutil.py
+++ b/test/test_psutil.py
@@ -42,7 +42,9 @@ import time
import traceback
import types
import warnings
-from socket import AF_INET, SOCK_STREAM, SOCK_DGRAM
+from socket import AF_INET
+from socket import SOCK_DGRAM
+from socket import SOCK_STREAM
try:
import ipaddress # python >= 3.3
except ImportError:
@@ -53,7 +55,12 @@ except ImportError:
import mock # requires "pip install mock"
import psutil
-from psutil._compat import PY3, callable, long, unicode, which
+from psutil._common import supports_ipv6
+from psutil._compat import callable
+from psutil._compat import long
+from psutil._compat import PY3
+from psutil._compat import unicode
+from psutil._compat import which
if sys.version_info < (2, 7):
import unittest2 as unittest # https://pypi.python.org/pypi/unittest2
@@ -484,23 +491,6 @@ def skip_on_not_implemented(only_if=None):
return decorator
-def supports_ipv6():
- """Return True if IPv6 is supported on this platform."""
- if not socket.has_ipv6 or not hasattr(socket, "AF_INET6"):
- return False
- sock = None
- try:
- sock = socket.socket(AF_INET6, SOCK_STREAM)
- sock.bind(("::1", 0))
- except (socket.error, socket.gaierror):
- return False
- else:
- return True
- finally:
- if sock is not None:
- sock.close()
-
-
def create_temp_executable_file(suffix):
tmpdir = None
if TRAVIS and OSX:
@@ -1721,6 +1711,7 @@ class TestProcess(unittest.TestCase):
pyexe = os.path.basename(os.path.realpath(sys.executable)).lower()
assert pyexe.startswith(name), (pyexe, name)
+ @unittest.skipIf(SUNOS, "doesn't work on Solaris")
def test_prog_w_funky_name(self):
# Test that name(), exe() and cmdline() correctly handle programs
# with funky chars such as spaces and ")", see:
@@ -2917,6 +2908,29 @@ class TestMisc(unittest.TestCase):
# docstring
self.assertEqual(foo.__doc__, "foo docstring")
+ def test_supports_ipv6(self):
+ if supports_ipv6():
+ with mock.patch('psutil._common.socket') as s:
+ s.has_ipv6 = False
+ assert not supports_ipv6()
+ with mock.patch('psutil._common.socket.socket',
+ side_effect=socket.error) as s:
+ assert not supports_ipv6()
+ assert s.called
+ with mock.patch('psutil._common.socket.socket',
+ side_effect=socket.gaierror) as s:
+ assert not supports_ipv6()
+ assert s.called
+ with mock.patch('psutil._common.socket.socket.bind',
+ side_effect=socket.gaierror) as s:
+ assert not supports_ipv6()
+ assert s.called
+ else:
+ if hasattr(socket, 'AF_INET6'):
+ with self.assertRaises(Exception):
+ sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
+ sock.bind(("::1", 0))
+
def test_isfile_strict(self):
from psutil._common import isfile_strict
this_file = os.path.abspath(__file__)