diff options
author | Giampaolo Rodola <g.rodola@gmail.com> | 2015-01-03 11:33:30 +0100 |
---|---|---|
committer | Giampaolo Rodola <g.rodola@gmail.com> | 2015-01-03 11:33:30 +0100 |
commit | bba6b31848c6ca1a9023049d4c544293f4b5c889 (patch) | |
tree | 4ec76e0511118930ee655ffc15f18445ee36d90f | |
parent | 80b04a57c00036926de9f872ee858b8497a43440 (diff) | |
parent | 39af7af7ca5438d7feac816b457b9ebe48747ddd (diff) | |
download | psutil-bba6b31848c6ca1a9023049d4c544293f4b5c889.tar.gz |
merge from master
-rw-r--r-- | CREDITS | 7 | ||||
-rw-r--r-- | HISTORY.rst | 10 | ||||
-rw-r--r-- | README.rst | 16 | ||||
-rw-r--r-- | TODO | 16 | ||||
-rw-r--r-- | docs/index.rst | 19 | ||||
-rwxr-xr-x | examples/iotop.py | 13 | ||||
-rwxr-xr-x | examples/nettop.py | 10 | ||||
-rwxr-xr-x | examples/top.py | 11 | ||||
-rw-r--r-- | psutil/__init__.py | 74 | ||||
-rw-r--r-- | psutil/_common.py | 30 | ||||
-rw-r--r-- | psutil/_compat.py | 4 | ||||
-rw-r--r-- | psutil/_psbsd.py | 33 | ||||
-rwxr-xr-x[-rw-r--r--] | psutil/_pslinux.py | 10 | ||||
-rw-r--r-- | psutil/_psosx.py | 5 | ||||
-rw-r--r-- | psutil/_psposix.py | 6 | ||||
-rw-r--r-- | psutil/_pssunos.py | 11 | ||||
-rw-r--r-- | psutil/_psutil_bsd.c | 41 | ||||
-rw-r--r-- | psutil/_psutil_windows.c | 11 | ||||
-rw-r--r-- | psutil/_pswindows.py | 13 | ||||
-rw-r--r-- | psutil/arch/windows/ntextapi.h | 5 | ||||
-rw-r--r-- | psutil/arch/windows/process_handles.c | 128 | ||||
-rw-r--r-- | psutil/arch/windows/process_info.h | 9 | ||||
-rw-r--r-- | setup.py | 1 | ||||
-rw-r--r-- | test/_bsd.py | 1 | ||||
-rw-r--r-- | test/_windows.py | 10 | ||||
-rw-r--r-- | test/test_memory_leaks.py | 10 | ||||
-rw-r--r-- | test/test_psutil.py | 36 | ||||
-rw-r--r-- | tox.ini | 1 |
28 files changed, 347 insertions, 194 deletions
@@ -282,4 +282,9 @@ E: bruno.binet@gmail.com I: 572 N: Gabi Davar -I: 581 +I: 578, 581 + +N: spacewanderlzx +C: Guangzhou,China +E: spacewanderlzx@gmail.com +I: 555
\ No newline at end of file diff --git a/HISTORY.rst b/HISTORY.rst index 4632cca5..af3c7c0b 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -6,7 +6,17 @@ Bug tracker at https://github.com/giampaolo/psutil/issues **Enhancements** - #581: add .gitignore. (patch by Gabi Davar) +- #582: connection constants returned by psutil.net_connections() and + psutil.Process.connections() were turned from int to enums on Python > 3.4. +**Bug fixes** + +- #555: [Linux] psutil.users() correctly handles ":0" as an alias for + "localhost" +- #579: [Windows] fixed many compiler warnings. +- #585: [FreeBSD] net_connections() may raise KeyError. +- #586: [FreeBSD] cpu_affinity() segfaults on set in case an invalid CPU + number is provided. 2.2.1 - 2015-02-02 ================== @@ -142,10 +142,10 @@ Network 'lo': netio(bytes_sent=2838627, bytes_recv=2838627, packets_sent=30567, packets_recv=30567, errin=0, errout=0, dropin=0, dropout=0)} >>> >>> psutil.net_connections() - [pconn(fd=115, family=2, type=1, laddr=('10.0.0.1', 48776), raddr=('93.186.135.91', 80), status='ESTABLISHED', pid=1254), - pconn(fd=117, family=2, type=1, laddr=('10.0.0.1', 43761), raddr=('72.14.234.100', 80), status='CLOSING', pid=2987), - pconn(fd=-1, family=2, type=1, laddr=('10.0.0.1', 60759), raddr=('72.14.234.104', 80), status='ESTABLISHED', pid=None), - pconn(fd=-1, family=2, type=1, laddr=('10.0.0.1', 51314), raddr=('72.14.234.83', 443), status='SYN_SENT', pid=None) + [pconn(fd=115, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 48776), raddr=('93.186.135.91', 80), status='ESTABLISHED', pid=1254), + pconn(fd=117, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 43761), raddr=('72.14.234.100', 80), status='CLOSING', pid=2987), + pconn(fd=-1, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 60759), raddr=('72.14.234.104', 80), status='ESTABLISHED', pid=None), + pconn(fd=-1, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 51314), raddr=('72.14.234.83', 443), status='SYN_SENT', pid=None) ...] Other system info @@ -229,10 +229,10 @@ Process management [popenfile(path='/home/giampaolo/svn/psutil/somefile', fd=3)] >>> >>> p.connections() - [pconn(fd=115, family=2, type=1, laddr=('10.0.0.1', 48776), raddr=('93.186.135.91', 80), status='ESTABLISHED'), - pconn(fd=117, family=2, type=1, laddr=('10.0.0.1', 43761), raddr=('72.14.234.100', 80), status='CLOSING'), - pconn(fd=119, family=2, type=1, laddr=('10.0.0.1', 60759), raddr=('72.14.234.104', 80), status='ESTABLISHED'), - pconn(fd=123, family=2, type=1, laddr=('10.0.0.1', 51314), raddr=('72.14.234.83', 443), status='SYN_SENT')] + [pconn(fd=115, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 48776), raddr=('93.186.135.91', 80), status='ESTABLISHED'), + pconn(fd=117, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 43761), raddr=('72.14.234.100', 80), status='CLOSING'), + pconn(fd=119, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 60759), raddr=('72.14.234.104', 80), status='ESTABLISHED'), + pconn(fd=123, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 51314), raddr=('72.14.234.83', 443), status='SYN_SENT')] >>> >>> p.num_threads() 4 @@ -21,7 +21,8 @@ HIGHER PRIORITY * #269: expose network ifaces RX/TW queues. - * Process.threads(): thread names + * Process.threads(): thread names; patch for OSX available at: + https://code.google.com/p/plcrashreporter/issues/detail?id=65 * Asynchronous psutil.Popen (see http://bugs.python.org/issue1191964) @@ -50,10 +51,7 @@ LOWER PRIORITY * #357: what CPU a process is on. - * thread names: - * https://code.google.com/p/plcrashreporter/issues/detail?id=65 - - * Doc / wiki which compares similarities between UNIX cli tools and psutil. + * Doc / wiki which compares similarities between UNIX cli tools and psutil. Example: df -a -> psutil.disk_partitions lsof -> psutil.Process.open_files() and psutil.Process.open_connections() @@ -65,7 +63,13 @@ LOWER PRIORITY DEBATABLE ========= - * support wheels? http://pythonwheels.com/ + * psutil.proc_tree() something which obtains a {pid:ppid, ...} dict for + all running processes in one shot. This can be factored out from + Process.children() and exposed as a first class function. + PROS: on Windows we can take advantage of _psutil_windows.ppid_map() + which is faster than iterating over all pids and calling ppid(). + CONS: examples/pstree.py shows this can be easily done in the user code + so maybe it's not worth the addition. * advanced cmdline interface exposing the whole API and providing different kind of outputs (e.g. pprinted, colorized, json). diff --git a/docs/index.rst b/docs/index.rst index 76de5936..92d7fe73 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -391,10 +391,10 @@ Network >>> import psutil >>> psutil.net_connections() - [pconn(fd=115, family=2, type=1, laddr=('10.0.0.1', 48776), raddr=('93.186.135.91', 80), status='ESTABLISHED', pid=1254), - pconn(fd=117, family=2, type=1, laddr=('10.0.0.1', 43761), raddr=('72.14.234.100', 80), status='CLOSING', pid=2987), - pconn(fd=-1, family=2, type=1, laddr=('10.0.0.1', 60759), raddr=('72.14.234.104', 80), status='ESTABLISHED', pid=None), - pconn(fd=-1, family=2, type=1, laddr=('10.0.0.1', 51314), raddr=('72.14.234.83', 443), status='SYN_SENT', pid=None) + [pconn(fd=115, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 48776), raddr=('93.186.135.91', 80), status='ESTABLISHED', pid=1254), + pconn(fd=117, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 43761), raddr=('72.14.234.100', 80), status='CLOSING', pid=2987), + pconn(fd=-1, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 60759), raddr=('72.14.234.104', 80), status='ESTABLISHED', pid=None), + pconn(fd=-1, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 51314), raddr=('72.14.234.83', 443), status='SYN_SENT', pid=None) ...] .. note:: (OSX) :class:`psutil.AccessDenied` is always raised unless running @@ -878,7 +878,8 @@ Process class `CPU affinity <http://www.linuxjournal.com/article/6799?page=0,0>`__. CPU affinity consists in telling the OS to run a certain process on a limited set of CPUs only. The number of eligible CPUs can be obtained with - ``list(range(psutil.cpu_count()))``. + ``list(range(psutil.cpu_count()))``. On set raises ``ValueError`` in case + an invalid CPU number is specified. >>> import psutil >>> psutil.cpu_count() @@ -1082,10 +1083,10 @@ Process class >>> p.name() 'firefox' >>> p.connections() - [pconn(fd=115, family=2, type=1, laddr=('10.0.0.1', 48776), raddr=('93.186.135.91', 80), status='ESTABLISHED'), - pconn(fd=117, family=2, type=1, laddr=('10.0.0.1', 43761), raddr=('72.14.234.100', 80), status='CLOSING'), - pconn(fd=119, family=2, type=1, laddr=('10.0.0.1', 60759), raddr=('72.14.234.104', 80), status='ESTABLISHED'), - pconn(fd=123, family=2, type=1, laddr=('10.0.0.1', 51314), raddr=('72.14.234.83', 443), status='SYN_SENT')] + [pconn(fd=115, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 48776), raddr=('93.186.135.91', 80), status='ESTABLISHED'), + pconn(fd=117, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 43761), raddr=('72.14.234.100', 80), status='CLOSING'), + pconn(fd=119, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 60759), raddr=('72.14.234.104', 80), status='ESTABLISHED'), + pconn(fd=123, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 51314), raddr=('72.14.234.83', 443), status='SYN_SENT')] .. method:: is_running() diff --git a/examples/iotop.py b/examples/iotop.py index a0986782..be3819b8 100755 --- a/examples/iotop.py +++ b/examples/iotop.py @@ -30,14 +30,15 @@ PID USER DISK READ DISK WRITE COMMAND Author: Giampaolo Rodola' <g.rodola@gmail.com> """ -import os +import atexit +import time import sys -import psutil -if not hasattr(psutil.Process, 'io_counters') or os.name != 'posix': +try: + import curses +except ImportError: sys.exit('platform not supported') -import time -import curses -import atexit + +import psutil # --- curses stuff diff --git a/examples/nettop.py b/examples/nettop.py index 857285cf..7a8343ee 100755 --- a/examples/nettop.py +++ b/examples/nettop.py @@ -31,13 +31,13 @@ pkts-sent 0 0 pkts-recv 1214470 0 """ -import sys -import os -if os.name != 'posix': - sys.exit('platform not supported') import atexit -import curses import time +import sys +try: + import curses +except ImportError: + sys.exit('platform not supported') import psutil diff --git a/examples/top.py b/examples/top.py index a305297f..7aebef1d 100755 --- a/examples/top.py +++ b/examples/top.py @@ -34,14 +34,15 @@ PID USER NI VIRT RES CPU% MEM% TIME+ NAME ... """ +from datetime import datetime, timedelta +import atexit import os +import time import sys -if os.name != 'posix': +try: + import curses +except ImportError: sys.exit('platform not supported') -import atexit -import curses -import time -from datetime import datetime, timedelta import psutil diff --git a/psutil/__init__.py b/psutil/__init__.py index 4e50563a..10239dc9 100644 --- a/psutil/__init__.py +++ b/psutil/__init__.py @@ -12,33 +12,6 @@ in Python. from __future__ import division -__author__ = "Giampaolo Rodola'" -__version__ = "3.0.0" -version_info = tuple([int(num) for num in __version__.split('.')]) - -__all__ = [ - # exceptions - "Error", "NoSuchProcess", "AccessDenied", "TimeoutExpired", - # constants - "version_info", "__version__", - "STATUS_RUNNING", "STATUS_IDLE", "STATUS_SLEEPING", "STATUS_DISK_SLEEP", - "STATUS_STOPPED", "STATUS_TRACING_STOP", "STATUS_ZOMBIE", "STATUS_DEAD", - "STATUS_WAKING", "STATUS_LOCKED", "STATUS_WAITING", "STATUS_LOCKED", - "CONN_ESTABLISHED", "CONN_SYN_SENT", "CONN_SYN_RECV", "CONN_FIN_WAIT1", - "CONN_FIN_WAIT2", "CONN_TIME_WAIT", "CONN_CLOSE", "CONN_CLOSE_WAIT", - "CONN_LAST_ACK", "CONN_LISTEN", "CONN_CLOSING", "CONN_NONE", - "AF_LINK", - # classes - "Process", "Popen", - # functions - "pid_exists", "pids", "process_iter", "wait_procs", # proc - "virtual_memory", "swap_memory", # memory - "cpu_times", "cpu_percent", "cpu_times_percent", "cpu_count", # cpu - "net_io_counters", "net_connections", "net_if_addrs", # network - "disk_io_counters", "disk_partitions", "disk_usage", # disk - "users", "boot_time", # others -] - import collections import errno import functools @@ -73,7 +46,7 @@ from psutil._common import (STATUS_RUNNING, # NOQA STATUS_LOCKED, STATUS_IDLE, # bsd STATUS_WAITING, # bsd - STATUS_LOCKED) # bsd +) from psutil._common import (CONN_ESTABLISHED, CONN_SYN_SENT, @@ -89,7 +62,7 @@ from psutil._common import (CONN_ESTABLISHED, CONN_NONE) if sys.platform.startswith("linux"): - import psutil._pslinux as _psplatform + from psutil import _pslinux as _psplatform from psutil._pslinux import (phymem_buffers, # NOQA cached_phymem) @@ -138,7 +111,7 @@ if sys.platform.startswith("linux"): del _psutil_linux elif sys.platform.startswith("win32"): - import psutil._pswindows as _psplatform + from psutil import _pswindows as _psplatform from _psutil_windows import (ABOVE_NORMAL_PRIORITY_CLASS, # NOQA BELOW_NORMAL_PRIORITY_CLASS, HIGH_PRIORITY_CLASS, @@ -148,23 +121,46 @@ elif sys.platform.startswith("win32"): from psutil._pswindows import CONN_DELETE_TCB # NOQA elif sys.platform.startswith("darwin"): - import psutil._psosx as _psplatform + from psutil import _psosx as _psplatform elif sys.platform.startswith("freebsd"): - import psutil._psbsd as _psplatform + from psutil import _psbsd as _psplatform elif sys.platform.startswith("sunos"): - import psutil._pssunos as _psplatform + from psutil import _pssunos as _psplatform from psutil._pssunos import (CONN_IDLE, # NOQA CONN_BOUND) else: raise NotImplementedError('platform %s is not supported' % sys.platform) -# extend the local __all__ context -__all__.extend(_psplatform.__extra__all__) - +__all__ = [ + # exceptions + "Error", "NoSuchProcess", "AccessDenied", "TimeoutExpired", + # constants + "version_info", "__version__", + "STATUS_RUNNING", "STATUS_IDLE", "STATUS_SLEEPING", "STATUS_DISK_SLEEP", + "STATUS_STOPPED", "STATUS_TRACING_STOP", "STATUS_ZOMBIE", "STATUS_DEAD", + "STATUS_WAKING", "STATUS_LOCKED", "STATUS_WAITING", "STATUS_LOCKED", + "CONN_ESTABLISHED", "CONN_SYN_SENT", "CONN_SYN_RECV", "CONN_FIN_WAIT1", + "CONN_FIN_WAIT2", "CONN_TIME_WAIT", "CONN_CLOSE", "CONN_CLOSE_WAIT", + "CONN_LAST_ACK", "CONN_LISTEN", "CONN_CLOSING", "CONN_NONE", + "AF_LINK", + # classes + "Process", "Popen", + # functions + "pid_exists", "pids", "process_iter", "wait_procs", # proc + "virtual_memory", "swap_memory", # memory + "cpu_times", "cpu_percent", "cpu_times_percent", "cpu_count", # cpu + "net_io_counters", "net_connections", "net_if_addrs", # network + "disk_io_counters", "disk_partitions", "disk_usage", # disk + "users", "boot_time", # others +] +__all__.extend(_psplatform.__extra__all__) +__author__ = "Giampaolo Rodola'" +__version__ = "3.0.0" +version_info = tuple([int(num) for num in __version__.split('.')]) AF_LINK = _psplatform.AF_LINK _TOTAL_PHYMEM = None _POSIX = os.name == 'posix' @@ -855,9 +851,11 @@ class Process(object): blocking = interval is not None and interval > 0.0 num_cpus = cpu_count() if _POSIX: - timer = lambda: _timer() * num_cpus + def timer(): + return _timer() * num_cpus else: - timer = lambda: sum(cpu_times()) + def timer(): + return sum(cpu_times()) if blocking: st1 = timer() pt1 = self._proc.cpu_times() diff --git a/psutil/_common.py b/psutil/_common.py index d52cea87..cc223cf8 100644 --- a/psutil/_common.py +++ b/psutil/_common.py @@ -17,6 +17,10 @@ try: import threading except ImportError: import dummy_threading as threading +try: + import enum # py >= 3.4 +except ImportError: + enum = None from collections import namedtuple from socket import AF_INET, SOCK_STREAM, SOCK_DGRAM @@ -160,6 +164,30 @@ def isfile_strict(path): return stat.S_ISREG(st.st_mode) +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. + """ + if enum is None: + return num + try: + return socket.AddressFamily(num) + except (ValueError, AttributeError): + return num + + +def socktype_to_enum(num): + """Convert a numeric socket type value to an IntEnum member. + If it's not a known member, return the numeric value itself. + """ + if enum is None: + return num + try: + return socket.AddressType(num) + except (ValueError, AttributeError): + return num + + # --- Process.connections() 'kind' parameter mapping conn_tmap = { @@ -184,7 +212,7 @@ if AF_UNIX is not None: "unix": ([AF_UNIX], [SOCK_STREAM, SOCK_DGRAM]), }) -del AF_INET, AF_INET6, AF_UNIX, SOCK_STREAM, SOCK_DGRAM, socket +del AF_INET, AF_INET6, AF_UNIX, SOCK_STREAM, SOCK_DGRAM # --- namedtuples for psutil.* system-related functions diff --git a/psutil/_compat.py b/psutil/_compat.py index b52a04f0..dbb8dc1c 100644 --- a/psutil/_compat.py +++ b/psutil/_compat.py @@ -6,12 +6,12 @@ """Module which provides compatibility with older Python versions.""" -__all__ = ["PY3", "long", "xrange", "unicode", "callable", "lru_cache"] - import collections import functools import sys +__all__ = ["PY3", "long", "xrange", "unicode", "callable", "lru_cache"] + PY3 = sys.version_info[0] == 3 if PY3: diff --git a/psutil/_psbsd.py b/psutil/_psbsd.py index d59c23f2..eb09f9dc 100644 --- a/psutil/_psbsd.py +++ b/psutil/_psbsd.py @@ -15,7 +15,8 @@ from collections import namedtuple from psutil import _common from psutil import _psposix -from psutil._common import conn_tmap, usage_percent +from psutil._common import conn_tmap, usage_percent, sockfam_to_enum +from psutil._common import socktype_to_enum import _psutil_bsd as cext import _psutil_posix @@ -50,7 +51,7 @@ TCP_STATUSES = { } PAGESIZE = os.sysconf("SC_PAGE_SIZE") -AF_LINK = socket.AF_LINK +AF_LINK = _psutil_posix.AF_LINK # extend base mem ntuple with BSD-specific memory metrics svmem = namedtuple( @@ -186,16 +187,25 @@ def net_connections(kind): raise ValueError("invalid %r kind argument; choose between %s" % (kind, ', '.join([repr(x) for x in conn_tmap]))) families, types = conn_tmap[kind] - ret = [] + ret = set() rawlist = cext.net_connections() for item in rawlist: fd, fam, type, laddr, raddr, status, pid = item # TODO: apply filter at C level if fam in families and type in types: - status = TCP_STATUSES[status] + try: + status = TCP_STATUSES[status] + except KeyError: + # XXX: Not sure why this happens. I saw this occurring + # with IPv6 sockets opened by 'vim'. Those sockets + # have a very short lifetime so maybe the kernel + # can't initialize their status? + status = TCP_STATUSES[cext.PSUTIL_CONN_NONE] + fam = sockfam_to_enum(fam) + type = socktype_to_enum(type) nt = _common.sconn(fd, fam, type, laddr, raddr, status, pid) - ret.append(nt) - return ret + ret.add(nt) + return list(ret) pids = cext.pids @@ -315,6 +325,8 @@ class Process(object): ret = [] for item in rawlist: fd, fam, type, laddr, raddr, status = item + fam = sockfam_to_enum(fam) + type = socktype_to_enum(type) status = TCP_STATUSES[status] nt = _common.pconn(fd, fam, type, laddr, raddr, status) ret.append(nt) @@ -397,6 +409,14 @@ class Process(object): @wrap_exceptions def cpu_affinity_set(self, cpus): + # Pre-emptively check if CPUs are valid because the C + # function has a weird behavior in case of invalid CPUs, + # see: https://github.com/giampaolo/psutil/issues/586 + allcpus = tuple(range(len(per_cpu_times()))) + for cpu in cpus: + if cpu not in allcpus: + raise ValueError("invalid CPU #%i (choose between %s)" + % (cpu, allcpus)) try: cext.proc_cpu_affinity_set(self.pid, cpus) except OSError as err: @@ -405,7 +425,6 @@ class Process(object): # on because the set does not overlap with the thread's # anonymous mask>> if err.errno in (errno.EINVAL, errno.EDEADLK): - allcpus = tuple(range(len(per_cpu_times()))) for cpu in cpus: if cpu not in allcpus: raise ValueError("invalid CPU #%i (choose between %s)" diff --git a/psutil/_pslinux.py b/psutil/_pslinux.py index fae23734..e1f9560e 100644..100755 --- a/psutil/_pslinux.py +++ b/psutil/_pslinux.py @@ -21,7 +21,7 @@ from collections import namedtuple, defaultdict from psutil import _common from psutil import _psposix -from psutil._common import (isfile_strict, usage_percent, deprecated) +from psutil._common import isfile_strict, usage_percent, deprecated from psutil._compat import PY3 import _psutil_linux as cext import _psutil_posix @@ -291,7 +291,7 @@ def users(): # to use them in the future. if not user_process: continue - if hostname == ':0.0': + if hostname == ':0.0' or hostname == ':0': hostname = 'localhost' nt = _common.suser(user, tty or None, hostname, tstamp) retlist.append(nt) @@ -504,7 +504,7 @@ class Connections: return [] else: inodes = self.get_all_inodes() - ret = [] + ret = set() for f, family, type_ in self.tmap[kind]: if family in (socket.AF_INET, socket.AF_INET6): ls = self.process_inet( @@ -519,8 +519,8 @@ class Connections: else: conn = _common.sconn(fd, family, type_, laddr, raddr, status, bound_pid) - ret.append(conn) - return ret + ret.add(conn) + return list(ret) _connections = Connections() diff --git a/psutil/_psosx.py b/psutil/_psosx.py index 2965b2c2..8d382e57 100644 --- a/psutil/_psosx.py +++ b/psutil/_psosx.py @@ -15,6 +15,7 @@ from collections import namedtuple from psutil import _common from psutil import _psposix from psutil._common import conn_tmap, usage_percent, isfile_strict +from psutil._common import sockfam_to_enum, socktype_to_enum import _psutil_osx as cext import _psutil_posix @@ -24,7 +25,7 @@ __extra__all__ = [] # --- constants PAGESIZE = os.sysconf("SC_PAGE_SIZE") -AF_LINK = socket.AF_LINK +AF_LINK = _psutil_posix.AF_LINK # http://students.mimuw.edu.pl/lxr/source/include/net/tcp_states.h TCP_STATUSES = { @@ -295,6 +296,8 @@ class Process(object): for item in rawlist: fd, fam, type, laddr, raddr, status = item status = TCP_STATUSES[status] + fam = sockfam_to_enum(fam) + type = socktype_to_enum(type) nt = _common.pconn(fd, fam, type, laddr, raddr, status) ret.append(nt) return ret diff --git a/psutil/_psposix.py b/psutil/_psposix.py index 94db351e..1f7dc96e 100644 --- a/psutil/_psposix.py +++ b/psutil/_psposix.py @@ -68,10 +68,12 @@ def wait_pid(pid, timeout=None): timer = getattr(time, 'monotonic', time.time) if timeout is not None: - waitcall = lambda: os.waitpid(pid, os.WNOHANG) + def waitcall(): + return os.waitpid(pid, os.WNOHANG) stop_at = timer() + timeout else: - waitcall = lambda: os.waitpid(pid, 0) + def waitcall(): + return os.waitpid(pid, 0) delay = 0.0001 while True: diff --git a/psutil/_pssunos.py b/psutil/_pssunos.py index 17968f67..031231b8 100644 --- a/psutil/_pssunos.py +++ b/psutil/_pssunos.py @@ -15,7 +15,8 @@ from collections import namedtuple from psutil import _common from psutil import _psposix -from psutil._common import usage_percent, isfile_strict +from psutil._common import isfile_strict, socktype_to_enum, sockfam_to_enum +from psutil._common import usage_percent from psutil._compat import PY3 import _psutil_posix import _psutil_sunos as cext @@ -212,7 +213,7 @@ def net_connections(kind, _pid=-1): % (kind, ', '.join([repr(x) for x in cmap]))) families, types = _common.conn_tmap[kind] rawlist = cext.net_connections(_pid, families, types) - ret = [] + ret = set() for item in rawlist: fd, fam, type_, laddr, raddr, status, pid = item if fam not in families: @@ -220,12 +221,14 @@ def net_connections(kind, _pid=-1): if type_ not in types: continue status = TCP_STATUSES[status] + fam = sockfam_to_enum(fam) + type_ = socktype_to_enum(type_) if _pid == -1: nt = _common.sconn(fd, fam, type_, laddr, raddr, status, pid) else: nt = _common.pconn(fd, fam, type_, laddr, raddr, status) - ret.append(nt) - return ret + ret.add(nt) + return list(ret) def wrap_exceptions(fun): diff --git a/psutil/_psutil_bsd.c b/psutil/_psutil_bsd.c index 0128c8c8..615c04ba 100644 --- a/psutil/_psutil_bsd.c +++ b/psutil/_psutil_bsd.c @@ -95,7 +95,7 @@ psutil_kinfo_proc(const pid_t pid, struct kinfo_proc *proc) /* * Set exception to AccessDenied if pid exists else NoSuchProcess. */ -int +void psutil_raise_ad_or_nsp(long pid) { if (psutil_pid_exists(pid) == 0) { NoSuchProcess(); @@ -905,7 +905,6 @@ psutil_fetch_tcplist(void) { char *buf; size_t len; - int error; for (;;) { if (sysctlbyname("net.inet.tcp.pcblist", NULL, &len, NULL, 0) < 0) { @@ -1158,7 +1157,7 @@ psutil_proc_connections(PyObject *self, PyObject *args) sun = (struct sockaddr_un *)&kif->kf_sa_local; snprintf( path, sizeof(path), "%.*s", - (sun->sun_len - (sizeof(*sun) - sizeof(sun->sun_path))), + (int)(sun->sun_len - (sizeof(*sun) - sizeof(sun->sun_path))), sun->sun_path); tuple = Py_BuildValue("(iiisOi)", @@ -1799,11 +1798,12 @@ int psutil_gather_inet(int proto, PyObject *py_retlist) struct xtcpcb *xtp; struct inpcb *inp; struct xsocket *so; - struct sock *sock; - const char *varname; + const char *varname = NULL; size_t len, bufsize; void *buf; - int hash, retry, vflag, type; + int hash; + int retry; + int type = NULL; PyObject *tuple = NULL; PyObject *laddr = NULL; @@ -1875,7 +1875,8 @@ int psutil_gather_inet(int proto, PyObject *py_retlist) inp = &xtp->xt_inp; so = &xtp->xt_socket; char lip[200], rip[200]; - int family, lport, rport, pid, status; + int family = NULL; + int lport, rport, pid, status; hash = (int)((uintptr_t)so->xso_so % HASHSIZE); pid = psutil_get_pid_from_sock(hash); @@ -1933,12 +1934,14 @@ int psutil_gather_unix(int proto, PyObject *py_retlist) { struct xunpgen *xug, *exug; struct xunpcb *xup; - struct sock *sock; - const char *varname, *protoname; - size_t len, bufsize; + const char *varname = NULL; + const char *protoname = NULL; + size_t len; + size_t bufsize; void *buf; - int hash, retry; - int family, lport, rport, pid; + int hash; + int retry; + int pid; struct sockaddr_un *sun; char path[PATH_MAX]; @@ -2002,7 +2005,7 @@ int psutil_gather_unix(int proto, PyObject *py_retlist) sun = (struct sockaddr_un *)&xup->xu_addr; snprintf(path, sizeof(path), "%.*s", - (sun->sun_len - (sizeof(*sun) - sizeof(sun->sun_path))), + (int)(sun->sun_len - (sizeof(*sun) - sizeof(sun->sun_path))), sun->sun_path); tuple = Py_BuildValue("(iiisOii)", -1, AF_UNIX, proto, path, Py_None, @@ -2033,8 +2036,6 @@ error: static PyObject* psutil_net_connections(PyObject* self, PyObject* args) { - PyObject *af_filter = NULL; - PyObject *type_filter = NULL; PyObject *py_retlist = PyList_New(0); if (psutil_populate_xfiles() != 1) @@ -2122,14 +2123,12 @@ psutil_proc_cpu_affinity_set(PyObject *self, PyObject *args) PyObject *py_cpu_set; PyObject *py_cpu_seq = NULL; - if (!PyArg_ParseTuple(args, "lO", &pid, &py_cpu_set)) { - goto error; - } + if (!PyArg_ParseTuple(args, "lO", &pid, &py_cpu_set)) + return NULL; py_cpu_seq = PySequence_Fast(py_cpu_set, "expected a sequence or integer"); - if (!py_cpu_seq) { - goto error; - } + if (!py_cpu_seq) + return NULL; seq_len = PySequence_Fast_GET_SIZE(py_cpu_seq); // calculate the mask diff --git a/psutil/_psutil_windows.c b/psutil/_psutil_windows.c index 13f5717e..0427bc1d 100644 --- a/psutil/_psutil_windows.c +++ b/psutil/_psutil_windows.c @@ -568,7 +568,7 @@ psutil_proc_exe(PyObject *self, PyObject *args) { if (NULL == hProcess) { return NULL; } - if (GetProcessImageFileNameW(hProcess, &exe, MAX_PATH) == 0) { + if (GetProcessImageFileNameW(hProcess, exe, MAX_PATH) == 0) { CloseHandle(hProcess); PyErr_SetFromWindowsErr(0); return NULL; @@ -602,7 +602,9 @@ psutil_proc_memory_info(PyObject *self, PyObject *args) return NULL; } - if (! GetProcessMemoryInfo(hProcess, &cnt, sizeof(cnt)) ) { + if (! GetProcessMemoryInfo(hProcess, (PPROCESS_MEMORY_COUNTERS)&cnt, + sizeof(cnt)) ) + { CloseHandle(hProcess); return PyErr_SetFromWindowsErr(0); } @@ -2125,8 +2127,8 @@ psutil_proc_cpu_affinity_get(PyObject *self, PyObject *args) { DWORD pid; HANDLE hProcess; - PDWORD_PTR proc_mask; - PDWORD_PTR system_mask; + DWORD_PTR proc_mask; + DWORD_PTR system_mask; if (! PyArg_ParseTuple(args, "l", &pid)) { return NULL; @@ -2261,7 +2263,6 @@ static PyObject * psutil_net_io_counters(PyObject *self, PyObject *args) { int attempts = 0; - int i; int outBufLen = 15000; char ifname[MAX_PATH]; DWORD dwRetVal = 0; diff --git a/psutil/_pswindows.py b/psutil/_pswindows.py index ca495955..c9a68a0a 100644 --- a/psutil/_pswindows.py +++ b/psutil/_pswindows.py @@ -13,9 +13,11 @@ from collections import namedtuple from psutil import _common from psutil._common import conn_tmap, usage_percent, isfile_strict +from psutil._common import sockfam_to_enum, socktype_to_enum from psutil._compat import PY3, xrange, lru_cache import _psutil_windows as cext + # process priority constants, import from __init__.py: # http://msdn.microsoft.com/en-us/library/ms686219(v=vs.85).aspx __extra__all__ = ["ABOVE_NORMAL_PRIORITY_CLASS", "BELOW_NORMAL_PRIORITY_CLASS", @@ -168,16 +170,18 @@ def net_connections(kind, _pid=-1): % (kind, ', '.join([repr(x) for x in conn_tmap]))) families, types = conn_tmap[kind] rawlist = cext.net_connections(_pid, families, types) - ret = [] + ret = set() for item in rawlist: fd, fam, type, laddr, raddr, status, pid = item status = TCP_STATUSES[status] + fam = sockfam_to_enum(fam) + type = socktype_to_enum(type) if _pid == -1: nt = _common.sconn(fd, fam, type, laddr, raddr, status, pid) else: nt = _common.pconn(fd, fam, type, laddr, raddr, status) - ret.append(nt) - return ret + ret.add(nt) + return list(ret) def users(): @@ -446,7 +450,8 @@ class Process(object): @wrap_exceptions def cpu_affinity_get(self): - from_bitmask = lambda x: [i for i in xrange(64) if (1 << i) & x] + def from_bitmask(x): + return [i for i in xrange(64) if (1 << i) & x] bitmask = cext.proc_cpu_affinity_get(self.pid) return from_bitmask(bitmask) diff --git a/psutil/arch/windows/ntextapi.h b/psutil/arch/windows/ntextapi.h index 298c0780..d1aa62df 100644 --- a/psutil/arch/windows/ntextapi.h +++ b/psutil/arch/windows/ntextapi.h @@ -4,6 +4,9 @@ * found in the LICENSE file. */ +#if !defined(__NTEXTAPI_H__) +#define __NTEXTAPI_H__ + typedef enum _KTHREAD_STATE { Initialized, Ready, @@ -285,3 +288,5 @@ typedef enum _PROCESSINFOCLASS { ProcessImageInformation, MaxProcessInfoClass } PROCESSINFOCLASS; + +#endif // __NTEXTAPI_H__ diff --git a/psutil/arch/windows/process_handles.c b/psutil/arch/windows/process_handles.c index f7479e99..6b0a4194 100644 --- a/psutil/arch/windows/process_handles.c +++ b/psutil/arch/windows/process_handles.c @@ -10,28 +10,26 @@ #endif #include <Python.h> -#include <windows.h> #include <stdio.h> +#include <windows.h> +#include <strsafe.h> #include "process_handles.h" #ifndef NT_SUCCESS #define NT_SUCCESS(x) ((x) >= 0) #endif + #define STATUS_INFO_LENGTH_MISMATCH 0xc0000004 -#define SystemHandleInformation 16 +#include <winternl.h> #define ObjectBasicInformation 0 #define ObjectNameInformation 1 #define ObjectTypeInformation 2 +#define HANDLE_TYPE_FILE 28 -typedef LONG NTSTATUS; -typedef struct _UNICODE_STRING { - USHORT Length; - USHORT MaximumLength; - PWSTR Buffer; -} UNICODE_STRING, *PUNICODE_STRING; +typedef LONG NTSTATUS; typedef NTSTATUS (NTAPI *_NtQuerySystemInformation)( ULONG SystemInformationClass, @@ -58,19 +56,29 @@ typedef NTSTATUS (NTAPI *_NtQueryObject)( PULONG ReturnLength ); -typedef struct _SYSTEM_HANDLE { - ULONG ProcessId; - BYTE ObjectTypeNumber; - BYTE Flags; - USHORT Handle; + +// Undocumented FILE_INFORMATION_CLASS: FileNameInformation +const SYSTEM_INFORMATION_CLASS SystemExtendedHandleInformation = (SYSTEM_INFORMATION_CLASS)64; + +typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX +{ PVOID Object; - ACCESS_MASK GrantedAccess; -} SYSTEM_HANDLE, *PSYSTEM_HANDLE; + HANDLE UniqueProcessId; + HANDLE HandleValue; + ULONG GrantedAccess; + USHORT CreatorBackTraceIndex; + USHORT ObjectTypeIndex; + ULONG HandleAttributes; + ULONG Reserved; +} SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX, *PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX; + +typedef struct _SYSTEM_HANDLE_INFORMATION_EX +{ + ULONG_PTR NumberOfHandles; + ULONG_PTR Reserved; + SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX Handles[1]; +} SYSTEM_HANDLE_INFORMATION_EX, *PSYSTEM_HANDLE_INFORMATION_EX; -typedef struct _SYSTEM_HANDLE_INFORMATION { - ULONG HandleCount; - SYSTEM_HANDLE Handles[1]; -} SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION; typedef enum _POOL_TYPE { NonPagedPool, @@ -114,28 +122,62 @@ GetLibraryProcAddress(PSTR LibraryName, PSTR ProcName) return GetProcAddress(GetModuleHandleA(LibraryName), ProcName); } +void PrintError(LPTSTR lpszFunction) +{ + // Retrieve the system error message for the last-error code + + LPVOID lpMsgBuf; + LPVOID lpDisplayBuf; + DWORD dw = GetLastError(); + + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + dw, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &lpMsgBuf, + 0, NULL ); + + // Display the error message + lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, + (lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR)); + StringCchPrintf((LPTSTR)lpDisplayBuf, + LocalSize(lpDisplayBuf) / sizeof(TCHAR), + TEXT("%s failed with error %d: %s"), + lpszFunction, dw, lpMsgBuf); + + wprintf(lpDisplayBuf); + LocalFree(lpMsgBuf); + LocalFree(GetLastError); +} PyObject * psutil_get_open_files(long pid, HANDLE processHandle) { _NtQuerySystemInformation NtQuerySystemInformation = GetLibraryProcAddress("ntdll.dll", "NtQuerySystemInformation"); + _NtQueryObject NtQueryObject = GetLibraryProcAddress("ntdll.dll", "NtQueryObject"); NTSTATUS status; - PSYSTEM_HANDLE_INFORMATION handleInfo; + PSYSTEM_HANDLE_INFORMATION_EX handleInfo; ULONG handleInfoSize = 0x10000; ULONG i; ULONG fileNameLength; PyObject *filesList = Py_BuildValue("[]"); PyObject *arg = NULL; PyObject *fileFromWchar = NULL; + DWORD nReturn = 0; if (filesList == NULL) return NULL; - handleInfo = (PSYSTEM_HANDLE_INFORMATION)malloc(handleInfoSize); + handleInfo = (PSYSTEM_HANDLE_INFORMATION_EX)HeapAlloc(GetProcessHeap(), 0, + handleInfoSize); + if (handleInfo == NULL) { Py_DECREF(filesList); PyErr_NoMemory(); @@ -145,25 +187,27 @@ psutil_get_open_files(long pid, HANDLE processHandle) // NtQuerySystemInformation won't give us the correct buffer size, // so we guess by doubling the buffer size. while ((status = NtQuerySystemInformation( - SystemHandleInformation, + SystemExtendedHandleInformation, handleInfo, handleInfoSize, - NULL + &nReturn )) == STATUS_INFO_LENGTH_MISMATCH) { - handleInfo = (PSYSTEM_HANDLE_INFORMATION) \ - realloc(handleInfo, handleInfoSize *= 2); + handleInfoSize *=2; + HeapFree(GetProcessHeap(), 0, handleInfo); + handleInfo = (PSYSTEM_HANDLE_INFORMATION_EX)HeapAlloc( + GetProcessHeap(), 0, handleInfoSize); } // NtQuerySystemInformation stopped giving us STATUS_INFO_LENGTH_MISMATCH if (!NT_SUCCESS(status)) { Py_DECREF(filesList); - free(handleInfo); + HeapFree(GetProcessHeap(), 0, handleInfo); return NULL; } - for (i = 0; i < handleInfo->HandleCount; i++) { - SYSTEM_HANDLE handle = handleInfo->Handles[i]; + for (i = 0; i < handleInfo->NumberOfHandles; i++) { + PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX handle = &handleInfo->Handles[i]; HANDLE dupHandle = NULL; HANDLE mapHandle = NULL; POBJECT_TYPE_INFORMATION objectTypeInfo = NULL; @@ -175,31 +219,33 @@ psutil_get_open_files(long pid, HANDLE processHandle) arg = NULL; // Check if this handle belongs to the PID the user specified. - if (handle.ProcessId != pid) + if (handle->UniqueProcessId != (HANDLE)pid || + handle->ObjectTypeIndex != HANDLE_TYPE_FILE) + { continue; + } // Skip handles with the following access codes as the next call // to NtDuplicateObject() or NtQueryObject() might hang forever. - if ((handle.GrantedAccess == 0x0012019f) - || (handle.GrantedAccess == 0x001a019f) - || (handle.GrantedAccess == 0x00120189) - || (handle.GrantedAccess == 0x00100000)) { + if ((handle->GrantedAccess == 0x0012019f) + || (handle->GrantedAccess == 0x001a019f) + || (handle->GrantedAccess == 0x00120189) + || (handle->GrantedAccess == 0x00100000)) { continue; } - if (!DuplicateHandle(processHandle, - handle.Handle, + if (!DuplicateHandle(processHandle, + handle->HandleValue, GetCurrentProcess(), &dupHandle, 0, TRUE, DUPLICATE_SAME_ACCESS)) { - //printf("[%#x] Error: %d \n", handle.Handle, GetLastError()); + //printf("[%#x] Error: %d \n", handle->HandleValue, GetLastError()); continue; } - mapHandle = CreateFileMapping(dupHandle, NULL, PAGE_READONLY, @@ -254,7 +300,7 @@ psutil_get_open_files(long pid, HANDLE processHandle) /* printf( "[%#x] %.*S: (could not get name)\n", - handle.Handle, + handle->HandleValue, objectTypeInfo->Name.Length / 2, objectTypeInfo->Name.Buffer ); @@ -300,7 +346,7 @@ psutil_get_open_files(long pid, HANDLE processHandle) /* printf( "[%#x] %.*S: %.*S\n", - handle.Handle, + handle->Handle, objectTypeInfo->Name.Length / 2, objectTypeInfo->Name.Buffer, objectName.Length / 2, @@ -314,7 +360,7 @@ psutil_get_open_files(long pid, HANDLE processHandle) /* printf( "[%#x] %.*S: (unnamed)\n", - handle.Handle, + handle->Handle, objectTypeInfo->Name.Length / 2, objectTypeInfo->Name.Buffer ); @@ -325,7 +371,7 @@ psutil_get_open_files(long pid, HANDLE processHandle) free(objectNameInfo); CloseHandle(dupHandle); } - free(handleInfo); + HeapFree(GetProcessHeap(), 0, handleInfo); CloseHandle(processHandle); return filesList; diff --git a/psutil/arch/windows/process_info.h b/psutil/arch/windows/process_info.h index 9544f5d6..a44c4ace 100644 --- a/psutil/arch/windows/process_info.h +++ b/psutil/arch/windows/process_info.h @@ -4,8 +4,13 @@ * found in the LICENSE file. */ +#if !defined(__PROCESS_INFO_H) +#define __PROCESS_INFO_H + #include <Python.h> #include <windows.h> +#include "security.h" +#include "ntextapi.h" DWORD* psutil_get_pids(DWORD *numberOfReturnedPIDs); HANDLE psutil_handle_from_pid(DWORD pid); @@ -15,3 +20,7 @@ int psutil_pid_in_proclist(DWORD pid); int psutil_pid_is_running(DWORD pid); PVOID psutil_get_peb_address(HANDLE ProcessHandle); PyObject* psutil_get_arg_list(long pid); +int psutil_get_proc_info(DWORD pid, PSYSTEM_PROCESS_INFORMATION *retProcess, + PVOID *retBuffer); + +#endif @@ -72,6 +72,7 @@ if sys.platform.startswith("win32"): # http://www.mingw.org/wiki/Use_more_recent_defined_functions ('_WIN32_WINNT', get_winver()), ('_AVAIL_WINVER_', get_winver()), + ('_CRT_SECURE_NO_WARNINGS', None), # see: https://github.com/giampaolo/psutil/issues/348 ('PSAPI_VERSION', 1), ], diff --git a/test/_bsd.py b/test/_bsd.py index 59be49bf..77691eb4 100644 --- a/test/_bsd.py +++ b/test/_bsd.py @@ -106,6 +106,7 @@ class BSDSpecificTestCase(unittest.TestCase): if abs(usage.used - used) > 10 * 1024 * 1024: self.fail("psutil=%s, df=%s" % (usage.used, used)) + @retry_before_failing() def test_memory_maps(self): out = sh('procstat -v %s' % self.pid) maps = psutil.Process(self.pid).memory_maps(grouped=False) diff --git a/test/_windows.py b/test/_windows.py index 9c07142a..969cc894 100644 --- a/test/_windows.py +++ b/test/_windows.py @@ -29,7 +29,7 @@ except ImportError: from psutil._compat import PY3, callable, long from psutil._pswindows import ACCESS_DENIED_SET -import _psutil_windows +import psutil._psutil_windows as _psutil_windows import psutil @@ -165,7 +165,7 @@ class WindowsSpecificTestCase(unittest.TestCase): # --- psutil namespace functions and constants tests - @unittest.skipUnless(hasattr(os, 'NUMBER_OF_PROCESSORS'), + @unittest.skipUnless('NUMBER_OF_PROCESSORS' in os.environ, 'NUMBER_OF_PROCESSORS env var is not available') def test_cpu_count(self): num_cpus = int(os.environ['NUMBER_OF_PROCESSORS']) @@ -289,8 +289,8 @@ class TestDualProcessImplementation(unittest.TestCase): ('proc_cpu_times', 0.2), ('proc_create_time', 0.5), ('proc_num_handles', 1), # 1 because impl #1 opens a handle - ('proc_io_counters', 0), ('proc_memory_info', 1024), # KB + ('proc_io_counters', 0), ] def test_compare_values(self): @@ -370,7 +370,7 @@ class TestDualProcessImplementation(unittest.TestCase): self.assertRaises(psutil.NoSuchProcess, meth, ZOMBIE_PID) -def test_main(): +def main(): test_suite = unittest.TestSuite() test_suite.addTest(unittest.makeSuite(WindowsSpecificTestCase)) test_suite.addTest(unittest.makeSuite(TestDualProcessImplementation)) @@ -378,5 +378,5 @@ def test_main(): return result.wasSuccessful() if __name__ == '__main__': - if not test_main(): + if not main(): sys.exit(1) diff --git a/test/test_memory_leaks.py b/test/test_memory_leaks.py index 488ac621..1441daa1 100644 --- a/test/test_memory_leaks.py +++ b/test/test_memory_leaks.py @@ -17,11 +17,6 @@ import sys import threading import time -if sys.version_info < (2, 7): - import unittest2 as unittest # https://pypi.python.org/pypi/unittest2 -else: - import unittest - import psutil import psutil._common @@ -31,6 +26,11 @@ from test_psutil import (WINDOWS, POSIX, OSX, LINUX, SUNOS, BSD, TESTFN, from test_psutil import (reap_children, supports_ipv6, safe_remove, get_test_subprocess) +if sys.version_info < (2, 7): + import unittest2 as unittest # https://pypi.python.org/pypi/unittest2 +else: + import unittest + LOOPS = 1000 TOLERANCE = 4096 diff --git a/test/test_psutil.py b/test/test_psutil.py index fad37c8c..efbcead1 100644 --- a/test/test_psutil.py +++ b/test/test_psutil.py @@ -47,14 +47,19 @@ try: except ImportError: ipaddress = None +try: + import enum # python >= 3.4 +except ImportError: + enum = None + +import psutil +from psutil._compat import PY3, callable, long, unicode + if sys.version_info < (2, 7): import unittest2 as unittest # https://pypi.python.org/pypi/unittest2 else: import unittest -import psutil -from psutil._compat import PY3, callable, long, unicode - # =================================================================== # --- Constants @@ -282,18 +287,20 @@ def reap_children(search_all=False): def check_ip_address(addr, family): """Attempts to check IP address's validity.""" + if enum and PY3: + assert isinstance(family, enum.IntEnum), family if family == AF_INET: octs = [int(x) for x in addr.split('.')] assert len(octs) == 4, addr for num in octs: assert 0 <= num <= 255, addr - if ipaddress is not None: + if ipaddress: if not PY3: addr = unicode(addr) ipaddress.IPv4Address(addr) elif family == AF_INET6: assert isinstance(addr, str), addr - if ipaddress is not None: + if ipaddress: if not PY3: addr = unicode(addr) ipaddress.IPv6Address(addr) @@ -542,9 +549,10 @@ class TestSystemAPIs(unittest.TestCase): self.assertEqual(len(list(psutil.process_iter())), len(psutil.pids())) def test_wait_procs(self): - l = [] - callback = lambda p: l.append(p.pid) + def callback(p): + l.append(p.pid) + l = [] sproc1 = get_test_subprocess() sproc2 = get_test_subprocess() sproc3 = get_test_subprocess() @@ -1003,6 +1011,7 @@ class TestSystemAPIs(unittest.TestCase): continue families, types_ = groups cons = psutil.net_connections(kind) + self.assertEqual(len(cons), len(set(cons))) check(cons, families, types_) def test_net_io_counters(self): @@ -1073,7 +1082,8 @@ class TestSystemAPIs(unittest.TestCase): check_ip_address(ip, addr.family) if BSD or OSX or SUNOS: - self.assertEqual(psutil.AF_LINK, socket.AF_LINK) + if hasattr(socket, "AF_LINK"): + self.assertEqual(psutil.AF_LINK, socket.AF_LINK) elif LINUX: self.assertEqual(psutil.AF_LINK, socket.AF_PACKET) elif WINDOWS: @@ -1705,7 +1715,7 @@ class TestProcess(unittest.TestCase): assert os.path.isfile(file), file # another process - cmdline = "import time; f = open(r'%s', 'r'); time.sleep(2);" % TESTFN + cmdline = "import time; f = open(r'%s', 'r'); time.sleep(60);" % TESTFN sproc = get_test_subprocess([PYTHON, "-c", cmdline], wait=True) p = psutil.Process(sproc.pid) @@ -1983,9 +1993,9 @@ class TestProcess(unittest.TestCase): # A (parent) -> B (child) -> C (grandchild) s = "import subprocess, os, sys, time;" s += "PYTHON = os.path.realpath(sys.executable);" - s += "cmd = [PYTHON, '-c', 'import time; time.sleep(2);'];" + s += "cmd = [PYTHON, '-c', 'import time; time.sleep(4);'];" s += "subprocess.Popen(cmd);" - s += "time.sleep(2);" + s += "time.sleep(4);" get_test_subprocess(cmd=[PYTHON, "-c", s]) p = psutil.Process() self.assertEqual(len(p.children(recursive=False)), 1) @@ -2737,7 +2747,7 @@ class TestExampleScripts(unittest.TestCase): self.assertIn(str(os.getpid()), output) -def test_main(): +def main(): tests = [] test_suite = unittest.TestSuite() tests.append(TestSystemAPIs) @@ -2774,5 +2784,5 @@ def test_main(): return result.wasSuccessful() if __name__ == '__main__': - if not test_main(): + if not main(): sys.exit(1) @@ -18,6 +18,7 @@ commands = git ls-files | grep \\.py$ | xargs flake8 # suppress "WARNING: 'git' command found but not installed in testenv whitelist_externals = git +usedevelop = True [testenv:py26] deps = |