summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGiampaolo Rodola <g.rodola@gmail.com>2017-01-23 23:06:30 +0100
committerGiampaolo Rodola <g.rodola@gmail.com>2017-01-23 23:06:30 +0100
commit5f186957a4ae6505810488c7b3118453c459fdec (patch)
tree43ee8a0811724b2d6bbd267808ee49b3becf08f6
parent29496900f772c8c594fa9c5142a88a5291c05f55 (diff)
parentf8c07ae1082ee07fd08c25fa163fc8edb31e5b7f (diff)
downloadpsutil-5f186957a4ae6505810488c7b3118453c459fdec.tar.gz
merge from master
-rw-r--r--.travis.yml1
-rw-r--r--CREDITS5
-rw-r--r--DEVGUIDE.rst6
-rw-r--r--HISTORY.rst18
-rw-r--r--INSTALL.rst15
-rw-r--r--MANIFEST.in15
-rw-r--r--Makefile12
-rw-r--r--README.rst5
-rw-r--r--appveyor.yml11
-rw-r--r--docs/_themes/pydoctheme/static/pydoctheme.css10
-rw-r--r--docs/conf.py2
-rw-r--r--docs/index.rst348
-rw-r--r--psutil/__init__.py68
-rw-r--r--psutil/_common.py2
-rw-r--r--psutil/_psbsd.py22
-rw-r--r--psutil/_pslinux.py63
-rw-r--r--psutil/_psosx.py10
-rw-r--r--psutil/_psutil_bsd.c109
-rw-r--r--psutil/_psutil_osx.c31
-rw-r--r--psutil/_psutil_posix.c63
-rw-r--r--psutil/_psutil_windows.c67
-rw-r--r--psutil/_pswindows.py9
-rw-r--r--psutil/arch/bsd/netbsd.c4
-rw-r--r--psutil/tests/__init__.py4
-rwxr-xr-xpsutil/tests/test_linux.py149
-rwxr-xr-xpsutil/tests/test_memory_leaks.py5
-rwxr-xr-xpsutil/tests/test_osx.py15
-rwxr-xr-xpsutil/tests/test_process.py13
-rwxr-xr-xpsutil/tests/test_system.py19
-rwxr-xr-xpsutil/tests/test_windows.py6
-rwxr-xr-xscripts/internal/winmake.py18
-rwxr-xr-xsetup.py49
32 files changed, 840 insertions, 334 deletions
diff --git a/.travis.yml b/.travis.yml
index 17206c58..48c84a7b 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -8,6 +8,7 @@ matrix:
- python: 3.3
- python: 3.4
- python: 3.5
+ - python: 3.6
- "pypy"
# XXX - commented because OSX builds are deadly slow
# - language: generic
diff --git a/CREDITS b/CREDITS
index ccc4515f..031548ae 100644
--- a/CREDITS
+++ b/CREDITS
@@ -420,3 +420,8 @@ I: 919
N: Max Bélanger
W: https://github.com/maxbelanger
I: 936
+
+N: Pierre Fersing
+C: France
+E: pierre.fersing@bleemeo.com
+I: 950
diff --git a/DEVGUIDE.rst b/DEVGUIDE.rst
index 95bea79a..93dfa690 100644
--- a/DEVGUIDE.rst
+++ b/DEVGUIDE.rst
@@ -1,6 +1,6 @@
-=====
-Setup
-=====
+=======================
+Setup and running tests
+=======================
If you plan on hacking on psutil this is what you're supposed to do first:
diff --git a/HISTORY.rst b/HISTORY.rst
index f93e0974..c6db2aa0 100644
--- a/HISTORY.rst
+++ b/HISTORY.rst
@@ -1,10 +1,24 @@
*Bug tracker at https://github.com/giampaolo/psutil/issues*
-5.0.1
+5.0.2
=====
*XXXX-XX-XX*
+**Bug fixes**
+
+- 687_: [Linux] pid_exists() no longer returns True if passed a process thread
+ ID.
+- 948_: cannot install psutil with PYTHONOPTIMIZE=2.
+- 950_: [Windows] Process.cpu_percent() was calculated incorrectly and showed
+ higher number than real usage.
+
+
+5.0.1
+=====
+
+*2016-12-21*
+
**Enhancements**
- 939_: tar.gz distribution went from 1.8M to 258K.
@@ -13,10 +27,12 @@
**Bug fixes**
+- 609_: [SunOS] psutil does not compile on Solaris 10.
- 936_: [Windows] fix compilation error on VS 2013 (patch by Max Bélanger).
- 940_: [Linux] cpu_percent() and cpu_times_percent() was calculated
incorrectly as "iowait", "guest" and "guest_nice" times were not properly
taken into account.
+- 944_: [OpenBSD] psutil.pids() was omitting PID 0.
5.0.0
diff --git a/INSTALL.rst b/INSTALL.rst
index b1b40d68..d731bd3d 100644
--- a/INSTALL.rst
+++ b/INSTALL.rst
@@ -5,12 +5,13 @@ pip is the easiest way to install psutil.
It is shipped by default with Python 2.7.9+ and 3.4+. If you're using an
older Python version `install pip <https://pip.pypa.io/en/latest/installing/>`__
first.
-If you GIT cloned psutil source code you can also install pip with::
+If you GIT cloned psutil source code you can also install pip and/or upgrade
+it to latest version with::
make install-pip
Unless you're on Windows, in order to install psutil with pip you'll also need
-a C compiler installed.
+a C compiler installed (e.g. gcc).
pip will retrieve psutil source code or binaries from
`PYPI <https://pypi.python.org/pypi/psutil>`__ repository.
@@ -62,7 +63,7 @@ versions.
OSX
===
-Install `XcodeTools <https://developer.apple.com/downloads/?name=Xcode>`__
+Install `Xcode <https://developer.apple.com/downloads/?name=Xcode>`__
first, then:
::
@@ -137,6 +138,14 @@ Install:
pkg install gcc
python -m pip install psutil
+Install from sources
+====================
+
+ git clone https://github.com/giampaolo/psutil.git
+ cd psutil
+ python setup.py install
+
+
Dev Guide
=========
diff --git a/MANIFEST.in b/MANIFEST.in
index 94532292..b0c15645 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,7 +1,18 @@
+include *.bat
include *.rst
+include .coveragerc
include CREDITS*
+include IDEAS
include INSTALL*
include LICENSE*
-include make.bar
+include HISTORY*
include Makefile
-recursive-include psutil *.py *.c *.h
+include tox.ini
+
+recursive-include psutil *.py *.c *.h *.rst
+recursive-include scripts *.py
+recursive-include README*
+
+recursive-include docs *.conf *.rst *.js *.html *.css *.py *.bat *Makefile* README*
+recursive-exclude docs/_build *
+recursive-exclude .ci *
diff --git a/Makefile b/Makefile
index c91d3b96..95db068c 100644
--- a/Makefile
+++ b/Makefile
@@ -8,6 +8,7 @@ ARGS =
# List of nice-to-have dev libs.
DEPS = argparse \
+ check-manifest \
coverage \
flake8 \
futures \
@@ -171,6 +172,9 @@ pyflakes:
flake8:
@git ls-files | grep \\.py$ | xargs $(PYTHON) -m flake8
+check-manifest:
+ $(PYTHON) -m check_manifest -v $(ARGS)
+
# ===================================================================
# GIT
# ===================================================================
@@ -206,7 +210,7 @@ win-download-exes:
# Upload exes/wheels in dist/* directory to PYPI.
win-upload-exes:
$(PYTHON) -m twine upload dist/*.exe
- $(PYTHON) -m twine upload dist/*.wheel
+ $(PYTHON) -m twine upload dist/*.whl
# All the necessary steps before making a release.
pre-release:
@@ -249,3 +253,9 @@ bench-oneshot: install
# same as above but using perf module (supposed to be more precise)
bench-oneshot-2: install
$(PYTHON) scripts/internal/bench_oneshot_2.py
+
+# generate a doc.zip file and manually upload it to PYPI.
+doc:
+ cd docs && make html && cd _build/html/ && zip doc.zip -r .
+ mv docs/_build/html/doc.zip .
+ echo "done; now manually upload doc.zip from here: https://pypi.python.org/pypi?:action=pkg_edit&name=psutil"
diff --git a/README.rst b/README.rst
index 91d41cdb..67e5bc92 100644
--- a/README.rst
+++ b/README.rst
@@ -71,7 +71,7 @@ Projects using psutil
=====================
At the time of writing there are over
-`4000 projects <https://libraries.io/pypi/psutil/dependent_repositories?page=1>`__
+`4200 open source projects <https://libraries.io/pypi/psutil/dependent_repositories?page=1>`__
on github which depend from psutil.
Here's some I find particularly interesting:
@@ -122,6 +122,9 @@ CPU
>>>
>>> psutil.cpu_stats()
scpustats(ctx_switches=20455687, interrupts=6598984, soft_interrupts=2134212, syscalls=0)
+ >>>
+ >>> psutil.cpu_freq()
+ scpufreq(current=931.42925, min=800.0, max=3500.0)
Memory
======
diff --git a/appveyor.yml b/appveyor.yml
index 927d9cb3..4428f776 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -30,6 +30,10 @@ environment:
PYTHON_VERSION: "3.5.x"
PYTHON_ARCH: "32"
+ - PYTHON: "C:\\Python36"
+ PYTHON_VERSION: "3.6.x"
+ PYTHON_ARCH: "32"
+
# 64 bits
- PYTHON: "C:\\Python27-x64"
@@ -51,6 +55,13 @@ environment:
VS_VER: "2015"
INSTANCENAME: "SQL2012SP1"
+ - PYTHON: "C:\\Python36-x64"
+ PYTHON_VERSION: "3.6.x"
+ PYTHON_ARCH: "64"
+ ARCH: x86_64
+ VS_VER: "2015"
+ INSTANCENAME: "SQL2012SP1"
+
# Also build on a Python version not pre-installed by Appveyor.
# See: https://github.com/ogrisel/python-appveyor-demo/issues/10
diff --git a/docs/_themes/pydoctheme/static/pydoctheme.css b/docs/_themes/pydoctheme/static/pydoctheme.css
index 4196e558..c6f19ab7 100644
--- a/docs/_themes/pydoctheme/static/pydoctheme.css
+++ b/docs/_themes/pydoctheme/static/pydoctheme.css
@@ -185,3 +185,13 @@ div.body h3 {
div.body h2 {
padding-left:10px;
}
+
+.data {
+ margin-top: 4px !important;
+ margin-bottom: 4px !important;
+}
+
+.data dd {
+ margin-top: 0px !important;
+ margin-bottom: 0px !important;
+}
diff --git a/docs/conf.py b/docs/conf.py
index 2267b5d1..f0a206db 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -46,7 +46,7 @@ needs_sphinx = '1.0'
# ones.
extensions = ['sphinx.ext.autodoc',
'sphinx.ext.coverage',
- 'sphinx.ext.pngmath',
+ 'sphinx.ext.imgmath',
'sphinx.ext.viewcode',
'sphinx.ext.intersphinx']
diff --git a/docs/index.rst b/docs/index.rst
index a18bba81..7efddb24 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -39,11 +39,12 @@ The psutil documentation you're reading is distributed as a single HTML page.
Install
-------
-On Windows, or on UNIX if you have a C compiler installed, the easiest way to
-install psutil is via ``pip``::
+The easiest way to install psutil is via ``pip``::
pip install psutil
+On UNIX this requires a C compiler (e.g. gcc) installed. On Windows pip will
+automatically retrieve a pre-compiled wheel version.
Alternatively, see more detailed
`install <https://github.com/giampaolo/psutil/blob/master/INSTALL.rst>`_
instructions.
@@ -138,6 +139,8 @@ CPU
:func:`psutil.cpu_times(percpu=True)<cpu_times()>`.
*interval* and
*percpu* arguments have the same meaning as in :func:`cpu_percent()`.
+ On Linux "guest" and "guest_nice" percentages are not accounted in "user"
+ and "user_nice" percentages.
.. warning::
the first time this function is called with *interval* = ``0.0`` or
@@ -154,13 +157,14 @@ CPU
in Python 3.4).
If *logical* is ``False`` return the number of physical cores only (hyper
thread CPUs are excluded). Return ``None`` if undetermined.
+ On OpenBSD and NetBSD ``psutil.cpu_count(logical=False)`` always return
+ ``None``. Example on a system having 2 physical hyper-thread CPU cores:
>>> import psutil
>>> psutil.cpu_count()
4
>>> psutil.cpu_count(logical=False)
2
- >>>
.. function:: cpu_stats()
@@ -187,6 +191,33 @@ CPU
.. versionadded:: 4.1.0
+.. function:: cpu_freq(percpu=False)
+
+ Return CPU frequency as a nameduple including *current*, *min* and *max*
+ frequencies expressed in Mhz.
+ If *percpu* is ``True`` and the system supports per-cpu frequency
+ retrieval (Linux only) a list of frequencies is returned for each CPU,
+ if not, a list with a single element is returned.
+ If *min* and *max* cannot be determined they are set to ``0``.
+
+ Example (Linux):
+
+ .. code-block:: python
+
+ >>> import psutil
+ >>> psutil.cpu_freq()
+ scpufreq(current=931.42925, min=800.0, max=3500.0)
+ >>> psutil.cpu_freq(percpu=True)
+ [scpufreq(current=2394.945, min=800.0, max=3500.0),
+ scpufreq(current=2236.812, min=800.0, max=3500.0),
+ scpufreq(current=1703.609, min=800.0, max=3500.0),
+ scpufreq(current=1754.289, min=800.0, max=3500.0)]
+
+ Availability: Linux, OSX, Windows
+
+ .. versionadded:: 5.1.0
+
+
Memory
------
@@ -451,7 +482,7 @@ Network
else ``None``. On some platforms (e.g. Linux) the availability of this
field changes depending on process privileges (root is needed).
- The *kind* parameter is a string which filters for connections that fit the
+ The *kind* parameter is a string which filters for connections matching the
following criteria:
.. table::
@@ -459,27 +490,27 @@ Network
+----------------+-----------------------------------------------------+
| **Kind value** | **Connections using** |
+================+=====================================================+
- | "inet" | IPv4 and IPv6 |
+ | ``"inet"`` | IPv4 and IPv6 |
+----------------+-----------------------------------------------------+
- | "inet4" | IPv4 |
+ | ``"inet4"`` | IPv4 |
+----------------+-----------------------------------------------------+
- | "inet6" | IPv6 |
+ | ``"inet6"`` | IPv6 |
+----------------+-----------------------------------------------------+
- | "tcp" | TCP |
+ | ``"tcp"`` | TCP |
+----------------+-----------------------------------------------------+
- | "tcp4" | TCP over IPv4 |
+ | ``"tcp4"`` | TCP over IPv4 |
+----------------+-----------------------------------------------------+
- | "tcp6" | TCP over IPv6 |
+ | ``"tcp6"`` | TCP over IPv6 |
+----------------+-----------------------------------------------------+
- | "udp" | UDP |
+ | ``"udp"`` | UDP |
+----------------+-----------------------------------------------------+
- | "udp4" | UDP over IPv4 |
+ | ``"udp4"`` | UDP over IPv4 |
+----------------+-----------------------------------------------------+
- | "udp6" | UDP over IPv6 |
+ | ``"udp6"`` | UDP over IPv6 |
+----------------+-----------------------------------------------------+
- | "unix" | UNIX socket (both UDP and TCP protocols) |
+ | ``"unix"`` | UNIX socket (both UDP and TCP protocols) |
+----------------+-----------------------------------------------------+
- | "all" | the sum of all the possible families and protocols |
+ | ``"all"`` | the sum of all the possible families and protocols |
+----------------+-----------------------------------------------------+
On OSX this function requires root privileges.
@@ -630,12 +661,16 @@ Functions
.. function:: pids()
Return a list of current running PIDs. To iterate over all processes
- :func:`process_iter()` should be preferred.
+ and avoid race conditions :func:`process_iter()` should be preferred.
+
+ >>> import psutil
+ >>> psutil.pids()
+ [1, 2, 3, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17, 18, 19, ..., 32498]
.. function:: pid_exists(pid)
Check whether the given PID exists in the current process list. This is
- faster than doing ``"pid in psutil.pids()"`` and should be preferred.
+ faster than doing ``pid in psutil.pids()`` and should be preferred.
.. function:: process_iter()
@@ -676,18 +711,18 @@ Functions
- give them some time to terminate
- send SIGKILL to those ones which are still alive
- Example::
+ Example which terminates and waits all the children of this process::
import psutil
def on_terminate(proc):
print("process {} terminated with exit code {}".format(proc, proc.returncode))
- procs = [...] # a list of Process instances
+ procs = psutil.Process().children()
for p in procs:
p.terminate()
- gone, alive = psutil.wait_procs(procs, timeout=3, callback=on_terminate)
- for p in alive:
+ gone, still_alive = psutil.wait_procs(procs, timeout=3, callback=on_terminate)
+ for p in still_alive:
p.kill()
Exceptions
@@ -700,8 +735,8 @@ Exceptions
.. class:: NoSuchProcess(pid, name=None, msg=None)
Raised by :class:`Process` class methods when no process with the given
- pid* is found in the current process list or when a process no longer
- exists. "name" is the name the process had before disappearing
+ *pid* is found in the current process list or when a process no longer
+ exists. *name* is the name the process had before disappearing
and gets set only if :meth:`Process.name()` was previously called.
.. class:: ZombieProcess(pid, name=None, ppid=None, msg=None)
@@ -731,10 +766,12 @@ Process class
.. class:: Process(pid=None)
- Represents an OS process with the given *pid*. If *pid* is omitted current
- process *pid* (`os.getpid() <http://docs.python.org/library/os.html#os.getpid>`__)
- is used.
+ Represents an OS process with the given *pid*.
+ If *pid* is omitted current process *pid*
+ (`os.getpid() <http://docs.python.org/library/os.html#os.getpid>`__) is used.
Raise :class:`NoSuchProcess` if *pid* does not exist.
+ On Linux *pid* can also refer to a thread ID (the *id* field returned by
+ :meth:`threads` method).
When accessing methods of this class always be prepared to catch
:class:`NoSuchProcess`, :class:`ZombieProcess` and :class:`AccessDenied`
exceptions.
@@ -856,7 +893,7 @@ Process class
.. method:: ppid()
- The process parent pid. On Windows the return value is cached after first
+ The process parent PID. On Windows the return value is cached after first
call. Not on POSIX because
`ppid may change <https://github.com/giampaolo/psutil/issues/321>`__
if process becomes a zombie.
@@ -873,16 +910,28 @@ Process class
On some systems this may also be an empty string.
The return value is cached after first call.
+ >>> import psutil
+ >>> psutil.Process().exe()
+ '/usr/bin/python2.7'
+
.. method:: cmdline()
- The command line this process has been called with. The return value is not
- cached because the cmdline of a process may change.
+ The command line this process has been called with as a list of strings.
+ The return value is not cached because the cmdline of a process may change.
+
+ >>> import psutil
+ >>> psutil.Process().cmdline()
+ ['python', 'manage.py', 'runserver']
.. method:: environ()
The environment variables of the process as a dict. Note: this might not
reflect changes made after the process started.
+ >>> import psutil
+ >>> psutil.Process().environ()
+ {'LC_NUMERIC': 'it_IT.UTF-8', 'QT_QPA_PLATFORMTHEME': 'appmenu-qt5', 'IM_CONFIG_PHASE': '1', 'XDG_GREETER_DATA_DIR': '/var/lib/lightdm-data/giampaolo', 'GNOME_DESKTOP_SESSION_ID': 'this-is-deprecated', 'XDG_CURRENT_DESKTOP': 'Unity', 'UPSTART_EVENTS': 'started starting', 'GNOME_KEYRING_PID': '', 'XDG_VTNR': '7', 'QT_IM_MODULE': 'ibus', 'LOGNAME': 'giampaolo', 'USER': 'giampaolo', 'PATH': '/home/giampaolo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/home/giampaolo/svn/sysconf/bin', 'LC_PAPER': 'it_IT.UTF-8', 'GNOME_KEYRING_CONTROL': '', 'GTK_IM_MODULE': 'ibus', 'DISPLAY': ':0', 'LANG': 'en_US.UTF-8', 'LESS_TERMCAP_se': '\x1b[0m', 'TERM': 'xterm-256color', 'SHELL': '/bin/bash', 'XDG_SESSION_PATH': '/org/freedesktop/DisplayManager/Session0', 'XAUTHORITY': '/home/giampaolo/.Xauthority', 'LANGUAGE': 'en_US', 'COMPIZ_CONFIG_PROFILE': 'ubuntu', 'LC_MONETARY': 'it_IT.UTF-8', 'QT_LINUX_ACCESSIBILITY_ALWAYS_ON': '1', 'LESS_TERMCAP_me': '\x1b[0m', 'LESS_TERMCAP_md': '\x1b[01;38;5;74m', 'LESS_TERMCAP_mb': '\x1b[01;31m', 'HISTSIZE': '100000', 'UPSTART_INSTANCE': '', 'CLUTTER_IM_MODULE': 'xim', 'WINDOWID': '58786407', 'EDITOR': 'vim', 'SESSIONTYPE': 'gnome-session', 'XMODIFIERS': '@im=ibus', 'GPG_AGENT_INFO': '/home/giampaolo/.gnupg/S.gpg-agent:0:1', 'HOME': '/home/giampaolo', 'HISTFILESIZE': '100000', 'QT4_IM_MODULE': 'xim', 'GTK2_MODULES': 'overlay-scrollbar', 'XDG_SESSION_DESKTOP': 'ubuntu', 'SHLVL': '1', 'XDG_RUNTIME_DIR': '/run/user/1000', 'INSTANCE': 'Unity', 'LC_ADDRESS': 'it_IT.UTF-8', 'SSH_AUTH_SOCK': '/run/user/1000/keyring/ssh', 'VTE_VERSION': '4205', 'GDMSESSION': 'ubuntu', 'MANDATORY_PATH': '/usr/share/gconf/ubuntu.mandatory.path', 'VISUAL': 'vim', 'DESKTOP_SESSION': 'ubuntu', 'QT_ACCESSIBILITY': '1', 'XDG_SEAT_PATH': '/org/freedesktop/DisplayManager/Seat0', 'LESSCLOSE': '/usr/bin/lesspipe %s %s', 'LESSOPEN': '| /usr/bin/lesspipe %s', 'XDG_SESSION_ID': 'c2', 'DBUS_SESSION_BUS_ADDRESS': 'unix:abstract=/tmp/dbus-9GAJpvnt8r', '_': '/usr/bin/python', 'DEFAULTS_PATH': '/usr/share/gconf/ubuntu.default.path', 'LC_IDENTIFICATION': 'it_IT.UTF-8', 'LESS_TERMCAP_ue': '\x1b[0m', 'UPSTART_SESSION': 'unix:abstract=/com/ubuntu/upstart-session/1000/1294', 'XDG_CONFIG_DIRS': '/etc/xdg/xdg-ubuntu:/usr/share/upstart/xdg:/etc/xdg', 'GTK_MODULES': 'gail:atk-bridge:unity-gtk-module', 'XDG_SESSION_TYPE': 'x11', 'PYTHONSTARTUP': '/home/giampaolo/.pythonstart', 'LC_NAME': 'it_IT.UTF-8', 'OLDPWD': '/home/giampaolo/svn/curio_giampaolo/tests', 'GDM_LANG': 'en_US', 'LC_TELEPHONE': 'it_IT.UTF-8', 'HISTCONTROL': 'ignoredups:erasedups', 'LC_MEASUREMENT': 'it_IT.UTF-8', 'PWD': '/home/giampaolo/svn/curio_giampaolo', 'JOB': 'gnome-session', 'LESS_TERMCAP_us': '\x1b[04;38;5;146m', 'UPSTART_JOB': 'unity-settings-daemon', 'LC_TIME': 'it_IT.UTF-8', 'LESS_TERMCAP_so': '\x1b[38;5;246m', 'PAGER': 'less', 'XDG_DATA_DIRS': '/usr/share/ubuntu:/usr/share/gnome:/usr/local/share/:/usr/share/:/var/lib/snapd/desktop', 'XDG_SEAT': 'seat0'}
+
Availability: Linux, OSX, Windows
.. versionadded:: 4.0.0
@@ -1098,7 +1147,7 @@ Process class
Return threads opened by process as a list of namedtuples including thread
id and thread CPU times (user/system). On OpenBSD this method requires
- root access.
+ root privileges.
.. method:: cpu_times()
@@ -1116,9 +1165,9 @@ Process class
.. method:: cpu_percent(interval=None)
- Return a float representing the process CPU utilization as a percentage.
- The returned value refers to the utilization of a single CPU, i.e. it is
- not evenly split between the number of available CPU cores.
+ Return a float representing the process CPU utilization as a percentage
+ which can also be ``> 100.0`` in case of a process running multiple threads
+ on different CPUs.
When *interval* is > ``0.0`` compares process times to system CPU times
elapsed before and after the interval (blocking). When interval is ``0.0``
or ``None`` compares process times to system CPU times elapsed since last
@@ -1130,30 +1179,28 @@ Process class
>>> import psutil
>>> p = psutil.Process()
- >>>
>>> # blocking
>>> p.cpu_percent(interval=1)
2.0
>>> # non-blocking (percentage since last call)
>>> p.cpu_percent(interval=None)
2.9
- >>>
.. note::
- a percentage > 100 is legitimate as it can result from a process with
- multiple threads running on different CPU cores.
+ the returned value can be > 100.0 in case of a process running multiple
+ threads on different CPU cores.
.. note::
- the returned value is explicitly **not** split evenly between all CPUs
- cores (differently from :func:`psutil.cpu_percent()`).
- This means that a busy loop process running on a system with 2 CPU
- cores will be reported as having 100% CPU utilization instead of 50%.
- This was done in order to be consistent with UNIX's "top" utility
+ the returned value is explicitly *not* split evenly between all available
+ CPUs (differently from :func:`psutil.cpu_percent()`).
+ This means that a busy loop process running on a system with 2 logical
+ CPUs will be reported as having 100% CPU utilization instead of 50%.
+ This was done in order to be consistent with ``top`` UNIX utility
and also to make it easier to identify processes hogging CPU resources
- (independently from the number of CPU cores).
- It must be noted that in the example above taskmgr.exe on Windows will
- report 50% usage instead.
- To emulate Windows's taskmgr.exe behavior you can do:
+ independently from the number of CPUs.
+ It must be noted that ``taskmgr.exe`` on Windows does not behave like
+ this (it would report 50% usage instead).
+ To emulate Windows ``taskmgr.exe`` behavior you can do:
``p.cpu_percent() / psutil.cpu_count()``.
.. warning::
@@ -1301,8 +1348,8 @@ Process class
some platform (Linux, OSX, Windows), also provides additional metrics
(USS, PSS and swap).
The additional metrics provide a better representation of "effective"
- process memory consumption (in case of USS) as explained in detail
- `here <http://grodola.blogspot.com/2016/02/psutil-4-real-process-memory-and-environ.html>`__.
+ process memory consumption (in case of USS) as explained in detail in this
+ `blog post <http://grodola.blogspot.com/2016/02/psutil-4-real-process-memory-and-environ.html>`__.
It does so by passing through the whole process address.
As such it usually requires higher user privileges than
:meth:`memory_info` and is considerably slower.
@@ -1400,7 +1447,13 @@ Process class
pmmap_grouped(path='[heap]', rss=32768, size=139264, pss=32768, shared_clean=0, shared_dirty=0, private_clean=0, private_dirty=32768, referenced=32768, anonymous=32768, swap=0),
pmmap_grouped(path='[stack]', rss=2465792, size=2494464, pss=2465792, shared_clean=0, shared_dirty=0, private_clean=0, private_dirty=2465792, referenced=2277376, anonymous=2465792, swap=0),
...]
- >>>
+ >>> p.memory_maps(grouped=False)
+ [pmmap_ext(addr='00400000-006ea000', perms='r-xp', path='/usr/bin/python2.7', rss=2293760, size=3055616, pss=1157120, shared_clean=2273280, shared_dirty=0, private_clean=20480, private_dirty=0, referenced=2293760, anonymous=0, swap=0),
+ pmmap_ext(addr='008e9000-008eb000', perms='r--p', path='/usr/bin/python2.7', rss=8192, size=8192, pss=6144, shared_clean=4096, shared_dirty=0, private_clean=0, private_dirty=4096, referenced=8192, anonymous=4096, swap=0),
+ pmmap_ext(addr='008eb000-00962000', perms='rw-p', path='/usr/bin/python2.7', rss=417792, size=487424, pss=317440, shared_clean=200704, shared_dirty=0, private_clean=16384, private_dirty=200704, referenced=417792, anonymous=200704, swap=0),
+ pmmap_ext(addr='00962000-00985000', perms='rw-p', path='[anon]', rss=139264, size=143360, pss=139264, shared_clean=0, shared_dirty=0, private_clean=0, private_dirty=139264, referenced=139264, anonymous=139264, swap=0),
+ pmmap_ext(addr='02829000-02ccf000', perms='rw-p', path='[heap]', rss=4743168, size=4874240, pss=4743168, shared_clean=0, shared_dirty=0, private_clean=0, private_dirty=4743168, referenced=4718592, anonymous=4743168, swap=0),
+ ...]
Availability: All platforms except OpenBSD and NetBSD.
@@ -1409,7 +1462,7 @@ Process class
Return the children of this process as a list of :Class:`Process` objects,
preemptively checking whether PID has been reused. If recursive is `True`
return all the parent descendants.
- Example assuming *A == this process*:
+ Pseudo code example assuming *A == this process*:
::
A ─┐
@@ -1452,8 +1505,7 @@ Process class
>>> f = open('file.ext', 'w')
>>> p = psutil.Process()
>>> p.open_files()
- [popenfile(path='/home/giampaolo/svn/psutil/setup.py', fd=3, position=0, mode='r', flags=32768),
- popenfile(path='/var/log/monitd', fd=4, position=235542, mode='a', flags=33793)]
+ [popenfile(path='/home/giampaolo/svn/psutil/file.ext', fd=3, position=0, mode='w', flags=32769)]
.. warning::
on Windows this is not fully reliable as due to some limitations of the
@@ -1512,27 +1564,27 @@ Process class
+----------------+-----------------------------------------------------+
| **Kind value** | **Connections using** |
+================+=====================================================+
- | "inet" | IPv4 and IPv6 |
+ | ``"inet"`` | IPv4 and IPv6 |
+----------------+-----------------------------------------------------+
- | "inet4" | IPv4 |
+ | ``"inet4"`` | IPv4 |
+----------------+-----------------------------------------------------+
- | "inet6" | IPv6 |
+ | ``"inet6"`` | IPv6 |
+----------------+-----------------------------------------------------+
- | "tcp" | TCP |
+ | ``"tcp"`` | TCP |
+----------------+-----------------------------------------------------+
- | "tcp4" | TCP over IPv4 |
+ | ``"tcp4"`` | TCP over IPv4 |
+----------------+-----------------------------------------------------+
- | "tcp6" | TCP over IPv6 |
+ | ``"tcp6"`` | TCP over IPv6 |
+----------------+-----------------------------------------------------+
- | "udp" | UDP |
+ | ``"udp"`` | UDP |
+----------------+-----------------------------------------------------+
- | "udp4" | UDP over IPv4 |
+ | ``"udp4"`` | UDP over IPv4 |
+----------------+-----------------------------------------------------+
- | "udp6" | UDP over IPv6 |
+ | ``"udp6"`` | UDP over IPv6 |
+----------------+-----------------------------------------------------+
- | "unix" | UNIX socket (both UDP and TCP protocols) |
+ | ``"unix"`` | UNIX socket (both UDP and TCP protocols) |
+----------------+-----------------------------------------------------+
- | "all" | the sum of all the possible families and protocols |
+ | ``"all"`` | the sum of all the possible families and protocols |
+----------------+-----------------------------------------------------+
Example:
@@ -1612,6 +1664,10 @@ Process class
either return immediately or raise :class:`TimeoutExpired`.
To wait for multiple processes use :func:`psutil.wait_procs()`.
+ >>> import psutil
+ >>> p = psutil.Process(9891)
+ >>> p.terminate()
+ >>> p.wait()
Popen class
-----------
@@ -1766,14 +1822,14 @@ Constants
.. _const-oses:
.. data:: POSIX
- WINDOWS
- LINUX
- OSX
- FREEBSD
- NETBSD
- OPENBSD
- BSD
- SUNOS
+.. data:: WINDOWS
+.. data:: LINUX
+.. data:: OSX
+.. data:: FREEBSD
+.. data:: NETBSD
+.. data:: OPENBSD
+.. data:: BSD
+.. data:: SUNOS
``bool`` constants which define what platform you're on. E.g. if on Windows,
*WINDOWS* constant will be ``True``, all others will be ``False``.
@@ -1794,18 +1850,18 @@ Constants
.. _const-pstatus:
.. data:: STATUS_RUNNING
- STATUS_SLEEPING
- STATUS_DISK_SLEEP
- STATUS_STOPPED
- STATUS_TRACING_STOP
- STATUS_ZOMBIE
- STATUS_DEAD
- STATUS_WAKE_KILL
- STATUS_WAKING
- STATUS_IDLE (OSX, FreeBSD)
- STATUS_LOCKED (FreeBSD)
- STATUS_WAITING (FreeBSD)
- STATUS_SUSPENDED (NetBSD)
+.. data:: STATUS_SLEEPING
+.. data:: STATUS_DISK_SLEEP
+.. data:: STATUS_STOPPED
+.. data:: STATUS_TRACING_STOP
+.. data:: STATUS_ZOMBIE
+.. data:: STATUS_DEAD
+.. data:: STATUS_WAKE_KILL
+.. data:: STATUS_WAKING
+.. data:: STATUS_IDLE (OSX, FreeBSD)
+.. data:: STATUS_LOCKED (FreeBSD)
+.. data:: STATUS_WAITING (FreeBSD)
+.. data:: STATUS_SUSPENDED (NetBSD)
A set of strings representing the status of a process.
Returned by :meth:`psutil.Process.status()`.
@@ -1814,31 +1870,31 @@ Constants
.. _const-conn:
.. data:: 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
- CONN_DELETE_TCB (Windows)
- CONN_IDLE (Solaris)
- CONN_BOUND (Solaris)
+.. data:: CONN_SYN_SENT
+.. data:: CONN_SYN_RECV
+.. data:: CONN_FIN_WAIT1
+.. data:: CONN_FIN_WAIT2
+.. data:: CONN_TIME_WAIT
+.. data:: CONN_CLOSE
+.. data:: CONN_CLOSE_WAIT
+.. data:: CONN_LAST_ACK
+.. data:: CONN_LISTEN
+.. data:: CONN_CLOSING
+.. data:: CONN_NONE
+.. data:: CONN_DELETE_TCB (Windows)
+.. data:: CONN_IDLE (Solaris)
+.. data:: CONN_BOUND (Solaris)
A set of strings representing the status of a TCP connection.
Returned by :meth:`psutil.Process.connections()` (`status` field).
.. _const-prio:
.. data:: ABOVE_NORMAL_PRIORITY_CLASS
- BELOW_NORMAL_PRIORITY_CLASS
- HIGH_PRIORITY_CLASS
- IDLE_PRIORITY_CLASS
- NORMAL_PRIORITY_CLASS
- REALTIME_PRIORITY_CLASS
+.. data:: BELOW_NORMAL_PRIORITY_CLASS
+.. data:: HIGH_PRIORITY_CLASS
+.. data:: IDLE_PRIORITY_CLASS
+.. data:: NORMAL_PRIORITY_CLASS
+.. data:: REALTIME_PRIORITY_CLASS
A set of integers representing the priority of a process on Windows (see
`MSDN documentation <http://msdn.microsoft.com/en-us/library/ms686219(v=vs.85).aspx>`__).
@@ -1854,9 +1910,9 @@ Constants
.. _const-ioprio:
.. data:: IOPRIO_CLASS_NONE
- IOPRIO_CLASS_RT
- IOPRIO_CLASS_BE
- IOPRIO_CLASS_IDLE
+.. data:: IOPRIO_CLASS_RT
+.. data:: IOPRIO_CLASS_BE
+.. data:: IOPRIO_CLASS_IDLE
A set of integers representing the I/O priority of a process on Linux. They
can be used in conjunction with :meth:`psutil.Process.ionice()` to get or set
@@ -1882,22 +1938,22 @@ Constants
.. _const-rlimit:
.. data:: RLIM_INFINITY
- RLIMIT_AS
- RLIMIT_CORE
- RLIMIT_CPU
- RLIMIT_DATA
- RLIMIT_FSIZE
- RLIMIT_LOCKS
- RLIMIT_MEMLOCK
- RLIMIT_MSGQUEUE
- RLIMIT_NICE
- RLIMIT_NOFILE
- RLIMIT_NPROC
- RLIMIT_RSS
- RLIMIT_RTPRIO
- RLIMIT_RTTIME
- RLIMIT_SIGPENDING
- RLIMIT_STACK
+.. data:: RLIMIT_AS
+.. data:: RLIMIT_CORE
+.. data:: RLIMIT_CPU
+.. data:: RLIMIT_DATA
+.. data:: RLIMIT_FSIZE
+.. data:: RLIMIT_LOCKS
+.. data:: RLIMIT_MEMLOCK
+.. data:: RLIMIT_MSGQUEUE
+.. data:: RLIMIT_NICE
+.. data:: RLIMIT_NOFILE
+.. data:: RLIMIT_NPROC
+.. data:: RLIMIT_RSS
+.. data:: RLIMIT_RTPRIO
+.. data:: RLIMIT_RTTIME
+.. data:: RLIMIT_SIGPENDING
+.. data:: RLIMIT_STACK
Constants used for getting and setting process resource limits to be used in
conjunction with :meth:`psutil.Process.rlimit()`. See
@@ -1915,8 +1971,8 @@ Constants
.. _const-duplex:
.. data:: NIC_DUPLEX_FULL
- NIC_DUPLEX_HALF
- NIC_DUPLEX_UNKNOWN
+.. data:: NIC_DUPLEX_HALF
+.. data:: NIC_DUPLEX_UNKNOWN
Constants which identifies whether a NIC (network interface card) has full or
half mode speed. NIC_DUPLEX_FULL means the NIC is able to send and receive
@@ -1935,6 +1991,36 @@ Constants
>>> if psutil.version_info >= (4, 5):
... pass
+Q&A
+===
+
+* Q: What Windows versions are supported?
+* A: From Windows **Vista** onwards, both 32 and 64 bit versions.
+ Latest binary (wheel / exe) release which supports Windows **2000**, **XP**
+ and **2003 server** is
+ `psutil 3.4.2 <https://pypi.python.org/pypi?name=psutil&version=3.4.2&:action=files>`__.
+ On such old systems psutil is no longer tested or maintained, but it can
+ still be compiled from sources (you'll need `Visual Studio <(https://github.com/giampaolo/psutil/blob/master/INSTALL.rst#windows>`__)
+ and it should "work" (more or less).
+
+----
+
+* Q: What SunOS versions are supported?
+* A: From Solaris 10 onwards.
+
+----
+
+* Q: Why do I get :class:`AccessDenied` for certain processes?
+* A: This may happen when you query processess owned by another user,
+ especially on `OSX <https://github.com/giampaolo/psutil/issues/883>`__ and
+ Windows.
+ Unfortunately there's not much you can do about this except running the
+ Python process with higher privileges.
+ On Unix you may run the the Python process as root or use the SUID bit
+ (this is the trick used by tools such as ``ps`` and ``netstat``).
+ On Windows you may run the Python process as NT AUTHORITY\\SYSTEM or install
+ the Python script as a Windows service (this is the trick used by tools
+ such as ProcessHacker).
Development guide
=================
@@ -1943,23 +2029,11 @@ If you plan on hacking on psutil (e.g. want to add a new feature or fix a bug)
take a look at the
`development guide <https://github.com/giampaolo/psutil/blob/master/DEVGUIDE.rst>`_.
-
-Q&A
-===
-
-* Q: What Windows versions are supported?
-* A: From Windows **Vista** onwards. Latest binary (wheel / exe) release
- supporting Windows **2000**, **XP** and **2003 server** which can installed
- via pip without a compiler being installed is
- `psutil 3.4.2 <https://pypi.python.org/pypi?name=psutil&version=3.4.2&:action=files>`__.
- More recent psutil versions may still be compiled from sources and work
- (more or less) but they are no longer being tested or maintained.
-
-
Timeline
========
-- 2016-11-06: `5.5.0 <https://pypi.python.org/pypi?name=psutil&version=5.5.0&:action=files>`__ - `what's new <https://github.com/giampaolo/psutil/blob/master/HISTORY.rst#550>`__
+- 2016-12-21: `5.0.1 <https://pypi.python.org/pypi?name=psutil&version=5.0.1&:action=files>`__ - `what's new <https://github.com/giampaolo/psutil/blob/master/HISTORY.rst#550>`__
+- 2016-11-06: `5.0.0 <https://pypi.python.org/pypi?name=psutil&version=5.0.0&:action=files>`__ - `what's new <https://github.com/giampaolo/psutil/blob/master/HISTORY.rst#550>`__
- 2016-10-26: `4.4.2 <https://pypi.python.org/pypi?name=psutil&version=4.4.2&:action=files>`__ - `what's new <https://github.com/giampaolo/psutil/blob/master/HISTORY.rst#442>`__
- 2016-10-25: `4.4.1 <https://pypi.python.org/pypi?name=psutil&version=4.4.1&:action=files>`__ - `what's new <https://github.com/giampaolo/psutil/blob/master/HISTORY.rst#441>`__
- 2016-10-23: `4.4.0 <https://pypi.python.org/pypi?name=psutil&version=4.4.0&:action=files>`__ - `what's new <https://github.com/giampaolo/psutil/blob/master/HISTORY.rst#440>`__
diff --git a/psutil/__init__.py b/psutil/__init__.py
index 0ed28945..68fdee8f 100644
--- a/psutil/__init__.py
+++ b/psutil/__init__.py
@@ -143,8 +143,8 @@ elif SUNOS:
from ._pssunos import CONN_BOUND # NOQA
from ._pssunos import CONN_IDLE # NOQA
- # This is public API and it will be retrieved from _pssunos.py
- # via sys.modules.
+ # This is public writable API which is read from _pslinux.py and
+ # _pssunos.py via sys.modules.
PROCFS_PATH = "/proc"
else: # pragma: no cover
@@ -181,7 +181,7 @@ __all__ = [
"pid_exists", "pids", "process_iter", "wait_procs", # proc
"virtual_memory", "swap_memory", # memory
"cpu_times", "cpu_percent", "cpu_times_percent", "cpu_count", # cpu
- "cpu_stats",
+ "cpu_stats", # "cpu_freq",
"net_io_counters", "net_connections", "net_if_addrs", # network
"net_if_stats",
"disk_io_counters", "disk_partitions", "disk_usage", # disk
@@ -189,7 +189,7 @@ __all__ = [
]
__all__.extend(_psplatform.__extra__all__)
__author__ = "Giampaolo Rodola'"
-__version__ = "5.0.1"
+__version__ = "5.0.2"
version_info = tuple([int(num) for num in __version__.split('.')])
AF_LINK = _psplatform.AF_LINK
_TOTAL_PHYMEM = None
@@ -222,6 +222,7 @@ if (int(__version__.replace('.', '')) !=
# --- exceptions
# =====================================================================
+
class Error(Exception):
"""Base exception class. All other psutil exceptions inherit
from this one.
@@ -453,6 +454,11 @@ class Process(object):
self._hash = hash(self._ident)
return self._hash
+ @property
+ def pid(self):
+ """The process PID."""
+ return self._pid
+
# --- utility methods
@contextlib.contextmanager
@@ -601,11 +607,6 @@ class Process(object):
# --- actual API
- @property
- def pid(self):
- """The process PID."""
- return self._pid
-
@memoize_when_activated
def ppid(self):
"""The process parent PID.
@@ -993,6 +994,14 @@ class Process(object):
In this case is recommended for accuracy that this function
be called with at least 0.1 seconds between calls.
+ A value > 100.0 can be returned in case of processes running
+ multiple threads on different CPU cores.
+
+ The returned value is explicitly *not* split evenly between
+ all available logical CPUs. This means that a busy loop process
+ running on a system with 2 logical CPUs will be reported as
+ having 100% CPU utilization instead of 50%.
+
Examples:
>>> import psutil
@@ -1010,13 +1019,8 @@ class Process(object):
raise ValueError("interval is not positive (got %r)" % interval)
num_cpus = cpu_count() or 1
- if POSIX:
- def timer():
- return _timer() * num_cpus
- else:
- def timer():
- t = cpu_times()
- return sum((t.user, t.system))
+ def timer():
+ return _timer() * num_cpus
if blocking:
st1 = timer()
@@ -1198,6 +1202,8 @@ class Process(object):
"""
return self._proc.connections(kind)
+ # --- signals
+
if POSIX:
def _send_signal(self, sig):
assert not self.pid < 0, self.pid
@@ -1858,6 +1864,36 @@ def cpu_stats():
return _psplatform.cpu_stats()
+if hasattr(_psplatform, "cpu_freq"):
+
+ def cpu_freq(percpu=False):
+ """Return CPU frequency as a nameduple including current,
+ min and max frequency expressed in Mhz.
+
+ If percpu is True and the system supports per-cpu frequency
+ retrieval (Linux only) a list of frequencies is returned for
+ each CPU. If not a list with one element is returned.
+ """
+ ret = _psplatform.cpu_freq()
+ if percpu:
+ return ret
+ else:
+ num_cpus = len(ret)
+ if num_cpus == 1:
+ return ret[0]
+ currs, mins, maxs = [], [], []
+ for cpu in ret:
+ currs.append(cpu.current)
+ mins.append(cpu.min)
+ maxs.append(cpu.max)
+ return _common.scpufreq(
+ sum(currs) / num_cpus,
+ sum(mins) / num_cpus,
+ sum(maxs) / num_cpus)
+
+ __all__.append("cpu_freq")
+
+
# =====================================================================
# --- system memory related functions
# =====================================================================
diff --git a/psutil/_common.py b/psutil/_common.py
index 3879a1d7..68134820 100644
--- a/psutil/_common.py
+++ b/psutil/_common.py
@@ -156,6 +156,8 @@ snicstats = namedtuple('snicstats', ['isup', 'duplex', 'speed', 'mtu'])
# psutil.cpu_stats()
scpustats = namedtuple(
'scpustats', ['ctx_switches', 'interrupts', 'soft_interrupts', 'syscalls'])
+# psutil.cpu_freq()
+scpufreq = namedtuple('scpufreq', ['current', 'min', 'max'])
# --- for Process methods
diff --git a/psutil/_psbsd.py b/psutil/_psbsd.py
index 0a14bf80..022f5758 100644
--- a/psutil/_psbsd.py
+++ b/psutil/_psbsd.py
@@ -17,6 +17,7 @@ from . import _psutil_bsd as cext
from . import _psutil_posix as cext_posix
from ._common import conn_tmap
from ._common import FREEBSD
+from ._common import memoize
from ._common import memoize_when_activated
from ._common import NETBSD
from ._common import OPENBSD
@@ -421,7 +422,26 @@ def users():
# =====================================================================
-pids = cext.pids
+@memoize
+def _pid_0_exists():
+ try:
+ Process(0).name()
+ except NoSuchProcess:
+ return False
+ except AccessDenied:
+ return True
+ else:
+ return True
+
+
+def pids():
+ ret = cext.pids()
+ if OPENBSD and (0 not in ret) and _pid_0_exists():
+ # On OpenBSD the kernel does not return PID 0 (neither does
+ # ps) but it's actually querable (Process(0) will succeed).
+ ret.insert(0, 0)
+ return ret
+
if OPENBSD or NETBSD:
def pid_exists(pid):
diff --git a/psutil/_pslinux.py b/psutil/_pslinux.py
index c2c17a9a..ad95e39a 100644
--- a/psutil/_pslinux.py
+++ b/psutil/_pslinux.py
@@ -9,6 +9,7 @@ from __future__ import division
import base64
import errno
import functools
+import glob
import os
import re
import socket
@@ -133,6 +134,8 @@ TCP_STATUSES = {
"0B": _common.CONN_CLOSING
}
+_DEFAULT = object()
+
# =====================================================================
# -- exceptions
@@ -276,6 +279,18 @@ def set_scputimes_ntuple(procfs_path):
return scputimes
+def cat(fname, fallback=_DEFAULT, binary=True):
+ """Return file content."""
+ try:
+ with open_binary(fname) if binary else open_text(fname) as f:
+ return f.read()
+ except IOError:
+ if fallback != _DEFAULT:
+ return fallback
+ else:
+ raise
+
+
try:
scputimes = set_scputimes_ntuple("/proc")
except Exception:
@@ -607,6 +622,26 @@ def cpu_stats():
ctx_switches, interrupts, soft_interrupts, syscalls)
+if os.path.exists("/sys/devices/system/cpu/cpufreq"):
+
+ def cpu_freq():
+ # scaling_* files seem preferable to cpuinfo_*, see:
+ # http://unix.stackexchange.com/a/87537/168884
+ ret = []
+ ls = glob.glob("/sys/devices/system/cpu/cpufreq/policy*")
+ # Sort the list so that '10' comes after '2'. This should
+ # ensure the CPU order is consistent with other CPU functions
+ # having a 'percpu' argument and returning results for multiple
+ # CPUs (cpu_times(), cpu_percent(), cpu_times_percent()).
+ ls.sort(key=lambda x: int(os.path.basename(x)[6:]))
+ for path in ls:
+ curr = int(cat(os.path.join(path, "scaling_cur_freq"))) / 1000
+ max_ = int(cat(os.path.join(path, "scaling_max_freq"))) / 1000
+ min_ = int(cat(os.path.join(path, "scaling_min_freq"))) / 1000
+ ret.append(_common.scpufreq(curr, min_, max_))
+ return ret
+
+
# =====================================================================
# --- network
# =====================================================================
@@ -1070,8 +1105,32 @@ def pids():
def pid_exists(pid):
- """Check For the existence of a unix pid."""
- return _psposix.pid_exists(pid)
+ """Check for the existence of a unix PID."""
+ if not _psposix.pid_exists(pid):
+ return False
+ else:
+ # Linux's apparently does not distinguish between PIDs and TIDs
+ # (thread IDs).
+ # listdir("/proc") won't show any TID (only PIDs) but
+ # os.stat("/proc/{tid}") will succeed if {tid} exists.
+ # os.kill() can also be passed a TID. This is quite confusing.
+ # In here we want to enforce this distinction and support PIDs
+ # only, see:
+ # https://github.com/giampaolo/psutil/issues/687
+ try:
+ # Note: already checked that this is faster than using a
+ # regular expr. Also (a lot) faster than doing
+ # 'return pid in pids()'
+ with open_binary("%s/%s/status" % (get_procfs_path(), pid)) as f:
+ for line in f:
+ if line.startswith(b"Tgid:"):
+ tgid = int(line.split()[1])
+ # If tgid and pid are the same then we're
+ # dealing with a process PID.
+ return tgid == pid
+ raise ValueError("'Tgid' line not found")
+ except (EnvironmentError, ValueError):
+ return pid in pids()
def wrap_exceptions(fun):
diff --git a/psutil/_psosx.py b/psutil/_psosx.py
index 2665080e..f7adb43a 100644
--- a/psutil/_psosx.py
+++ b/psutil/_psosx.py
@@ -165,6 +165,16 @@ def cpu_stats():
ctx_switches, interrupts, soft_interrupts, syscalls)
+def cpu_freq():
+ """Return CPU frequency.
+ On OSX per-cpu frequency is not supported.
+ Also, the returned frequency never changes, see:
+ https://arstechnica.com/civis/viewtopic.php?f=19&t=465002
+ """
+ curr, min_, max_ = cext.cpu_freq()
+ return [_common.scpufreq(curr, min_, max_)]
+
+
# =====================================================================
# --- disks
# =====================================================================
diff --git a/psutil/_psutil_bsd.c b/psutil/_psutil_bsd.c
index b1bce487..adcedf79 100644
--- a/psutil/_psutil_bsd.c
+++ b/psutil/_psutil_bsd.c
@@ -15,8 +15,8 @@
* - psutil.Process.memory_maps()
*/
-#if defined(__NetBSD__)
-#define _KMEMUSER
+#if defined(PSUTIL_NETBSD)
+ #define _KMEMUSER
#endif
#include <Python.h>
@@ -61,17 +61,10 @@
#include "_psutil_common.h"
-#ifdef __FreeBSD__
+#ifdef PSUTIL_FREEBSD
#include "arch/bsd/freebsd.h"
#include "arch/bsd/freebsd_socks.h"
-#elif __OpenBSD__
- #include "arch/bsd/openbsd.h"
-#elif __NetBSD__
- #include "arch/bsd/netbsd.h"
- #include "arch/bsd/netbsd_socks.h"
-#endif
-#ifdef __FreeBSD__
#include <net/if_media.h>
#include <devstat.h> // get io counters
#include <libutil.h> // process open files, shared libs (kinfo_getvmmap)
@@ -80,37 +73,39 @@
#else
#include <utmpx.h>
#endif
-#endif
+#elif PSUTIL_OPENBSD
+ #include "arch/bsd/openbsd.h"
-#ifdef __OpenBSD__
#include <utmp.h>
#include <sys/vnode.h> // for VREG
#define _KERNEL // for DTYPE_VNODE
#include <sys/file.h>
#undef _KERNEL
#include <sys/sched.h> // for CPUSTATES & CP_*
-#endif
+#elif PSUTIL_NETBSD
+ #include "arch/bsd/netbsd.h"
+ #include "arch/bsd/netbsd_socks.h"
-#if defined(__NetBSD__)
#include <utmpx.h>
#include <sys/vnode.h> // for VREG
#include <sys/sched.h> // for CPUSTATES & CP_*
#ifndef DTYPE_VNODE
- #define DTYPE_VNODE 1
+ #define DTYPE_VNODE 1
#endif
#endif
+
// convert a timeval struct to a double
#define PSUTIL_TV2DOUBLE(t) ((t).tv_sec + (t).tv_usec / 1000000.0)
-#ifdef __FreeBSD__
+#ifdef PSUTIL_FREEBSD
// convert a bintime struct to milliseconds
#define PSUTIL_BT2MSEC(bt) (bt.sec * 1000 + (((uint64_t) 1000000000 * \
(uint32_t) (bt.frac >> 32) ) >> 32 ) / 1000000)
#endif
-#if defined(__OpenBSD__) || defined (__NetBSD__)
+#if defined(PSUTIL_OPENBSD) || defined (PSUTIL_NETBSD)
#define PSUTIL_KPT2DOUBLE(t) (t ## _sec + t ## _usec / 1000000.0)
#endif
@@ -146,9 +141,9 @@ psutil_pids(PyObject *self, PyObject *args) {
if (num_processes > 0) {
orig_address = proclist; // save so we can free it after we're done
for (idx = 0; idx < num_processes; idx++) {
-#ifdef __FreeBSD__
+#ifdef PSUTIL_FREEBSD
py_pid = Py_BuildValue("i", proclist->ki_pid);
-#elif defined(__OpenBSD__) || defined(__NetBSD__)
+#elif defined(PSUTIL_OPENBSD) || defined(PSUTIL_NETBSD)
py_pid = Py_BuildValue("i", proclist->p_pid);
#endif
if (!py_pid)
@@ -216,9 +211,9 @@ psutil_proc_oneshot_info(PyObject *self, PyObject *args) {
return NULL;
// Process
-#ifdef __FreeBSD__
+#ifdef PSUTIL_FREEBSD
sprintf(str, "%s", kp.ki_comm);
-#elif defined(__OpenBSD__) || defined(__NetBSD__)
+#elif defined(PSUTIL_OPENBSD) || defined(PSUTIL_NETBSD)
sprintf(str, "%s", kp.p_comm);
#endif
#if PY_MAJOR_VERSION >= 3
@@ -234,7 +229,7 @@ psutil_proc_oneshot_info(PyObject *self, PyObject *args) {
}
// Calculate memory.
-#ifdef __FreeBSD__
+#ifdef PSUTIL_FREEBSD
rss = (long)kp.ki_rssize * pagesize;
vms = (long)kp.ki_size;
memtext = (long)kp.ki_tsize * pagesize;
@@ -242,12 +237,12 @@ psutil_proc_oneshot_info(PyObject *self, PyObject *args) {
memstack = (long)kp.ki_ssize * pagesize;
#else
rss = (long)kp.p_vm_rssize * pagesize;
- #ifdef __OpenBSD__
+ #ifdef PSUTIL_OPENBSD
// VMS, this is how ps determines it on OpenBSD:
// http://anoncvs.spacehopper.org/openbsd-src/tree/bin/ps/print.c#n461
// vms
vms = (long)(kp.p_vm_dsize + kp.p_vm_ssize + kp.p_vm_tsize) * pagesize;
- #elif __NetBSD__
+ #elif PSUTIL_NETBSD
// VMS, this is how top determines it on NetBSD:
// ftp://ftp.iij.ad.jp/pub/NetBSD/NetBSD-release-6/src/external/bsd/
// top/dist/machine/m_netbsd.c
@@ -258,7 +253,7 @@ psutil_proc_oneshot_info(PyObject *self, PyObject *args) {
memstack = (long)kp.p_vm_ssize * pagesize;
#endif
-#ifdef __FreeBSD__
+#ifdef PSUTIL_FREEBSD
// what CPU we're on; top was used as an example:
// https://svnweb.freebsd.org/base/head/usr.bin/top/machine.c?
// view=markup&pathrev=273835
@@ -277,7 +272,8 @@ psutil_proc_oneshot_info(PyObject *self, PyObject *args) {
// Return a single big tuple with all process info.
py_retlist = Py_BuildValue(
"(lillllllidllllddddlllllbO)",
-#ifdef __FreeBSD__
+#ifdef PSUTIL_FREEBSD
+ //
(long)kp.ki_ppid, // (long) ppid
(int)kp.ki_stat, // (int) status
// UIDs
@@ -310,7 +306,8 @@ psutil_proc_oneshot_info(PyObject *self, PyObject *args) {
memstack, // (long) mem stack
// others
oncpu, // (unsigned char) the CPU we are on
-#elif defined(__OpenBSD__) || defined(__NetBSD__)
+#elif defined(PSUTIL_OPENBSD) || defined(PSUTIL_NETBSD)
+ //
(long)kp.p_ppid, // (long) ppid
(int)kp.p_stat, // (int) status
// UIDs
@@ -371,9 +368,9 @@ psutil_proc_name(PyObject *self, PyObject *args) {
if (psutil_kinfo_proc(pid, &kp) == -1)
return NULL;
-#ifdef __FreeBSD__
+#ifdef PSUTIL_FREEBSD
sprintf(str, "%s", kp.ki_comm);
-#elif defined(__OpenBSD__) || defined(__NetBSD__)
+#elif defined(PSUTIL_OPENBSD) || defined(PSUTIL_NETBSD)
sprintf(str, "%s", kp.p_comm);
#endif
@@ -431,7 +428,7 @@ psutil_cpu_count_logical(PyObject *self, PyObject *args) {
*/
static PyObject *
psutil_cpu_times(PyObject *self, PyObject *args) {
-#if defined(__NetBSD__)
+#ifdef PSUTIL_NETBSD
u_int64_t cpu_time[CPUSTATES];
#else
long cpu_time[CPUSTATES];
@@ -439,9 +436,9 @@ psutil_cpu_times(PyObject *self, PyObject *args) {
size_t size = sizeof(cpu_time);
int ret;
-#if defined(__FreeBSD__) || defined(__NetBSD__)
+#if defined(PSUTIL_FREEBSD) || defined(PSUTIL_NETBSD)
ret = sysctlbyname("kern.cp_time", &cpu_time, &size, NULL, 0);
-#elif __OpenBSD__
+#elif PSUTIL_OPENBSD
int mib[] = {CTL_KERN, KERN_CPTIME};
ret = sysctl(mib, 2, &cpu_time, &size, NULL, 0);
#endif
@@ -466,7 +463,7 @@ psutil_cpu_times(PyObject *self, PyObject *args) {
* utility has the same problem see:
* https://github.com/giampaolo/psutil/issues/595
*/
-#if (defined(__FreeBSD_version) && __FreeBSD_version >= 800000) || __OpenBSD__ || defined(__NetBSD__)
+#if (defined(__FreeBSD_version) && __FreeBSD_version >= 800000) || PSUTIL_OPENBSD || defined(PSUTIL_NETBSD)
static PyObject *
psutil_proc_open_files(PyObject *self, PyObject *args) {
long pid;
@@ -493,17 +490,17 @@ psutil_proc_open_files(PyObject *self, PyObject *args) {
for (i = 0; i < cnt; i++) {
kif = &freep[i];
-#ifdef __FreeBSD__
+#ifdef PSUTIL_FREEBSD
if ((kif->kf_type == KF_TYPE_VNODE) &&
(kif->kf_vnode_type == KF_VTYPE_VREG))
{
py_tuple = Py_BuildValue("(si)", kif->kf_path, kif->kf_fd);
-#elif defined(__OpenBSD__)
+#elif PSUTIL_OPENBSD
if ((kif->f_type == DTYPE_VNODE) &&
(kif->v_type == VREG))
{
py_tuple = Py_BuildValue("(si)", "", kif->fd_fd);
-#elif defined(__NetBSD__)
+#elif PSUTIL_NETBSD
if ((kif->ki_ftype == DTYPE_VNODE) &&
(kif->ki_vtype == VREG))
{
@@ -540,7 +537,7 @@ psutil_disk_partitions(PyObject *self, PyObject *args) {
long len;
uint64_t flags;
char opts[200];
-#if defined(__NetBSD__)
+#ifdef PSUTIL_NETBSD
struct statvfs *fs = NULL;
#else
struct statfs *fs = NULL;
@@ -553,7 +550,7 @@ psutil_disk_partitions(PyObject *self, PyObject *args) {
// get the number of mount points
Py_BEGIN_ALLOW_THREADS
-#if defined(__NetBSD__)
+#ifdef PSUTIL_NETBSD
num = getvfsstat(NULL, 0, MNT_NOWAIT);
#else
num = getfsstat(NULL, 0, MNT_NOWAIT);
@@ -572,7 +569,7 @@ psutil_disk_partitions(PyObject *self, PyObject *args) {
}
Py_BEGIN_ALLOW_THREADS
-#if defined(__NetBSD__)
+#ifdef PSUTIL_NETBSD
num = getvfsstat(fs, len, MNT_NOWAIT);
#else
num = getfsstat(fs, len, MNT_NOWAIT);
@@ -586,7 +583,7 @@ psutil_disk_partitions(PyObject *self, PyObject *args) {
for (i = 0; i < num; i++) {
py_tuple = NULL;
opts[0] = 0;
-#if defined(__NetBSD__)
+#ifdef PSUTIL_NETBSD
flags = fs[i].f_flag;
#else
flags = fs[i].f_flags;
@@ -609,7 +606,7 @@ psutil_disk_partitions(PyObject *self, PyObject *args) {
strlcat(opts, ",noatime", sizeof(opts));
if (flags & MNT_SOFTDEP)
strlcat(opts, ",softdep", sizeof(opts));
-#ifdef __FreeBSD__
+#ifdef PSUTIL_FREEBSD
if (flags & MNT_UNION)
strlcat(opts, ",union", sizeof(opts));
if (flags & MNT_SUIDDIR)
@@ -630,24 +627,24 @@ psutil_disk_partitions(PyObject *self, PyObject *args) {
strlcat(opts, ",noclusterw", sizeof(opts));
if (flags & MNT_NFS4ACLS)
strlcat(opts, ",nfs4acls", sizeof(opts));
-#elif __NetBSD__
+#elif PSUTIL_NETBSD
if (flags & MNT_NODEV)
strlcat(opts, ",nodev", sizeof(opts));
if (flags & MNT_UNION)
strlcat(opts, ",union", sizeof(opts));
if (flags & MNT_NOCOREDUMP)
strlcat(opts, ",nocoredump", sizeof(opts));
-#if defined(MNT_RELATIME)
+#ifdef MNT_RELATIME
if (flags & MNT_RELATIME)
strlcat(opts, ",relatime", sizeof(opts));
#endif
if (flags & MNT_IGNORE)
strlcat(opts, ",ignore", sizeof(opts));
-#if defined(MNT_DISCARD)
+#ifdef MNT_DISCARD
if (flags & MNT_DISCARD)
strlcat(opts, ",discard", sizeof(opts));
#endif
-#if defined(MNT_EXTATTR)
+#ifdef MNT_EXTATTR
if (flags & MNT_EXTATTR)
strlcat(opts, ",extattr", sizeof(opts));
#endif
@@ -788,7 +785,7 @@ psutil_users(PyObject *self, PyObject *args) {
if (py_retlist == NULL)
return NULL;
-#if (defined(__FreeBSD_version) && (__FreeBSD_version < 900000)) || __OpenBSD__
+#if (defined(__FreeBSD_version) && (__FreeBSD_version < 900000)) || PSUTIL_OPENBSD
struct utmp ut;
FILE *fp;
@@ -868,7 +865,7 @@ PsutilMethods[] = {
"Return multiple info about a process"},
{"proc_name", psutil_proc_name, METH_VARARGS,
"Return process name"},
-#if !defined(__NetBSD__)
+#if !defined(PSUTIL_NETBSD)
{"proc_connections", psutil_proc_connections, METH_VARARGS,
"Return connections opened by process"},
#endif
@@ -876,25 +873,25 @@ PsutilMethods[] = {
"Return process cmdline as a list of cmdline arguments"},
{"proc_threads", psutil_proc_threads, METH_VARARGS,
"Return process threads"},
-#if defined(__FreeBSD__) || defined(__OpenBSD__)
+#if defined(PSUTIL_FREEBSD) || defined(PSUTIL_OPENBSD)
{"proc_cwd", psutil_proc_cwd, METH_VARARGS,
"Return process current working directory."},
#endif
-#if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 || __OpenBSD__ || defined(__NetBSD__)
+#if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 || PSUTIL_OPENBSD || defined(PSUTIL_NETBSD)
{"proc_num_fds", psutil_proc_num_fds, METH_VARARGS,
"Return the number of file descriptors opened by this process"},
#endif
-#if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 || __OpenBSD__ || defined(__NetBSD__)
+#if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 || PSUTIL_OPENBSD || defined(PSUTIL_NETBSD)
{"proc_open_files", psutil_proc_open_files, METH_VARARGS,
"Return files opened by process as a list of (path, fd) tuples"},
#endif
-#if defined(__FreeBSD__) || defined(__NetBSD__)
+#if defined(PSUTIL_FREEBSD) || defined(PSUTIL_NETBSD)
{"proc_exe", psutil_proc_exe, METH_VARARGS,
"Return process pathname executable"},
{"proc_num_threads", psutil_proc_num_threads, METH_VARARGS,
"Return number of threads used by process"},
-#if defined(__FreeBSD__)
+#if defined(PSUTIL_FREEBSD)
{"proc_memory_maps", psutil_proc_memory_maps, METH_VARARGS,
"Return a list of tuples for every process's memory map"},
{"proc_cpu_affinity_get", psutil_proc_cpu_affinity_get, METH_VARARGS,
@@ -933,7 +930,7 @@ PsutilMethods[] = {
"Return currently connected users as a list of tuples"},
{"cpu_stats", psutil_cpu_stats, METH_VARARGS,
"Return CPU statistics"},
-#if defined(__FreeBSD__) || defined(__NetBSD__)
+#if defined(PSUTIL_FREEBSD) || defined(PSUTIL_NETBSD)
{"net_connections", psutil_net_connections, METH_VARARGS,
"Return system-wide open connections."},
#endif
@@ -995,7 +992,7 @@ void init_psutil_bsd(void)
PyModule_AddIntConstant(module, "version", PSUTIL_VERSION);
// process status constants
-#ifdef __FreeBSD__
+#ifdef PSUTIL_FREEBSD
PyModule_AddIntConstant(module, "SIDL", SIDL);
PyModule_AddIntConstant(module, "SRUN", SRUN);
PyModule_AddIntConstant(module, "SSLEEP", SSLEEP);
@@ -1003,7 +1000,7 @@ void init_psutil_bsd(void)
PyModule_AddIntConstant(module, "SZOMB", SZOMB);
PyModule_AddIntConstant(module, "SWAIT", SWAIT);
PyModule_AddIntConstant(module, "SLOCK", SLOCK);
-#elif __OpenBSD__
+#elif PSUTIL_OPENBSD
PyModule_AddIntConstant(module, "SIDL", SIDL);
PyModule_AddIntConstant(module, "SRUN", SRUN);
PyModule_AddIntConstant(module, "SSLEEP", SSLEEP);
@@ -1011,7 +1008,7 @@ void init_psutil_bsd(void)
PyModule_AddIntConstant(module, "SZOMB", SZOMB); // unused
PyModule_AddIntConstant(module, "SDEAD", SDEAD);
PyModule_AddIntConstant(module, "SONPROC", SONPROC);
-#elif defined(__NetBSD__)
+#elif defined(PSUTIL_NETBSD)
PyModule_AddIntConstant(module, "SIDL", LSIDL);
PyModule_AddIntConstant(module, "SRUN", LSRUN);
PyModule_AddIntConstant(module, "SSLEEP", LSSLEEP);
diff --git a/psutil/_psutil_osx.c b/psutil/_psutil_osx.c
index a1168c29..fb26dc9b 100644
--- a/psutil/_psutil_osx.c
+++ b/psutil/_psutil_osx.c
@@ -809,6 +809,35 @@ error:
/*
+ * Retrieve CPU frequency.
+ */
+static PyObject *
+psutil_cpu_freq(PyObject *self, PyObject *args) {
+ int64_t curr;
+ int64_t min;
+ int64_t max;
+ size_t size = sizeof(int64_t);
+
+ if (sysctlbyname("hw.cpufrequency", &curr, &size, NULL, 0))
+ goto error;
+ if (sysctlbyname("hw.cpufrequency_min", &min, &size, NULL, 0))
+ goto error;
+ if (sysctlbyname("hw.cpufrequency_max", &max, &size, NULL, 0))
+ goto error;
+
+ return Py_BuildValue(
+ "KKK",
+ curr / 1000 / 1000,
+ min / 1000 / 1000,
+ max / 1000 / 1000);
+
+error:
+ PyErr_SetFromErrno(PyExc_OSError);
+ return NULL;
+}
+
+
+/*
* Return a Python float indicating the system boot time expressed in
* seconds since the epoch.
*/
@@ -1778,6 +1807,8 @@ PsutilMethods[] = {
"Return system cpu times as a tuple (user, system, nice, idle, irc)"},
{"per_cpu_times", psutil_per_cpu_times, METH_VARARGS,
"Return system per-cpu times as a list of tuples"},
+ {"cpu_freq", psutil_cpu_freq, METH_VARARGS,
+ "Return cpu current frequency"},
{"boot_time", psutil_boot_time, METH_VARARGS,
"Return the system boot time expressed in seconds since the epoch."},
{"disk_partitions", psutil_disk_partitions, METH_VARARGS,
diff --git a/psutil/_psutil_posix.c b/psutil/_psutil_posix.c
index 2d9630ac..7aa4b553 100644
--- a/psutil/_psutil_posix.c
+++ b/psutil/_psutil_posix.c
@@ -16,25 +16,21 @@
#include <net/if.h>
#ifdef PSUTIL_SUNOS10
-#include "arch/solaris/v10/ifaddrs.h"
+ #include "arch/solaris/v10/ifaddrs.h"
#else
-#include <ifaddrs.h>
+ #include <ifaddrs.h>
#endif
-#ifdef __linux
-#include <netdb.h>
-#include <linux/if_packet.h>
-#endif // end linux
-
-#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__) || defined(__NetBSD__)
-#include <netdb.h>
-#include <netinet/in.h>
-#include <net/if_dl.h>
-#endif
-
-#if defined(__sun)
-#include <netdb.h>
-#include <sys/sockio.h>
+#if defined(PSUTIL_LINUX)
+ #include <netdb.h>
+ #include <linux/if_packet.h>
+#elif defined(PSUTIL_BSD) || defined(PSUTIL_OSX)
+ #include <netdb.h>
+ #include <netinet/in.h>
+ #include <net/if_dl.h>
+#elif defined(PSUTIL_SUNOS)
+ #include <netdb.h>
+ #include <sys/sockio.h>
#endif
@@ -50,7 +46,7 @@ psutil_posix_getpriority(PyObject *self, PyObject *args) {
if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
-#if defined(__APPLE__)
+#ifdef PSUTIL_OSX
priority = getpriority(PRIO_PROCESS, (id_t)pid);
#else
priority = getpriority(PRIO_PROCESS, pid);
@@ -73,7 +69,7 @@ psutil_posix_setpriority(PyObject *self, PyObject *args) {
if (! PyArg_ParseTuple(args, "li", &pid, &priority))
return NULL;
-#if defined(__APPLE__)
+#ifdef PSUTIL_OSX
retval = setpriority(PRIO_PROCESS, (id_t)pid, priority);
#else
retval = setpriority(PRIO_PROCESS, pid, priority);
@@ -122,14 +118,13 @@ psutil_convert_ipaddr(struct sockaddr *addr, int family) {
return Py_BuildValue("s", buf);
}
}
-#ifdef __linux
+#ifdef PSUTIL_LINUX
else if (family == AF_PACKET) {
struct sockaddr_ll *lladdr = (struct sockaddr_ll *)addr;
len = lladdr->sll_halen;
data = (const char *)lladdr->sll_addr;
}
-#endif
-#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__) || defined(__NetBSD__)
+#elif defined(PSUTIL_BSD) || defined(PSUTIL_OSX)
else if (addr->sa_family == AF_LINK) {
// Note: prior to Python 3.4 socket module does not expose
// AF_LINK so we'll do.
@@ -264,8 +259,11 @@ psutil_net_if_mtu(PyObject *self, PyObject *args) {
char *nic_name;
int sock = 0;
int ret;
- int mtu;
+#ifdef PSUTIL_SUNOS10
+ struct lifreq lifr;
+#else
struct ifreq ifr;
+#endif
if (! PyArg_ParseTuple(args, "s", &nic_name))
return NULL;
@@ -274,14 +272,22 @@ psutil_net_if_mtu(PyObject *self, PyObject *args) {
if (sock == -1)
goto error;
+#ifdef PSUTIL_SUNOS10
+ strncpy(lifr.lifr_name, nic_name, sizeof(lifr.lifr_name));
+ ret = ioctl(sock, SIOCGIFMTU, &lifr);
+#else
strncpy(ifr.ifr_name, nic_name, sizeof(ifr.ifr_name));
ret = ioctl(sock, SIOCGIFMTU, &ifr);
+#endif
if (ret == -1)
goto error;
close(sock);
- mtu = ifr.ifr_mtu;
- return Py_BuildValue("i", mtu);
+#ifdef PSUTIL_SUNOS10
+ return Py_BuildValue("i", lifr.lifr_mtu);
+#else
+ return Py_BuildValue("i", ifr.ifr_mtu);
+#endif
error:
if (sock != 0)
@@ -332,7 +338,7 @@ error:
/*
* net_if_stats() OSX/BSD implementation.
*/
-#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__) || defined(__NetBSD__)
+#if defined(PSUTIL_BSD) || defined(PSUTIL_OSX)
#include <sys/sockio.h>
#include <net/if_media.h>
@@ -369,7 +375,7 @@ int psutil_get_nic_speed(int ifm_active) {
case(IFM_1000_SX): // 1000BaseSX - multi-mode fiber
case(IFM_1000_LX): // 1000baseLX - single-mode fiber
case(IFM_1000_CX): // 1000baseCX - 150ohm STP
-#if defined(IFM_1000_TX) && !defined(__OpenBSD__)
+#if defined(IFM_1000_TX) && !defined(PSUTIL_OPENBSD)
// FreeBSD 4 and others (but NOT OpenBSD) -> #define IFM_1000_T in net/if_media.h
case(IFM_1000_TX):
#endif
@@ -542,7 +548,7 @@ PsutilMethods[] = {
"Retrieve NIC MTU"},
{"net_if_flags", psutil_net_if_flags, METH_VARARGS,
"Retrieve NIC flags"},
-#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__) || defined(__NetBSD__)
+#if defined(PSUTIL_BSD) || defined(PSUTIL_OSX)
{"net_if_duplex_speed", psutil_net_if_duplex_speed, METH_VARARGS,
"Return NIC stats."},
#endif
@@ -567,6 +573,7 @@ psutil_posix_traverse(PyObject *m, visitproc visit, void *arg) {
return 0;
}
+
static int
psutil_posix_clear(PyObject *m) {
Py_CLEAR(GETSTATE(m)->error);
@@ -601,7 +608,7 @@ void init_psutil_posix(void)
PyObject *module = Py_InitModule("_psutil_posix", PsutilMethods);
#endif
-#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__) || defined(__sun) || defined(__NetBSD__)
+#if defined(PSUTIL_BSD) || defined(PSUTIL_OSX) || defined(PSUTIL_SUNOS)
PyModule_AddIntConstant(module, "AF_LINK", AF_LINK);
#endif
diff --git a/psutil/_psutil_windows.c b/psutil/_psutil_windows.c
index 4d939aff..4caace7d 100644
--- a/psutil/_psutil_windows.c
+++ b/psutil/_psutil_windows.c
@@ -24,6 +24,7 @@
#include <iphlpapi.h>
#include <wtsapi32.h>
#include <Winsvc.h>
+#include <PowrProf.h>
// Link with Iphlpapi.lib
#pragma comment(lib, "IPHLPAPI.lib")
@@ -145,6 +146,16 @@ typedef struct _MIB_UDP6TABLE_OWNER_PID {
} MIB_UDP6TABLE_OWNER_PID, *PMIB_UDP6TABLE_OWNER_PID;
#endif
+typedef struct _PROCESSOR_POWER_INFORMATION {
+ ULONG Number;
+ ULONG MaxMhz;
+ ULONG CurrentMhz;
+ ULONG MhzLimit;
+ ULONG MaxIdleState;
+ ULONG CurrentIdleState;
+} PROCESSOR_POWER_INFORMATION, *PPROCESSOR_POWER_INFORMATION;
+
+
PIP_ADAPTER_ADDRESSES
psutil_get_nic_addresses() {
// allocate a 15 KB buffer to start with
@@ -3391,6 +3402,60 @@ error:
}
+/*
+ * Return CPU frequency.
+ */
+static PyObject *
+psutil_cpu_freq(PyObject *self, PyObject *args) {
+ PROCESSOR_POWER_INFORMATION *ppi;
+ NTSTATUS ret;
+ size_t size;
+ LPBYTE pBuffer = NULL;
+ ULONG current;
+ ULONG max;
+ unsigned int num_cpus;
+ SYSTEM_INFO system_info;
+ system_info.dwNumberOfProcessors = 0;
+
+ // Get the number of CPUs.
+ GetSystemInfo(&system_info);
+ if (system_info.dwNumberOfProcessors == 0)
+ num_cpus = 1;
+ else
+ num_cpus = system_info.dwNumberOfProcessors;
+
+ // Allocate size.
+ size = num_cpus * sizeof(PROCESSOR_POWER_INFORMATION);
+ pBuffer = (BYTE*)LocalAlloc(LPTR, size);
+ if (! pBuffer) {
+ PyErr_SetFromWindowsErr(0);
+ return NULL;
+ }
+
+ // Syscall.
+ ret = CallNtPowerInformation(
+ ProcessorInformation, NULL, 0, pBuffer, size);
+ if (ret != 0) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "CallNtPowerInformation syscall failed");
+ goto error;
+ }
+
+ // Results.
+ ppi = (PROCESSOR_POWER_INFORMATION *)pBuffer;
+ max = ppi->MaxMhz;
+ current = ppi->CurrentMhz;
+ LocalFree(pBuffer);
+
+ return Py_BuildValue("kk", current, max);
+
+error:
+ if (pBuffer != NULL)
+ LocalFree(pBuffer);
+ return NULL;
+}
+
+
// ------------------------ Python init ---------------------------
static PyMethodDef
@@ -3495,6 +3560,8 @@ PsutilMethods[] = {
"Return NICs stats."},
{"cpu_stats", psutil_cpu_stats, METH_VARARGS,
"Return NICs stats."},
+ {"cpu_freq", psutil_cpu_freq, METH_VARARGS,
+ "Return CPU frequency."},
// --- windows services
{"winservice_enumerate", psutil_winservice_enumerate, METH_VARARGS,
diff --git a/psutil/_pswindows.py b/psutil/_pswindows.py
index cb816f73..da8552e1 100644
--- a/psutil/_pswindows.py
+++ b/psutil/_pswindows.py
@@ -299,6 +299,15 @@ def cpu_stats():
syscalls)
+def cpu_freq():
+ """Return CPU frequency.
+ On Windows per-cpu frequency is not supported.
+ """
+ curr, max_ = cext.cpu_freq()
+ min_ = 0.0
+ return [_common.scpufreq(float(curr), min_, float(max_))]
+
+
# =====================================================================
# --- network
# =====================================================================
diff --git a/psutil/arch/bsd/netbsd.c b/psutil/arch/bsd/netbsd.c
index 2cf2ef22..d5c3e3b9 100644
--- a/psutil/arch/bsd/netbsd.c
+++ b/psutil/arch/bsd/netbsd.c
@@ -7,8 +7,8 @@
* Platform-specific module methods for NetBSD.
*/
-#if defined(__NetBSD__)
-#define _KMEMUSER
+#if defined(PSUTIL_NETBSD)
+ #define _KMEMUSER
#endif
#include <Python.h>
diff --git a/psutil/tests/__init__.py b/psutil/tests/__init__.py
index 883d9285..b119a788 100644
--- a/psutil/tests/__init__.py
+++ b/psutil/tests/__init__.py
@@ -506,6 +506,7 @@ def chdir(dirname):
def create_exe(outpath, c_code=None):
+ """Creates an executable file in the given location."""
assert not os.path.exists(outpath), outpath
if which("gcc"):
if c_code is None:
@@ -526,6 +527,9 @@ def create_exe(outpath, c_code=None):
safe_rmpath(f.name)
else:
# fallback - use python's executable
+ if c_code is not None:
+ raise ValueError(
+ "can't specify c_code arg as gcc is not installed")
shutil.copyfile(sys.executable, outpath)
if POSIX:
st = os.stat(outpath)
diff --git a/psutil/tests/test_linux.py b/psutil/tests/test_linux.py
index d063fb40..37352ecf 100755
--- a/psutil/tests/test_linux.py
+++ b/psutil/tests/test_linux.py
@@ -40,6 +40,7 @@ from psutil.tests import safe_rmpath
from psutil.tests import sh
from psutil.tests import skip_on_not_implemented
from psutil.tests import TESTFN
+from psutil.tests import ThreadTask
from psutil.tests import TRAVIS
from psutil.tests import unittest
from psutil.tests import which
@@ -461,6 +462,21 @@ class TestSystemCPU(unittest.TestCase):
else:
self.assertNotIn('guest_nice', fields)
+ @unittest.skipUnless(os.path.exists("/sys/devices/system/cpu/online"),
+ "/sys/devices/system/cpu/online does not exist")
+ def test_cpu_count_logical_w_sysdev_cpu_online(self):
+ with open("/sys/devices/system/cpu/online") as f:
+ value = f.read().strip()
+ value = int(value.split('-')[1]) + 1
+ self.assertEqual(psutil.cpu_count(), value)
+
+ @unittest.skipUnless(os.path.exists("/sys/devices/system/cpu"),
+ "/sys/devices/system/cpu does not exist")
+ def test_cpu_count_logical_w_sysdev_cpu_num(self):
+ ls = os.listdir("/sys/devices/system/cpu")
+ count = len([x for x in ls if re.search("cpu\d+$", x) is not None])
+ self.assertEqual(psutil.cpu_count(), count)
+
@unittest.skipUnless(which("nproc"), "nproc utility not available")
def test_cpu_count_logical_w_nproc(self):
num = int(sh("nproc --all"))
@@ -565,7 +581,8 @@ class TestSystemNetwork(unittest.TestCase):
except RuntimeError:
pass
else:
- self.assertEqual(stats.isup, 'RUNNING' in out, msg=out)
+ # Not always reliable.
+ # self.assertEqual(stats.isup, 'RUNNING' in out, msg=out)
self.assertEqual(stats.mtu,
int(re.findall('MTU:(\d+)', out)[0]))
@@ -989,6 +1006,24 @@ class TestMisc(unittest.TestCase):
importlib.reload(psutil._pslinux)
importlib.reload(psutil)
+ def test_issue_687(self):
+ # In case of thread ID:
+ # - pid_exists() is supposed to return False
+ # - Process(tid) is supposed to work
+ # - pids() should not return the TID
+ # See: https://github.com/giampaolo/psutil/issues/687
+ t = ThreadTask()
+ t.start()
+ try:
+ p = psutil.Process()
+ tid = p.threads()[1].id
+ assert not psutil.pid_exists(tid), tid
+ pt = psutil.Process(tid)
+ pt.as_dict()
+ self.assertNotIn(tid, psutil.pids())
+ finally:
+ t.stop()
+
# =====================================================================
# test process
@@ -1003,49 +1038,6 @@ class TestProcess(unittest.TestCase):
tearDown = setUp
- def test_compare_stat_and_status_files(self):
- # /proc/pid/stat and /proc/pid/status have many values in common.
- # Whenever possible, psutil uses /proc/pid/stat (it's faster).
- # For all those cases we check that the value found in
- # /proc/pid/stat (by psutil) matches the one found in
- # /proc/pid/status.
- p = psutil.Process()
- with psutil._psplatform.open_text('/proc/%s/status' % p.pid) as f:
- for line in f:
- line = line.strip()
- if line.startswith('Name:'):
- name = line.split()[1]
- # Name is truncated to 15 chars
- self.assertEqual(p.name()[:15], name[:15])
- elif line.startswith('State:'):
- status = line[line.find('(') + 1:line.rfind(')')]
- status = status.replace(' ', '-')
- self.assertEqual(p.status(), status)
- elif line.startswith('PPid:'):
- ppid = int(line.split()[1])
- self.assertEqual(p.ppid(), ppid)
- # The ones below internally are determined by reading
- # 'status' file but we use a re to extract the info
- # so it makes sense to check them.
- elif line.startswith('Threads:'):
- num_threads = int(line.split()[1])
- self.assertEqual(p.num_threads(), num_threads)
- elif line.startswith('Uid:'):
- uids = tuple(map(int, line.split()[1:4]))
- self.assertEqual(tuple(p.uids()), uids)
- elif line.startswith('Gid:'):
- gids = tuple(map(int, line.split()[1:4]))
- self.assertEqual(tuple(p.gids()), gids)
- elif line.startswith('voluntary_ctxt_switches:'):
- vol = int(line.split()[1])
- self.assertAlmostEqual(
- p.num_ctx_switches().voluntary, vol, delta=2)
- elif line.startswith('nonvoluntary_ctxt_switches:'):
- invol = int(line.split()[1])
- self.assertAlmostEqual(
- p.num_ctx_switches().involuntary, invol,
- delta=2)
-
def test_memory_full_info(self):
src = textwrap.dedent("""
import time
@@ -1217,5 +1209,74 @@ class TestProcess(unittest.TestCase):
self.assertRaises(psutil.ZombieProcess, psutil.Process().exe)
+@unittest.skipUnless(LINUX, "LINUX only")
+class TestProcessAgainstStatus(unittest.TestCase):
+ """/proc/pid/stat and /proc/pid/status have many values in common.
+ Whenever possible, psutil uses /proc/pid/stat (it's faster).
+ For all those cases we check that the value found in
+ /proc/pid/stat (by psutil) matches the one found in
+ /proc/pid/status.
+ """
+
+ @classmethod
+ def setUpClass(cls):
+ cls.proc = psutil.Process()
+
+ def read_status_file(self, linestart):
+ with psutil._psplatform.open_text(
+ '/proc/%s/status' % self.proc.pid) as f:
+ for line in f:
+ line = line.strip()
+ if line.startswith(linestart):
+ value = line.partition('\t')[2]
+ try:
+ return int(value)
+ except ValueError:
+ return value
+ else:
+ raise ValueError("can't find %r" % linestart)
+
+ def test_name(self):
+ value = self.read_status_file("Name:")
+ self.assertEqual(self.proc.name(), value)
+
+ def test_status(self):
+ value = self.read_status_file("State:")
+ value = value[value.find('(') + 1:value.rfind(')')]
+ value = value.replace(' ', '-')
+ self.assertEqual(self.proc.status(), value)
+
+ def test_ppid(self):
+ value = self.read_status_file("PPid:")
+ self.assertEqual(self.proc.ppid(), value)
+
+ def test_num_threads(self):
+ value = self.read_status_file("Threads:")
+ self.assertEqual(self.proc.num_threads(), value)
+
+ def test_uids(self):
+ value = self.read_status_file("Uid:")
+ value = tuple(map(int, value.split()[1:4]))
+ self.assertEqual(self.proc.uids(), value)
+
+ def test_gids(self):
+ value = self.read_status_file("Gid:")
+ value = tuple(map(int, value.split()[1:4]))
+ self.assertEqual(self.proc.gids(), value)
+
+ @retry_before_failing()
+ def test_num_ctx_switches(self):
+ value = self.read_status_file("voluntary_ctxt_switches:")
+ self.assertEqual(self.proc.num_ctx_switches().voluntary, value)
+ value = self.read_status_file("nonvoluntary_ctxt_switches:")
+ self.assertEqual(self.proc.num_ctx_switches().involuntary, value)
+
+ def test_cpu_affinity(self):
+ value = self.read_status_file("Cpus_allowed_list:")
+ min_, max_ = map(int, value.split('-'))
+ self.assertEqual(
+ self.proc.cpu_affinity(), list(range(min_, max_ + 1)))
+
+
if __name__ == '__main__':
run_test_module_by_name(__file__)
diff --git a/psutil/tests/test_memory_leaks.py b/psutil/tests/test_memory_leaks.py
index 46186e41..f1a951f0 100755
--- a/psutil/tests/test_memory_leaks.py
+++ b/psutil/tests/test_memory_leaks.py
@@ -458,6 +458,11 @@ class TestModuleFunctionsLeaks(TestMemLeak):
def test_cpu_stats(self):
self.execute(psutil.cpu_stats)
+ @skip_if_linux()
+ @unittest.skipUnless(hasattr(psutil, "cpu_freq"), "platform not supported")
+ def test_cpu_freq(self):
+ self.execute(psutil.cpu_freq)
+
# --- mem
def test_virtual_memory(self):
diff --git a/psutil/tests/test_osx.py b/psutil/tests/test_osx.py
index 7b61bc74..6e7a5891 100755
--- a/psutil/tests/test_osx.py
+++ b/psutil/tests/test_osx.py
@@ -111,6 +111,8 @@ class TestProcess(unittest.TestCase):
@unittest.skipUnless(OSX, "OSX only")
class TestSystemAPIs(unittest.TestCase):
+ # --- disk
+
def test_disks(self):
# test psutil.disk_usage() and psutil.disk_partitions()
# against "df -a"
@@ -138,6 +140,8 @@ class TestSystemAPIs(unittest.TestCase):
if abs(usage.used - used) > 10 * 1024 * 1024:
self.fail("psutil=%s, df=%s" % usage.used, used)
+ # --- cpu
+
def test_cpu_count_logical(self):
num = sysctl("sysctl hw.logicalcpu")
self.assertEqual(num, psutil.cpu_count(logical=True))
@@ -146,6 +150,15 @@ class TestSystemAPIs(unittest.TestCase):
num = sysctl("sysctl hw.physicalcpu")
self.assertEqual(num, psutil.cpu_count(logical=False))
+ def test_cpu_freq(self):
+ freq = psutil.cpu_freq()[0]
+ self.assertEqual(
+ freq.current * 1000 * 1000, sysctl("sysctl hw.cpufrequency"))
+ self.assertEqual(
+ freq.min * 1000 * 1000, sysctl("sysctl hw.cpufrequency_min"))
+ self.assertEqual(
+ freq.max * 1000 * 1000, sysctl("sysctl hw.cpufrequency_max"))
+
# --- virtual mem
def test_vmem_total(self):
@@ -206,6 +219,8 @@ class TestSystemAPIs(unittest.TestCase):
# self.assertEqual(psutil_smem.used, human2bytes(used))
# self.assertEqual(psutil_smem.free, human2bytes(free))
+ # --- network
+
def test_net_if_stats(self):
for name, stats in psutil.net_if_stats().items():
try:
diff --git a/psutil/tests/test_process.py b/psutil/tests/test_process.py
index 62fa36ff..74750473 100755
--- a/psutil/tests/test_process.py
+++ b/psutil/tests/test_process.py
@@ -312,7 +312,7 @@ class TestProcess(unittest.TestCase):
@unittest.skipIf(TRAVIS, 'not reliable on TRAVIS')
def test_terminal(self):
terminal = psutil.Process().terminal()
- if sys.stdin.isatty():
+ if sys.stdin.isatty() or sys.stdout.isatty():
tty = os.path.realpath(sh('tty'))
self.assertEqual(terminal, tty)
else:
@@ -511,10 +511,8 @@ class TestProcess(unittest.TestCase):
try:
step2 = p.num_threads()
self.assertEqual(step2, step1 + 1)
- thread.stop()
finally:
- if thread._running:
- thread.stop()
+ thread.stop()
@unittest.skipUnless(WINDOWS, 'WINDOWS only')
def test_num_handles(self):
@@ -534,7 +532,6 @@ class TestProcess(unittest.TestCase):
thread = ThreadTask()
thread.start()
-
try:
step2 = p.threads()
self.assertEqual(len(step2), len(step1) + 1)
@@ -546,11 +543,8 @@ class TestProcess(unittest.TestCase):
self.assertEqual(athread.id, athread[0])
self.assertEqual(athread.user_time, athread[1])
self.assertEqual(athread.system_time, athread[2])
- # test num threads
- thread.stop()
finally:
- if thread._running:
- thread.stop()
+ thread.stop()
@retry_before_failing()
# see: https://travis-ci.org/giampaolo/psutil/jobs/111842553
@@ -855,6 +849,7 @@ class TestProcess(unittest.TestCase):
def test_cpu_affinity(self):
p = psutil.Process()
initial = p.cpu_affinity()
+ self.addCleanup(p.cpu_affinity, initial)
if hasattr(os, "sched_getaffinity"):
self.assertEqual(initial, list(os.sched_getaffinity(p.pid)))
self.assertEqual(len(initial), len(set(initial)))
diff --git a/psutil/tests/test_system.py b/psutil/tests/test_system.py
index e2220be4..4cbdb056 100755
--- a/psutil/tests/test_system.py
+++ b/psutil/tests/test_system.py
@@ -697,6 +697,25 @@ class TestSystemAPIs(unittest.TestCase):
if name in ('ctx_switches', 'interrupts'):
self.assertGreater(value, 0)
+ @unittest.skipUnless(hasattr(psutil, "cpu_freq"),
+ "platform not suported")
+ def test_cpu_freq(self):
+ def check_ls(ls):
+ for nt in ls:
+ self.assertLessEqual(nt.current, nt.max)
+ for name in nt._fields:
+ value = getattr(nt, name)
+ self.assertGreaterEqual(value, 0)
+
+ ls = psutil.cpu_freq(percpu=True)
+ if not TRAVIS:
+ assert ls, ls
+
+ check_ls([psutil.cpu_freq(percpu=False)])
+
+ if LINUX:
+ self.assertEqual(len(ls), psutil.cpu_count())
+
def test_os_constants(self):
names = ["POSIX", "WINDOWS", "LINUX", "OSX", "FREEBSD", "OPENBSD",
"NETBSD", "BSD", "SUNOS"]
diff --git a/psutil/tests/test_windows.py b/psutil/tests/test_windows.py
index 802242b5..07f1d796 100755
--- a/psutil/tests/test_windows.py
+++ b/psutil/tests/test_windows.py
@@ -85,6 +85,12 @@ class TestSystemAPIs(unittest.TestCase):
num_cpus = int(os.environ['NUMBER_OF_PROCESSORS'])
self.assertEqual(num_cpus, psutil.cpu_count())
+ def test_cpu_freq(self):
+ w = wmi.WMI()
+ proc = w.Win32_Processor()[0]
+ self.assertEqual(proc.CurrentClockSpeed, psutil.cpu_freq().current)
+ self.assertEqual(proc.MaxClockSpeed, psutil.cpu_freq().max)
+
def test_total_phymem(self):
w = wmi.WMI().Win32_ComputerSystem()[0]
self.assertEqual(int(w.TotalPhysicalMemory),
diff --git a/scripts/internal/winmake.py b/scripts/internal/winmake.py
index bbe73e0d..8ce51ed0 100755
--- a/scripts/internal/winmake.py
+++ b/scripts/internal/winmake.py
@@ -171,6 +171,20 @@ def build():
@cmd
+def build_exe():
+ """Create exe file."""
+ build()
+ sh("%s setup.py bdist_wininst" % PYTHON)
+
+
+@cmd
+def build_wheel():
+ """Create wheel file."""
+ build()
+ sh("%s setup.py bdist_wheel" % PYTHON)
+
+
+@cmd
def install_pip():
"""Install pip"""
try:
@@ -211,11 +225,12 @@ def install():
@cmd
def uninstall():
"""Uninstall psutil"""
- clean()
try:
import psutil
except ImportError:
+ clean()
return
+ clean()
install_pip()
sh("%s -m pip uninstall -y psutil" % PYTHON)
@@ -230,6 +245,7 @@ def uninstall():
try:
import psutil # NOQA
except ImportError:
+ clean()
return
sh("%s -m pip uninstall -y psutil" % PYTHON)
finally:
diff --git a/setup.py b/setup.py
index 938cfef9..01543bee 100755
--- a/setup.py
+++ b/setup.py
@@ -85,18 +85,6 @@ def silenced_output(stream_name):
VERSION = get_version()
macros.append(('PSUTIL_VERSION', int(VERSION.replace('.', ''))))
-
-# POSIX
-if POSIX:
- posix_extension = Extension(
- 'psutil._psutil_posix',
- sources=['psutil/_psutil_posix.c'])
- if SUNOS:
- posix_extension.libraries.append('socket')
- if platform.release() == '5.10':
- posix_extension.sources.append('psutil/arch/solaris/v10/ifaddrs.c')
- posix_extension.define_macros.append(('PSUTIL_SUNOS10', 1))
-
# Windows
if WINDOWS:
def get_winver():
@@ -134,12 +122,11 @@ if WINDOWS:
define_macros=macros,
libraries=[
"psapi", "kernel32", "advapi32", "shell32", "netapi32",
- "iphlpapi", "wtsapi32", "ws2_32",
+ "iphlpapi", "wtsapi32", "ws2_32", "PowrProf",
],
# extra_compile_args=["/Z7"],
# extra_link_args=["/DEBUG"]
)
- extensions = [ext]
# OS X
elif OSX:
@@ -155,7 +142,6 @@ elif OSX:
extra_link_args=[
'-framework', 'CoreFoundation', '-framework', 'IOKit'
])
- extensions = [ext, posix_extension]
# FreeBSD
elif FREEBSD:
@@ -170,7 +156,6 @@ elif FREEBSD:
],
define_macros=macros,
libraries=["devstat"])
- extensions = [ext, posix_extension]
# OpenBSD
elif OPENBSD:
@@ -184,7 +169,6 @@ elif OPENBSD:
],
define_macros=macros,
libraries=["kvm"])
- extensions = [ext, posix_extension]
# NetBSD
elif NETBSD:
@@ -199,7 +183,6 @@ elif NETBSD:
],
define_macros=macros,
libraries=["kvm"])
- extensions = [ext, posix_extension]
# Linux
elif LINUX:
@@ -229,15 +212,15 @@ elif LINUX:
else:
return None
- macros.append(("PSUTIL_LINUX", 1))
ETHTOOL_MACRO = get_ethtool_macro()
+
+ macros.append(("PSUTIL_LINUX", 1))
if ETHTOOL_MACRO is not None:
macros.append(ETHTOOL_MACRO)
ext = Extension(
'psutil._psutil_linux',
sources=['psutil/_psutil_linux.c'],
define_macros=macros)
- extensions = [ext, posix_extension]
# Solaris
elif SUNOS:
@@ -247,17 +230,32 @@ elif SUNOS:
sources=['psutil/_psutil_sunos.c'],
define_macros=macros,
libraries=['kstat', 'nsl', 'socket'])
- extensions = [ext, posix_extension]
else:
sys.exit('platform %s is not supported' % sys.platform)
+# POSIX
+if POSIX:
+ posix_extension = Extension(
+ 'psutil._psutil_posix',
+ define_macros=macros,
+ sources=['psutil/_psutil_posix.c'])
+ if SUNOS:
+ posix_extension.libraries.append('socket')
+ if platform.release() == '5.10':
+ posix_extension.sources.append('psutil/arch/solaris/v10/ifaddrs.c')
+ posix_extension.define_macros.append(('PSUTIL_SUNOS10', 1))
+
+ extensions = [ext, posix_extension]
+else:
+ extensions = [ext]
+
def main():
- setup_args = dict(
+ setup(
name='psutil',
version=VERSION,
- description=__doc__.replace('\n', '').strip(),
+ description=__doc__ .replace('\n', '').strip() if __doc__ else '',
long_description=get_description(),
keywords=[
'ps', 'top', 'kill', 'free', 'lsof', 'netstat', 'nice', 'tty',
@@ -271,6 +269,7 @@ def main():
platforms='Platform Independent',
license='BSD',
packages=['psutil', 'psutil.tests'],
+ ext_modules=extensions,
# see: python setup.py register --list-classifiers
classifiers=[
'Development Status :: 5 - Production/Stable',
@@ -302,6 +301,7 @@ def main():
'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
+ 'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: Implementation :: CPython',
'Programming Language :: Python :: Implementation :: PyPy',
'Programming Language :: Python',
@@ -317,9 +317,6 @@ def main():
'Topic :: Utilities',
],
)
- if extensions is not None:
- setup_args["ext_modules"] = extensions
- setup(**setup_args)
if __name__ == '__main__':