Repository: giampaolo/psutil
Pull request #1565 (2019-08-15 16:34:32)

add PEP 517/8 build backend and requirements specification
👍 


Patch:
diff --git a/.github/ISSUE_TEMPLATE/bug.md b/.github/ISSUE_TEMPLATE/bug.md
index 283d8dc6..ba4a026c 100644
--- a/.github/ISSUE_TEMPLATE/bug.md
+++ b/.github/ISSUE_TEMPLATE/bug.md
@@ -3,7 +3,6 @@ name: Bug
 about: Report a bug
 title: "[OS] title"
 labels: 'bug'
-assignees: 'giampaolo'
 
 ---
 **Platform**
diff --git a/.github/ISSUE_TEMPLATE/enhancement.md b/.github/ISSUE_TEMPLATE/enhancement.md
index 1a5e14e5..7e7159f2 100644
--- a/.github/ISSUE_TEMPLATE/enhancement.md
+++ b/.github/ISSUE_TEMPLATE/enhancement.md
@@ -2,7 +2,6 @@
 name: Enhancement
 about: Propose an enhancement
 labels: 'enhancement'
-assignees: 'giampaolo'
 title: "[OS] title"
 
 ---
diff --git a/CREDITS b/CREDITS
index 3b1de50d..9a70238e 100644
--- a/CREDITS
+++ b/CREDITS
@@ -622,3 +622,11 @@ N: Kamil Rytarowski
 W: https://github.com/krytarowski
 C: Poland
 I: 1526, 1530
+
+N: Athos Ribeiro
+W: https://github.com/athos-ribeiro
+I: 1585
+
+N: Erwan Le Pape
+W: https://github.com/erwan-le-pape
+I: 1570
diff --git a/HISTORY.rst b/HISTORY.rst
index 1f83b02c..35ae6a18 100644
--- a/HISTORY.rst
+++ b/HISTORY.rst
@@ -5,14 +5,29 @@
 
 XXXX-XX-XX
 
+**Enhancements**
+
+- 1527_: [Linux] added Process.cpu_times().iowait counter, which is the time
+  spent waiting for blocking I/O to complete.
+
 **Bug fixes**
 
+- 875_: [Windows] Process' cmdline(), environ() or cwd() may occasionally fail
+  with ERROR_PARTIAL_COPY which now gets translated to AccessDenied.
+- 1126_: [Linux] cpu_affinity() segfaults on CentOS 5 / manylinux.
+  cpu_affinity() support for CentOS 5 was removed.
 - 1528_: [AIX] compilation error on AIX 7.2 due to 32 vs 64 bit differences.
   (patch by Arnon Yaari)
 - 1535_: 'type' and 'family' fields returned by net_connections() are not
   always turned into enums.
 - 1536_: [NetBSD] process cmdline() erroneously raise ZombieProcess error if
   cmdline has non encodable chars.
+- 1546_: usage percent may be rounded to 0 on Python 2.
+- 1552_: [Windows] getloadavg() math for calculating 5 and 15 mins values is
+  incorrect.
+- 1570_: [Windows] NtWow64* syscalls fail to raise the proper error code
+- 1585_: [OSX] calling close() (in C) on possible negative integers.  (patch
+  by Athos Ribeiro)
 
 5.6.3
 =====
diff --git a/MANIFEST.in b/MANIFEST.in
index 027e4e94..5532ec5d 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -135,3 +135,4 @@ include scripts/who.py
 include scripts/winservices.py
 include setup.py
 include tox.ini
+include pyproject.toml
diff --git a/Makefile b/Makefile
index a3763848..71f93001 100644
--- a/Makefile
+++ b/Makefile
@@ -14,7 +14,7 @@ DEPS = \
 	futures \
 	ipaddress \
 	mock==1.0.1 \
-	perf \
+	pyperf \
 	readline \
 	requests \
 	setuptools \
@@ -55,8 +55,7 @@ clean:  ## Remove all build files.
 		build/ \
 		dist/ \
 		docs/_build/ \
-		htmlcov/ \
-		tmp/
+		htmlcov/
 
 _:
 
@@ -68,13 +67,11 @@ build: _  ## Compile without installing.
 	@# "import psutil" when using the interactive interpreter from within
 	@# this directory.
 	PYTHONWARNINGS=all $(PYTHON) setup.py build_ext -i
-	rm -rf tmp
 	$(PYTHON) -c "import psutil"  # make sure it actually worked
 
 install:  ## Install this package as current user in "edit" mode.
 	${MAKE} build
 	PYTHONWARNINGS=all $(PYTHON) setup.py develop $(INSTALL_OPTS)
-	rm -rf tmp
 
 uninstall:  ## Uninstall this package via pip.
 	cd ..; $(PYTHON) -m pip uninstall -y -v psutil || true
@@ -174,6 +171,9 @@ test-coverage:  ## Run test coverage.
 flake8:  ## flake8 linter.
 	@git ls-files | grep \\.py$ | xargs $(PYTHON) -m flake8
 
+fix-flake8:  ## Attempt to automaticall fix some flake8 issues.
+	@git ls-files | grep \\.py$ | xargs $(PYTHON) -m flake8 --exit-zero | $(PYTHON) scripts/internal/fix_flake8.py
+
 # ===================================================================
 # GIT
 # ===================================================================
diff --git a/README.rst b/README.rst
index 4f1a71c3..44b88e7a 100644
--- a/README.rst
+++ b/README.rst
@@ -121,6 +121,12 @@ Professional support
 
 .. _Tidelift Subscription: https://tidelift.com/subscription/pkg/pypi-psutil?utm_source=pypi-psutil&utm_medium=referral&utm_campaign=readme
 
+Security
+========
+
+To report a security vulnerability, please use the `Tidelift security
+contact`_.  Tidelift will coordinate the fix and disclosure.
+
 Example applications
 ====================
 
@@ -359,7 +365,7 @@ Process management
     pgids(real=1000, effective=1000, saved=1000)
     >>>
     >>> p.cpu_times()
-    pcputimes(user=1.02, system=0.31, children_user=0.32, children_system=0.1)
+    pcputimes(user=1.02, system=0.31, children_user=0.32, children_system=0.1, iowait=0.0)
     >>> p.cpu_percent(interval=1.0)
     12.1
     >>> p.cpu_affinity()
@@ -385,8 +391,8 @@ Process management
     pio(read_count=478001, write_count=59371, read_bytes=700416, write_bytes=69632, read_chars=456232, write_chars=517543)
     >>>
     >>> 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/monit.py', fd=3, position=0, mode='r', flags=32768),
+     popenfile(path='/var/log/monit.log', fd=4, position=235542, mode='a', flags=33793)]
     >>>
     >>> p.connections()
     [pconn(fd=115, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=48776), raddr=addr(ip='93.186.135.91', port=80), status='ESTABLISHED'),
@@ -428,6 +434,7 @@ Process management
     >>> p.resume()
     >>>
     >>> p.terminate()
+    >>> p.kill()
     >>> p.wait(timeout=3)
     0
     >>>
@@ -507,3 +514,4 @@ Windows services
 
 .. _`Giampaolo Rodola`: http://grodola.blogspot.com/p/about.html
 .. _`donation`: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A9ZS7PKKRM3S8
+.. _Tidelift security contact: https://tidelift.com/security
diff --git a/docs/index.rst b/docs/index.rst
index 8c0ee74a..c853abae 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -13,7 +13,7 @@ Quick links
 - `Blog <http://grodola.blogspot.com/search/label/psutil>`__
 - `Forum <http://groups.google.com/group/psutil/topics>`__
 - `Download <https://pypi.org/project/psutil/#files>`__
-- `Development guide <https://github.com/giampaolo/psutil/blob/master/DEVGUIDE.rst>`_
+- `Development guide <https://github.com/giampaolo/psutil/blob/master/docs/DEVGUIDE.rst>`_
 - `What's new <https://github.com/giampaolo/psutil/blob/master/HISTORY.rst>`__
 
 About
@@ -78,7 +78,8 @@ CPU
 
   - **nice** *(UNIX)*: time spent by niced (prioritized) processes executing in
     user mode; on Linux this also includes **guest_nice** time
-  - **iowait** *(Linux)*: time spent waiting for I/O to complete
+  - **iowait** *(Linux)*: time spent waiting for I/O to complete. This is *not*
+    accounted in **idle** time counter.
   - **irq** *(Linux, BSD)*: time spent for servicing hardware interrupts
   - **softirq** *(Linux)*: time spent for servicing software interrupts
   - **steal** *(Linux 2.6.11+)*: time spent by other operating systems running
@@ -241,19 +242,27 @@ CPU
 .. function:: getloadavg()
 
     Return the average system load over the last 1, 5 and 15 minutes as a tuple.
-    The load represents how many processes are waiting to be run by the
-    operating system.
-    On UNIX systems this relies on `os.getloadavg`_. On Windows this is
-    emulated by using a Windows API that spawns a thread which updates the
-    average every 5 seconds, mimicking the UNIX behavior. Thus, the first time
-    this is called and for the next 5 seconds it will return a meaningless
-    ``(0.0, 0.0, 0.0)`` tuple. Example:
+    The load represents the processes which are in a runnable state, either
+    using the CPU or waiting to use the CPU (e.g. waiting for disk I/O).
+    On UNIX systems this relies on `os.getloadavg`_. On Windows this is emulated
+    by using a Windows API that spawns a thread which keeps running in
+    background and updates the load average every 5 seconds, mimicking the UNIX
+    behavior. Thus, the first time this is called and for the next 5 seconds
+    it will return a meaningless ``(0.0, 0.0, 0.0)`` tuple.
+    The numbers returned only make sense if related to the number of CPU cores
+    installed on the system. So, for instance, `3.14` on a system with 10 CPU
+    cores means that the system load was 31.4% percent over the last N minutes.
 
     .. code-block:: python
 
        >>> import psutil
        >>> psutil.getloadavg()
        (3.14, 3.89, 4.67)
+       >>> psutil.cpu_count()
+       10
+       >>> # percentage representation
+       >>> [x / psutil.cpu_count() * 100 for x in psutil.getloadavg()]
+       [31.4, 38.9, 46.7]
 
     Availability: Unix, Windows
 
@@ -1290,13 +1299,15 @@ Process class
     Here's an example on how to set the highest I/O priority depending on what
     platform you're on::
 
-      import psutil
-      p = psutil.Process()
-      if psutil.LINUX
-          p.ionice(psutil.IOPRIO_CLASS_RT, value=7)
-      else:  # Windows
-          p.ionice(psutil.IOPRIO_HIGH)
-      p.ionice()  # get
+      >>> import psutil
+      >>> p = psutil.Process()
+      >>> if psutil.LINUX:
+      ...     p.ionice(psutil.IOPRIO_CLASS_RT, value=7)
+      ... else:
+      ...     p.ionice(psutil.IOPRIO_HIGH)
+      ...
+      >>> p.ionice()  # get
+      pionice(ioclass=<IOPriority.IOPRIO_CLASS_RT: 1>, value=7)
 
     Availability: Linux, Windows Vista+
 
@@ -1404,16 +1415,33 @@ Process class
 
   .. method:: cpu_times()
 
-    Return a `(user, system, children_user, children_system)` named tuple
-    representing the accumulated process time, in seconds (see
-    `explanation <http://stackoverflow.com/questions/556405/>`__).
-    On Windows and macOS only *user* and *system* are filled, the others are
-    set to ``0``.
+    Return a named tuple representing the accumulated process times, in seconds
+    (see `explanation <http://stackoverflow.com/questions/556405/>`__).
     This is similar to `os.times`_ but can be used for any process PID.
 
+    - **user**: time spent in user mode.
+    - **system**: time spent in kernel mode.
+    - **children_user**: user time of all child processes (always ``0`` on
+      Windows and macOS).
+    - **system_user**: user time of all child processes (always ``0`` on
+      Windows and macOS).
+    - **iowait**: (Linux) time spent waiting for blocking I/O to complete.
+      This value is excluded from `user` and `system` times count (because the
+      CPU is not doing any work).
+
+    >>> import psutil
+    >>> p = psutil.Process()
+    >>> p.cpu_times()
+    pcputimes(user=0.03, system=0.67, children_user=0.0, children_system=0.0, iowait=0.08)
+    >>> sum(p.cpu_times()[:2])  # cumulative, excluding children and iowait
+    0.70
+
     .. versionchanged::
       4.1.0 return two extra fields: *children_user* and *children_system*.
 
+    .. versionchanged::
+      5.6.4 added *iowait* on Linux.
+
   .. method:: cpu_percent(interval=None)
 
     Return a float representing the process CPU utilization as a percentage
@@ -2193,7 +2221,7 @@ Process priority constants
 .. data:: IOPRIO_NORMAL
 .. data:: IOPRIO_HIGH
 
-  A set of integers representing the I/O priority of a process on Linux.
+  A set of integers representing the I/O priority of a process on Windows.
   They can be used in conjunction with :meth:`psutil.Process.ionice()` to get
   or set process I/O priority.
 
@@ -2427,7 +2455,7 @@ resources.
       if alive:
           # send SIGKILL
           for p in alive:
-              print("process {} survived SIGTERM; trying SIGKILL" % p)
+              print("process {} survived SIGTERM; trying SIGKILL".format(p))
               try:
                   p.kill()
               except psutil.NoSuchProcess:
@@ -2436,7 +2464,7 @@ resources.
           if alive:
               # give up
               for p in alive:
-                  print("process {} survived SIGKILL; giving up" % p)
+                  print("process {} survived SIGKILL; giving up".format(p))
 
 Filtering and sorting processes
 -------------------------------
@@ -2580,7 +2608,7 @@ FAQs
   especially on macOS (see `issue #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
+  On Unix you may run 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
@@ -2910,7 +2938,7 @@ Timeline
 .. _`BPO-6973`: https://bugs.python.org/issue6973
 .. _`CPU affinity`: https://www.linuxjournal.com/article/6799?page=0,0
 .. _`cpu_distribution.py`: https://github.com/giampaolo/psutil/blob/master/scripts/cpu_distribution.py
-.. _`development guide`: https://github.com/giampaolo/psutil/blob/master/DEVGUIDE.rst
+.. _`development guide`: https://github.com/giampaolo/psutil/blob/master/docs/DEVGUIDE.rst
 .. _`disk_usage.py`: https://github.com/giampaolo/psutil/blob/master/scripts/disk_usage.py
 .. _`enums`: https://docs.python.org/3/library/enum.html#module-enum
 .. _`fans.py`: https://github.com/giampaolo/psutil/blob/master/scripts/fans.py
@@ -2927,7 +2955,7 @@ Timeline
 .. _`issue #883`: https://github.com/giampaolo/psutil/issues/883
 .. _`man prlimit`: https://linux.die.net/man/2/prlimit
 .. _`meminfo.py`: https://github.com/giampaolo/psutil/blob/master/scripts/meminfo.py
-.. _`netstat.py`: https://github.com/giampaolo/psutil/blob/master/scripts/netstat.py.
+.. _`netstat.py`: https://github.com/giampaolo/psutil/blob/master/scripts/netstat.py
 .. _`nettop.py`: https://github.com/giampaolo/psutil/blob/master/scripts/nettop.py
 .. _`open`: https://docs.python.org/3/library/functions.html#open
 .. _`os.cpu_count`: https://docs.python.org/3/library/os.html#os.cpu_count
diff --git a/make.bat b/make.bat
index d47eaecc..ae897aa5 100644
--- a/make.bat
+++ b/make.bat
@@ -20,8 +20,8 @@ rem      set PYTHON=C:\Python34\python.exe & set TSCRIPT=foo.py & make.bat test
 rem ==========================================================================
 
 if "%PYTHON%" == "" (
-    if exist "C:\Python37\python.exe" (
-        set PYTHON=C:\Python37\python.exe
+    if exist "C:\Python38-64\python.exe" (
+        set PYTHON=C:\Python38-64\python.exe
     ) else (
         set PYTHON=C:\Python27\python.exe
     )
diff --git a/psutil/_common.py b/psutil/_common.py
index 4a006c1d..126d9d6f 100644
--- a/psutil/_common.py
+++ b/psutil/_common.py
@@ -266,12 +266,12 @@ if AF_UNIX is not None:
 def usage_percent(used, total, round_=None):
     """Calculate percentage usage of 'used' against 'total'."""
     try:
-        ret = (used / total) * 100
+        ret = (float(used) / total) * 100
     except ZeroDivisionError:
-        ret = 0.0 if isinstance(used, float) or isinstance(total, float) else 0
-    if round_ is not None:
-        return round(ret, round_)
+        return 0.0
     else:
+        if round_ is not None:
+            ret = round(ret, round_)
         return ret
 
 
diff --git a/psutil/_pslinux.py b/psutil/_pslinux.py
index 7a3a164b..d29ccc85 100644
--- a/psutil/_pslinux.py
+++ b/psutil/_pslinux.py
@@ -73,6 +73,7 @@ POWER_SUPPLY_PATH = "/sys/class/power_supply"
 HAS_SMAPS = os.path.exists('/proc/%s/smaps' % os.getpid())
 HAS_PRLIMIT = hasattr(cext, "linux_prlimit")
 HAS_PROC_IO_PRIORITY = hasattr(cext, "proc_ioprio_get")
+HAS_CPU_AFFINITY = hasattr(cext, "proc_cpu_affinity_get")
 _DEFAULT = object()
 
 # RLIMIT_* constants, not guaranteed to be present on all kernels
@@ -203,6 +204,10 @@ pmmap_ext = namedtuple(
 pio = namedtuple('pio', ['read_count', 'write_count',
                          'read_bytes', 'write_bytes',
                          'read_chars', 'write_chars'])
+# psutil.Process.cpu_times()
+pcputimes = namedtuple('pcputimes',
+                       ['user', 'system', 'children_user', 'children_system',
+                        'iowait'])
 
 
 # =====================================================================
@@ -1571,6 +1576,7 @@ class Process(object):
         ret['children_stime'] = fields[14]
         ret['create_time'] = fields[19]
         ret['cpu_num'] = fields[36]
+        ret['blkio_ticks'] = fields[39]  # aka 'delayacct_blkio_ticks'
 
         return ret
 
@@ -1700,7 +1706,8 @@ class Process(object):
         stime = float(values['stime']) / CLOCK_TICKS
         children_utime = float(values['children_utime']) / CLOCK_TICKS
         children_stime = float(values['children_stime']) / CLOCK_TICKS
-        return _common.pcputimes(utime, stime, children_utime, children_stime)
+        iowait = float(values['blkio_ticks']) / CLOCK_TICKS
+        return pcputimes(utime, stime, children_utime, children_stime, iowait)
 
     @wrap_exceptions
     def cpu_num(self):
@@ -1919,38 +1926,41 @@ class Process(object):
     def nice_set(self, value):
         return cext_posix.setpriority(self.pid, value)
 
-    @wrap_exceptions
-    def cpu_affinity_get(self):
-        return cext.proc_cpu_affinity_get(self.pid)
+    # starting from CentOS 6.
+    if HAS_CPU_AFFINITY:
 
-    def _get_eligible_cpus(
-            self, _re=re.compile(br"Cpus_allowed_list:\t(\d+)-(\d+)")):
-        # See: https://github.com/giampaolo/psutil/issues/956
-        data = self._read_status_file()
-        match = _re.findall(data)
-        if match:
-            return list(range(int(match[0][0]), int(match[0][1]) + 1))
-        else:
-            return list(range(len(per_cpu_times())))
+        @wrap_exceptions
+        def cpu_affinity_get(self):
+            return cext.proc_cpu_affinity_get(self.pid)
+
+        def _get_eligible_cpus(
+                self, _re=re.compile(br"Cpus_allowed_list:\t(\d+)-(\d+)")):
+            # See: https://github.com/giampaolo/psutil/issues/956
+            data = self._read_status_file()
+            match = _re.findall(data)
+            if match:
+                return list(range(int(match[0][0]), int(match[0][1]) + 1))
+            else:
+                return list(range(len(per_cpu_times())))
 
-    @wrap_exceptions
-    def cpu_affinity_set(self, cpus):
-        try:
-            cext.proc_cpu_affinity_set(self.pid, cpus)
-        except (OSError, ValueError) as err:
-            if isinstance(err, ValueError) or err.errno == errno.EINVAL:
-                eligible_cpus = self._get_eligible_cpus()
-                all_cpus = tuple(range(len(per_cpu_times())))
-                for cpu in cpus:
-                    if cpu not in all_cpus:
-                        raise ValueError(
-                            "invalid CPU number %r; choose between %s" % (
-                                cpu, eligible_cpus))
-                    if cpu not in eligible_cpus:
-                        raise ValueError(
-                            "CPU number %r is not eligible; choose "
-                            "between %s" % (cpu, eligible_cpus))
-            raise
+        @wrap_exceptions
+        def cpu_affinity_set(self, cpus):
+            try:
+                cext.proc_cpu_affinity_set(self.pid, cpus)
+            except (OSError, ValueError) as err:
+                if isinstance(err, ValueError) or err.errno == errno.EINVAL:
+                    eligible_cpus = self._get_eligible_cpus()
+                    all_cpus = tuple(range(len(per_cpu_times())))
+                    for cpu in cpus:
+                        if cpu not in all_cpus:
+                            raise ValueError(
+                                "invalid CPU number %r; choose between %s" % (
+                                    cpu, eligible_cpus))
+                        if cpu not in eligible_cpus:
+                            raise ValueError(
+                                "CPU number %r is not eligible; choose "
+                                "between %s" % (cpu, eligible_cpus))
+                raise
 
     # only starting from kernel 2.6.13
     if HAS_PROC_IO_PRIORITY:
diff --git a/psutil/_psutil_bsd.c b/psutil/_psutil_bsd.c
index 74fe5922..b4264ceb 100644
--- a/psutil/_psutil_bsd.c
+++ b/psutil/_psutil_bsd.c
@@ -906,8 +906,7 @@ error:
 /*
  * define the psutil C module methods and initialize the module.
  */
-static PyMethodDef
-PsutilMethods[] = {
+static PyMethodDef mod_methods[] = {
     // --- per-process functions
 
     {"proc_oneshot_info", psutil_proc_oneshot_info, METH_VARARGS,
@@ -994,109 +993,99 @@ PsutilMethods[] = {
     {NULL, NULL, 0, NULL}
 };
 
-struct module_state {
-    PyObject *error;
-};
-
-#if PY_MAJOR_VERSION >= 3
-#define GETSTATE(m) ((struct module_state*)PyModule_GetState(m))
-#else
-#define GETSTATE(m) (&_state)
-#endif
-
 #if PY_MAJOR_VERSION >= 3
-
-static int
-psutil_bsd_traverse(PyObject *m, visitproc visit, void *arg) {
-    Py_VISIT(GETSTATE(m)->error);
-    return 0;
-}
-
-static int
-psutil_bsd_clear(PyObject *m) {
-    Py_CLEAR(GETSTATE(m)->error);
-    return 0;
-}
-
-static struct PyModuleDef
-        moduledef = {
-    PyModuleDef_HEAD_INIT,
-    "psutil_bsd",
-    NULL,
-    sizeof(struct module_state),
-    PsutilMethods,
-    NULL,
-    psutil_bsd_traverse,
-    psutil_bsd_clear,
-    NULL
-};
-
-#define INITERROR return NULL
-
-PyMODINIT_FUNC PyInit__psutil_bsd(void)
-
-#else
-#define INITERROR return
-
-void init_psutil_bsd(void)
-#endif
+    #define INITERR return NULL
+
+    static struct PyModuleDef moduledef = {
+        PyModuleDef_HEAD_INIT,
+        "_psutil_bsd",
+        NULL,
+        -1,
+        mod_methods,
+        NULL,
+        NULL,
+        NULL,
+        NULL
+    };
+
+    PyObject *PyInit__psutil_bsd(void)
+#else  /* PY_MAJOR_VERSION */
+    #define INITERR return
+
+    void init_psutil_bsd(void)
+#endif  /* PY_MAJOR_VERSION */
 {
+    PyObject *v;
 #if PY_MAJOR_VERSION >= 3
-    PyObject *module = PyModule_Create(&moduledef);
+    PyObject *mod = PyModule_Create(&moduledef);
 #else
-    PyObject *module = Py_InitModule("_psutil_bsd", PsutilMethods);
+    PyObject *mod = Py_InitModule("_psutil_bsd", mod_methods);
 #endif
-    PyModule_AddIntConstant(module, "version", PSUTIL_VERSION);
+    if (mod == NULL)
+        INITERR;
+
+    if (PyModule_AddIntConstant(mod, "version", PSUTIL_VERSION)) INITERR;
     // process status constants
 
 #ifdef PSUTIL_FREEBSD
-    PyModule_AddIntConstant(module, "SIDL", SIDL);
-    PyModule_AddIntConstant(module, "SRUN", SRUN);
-    PyModule_AddIntConstant(module, "SSLEEP", SSLEEP);
-    PyModule_AddIntConstant(module, "SSTOP", SSTOP);
-    PyModule_AddIntConstant(module, "SZOMB", SZOMB);
-    PyModule_AddIntConstant(module, "SWAIT", SWAIT);
-    PyModule_AddIntConstant(module, "SLOCK", SLOCK);
+    if (PyModule_AddIntConstant(mod, "SIDL", SIDL)) INITERR;
+    if (PyModule_AddIntConstant(mod, "SRUN", SRUN)) INITERR;
+    if (PyModule_AddIntConstant(mod, "SSLEEP", SSLEEP)) INITERR;
+    if (PyModule_AddIntConstant(mod, "SSTOP", SSTOP)) INITERR;
+    if (PyModule_AddIntConstant(mod, "SZOMB", SZOMB)) INITERR;
+    if (PyModule_AddIntConstant(mod, "SWAIT", SWAIT)) INITERR;
+    if (PyModule_AddIntConstant(mod, "SLOCK", SLOCK)) INITERR;
 #elif  PSUTIL_OPENBSD
-    PyModule_AddIntConstant(module, "SIDL", SIDL);
-    PyModule_AddIntConstant(module, "SRUN", SRUN);
-    PyModule_AddIntConstant(module, "SSLEEP", SSLEEP);
-    PyModule_AddIntConstant(module, "SSTOP", SSTOP);
-    PyModule_AddIntConstant(module, "SZOMB", SZOMB);  // unused
-    PyModule_AddIntConstant(module, "SDEAD", SDEAD);
-    PyModule_AddIntConstant(module, "SONPROC", SONPROC);
+    if (PyModule_AddIntConstant(mod, "SIDL", SIDL)) INITERR;
+    if (PyModule_AddIntConstant(mod, "SRUN", SRUN)) INITERR;
+    if (PyModule_AddIntConstant(mod, "SSLEEP", SSLEEP)) INITERR;
+    if (PyModule_AddIntConstant(mod, "SSTOP", SSTOP)) INITERR;
+    if (PyModule_AddIntConstant(mod, "SZOMB", SZOMB); INITERR; // unused
+    if (PyModule_AddIntConstant(mod, "SDEAD", SDEAD)) INITERR;
+    if (PyModule_AddIntConstant(mod, "SONPROC", SONPROC)) INITERR;
 #elif defined(PSUTIL_NETBSD)
-    PyModule_AddIntConstant(module, "SIDL", LSIDL);
-    PyModule_AddIntConstant(module, "SRUN", LSRUN);
-    PyModule_AddIntConstant(module, "SSLEEP", LSSLEEP);
-    PyModule_AddIntConstant(module, "SSTOP", LSSTOP);
-    PyModule_AddIntConstant(module, "SZOMB", LSZOMB);
-    PyModule_AddIntConstant(module, "SDEAD", LSDEAD);
-    PyModule_AddIntConstant(module, "SONPROC", LSONPROC);
+    if (PyModule_AddIntConstant(mod, "SIDL", LSIDL)) INITERR;
+    if (PyModule_AddIntConstant(mod, "SRUN", LSRUN)) INITERR;
+    if (PyModule_AddIntConstant(mod, "SSLEEP", LSSLEEP)) INITERR;
+    if (PyModule_AddIntConstant(mod, "SSTOP", LSSTOP)) INITERR;
+    if (PyModule_AddIntConstant(mod, "SZOMB", LSZOMB)) INITERR;
+    if (PyModule_AddIntConstant(mod, "SDEAD", LSDEAD)) INITERR;
+    if (PyModule_AddIntConstant(mod, "SONPROC", LSONPROC)) INITERR;
     // unique to NetBSD
-    PyModule_AddIntConstant(module, "SSUSPENDED", LSSUSPENDED);
+    if (PyModule_AddIntConstant(mod, "SSUSPENDED", LSSUSPENDED)) INITERR;
 #endif
 
     // connection status constants
-    PyModule_AddIntConstant(module, "TCPS_CLOSED", TCPS_CLOSED);
-    PyModule_AddIntConstant(module, "TCPS_CLOSING", TCPS_CLOSING);
-    PyModule_AddIntConstant(module, "TCPS_CLOSE_WAIT", TCPS_CLOSE_WAIT);
-    PyModule_AddIntConstant(module, "TCPS_LISTEN", TCPS_LISTEN);
-    PyModule_AddIntConstant(module, "TCPS_ESTABLISHED", TCPS_ESTABLISHED);
-    PyModule_AddIntConstant(module, "TCPS_SYN_SENT", TCPS_SYN_SENT);
-    PyModule_AddIntConstant(module, "TCPS_SYN_RECEIVED", TCPS_SYN_RECEIVED);
-    PyModule_AddIntConstant(module, "TCPS_FIN_WAIT_1", TCPS_FIN_WAIT_1);
-    PyModule_AddIntConstant(module, "TCPS_FIN_WAIT_2", TCPS_FIN_WAIT_2);
-    PyModule_AddIntConstant(module, "TCPS_LAST_ACK", TCPS_LAST_ACK);
-    PyModule_AddIntConstant(module, "TCPS_TIME_WAIT", TCPS_TIME_WAIT);
+    if (PyModule_AddIntConstant(mod, "TCPS_CLOSED", TCPS_CLOSED))
+        INITERR;
+    if (PyModule_AddIntConstant(mod, "TCPS_CLOSING", TCPS_CLOSING))
+        INITERR;
+    if (PyModule_AddIntConstant(mod, "TCPS_CLOSE_WAIT", TCPS_CLOSE_WAIT))
+        INITERR;
+    if (PyModule_AddIntConstant(mod, "TCPS_LISTEN", TCPS_LISTEN))
+        INITERR;
+    if (PyModule_AddIntConstant(mod, "TCPS_ESTABLISHED", TCPS_ESTABLISHED))
+        INITERR;
+    if (PyModule_AddIntConstant(mod, "TCPS_SYN_SENT", TCPS_SYN_SENT))
+        INITERR;
+    if (PyModule_AddIntConstant(mod, "TCPS_SYN_RECEIVED", TCPS_SYN_RECEIVED))
+        INITERR;
+    if (PyModule_AddIntConstant(mod, "TCPS_FIN_WAIT_1", TCPS_FIN_WAIT_1))
+        INITERR;
+    if (PyModule_AddIntConstant(mod, "TCPS_FIN_WAIT_2", TCPS_FIN_WAIT_2))
+        INITERR;
+    if (PyModule_AddIntConstant(mod, "TCPS_LAST_ACK", TCPS_LAST_ACK))
+        INITERR;
+    if (PyModule_AddIntConstant(mod, "TCPS_TIME_WAIT", TCPS_TIME_WAIT))
+        INITERR;
     // PSUTIL_CONN_NONE
-    PyModule_AddIntConstant(module, "PSUTIL_CONN_NONE", 128);
+    if (PyModule_AddIntConstant(mod, "PSUTIL_CONN_NONE", 128)) INITERR;
 
     psutil_setup();
 
-    if (module == NULL)
-        INITERROR;
+    if (mod == NULL)
+        INITERR;
 #if PY_MAJOR_VERSION >= 3
-    return module;
+    return mod;
 #endif
 }
diff --git a/psutil/_psutil_linux.c b/psutil/_psutil_linux.c
index 4bf53b85..717723d0 100644
--- a/psutil/_psutil_linux.c
+++ b/psutil/_psutil_linux.c
@@ -54,6 +54,11 @@ static const int NCPUS_START = sizeof(unsigned long) * CHAR_BIT;
     #include <sys/resource.h>
 #endif
 
+// Should exist starting from CentOS 6 (year 2011).
+#ifdef CPU_ALLOC
+    #define PSUTIL_HAVE_CPU_AFFINITY
+#endif
+
 #include "_psutil_common.h"
 #include "_psutil_posix.h"
 
@@ -279,11 +284,8 @@ psutil_linux_sysinfo(PyObject *self, PyObject *args) {
 
 /*
  * Return process CPU affinity as a Python list
- * The dual implementation exists because of:
- * https://github.com/giampaolo/psutil/issues/536
  */
-
-#ifdef CPU_ALLOC
+#ifdef PSUTIL_HAVE_CPU_AFFINITY
 
 static PyObject *
 psutil_proc_cpu_affinity_get(PyObject *self, PyObject *args) {
@@ -347,49 +349,7 @@ error:
     Py_XDECREF(py_list);
     return NULL;
 }
-#else
-
-
-/*
- * Alternative implementation in case CPU_ALLOC is not defined.
- */
-static PyObject *
-psutil_proc_cpu_affinity_get(PyObject *self, PyObject *args) {
-    cpu_set_t cpuset;
-    unsigned int len = sizeof(cpu_set_t);
-    long pid;
-    int i;
-    PyObject* py_retlist = NULL;
-    PyObject *py_cpu_num = NULL;
-
-    if (!PyArg_ParseTuple(args, "l", &pid))
-        return NULL;
-	CPU_ZERO(&cpuset);
-    if (sched_getaffinity(pid, len, &cpuset) < 0)
-        return PyErr_SetFromErrno(PyExc_OSError);
-
-    py_retlist = PyList_New(0);
-    if (py_retlist == NULL)
-        goto error;
-    for (i = 0; i < CPU_SETSIZE; ++i) {
-        if (CPU_ISSET(i, &cpuset)) {
-            py_cpu_num = Py_BuildValue("i", i);
-            if (py_cpu_num == NULL)
-                goto error;
-            if (PyList_Append(py_retlist, py_cpu_num))
-                goto error;
-            Py_DECREF(py_cpu_num);
-        }
-    }
-
-    return py_retlist;
 
-error:
-    Py_XDECREF(py_cpu_num);
-    Py_XDECREF(py_retlist);
-    return NULL;
-}
-#endif
 
 /*
  * Set process CPU affinity; expects a bitmask
@@ -432,7 +392,6 @@ psutil_proc_cpu_affinity_set(PyObject *self, PyObject *args) {
         CPU_SET(value, &cpu_set);
     }
 
-
     len = sizeof(cpu_set);
     if (sched_setaffinity(pid, len, &cpu_set)) {
         PyErr_SetFromErrno(PyExc_OSError);
@@ -447,6 +406,7 @@ error:
         Py_DECREF(py_cpu_seq);
     return NULL;
 }
+#endif  /* PSUTIL_HAVE_CPU_AFFINITY */
 
 
 /*
@@ -577,22 +537,24 @@ error:
 
 
 /*
- * Define the psutil C module methods and initialize the module.
+ * Module init.
  */
-static PyMethodDef
-PsutilMethods[] = {
+
+static PyMethodDef mod_methods[] = {
     // --- per-process functions
 
-#if PSUTIL_HAVE_IOPRIO
+#ifdef PSUTIL_HAVE_IOPRIO
     {"proc_ioprio_get", psutil_proc_ioprio_get, METH_VARARGS,
      "Get process I/O priority"},
     {"proc_ioprio_set", psutil_proc_ioprio_set, METH_VARARGS,
      "Set process I/O priority"},
 #endif
+#ifdef PSUTIL_HAVE_CPU_AFFINITY
     {"proc_cpu_affinity_get", psutil_proc_cpu_affinity_get, METH_VARARGS,
      "Return process CPU affinity as a Python long (the bitmask)."},
     {"proc_cpu_affinity_set", psutil_proc_cpu_affinity_set, METH_VARARGS,
      "Set process CPU affinity; expects a bitmask."},
+#endif
 
     // --- system related functions
 
@@ -612,7 +574,6 @@ PsutilMethods[] = {
     {"linux_prlimit", psutil_linux_prlimit, METH_VARARGS,
      "Get or set process resource limits."},
 #endif
-
     // --- others
     {"set_testing", psutil_set_testing, METH_NOARGS,
      "Set psutil in testing mode"},
@@ -620,75 +581,51 @@ PsutilMethods[] = {
     {NULL, NULL, 0, NULL}
 };
 
-struct module_state {
-    PyObject *error;
-};
-
-#if PY_MAJOR_VERSION >= 3
-#define GETSTATE(m) ((struct module_state*)PyModule_GetState(m))
-#else
-#define GETSTATE(m) (&_state)
-#endif
 
 #if PY_MAJOR_VERSION >= 3
-
-static int
-psutil_linux_traverse(PyObject *m, visitproc visit, void *arg) {
-    Py_VISIT(GETSTATE(m)->error);
-    return 0;
-}
-
-static int
-psutil_linux_clear(PyObject *m) {
-    Py_CLEAR(GETSTATE(m)->error);
-    return 0;
-}
-
-static struct PyModuleDef
-        moduledef = {
-    PyModuleDef_HEAD_INIT,
-    "psutil_linux",
-    NULL,
-    sizeof(struct module_state),
-    PsutilMethods,
-    NULL,
-    psutil_linux_traverse,
-    psutil_linux_clear,
-    NULL
-};
-
-#define INITERROR return NULL
-
-PyMODINIT_FUNC PyInit__psutil_linux(void)
-
-#else
-#define INITERROR return
-
-void init_psutil_linux(void)
-#endif
+    #define INITERR return NULL
+
+    static struct PyModuleDef moduledef = {
+        PyModuleDef_HEAD_INIT,
+        "_psutil_linux",
+        NULL,
+        -1,
+        mod_methods,
+        NULL,
+        NULL,
+        NULL,
+        NULL
+    };
+
+    PyObject *PyInit__psutil_linux(void)
+#else  /* PY_MAJOR_VERSION */
+    #define INITERR return
+
+    void init_psutil_linux(void)
+#endif  /* PY_MAJOR_VERSION */
 {
     PyObject *v;
 #if PY_MAJOR_VERSION >= 3
-    PyObject *module = PyModule_Create(&moduledef);
+    PyObject *mod = PyModule_Create(&moduledef);
 #else
-    PyObject *module = Py_InitModule("_psutil_linux", PsutilMethods);
+    PyObject *mod = Py_InitModule("_psutil_linux", mod_methods);
 #endif
-    if (module == NULL)
-        INITERROR;
+    if (mod == NULL)
+        INITERR;
 
-    PyModule_AddIntConstant(module, "version", PSUTIL_VERSION);
+    if (PyModule_AddIntConstant(mod, "version", PSUTIL_VERSION)) INITERR;
 #if PSUTIL_HAVE_PRLIMIT
-    PyModule_AddIntConstant(module, "RLIMIT_AS", RLIMIT_AS);
-    PyModule_AddIntConstant(module, "RLIMIT_CORE", RLIMIT_CORE);
-    PyModule_AddIntConstant(module, "RLIMIT_CPU", RLIMIT_CPU);
-    PyModule_AddIntConstant(module, "RLIMIT_DATA", RLIMIT_DATA);
-    PyModule_AddIntConstant(module, "RLIMIT_FSIZE", RLIMIT_FSIZE);
-    PyModule_AddIntConstant(module, "RLIMIT_LOCKS", RLIMIT_LOCKS);
-    PyModule_AddIntConstant(module, "RLIMIT_MEMLOCK", RLIMIT_MEMLOCK);
-    PyModule_AddIntConstant(module, "RLIMIT_NOFILE", RLIMIT_NOFILE);
-    PyModule_AddIntConstant(module, "RLIMIT_NPROC", RLIMIT_NPROC);
-    PyModule_AddIntConstant(module, "RLIMIT_RSS", RLIMIT_RSS);
-    PyModule_AddIntConstant(module, "RLIMIT_STACK", RLIMIT_STACK);
+    if (PyModule_AddIntConstant(mod, "RLIMIT_AS", RLIMIT_AS)) INITERR;
+    if (PyModule_AddIntConstant(mod, "RLIMIT_CORE", RLIMIT_CORE)) INITERR;
+    if (PyModule_AddIntConstant(mod, "RLIMIT_CPU", RLIMIT_CPU)) INITERR;
+    if (PyModule_AddIntConstant(mod, "RLIMIT_DATA", RLIMIT_DATA)) INITERR;
+    if (PyModule_AddIntConstant(mod, "RLIMIT_FSIZE", RLIMIT_FSIZE)) INITERR;
+    if (PyModule_AddIntConstant(mod, "RLIMIT_LOCKS", RLIMIT_LOCKS)) INITERR;
+    if (PyModule_AddIntConstant(mod, "RLIMIT_MEMLOCK", RLIMIT_MEMLOCK)) INITERR;
+    if (PyModule_AddIntConstant(mod, "RLIMIT_NOFILE", RLIMIT_NOFILE)) INITERR;
+    if (PyModule_AddIntConstant(mod, "RLIMIT_NPROC", RLIMIT_NPROC)) INITERR;
+    if (PyModule_AddIntConstant(mod, "RLIMIT_RSS", RLIMIT_RSS)) INITERR;
+    if (PyModule_AddIntConstant(mod, "RLIMIT_STACK", RLIMIT_STACK)) INITERR;
 
 #if defined(HAVE_LONG_LONG)
     if (sizeof(RLIM_INFINITY) > sizeof(long)) {
@@ -699,32 +636,33 @@ void init_psutil_linux(void)
         v = PyLong_FromLong((long) RLIM_INFINITY);
     }
     if (v) {
-        PyModule_AddObject(module, "RLIM_INFINITY", v);
+        PyModule_AddObject(mod, "RLIM_INFINITY", v);
     }
 
 #ifdef RLIMIT_MSGQUEUE
-    PyModule_AddIntConstant(module, "RLIMIT_MSGQUEUE", RLIMIT_MSGQUEUE);
+    if (PyModule_AddIntConstant(mod, "RLIMIT_MSGQUEUE", RLIMIT_MSGQUEUE)) INITERR;
 #endif
 #ifdef RLIMIT_NICE
-    PyModule_AddIntConstant(module, "RLIMIT_NICE", RLIMIT_NICE);
+    if (PyModule_AddIntConstant(mod, "RLIMIT_NICE", RLIMIT_NICE)) INITERR;
 #endif
 #ifdef RLIMIT_RTPRIO
-    PyModule_AddIntConstant(module, "RLIMIT_RTPRIO", RLIMIT_RTPRIO);
+    if (PyModule_AddIntConstant(mod, "RLIMIT_RTPRIO", RLIMIT_RTPRIO)) INITERR;
 #endif
 #ifdef RLIMIT_RTTIME
-    PyModule_AddIntConstant(module, "RLIMIT_RTTIME", RLIMIT_RTTIME);
+    if (PyModule_AddIntConstant(mod, "RLIMIT_RTTIME", RLIMIT_RTTIME)) INITERR;
 #endif
 #ifdef RLIMIT_SIGPENDING
-    PyModule_AddIntConstant(module, "RLIMIT_SIGPENDING", RLIMIT_SIGPENDING);
+    if (PyModule_AddIntConstant(mod, "RLIMIT_SIGPENDING", RLIMIT_SIGPENDING))
+        INITERR;
 #endif
 #endif
-    PyModule_AddIntConstant(module, "DUPLEX_HALF", DUPLEX_HALF);
-    PyModule_AddIntConstant(module, "DUPLEX_FULL", DUPLEX_FULL);
-    PyModule_AddIntConstant(module, "DUPLEX_UNKNOWN", DUPLEX_UNKNOWN);
+    if (PyModule_AddIntConstant(mod, "DUPLEX_HALF", DUPLEX_HALF)) INITERR;
+    if (PyModule_AddIntConstant(mod, "DUPLEX_FULL", DUPLEX_FULL)) INITERR;
+    if (PyModule_AddIntConstant(mod, "DUPLEX_UNKNOWN", DUPLEX_UNKNOWN)) INITERR;
 
-    if (module == NULL)
-        INITERROR;
+    if (mod == NULL)
+        INITERR;
 #if PY_MAJOR_VERSION >= 3
-    return module;
+    return mod;
 #endif
 }
diff --git a/psutil/_psutil_osx.c b/psutil/_psutil_osx.c
index eaf4e514..d2ca94b5 100644
--- a/psutil/_psutil_osx.c
+++ b/psutil/_psutil_osx.c
@@ -1745,8 +1745,7 @@ error:
 /*
  * define the psutil C module methods and initialize the module.
  */
-static PyMethodDef
-PsutilMethods[] = {
+static PyMethodDef mod_methods[] = {
     // --- per-process functions
 
     {"proc_kinfo_oneshot", psutil_proc_kinfo_oneshot, METH_VARARGS,
@@ -1816,96 +1815,94 @@ PsutilMethods[] = {
 };
 
 
-struct module_state {
-    PyObject *error;
-};
-
-#if PY_MAJOR_VERSION >= 3
-#define GETSTATE(m) ((struct module_state*)PyModule_GetState(m))
-#else
-#define GETSTATE(m) (&_state)
-#endif
-
 #if PY_MAJOR_VERSION >= 3
-
-static int
-psutil_osx_traverse(PyObject *m, visitproc visit, void *arg) {
-    Py_VISIT(GETSTATE(m)->error);
-    return 0;
-}
-
-static int
-psutil_osx_clear(PyObject *m) {
-    Py_CLEAR(GETSTATE(m)->error);
-    return 0;
-}
-
-
-static struct PyModuleDef moduledef = {
-    PyModuleDef_HEAD_INIT,
-    "psutil_osx",
-    NULL,
-    sizeof(struct module_state),
-    PsutilMethods,
-    NULL,
-    psutil_osx_traverse,
-    psutil_osx_clear,
-    NULL
-};
-
-#define INITERROR return NULL
-
-PyMODINIT_FUNC PyInit__psutil_osx(void)
-
-#else
-#define INITERROR return
-
-void
-init_psutil_osx(void)
-#endif
+    #define INITERR return NULL
+
+    static struct PyModuleDef moduledef = {
+        PyModuleDef_HEAD_INIT,
+        "_psutil_osx",
+        NULL,
+        -1,
+        mod_methods,
+        NULL,
+        NULL,
+        NULL,
+        NULL
+    };
+
+    PyObject *PyInit__psutil_osx(void)
+#else  /* PY_MAJOR_VERSION */
+    #define INITERR return
+
+    void init_psutil_osx(void)
+#endif  /* PY_MAJOR_VERSION */
 {
+    PyObject *v;
 #if PY_MAJOR_VERSION >= 3
-    PyObject *module = PyModule_Create(&moduledef);
+    PyObject *mod = PyModule_Create(&moduledef);
 #else
-    PyObject *module = Py_InitModule("_psutil_osx", PsutilMethods);
+    PyObject *mod = Py_InitModule("_psutil_osx", mod_methods);
 #endif
-    if (module == NULL)
-        INITERROR;
+    if (mod == NULL)
+        INITERR;
 
     if (psutil_setup() != 0)
-        INITERROR;
+        INITERR;
 
-    PyModule_AddIntConstant(module, "version", PSUTIL_VERSION);
+    if (PyModule_AddIntConstant(mod, "version", PSUTIL_VERSION))
+        INITERR;
     // process status constants, defined in:
     // http://fxr.watson.org/fxr/source/bsd/sys/proc.h?v=xnu-792.6.70#L149
-    PyModule_AddIntConstant(module, "SIDL", SIDL);
-    PyModule_AddIntConstant(module, "SRUN", SRUN);
-    PyModule_AddIntConstant(module, "SSLEEP", SSLEEP);
-    PyModule_AddIntConstant(module, "SSTOP", SSTOP);
-    PyModule_AddIntConstant(module, "SZOMB", SZOMB);
+    if (PyModule_AddIntConstant(mod, "SIDL", SIDL))
+        INITERR;
+    if (PyModule_AddIntConstant(mod, "SRUN", SRUN))
+        INITERR;
+    if (PyModule_AddIntConstant(mod, "SSLEEP", SSLEEP))
+        INITERR;
+    if (PyModule_AddIntConstant(mod, "SSTOP", SSTOP))
+        INITERR;
+    if (PyModule_AddIntConstant(mod, "SZOMB", SZOMB))
+        INITERR;
     // connection status constants
-    PyModule_AddIntConstant(module, "TCPS_CLOSED", TCPS_CLOSED);
-    PyModule_AddIntConstant(module, "TCPS_CLOSING", TCPS_CLOSING);
-    PyModule_AddIntConstant(module, "TCPS_CLOSE_WAIT", TCPS_CLOSE_WAIT);
-    PyModule_AddIntConstant(module, "TCPS_LISTEN", TCPS_LISTEN);
-    PyModule_AddIntConstant(module, "TCPS_ESTABLISHED", TCPS_ESTABLISHED);
-    PyModule_AddIntConstant(module, "TCPS_SYN_SENT", TCPS_SYN_SENT);
-    PyModule_AddIntConstant(module, "TCPS_SYN_RECEIVED", TCPS_SYN_RECEIVED);
-    PyModule_AddIntConstant(module, "TCPS_FIN_WAIT_1", TCPS_FIN_WAIT_1);
-    PyModule_AddIntConstant(module, "TCPS_FIN_WAIT_2", TCPS_FIN_WAIT_2);
-    PyModule_AddIntConstant(module, "TCPS_LAST_ACK", TCPS_LAST_ACK);
-    PyModule_AddIntConstant(module, "TCPS_TIME_WAIT", TCPS_TIME_WAIT);
-    PyModule_AddIntConstant(module, "PSUTIL_CONN_NONE", PSUTIL_CONN_NONE);
+    if (PyModule_AddIntConstant(mod, "TCPS_CLOSED", TCPS_CLOSED))
+        INITERR;
+    if (PyModule_AddIntConstant(mod, "TCPS_CLOSING", TCPS_CLOSING))
+        INITERR;
+    if (PyModule_AddIntConstant(mod, "TCPS_CLOSE_WAIT", TCPS_CLOSE_WAIT))
+        INITERR;
+    if (PyModule_AddIntConstant(mod, "TCPS_LISTEN", TCPS_LISTEN))
+        INITERR;
+    if (PyModule_AddIntConstant(mod, "TCPS_ESTABLISHED", TCPS_ESTABLISHED))
+        INITERR;
+    if (PyModule_AddIntConstant(mod, "TCPS_SYN_SENT", TCPS_SYN_SENT))
+        INITERR;
+    if (PyModule_AddIntConstant(mod, "TCPS_SYN_RECEIVED", TCPS_SYN_RECEIVED))
+        INITERR;
+    if (PyModule_AddIntConstant(mod, "TCPS_FIN_WAIT_1", TCPS_FIN_WAIT_1))
+        INITERR;
+    if (PyModule_AddIntConstant(mod, "TCPS_FIN_WAIT_2", TCPS_FIN_WAIT_2))
+        INITERR;
+    if (PyModule_AddIntConstant(mod, "TCPS_LAST_ACK", TCPS_LAST_ACK))
+        INITERR;
+    if (PyModule_AddIntConstant(mod, "TCPS_TIME_WAIT", TCPS_TIME_WAIT))
+        INITERR;
+    if (PyModule_AddIntConstant(mod, "PSUTIL_CONN_NONE", PSUTIL_CONN_NONE))
+        INITERR;
 
     // Exception.
     ZombieProcessError = PyErr_NewException(
         "_psutil_osx.ZombieProcessError", NULL, NULL);
+    if (ZombieProcessError == NULL)
+        INITERR;
     Py_INCREF(ZombieProcessError);
-    PyModule_AddObject(module, "ZombieProcessError", ZombieProcessError);
+    if (PyModule_AddObject(mod, "ZombieProcessError", ZombieProcessError)) {
+        Py_DECREF(ZombieProcessError);
+        INITERR;
+    }
 
-    if (module == NULL)
-        INITERROR;
+    if (mod == NULL)
+        INITERR;
 #if PY_MAJOR_VERSION >= 3
-    return module;
+    return mod;
 #endif
 }
diff --git a/psutil/_psutil_posix.c b/psutil/_psutil_posix.c
index d9a8f6d1..209e787d 100644
--- a/psutil/_psutil_posix.c
+++ b/psutil/_psutil_posix.c
@@ -354,7 +354,7 @@ error:
 static PyObject *
 psutil_net_if_mtu(PyObject *self, PyObject *args) {
     char *nic_name;
-    int sock = 0;
+    int sock = -1;
     int ret;
 #ifdef PSUTIL_SUNOS10
     struct lifreq lifr;
@@ -387,7 +387,7 @@ psutil_net_if_mtu(PyObject *self, PyObject *args) {
 #endif
 
 error:
-    if (sock != 0)
+    if (sock != -1)
         close(sock);
     return PyErr_SetFromErrno(PyExc_OSError);
 }
@@ -401,7 +401,7 @@ error:
 static PyObject *
 psutil_net_if_flags(PyObject *self, PyObject *args) {
     char *nic_name;
-    int sock = 0;
+    int sock = -1;
     int ret;
     struct ifreq ifr;
 
@@ -424,7 +424,7 @@ psutil_net_if_flags(PyObject *self, PyObject *args) {
         return Py_BuildValue("O", Py_False);
 
 error:
-    if (sock != 0)
+    if (sock != -1)
         close(sock);
     return PyErr_SetFromErrno(PyExc_OSError);
 }
@@ -579,7 +579,7 @@ int psutil_get_nic_speed(int ifm_active) {
 static PyObject *
 psutil_net_if_duplex_speed(PyObject *self, PyObject *args) {
     char *nic_name;
-    int sock = 0;
+    int sock = -1;
     int ret;
     int duplex;
     int speed;
@@ -591,7 +591,7 @@ psutil_net_if_duplex_speed(PyObject *self, PyObject *args) {
 
     sock = socket(AF_INET, SOCK_DGRAM, 0);
     if (sock == -1)
-        goto error;
+        return PyErr_SetFromErrno(PyExc_OSError);
     strncpy(ifr.ifr_name, nic_name, sizeof(ifr.ifr_name));
 
     // speed / duplex
@@ -614,20 +614,19 @@ psutil_net_if_duplex_speed(PyObject *self, PyObject *args) {
 
     close(sock);
     return Py_BuildValue("[ii]", duplex, speed);
-
-error:
-    if (sock != 0)
-        close(sock);
-    return PyErr_SetFromErrno(PyExc_OSError);
 }
 #endif  // net_if_stats() macOS/BSD implementation
 
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
 /*
  * define the psutil C module methods and initialize the module.
  */
-static PyMethodDef
-PsutilMethods[] = {
+static PyMethodDef mod_methods[] = {
     {"getpriority", psutil_posix_getpriority, METH_VARARGS,
      "Return process priority"},
     {"setpriority", psutil_posix_setpriority, METH_VARARGS,
@@ -645,71 +644,45 @@ PsutilMethods[] = {
     {NULL, NULL, 0, NULL}
 };
 
-struct module_state {
-    PyObject *error;
-};
 
 #if PY_MAJOR_VERSION >= 3
-#define GETSTATE(m) ((struct module_state*)PyModule_GetState(m))
-#else
-#define GETSTATE(m) (&_state)
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#if PY_MAJOR_VERSION >= 3
-
-static int
-psutil_posix_traverse(PyObject *m, visitproc visit, void *arg) {
-    Py_VISIT(GETSTATE(m)->error);
-    return 0;
-}
-
-
-static int
-psutil_posix_clear(PyObject *m) {
-    Py_CLEAR(GETSTATE(m)->error);
-    return 0;
-}
-
-static struct PyModuleDef moduledef = {
-    PyModuleDef_HEAD_INIT,
-    "psutil_posix",
-    NULL,
-    sizeof(struct module_state),
-    PsutilMethods,
-    NULL,
-    psutil_posix_traverse,
-    psutil_posix_clear,
-    NULL
-};
-
-#define INITERROR return NULL
-
-PyMODINIT_FUNC PyInit__psutil_posix(void)
-
-#else
-#define INITERROR return
-
-void init_psutil_posix(void)
-#endif
+    #define INITERR return NULL
+
+    static struct PyModuleDef moduledef = {
+        PyModuleDef_HEAD_INIT,
+        "_psutil_posix",
+        NULL,
+        -1,
+        mod_methods,
+        NULL,
+        NULL,
+        NULL,
+        NULL
+    };
+
+    PyObject *PyInit__psutil_posix(void)
+#else  /* PY_MAJOR_VERSION */
+    #define INITERR return
+
+    void init_psutil_posix(void)
+#endif  /* PY_MAJOR_VERSION */
 {
 #if PY_MAJOR_VERSION >= 3
-    PyObject *module = PyModule_Create(&moduledef);
+    PyObject *mod = PyModule_Create(&moduledef);
 #else
-    PyObject *module = Py_InitModule("_psutil_posix", PsutilMethods);
+    PyObject *mod = Py_InitModule("_psutil_posix", mod_methods);
 #endif
+    if (mod == NULL)
+        INITERR;
 
 #if defined(PSUTIL_BSD) || defined(PSUTIL_OSX) || defined(PSUTIL_SUNOS) || defined(PSUTIL_AIX)
-    PyModule_AddIntConstant(module, "AF_LINK", AF_LINK);
+    if (PyModule_AddIntConstant(mod, "AF_LINK", AF_LINK)) INITERR;
 #endif
 
-    if (module == NULL)
-        INITERROR;
+    if (mod == NULL)
+        INITERR;
 #if PY_MAJOR_VERSION >= 3
-    return module;
+    return mod;
 #endif
 }
 
diff --git a/psutil/_psutil_sunos.c b/psutil/_psutil_sunos.c
index 49100ec6..919e76d6 100644
--- a/psutil/_psutil_sunos.c
+++ b/psutil/_psutil_sunos.c
@@ -1120,7 +1120,7 @@ psutil_net_connections(PyObject *self, PyObject *args) {
     mib2_udp6Entry_t     ude6;
 #endif
     char buf[512];
-    int i, flags, getcode, num_ent, state;
+    int i, flags, getcode, num_ent, state, ret;
     char lip[INET6_ADDRSTRLEN], rip[INET6_ADDRSTRLEN];
     int lport, rport;
     int processed_pid;
@@ -1147,7 +1147,7 @@ psutil_net_connections(PyObject *self, PyObject *args) {
         goto error;
     }
 
-    int ret = ioctl(sd, I_PUSH, "tcp");
+    ret = ioctl(sd, I_PUSH, "tcp");
     if (ret == -1) {
         PyErr_SetFromErrno(PyExc_OSError);
         goto error;
diff --git a/psutil/_psutil_windows.c b/psutil/_psutil_windows.c
index f071648f..beaba183 100644
--- a/psutil/_psutil_windows.c
+++ b/psutil/_psutil_windows.c
@@ -807,7 +807,7 @@ psutil_GetProcWsetInformation(
 
     if (!NT_SUCCESS(status)) {
         if (status == STATUS_ACCESS_DENIED) {
-            AccessDenied("");
+            AccessDenied("originated from NtQueryVirtualMemory");
         }
         else if (psutil_pid_is_running(pid) == 0) {
             NoSuchProcess("");
@@ -3510,9 +3510,10 @@ PsutilMethods[] = {
     {"cpu_freq", psutil_cpu_freq, METH_VARARGS,
      "Return CPU frequency."},
 #if (_WIN32_WINNT >= 0x0600)  // Windows Vista
-    {"init_loadavg_counter", psutil_init_loadavg_counter, METH_VARARGS,
+    {"init_loadavg_counter", (PyCFunction)psutil_init_loadavg_counter,
+     METH_VARARGS,
      "Initializes the emulated load average calculator."},
-    {"getloadavg", psutil_get_loadavg, METH_VARARGS,
+    {"getloadavg", (PyCFunction)psutil_get_loadavg, METH_VARARGS,
      "Returns the emulated POSIX-like load average."},
 #endif
     {"sensors_battery", psutil_sensors_battery, METH_VARARGS,
diff --git a/psutil/_pswindows.py b/psutil/_pswindows.py
index cf938a6f..636b0af9 100644
--- a/psutil/_pswindows.py
+++ b/psutil/_pswindows.py
@@ -80,6 +80,7 @@ __extra__all__ = [
 CONN_DELETE_TCB = "DELETE_TCB"
 HAS_PROC_IO_PRIORITY = hasattr(cext, "proc_io_priority_get")
 HAS_GETLOADAVG = hasattr(cext, "getloadavg")
+ERROR_PARTIAL_COPY = 299
 
 
 if enum is None:
@@ -709,6 +710,32 @@ def wrap_exceptions(fun):
     return wrapper
 
 
+def retry_error_partial_copy(fun):
+    """Workaround for https://github.com/giampaolo/psutil/issues/875.
+    See: https://stackoverflow.com/questions/4457745#4457745
+    """
+    @functools.wraps(fun)
+    def wrapper(self, *args, **kwargs):
+        delay = 0.0001
+        times = 33
+        for x in range(times):  # retries for roughly 1 second
+            try:
+                return fun(self, *args, **kwargs)
+            except WindowsError as _:
+                err = _
+                if err.winerror == ERROR_PARTIAL_COPY:
+                    time.sleep(delay)
+                    delay = min(delay * 2, 0.04)
+                    continue
+                else:
+                    raise
+        else:
+            msg = "%s retried %s times, converted to AccessDenied as it's " \
+                "still returning %r" % (fun, times, err)
+            raise AccessDenied(pid=self.pid, name=self._name, msg=msg)
+    return wrapper
+
+
 class Process(object):
     """Wrapper class around underlying C implementation."""
 
@@ -772,6 +799,7 @@ class Process(object):
         return py2_strencode(exe)
 
     @wrap_exceptions
+    @retry_error_partial_copy
     def cmdline(self):
         if cext.WINVER >= cext.WINDOWS_8_1:
             # PEB method detects cmdline changes but requires more
@@ -791,6 +819,7 @@ class Process(object):
             return [py2_strencode(s) for s in ret]
 
     @wrap_exceptions
+    @retry_error_partial_copy
     def environ(self):
         ustr = cext.proc_environ(self.pid)
         if ustr and not PY3:
@@ -963,6 +992,7 @@ class Process(object):
         cext.proc_suspend_or_resume(self.pid, False)
 
     @wrap_exceptions
+    @retry_error_partial_copy
     def cwd(self):
         if self.pid in (0, 4):
             raise AccessDenied(self.pid, self._name)
diff --git a/psutil/arch/windows/process_info.c b/psutil/arch/windows/process_info.c
index ba9966bb..62735728 100644
--- a/psutil/arch/windows/process_info.c
+++ b/psutil/arch/windows/process_info.c
@@ -512,18 +512,22 @@ psutil_get_process_data(long pid,
 
         // read PEB
         if (!ReadProcessMemory(hProcess, ppeb32, &peb32, sizeof(peb32), NULL)) {
-            PyErr_SetFromOSErrnoWithSyscall("ReadProcessMemory");
+            // May fail with ERROR_PARTIAL_COPY, see:
+            // https://github.com/giampaolo/psutil/issues/875
+            PyErr_SetFromWindowsErr(0);
             goto error;
         }
 
         // read process parameters
         if (!ReadProcessMemory(hProcess,
-                              UlongToPtr(peb32.ProcessParameters),
-                              &procParameters32,
-                              sizeof(procParameters32),
-                              NULL)) {
-            PyErr_SetFromOSErrnoWithSyscall(
-                "ReadProcessMemory(ProcessParameters)");
+                               UlongToPtr(peb32.ProcessParameters),
+                               &procParameters32,
+                               sizeof(procParameters32),
+                               NULL))
+        {
+            // May fail with ERROR_PARTIAL_COPY, see:
+            // https://github.com/giampaolo/psutil/issues/875
+            PyErr_SetFromWindowsErr(0);
             goto error;
         }
 
@@ -576,41 +580,44 @@ psutil_get_process_data(long pid,
             }
         }
 
-        if (! NT_SUCCESS(
-                NtWow64QueryInformationProcess64(
+        status = NtWow64QueryInformationProcess64(
                 hProcess,
                 ProcessBasicInformation,
                 &pbi64,
                 sizeof(pbi64),
-                NULL)))
-        {
-            PyErr_SetFromOSErrnoWithSyscall(
-                "NtWow64QueryInformationProcess64(ProcessBasicInformation)");
+                NULL);
+        if (!NT_SUCCESS(status)) {
+            psutil_SetFromNTStatusErr(
+                    status,
+                    "NtWow64QueryInformationProcess64(ProcessBasicInformation)"
+            );
             goto error;
         }
 
         // read peb
-        if (! NT_SUCCESS(NtWow64ReadVirtualMemory64(
-               hProcess,
-               pbi64.PebBaseAddress,
-               &peb64,
-               sizeof(peb64),
-               NULL)))
-        {
-            PyErr_SetFromOSErrnoWithSyscall("NtWow64ReadVirtualMemory64");
+        status = NtWow64ReadVirtualMemory64(
+                hProcess,
+                pbi64.PebBaseAddress,
+                &peb64,
+                sizeof(peb64),
+                NULL);
+        if (!NT_SUCCESS(status)) {
+            psutil_SetFromNTStatusErr(status, "NtWow64ReadVirtualMemory64");
             goto error;
         }
 
         // read process parameters
-        if (! NT_SUCCESS(NtWow64ReadVirtualMemory64(
+        status = NtWow64ReadVirtualMemory64(
                 hProcess,
                 peb64.ProcessParameters,
                 &procParameters64,
                 sizeof(procParameters64),
-                NULL)))
-        {
-            PyErr_SetFromOSErrnoWithSyscall(
-                "NtWow64ReadVirtualMemory64(ProcessParameters)");
+                NULL);
+        if (!NT_SUCCESS(status)) {
+            psutil_SetFromNTStatusErr(
+                    status,
+                    "NtWow64ReadVirtualMemory64(ProcessParameters)"
+            );
             goto error;
         }
 
@@ -654,8 +661,11 @@ psutil_get_process_data(long pid,
                                pbi.PebBaseAddress,
                                &peb,
                                sizeof(peb),
-                               NULL)) {
-            PyErr_SetFromOSErrnoWithSyscall("ReadProcessMemory");
+                               NULL))
+        {
+            // May fail with ERROR_PARTIAL_COPY, see:
+            // https://github.com/giampaolo/psutil/issues/875
+            PyErr_SetFromWindowsErr(0);
             goto error;
         }
 
@@ -664,9 +674,11 @@ psutil_get_process_data(long pid,
                                peb.ProcessParameters,
                                &procParameters,
                                sizeof(procParameters),
-                               NULL)) {
-            PyErr_SetFromOSErrnoWithSyscall(
-                "ReadProcessMemory(ProcessParameters)");
+                               NULL))
+        {
+            // May fail with ERROR_PARTIAL_COPY, see:
+            // https://github.com/giampaolo/psutil/issues/875
+            PyErr_SetFromWindowsErr(0);
             goto error;
         }
 
@@ -705,20 +717,22 @@ psutil_get_process_data(long pid,
 
 #ifndef _WIN64
     if (weAreWow64 && !theyAreWow64) {
-        if (! NT_SUCCESS(NtWow64ReadVirtualMemory64(
+        status = NtWow64ReadVirtualMemory64(
                 hProcess,
                 src64,
                 buffer,
                 size,
-                NULL)))
-        {
-            PyErr_SetFromOSErrnoWithSyscall("NtWow64ReadVirtualMemory64");
+                NULL);
+        if (!NT_SUCCESS(status)) {
+            psutil_SetFromNTStatusErr(status, "NtWow64ReadVirtualMemory64");
             goto error;
         }
     } else
 #endif
     if (!ReadProcessMemory(hProcess, src, buffer, size, NULL)) {
-        PyErr_SetFromOSErrnoWithSyscall("ReadProcessMemory");
+        // May fail with ERROR_PARTIAL_COPY, see:
+        // https://github.com/giampaolo/psutil/issues/875
+        PyErr_SetFromWindowsErr(0);
         goto error;
     }
 
diff --git a/psutil/arch/windows/wmi.c b/psutil/arch/windows/wmi.c
index 5858a9e0..f43d790c 100644
--- a/psutil/arch/windows/wmi.c
+++ b/psutil/arch/windows/wmi.c
@@ -22,8 +22,8 @@
 // This formula comes from linux's include/linux/sched/loadavg.h
 // https://github.com/torvalds/linux/blob/345671ea0f9258f410eb057b9ced9cefbbe5dc78/include/linux/sched/loadavg.h#L20-L23
 #define LOADAVG_FACTOR_1F  0.9200444146293232478931553241
-#define LOADAVG_FACTOR_5F  0.6592406302004437462547604110
-#define LOADAVG_FACTOR_15F 0.2865047968601901003248854266
+#define LOADAVG_FACTOR_5F  0.9834714538216174894737477501
+#define LOADAVG_FACTOR_15F 0.9944598480048967508795473394
 // The time interval in seconds between taking load counts, same as Linux
 #define SAMPLING_INTERVAL 5
 
@@ -112,4 +112,4 @@ error:
 PyObject *
 psutil_get_loadavg(PyObject *self, PyObject *args) {
     return Py_BuildValue("(ddd)", load_avg_1m, load_avg_5m, load_avg_15m);
-}
\ No newline at end of file
+}
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 00000000..7f59610c
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,6 @@
+[build-system]
+requires = [
+    "setuptools >= 41.0.0",
+    "wheel >= 0.29.0",
+]
+build-backend = 'setuptools.build_meta'
diff --git a/scripts/internal/bench_oneshot_2.py b/scripts/internal/bench_oneshot_2.py
index a25d1806..becf930c 100644
--- a/scripts/internal/bench_oneshot_2.py
+++ b/scripts/internal/bench_oneshot_2.py
@@ -11,7 +11,7 @@ supposed to be more precise.
 
 import sys
 
-import perf  # requires "pip install perf"
+import pyperf  # requires "pip install pyperf"
 
 import psutil
 from bench_oneshot import names
@@ -37,7 +37,7 @@ def add_cmdline_args(cmd, args):
 
 
 def main():
-    runner = perf.Runner()
+    runner = pyperf.Runner()
 
     args = runner.parse_args()
     if not args.worker:
diff --git a/scripts/internal/fix_flake8.py b/scripts/internal/fix_flake8.py
new file mode 100644
index 00000000..5aa84db5
--- /dev/null
+++ b/scripts/internal/fix_flake8.py
@@ -0,0 +1,185 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Fix some flake8 errors by rewriting files for which flake8 emitted
+an error/warning. Usage (from the root dir):
+
+    $ python3 -m flake8 --exit-zero | python3 scripts/fix_flake8.py
+"""
+
+import sys
+import tempfile
+import shutil
+from collections import defaultdict
+from collections import namedtuple
+from pprint import pprint as pp  # NOQA
+
+
+ntentry = namedtuple('ntentry', 'msg, issue, lineno, pos, descr')
+
+
+# =====================================================================
+# utils
+# =====================================================================
+
+
+def enter_pdb():
+    from pdb import set_trace as st  # trick GIT commit hook
+    sys.stdin = open('/dev/tty')
+    st()
+
+
+def read_lines(fname):
+    with open(fname, 'rt') as f:
+        return f.readlines()
+
+
+def read_line(fname, lineno):
+    with open(fname, 'rt') as f:
+        for i, line in enumerate(f, 1):
+            if i == lineno:
+                return line
+    raise ValueError("lineno too big")
+
+
+def write_file(fname, newlines):
+    with tempfile.NamedTemporaryFile('wt', delete=False) as f:
+        for line in newlines:
+            f.write(line)
+    shutil.move(f.name, fname)
+
+
+# =====================================================================
+# handlers
+# =====================================================================
+
+
+def handle_f401(fname, lineno):
+    """ This is 'module imported but not used'
+    Able to handle this case:
+        import os
+
+    ...but not this:
+        from os import listdir
+    """
+    line = read_line(fname, lineno).strip()
+    if line.startswith('import '):
+        return True
+    else:
+        mods = line.partition(' import ')[2]  # everything after import
+        return ',' not in mods
+
+
+# =====================================================================
+# converters
+# =====================================================================
+
+
+def remove_lines(fname, entries):
+    """Check if we should remove lines, then do it.
+    Return the numner of lines removed.
+    """
+    to_remove = []
+    for entry in entries:
+        msg, issue, lineno, pos, descr = entry
+        # 'module imported but not used'
+        if issue == 'F401' and handle_f401(fname, lineno):
+            to_remove.append(lineno)
+        # 'blank line(s) at end of file'
+        elif issue == 'W391':
+            lines = read_lines(fname)
+            i = len(lines) - 1
+            while lines[i] == '\n':
+                to_remove.append(i + 1)
+                i -= 1
+        # 'too many blank lines'
+        elif issue == 'E303':
+            howmany = descr.replace('(', '').replace(')', '')
+            howmany = int(howmany[-1])
+            for x in range(lineno - howmany, lineno):
+                to_remove.append(x)
+
+    if to_remove:
+        newlines = []
+        for i, line in enumerate(read_lines(fname), 1):
+            if i not in to_remove:
+                newlines.append(line)
+        print("removing line(s) from %s" % fname)
+        write_file(fname, newlines)
+
+    return len(to_remove)
+
+
+def add_lines(fname, entries):
+    """Check if we should remove lines, then do it.
+    Return the numner of lines removed.
+    """
+    EXPECTED_BLANK_LINES = (
+        'E302',  # 'expected 2 blank limes, found 1'
+        'E305')  # ìexpected 2 blank lines after class or fun definition'
+    to_add = {}
+    for entry in entries:
+        msg, issue, lineno, pos, descr = entry
+        if issue in EXPECTED_BLANK_LINES:
+            howmany = 2 if descr.endswith('0') else 1
+            to_add[lineno] = howmany
+
+    if to_add:
+        newlines = []
+        for i, line in enumerate(read_lines(fname), 1):
+            if i in to_add:
+                newlines.append('\n' * to_add[i])
+            newlines.append(line)
+        print("adding line(s) to %s" % fname)
+        write_file(fname, newlines)
+
+    return len(to_add)
+
+
+# =====================================================================
+# main
+# =====================================================================
+
+
+def build_table():
+    table = defaultdict(list)
+    for line in sys.stdin:
+        line = line.strip()
+        if not line:
+            break
+        fields = line.split(':')
+        fname, lineno, pos = fields[:3]
+        issue = fields[3].split()[0]
+        descr = fields[3].strip().partition(' ')[2]
+        lineno, pos = int(lineno), int(pos)
+        table[fname].append(ntentry(line, issue, lineno, pos, descr))
+    return table
+
+
+def main():
+    table = build_table()
+
+    # remove lines (unused imports)
+    removed = 0
+    for fname, entries in table.items():
+        removed += remove_lines(fname, entries)
+    if removed:
+        print("%s lines were removed from some file(s); please re-run" %
+              removed)
+        return
+
+    # add lines (missing \n between functions/classes)
+    added = 0
+    for fname, entries in table.items():
+        added += add_lines(fname, entries)
+    if added:
+        print("%s lines were added from some file(s); please re-run" %
+              added)
+        return
+
+
+main()
diff --git a/scripts/internal/print_timeline.py b/scripts/internal/print_timeline.py
index 4bfe76b3..9bf6e9d1 100644
--- a/scripts/internal/print_timeline.py
+++ b/scripts/internal/print_timeline.py
@@ -30,7 +30,7 @@ def get_tag_date(tag):
 
 def main():
     releases = []
-    out = sh("git tags")
+    out = sh("git tag")
     for line in out.split('\n'):
         tag = line.split(' ')[0]
         ver = tag.replace('release-', '')
diff --git a/scripts/internal/winmake.py b/scripts/internal/winmake.py
index 75b4c348..116809ca 100755
--- a/scripts/internal/winmake.py
+++ b/scripts/internal/winmake.py
@@ -39,8 +39,8 @@ DEPS = [
     "flake8",
     "nose",
     "pdbpp",
-    "perf",
     "pip",
+    "pyperf",
     "pypiwin32==219" if sys.version_info[:2] <= (3, 4) else "pypiwin32",
     "pyreadline",
     "setuptools",
diff --git a/setup.py b/setup.py
index 693bd89d..04a41d99 100755
--- a/setup.py
+++ b/setup.py
@@ -10,6 +10,7 @@ import contextlib
 import io
 import os
 import platform
+import shutil
 import sys
 import tempfile
 import warnings
@@ -205,20 +206,19 @@ elif LINUX:
                 suffix='.c', delete=False, mode="wt") as f:
             f.write("#include <linux/ethtool.h>")
 
+        output_dir = tempfile.mkdtemp()
         try:
             compiler = UnixCCompiler()
             with silenced_output('stderr'):
                 with silenced_output('stdout'):
-                    compiler.compile([f.name])
+                    compiler.compile([f.name], output_dir=output_dir)
         except CompileError:
             return ("PSUTIL_ETHTOOL_MISSING_TYPES", 1)
         else:
             return None
         finally:
-            try:
-                os.remove(f.name)
-            except OSError:
-                pass
+            os.remove(f.name)
+            shutil.rmtree(output_dir)
 
     macros.append(("PSUTIL_LINUX", 1))
     ETHTOOL_MACRO = get_ethtool_macro()
@@ -240,7 +240,7 @@ elif SUNOS:
         ],
         define_macros=macros,
         libraries=['kstat', 'nsl', 'socket'])
-# AIX
+
 elif AIX:
     macros.append(("PSUTIL_AIX", 1))
     ext = Extension(


Test patch:
diff --git a/psutil/tests/test_linux.py b/psutil/tests/test_linux.py
index bb74ab31..09fed4e4 100755
--- a/psutil/tests/test_linux.py
+++ b/psutil/tests/test_linux.py
@@ -10,6 +10,7 @@ from __future__ import division
 import collections
 import contextlib
 import errno
+import glob
 import io
 import os
 import re
@@ -55,7 +56,7 @@ SIOCGIFCONF = 0x8912
 SIOCGIFHWADDR = 0x8927
 if LINUX:
     SECTOR_SIZE = 512
-
+EMPTY_TEMPERATURES = not glob.glob('/sys/class/hwmon/hwmon*')
 
 # =====================================================================
 # --- utils
@@ -705,15 +706,12 @@ class TestSystemCPUFrequency(unittest.TestCase):
             if path.startswith("/sys/devices/system/cpu/cpufreq/policy"):
                 return False
             else:
-                flags.append(None)
                 return orig_exists(path)
 
-        flags = []
         orig_exists = os.path.exists
         with mock.patch("os.path.exists", side_effect=path_exists_mock,
                         create=True):
             assert psutil.cpu_freq()
-            self.assertEqual(len(flags), psutil.cpu_count(logical=True))
 
     @unittest.skipIf(not HAS_CPU_FREQ, "not supported")
     def test_emulate_use_cpuinfo(self):
@@ -844,25 +842,6 @@ class TestSystemCPUFrequency(unittest.TestCase):
                     freq = psutil.cpu_freq()
                     self.assertEqual(freq.current, 200)
 
-        # Also test that NotImplementedError is raised in case no
-        # current freq file is present.
-
-        def open_mock(name, *args, **kwargs):
-            if name.endswith('/scaling_cur_freq'):
-                raise IOError(errno.ENOENT, "")
-            elif name.endswith('/cpuinfo_cur_freq'):
-                raise IOError(errno.ENOENT, "")
-            elif name == '/proc/cpuinfo':
-                raise IOError(errno.ENOENT, "")
-            else:
-                return orig_open(name, *args, **kwargs)
-
-        orig_open = open
-        patch_point = 'builtins.open' if PY3 else '__builtin__.open'
-        with mock.patch(patch_point, side_effect=open_mock):
-            with mock.patch('os.path.exists', return_value=True):
-                self.assertRaises(NotImplementedError, psutil.cpu_freq)
-
 
 @unittest.skipIf(not LINUX, "LINUX only")
 class TestSystemCPUStats(unittest.TestCase):
@@ -1569,6 +1548,7 @@ class TestSensorsBattery(unittest.TestCase):
 class TestSensorsTemperatures(unittest.TestCase):
 
     @unittest.skipIf(TRAVIS, "unreliable on TRAVIS")
+    @unittest.skipIf(LINUX and EMPTY_TEMPERATURES, "no temperatures")
     def test_emulate_eio_error(self):
         def open_mock(name, *args, **kwargs):
             if name.endswith("_input"):
@@ -1993,6 +1973,9 @@ class TestProcess(unittest.TestCase):
             "0",      # cnswap
             "0",      # exit_signal
             "6",      # processor
+            "0",      # rt priority
+            "0",      # policy
+            "7",      # delayacct_blkio_ticks
         ]
         content = " ".join(args).encode()
         with mock_open_content('/proc/%s/stat' % os.getpid(), content):
@@ -2007,6 +1990,7 @@ class TestProcess(unittest.TestCase):
             self.assertEqual(cpu.system, 3 / CLOCK_TICKS)
             self.assertEqual(cpu.children_user, 4 / CLOCK_TICKS)
             self.assertEqual(cpu.children_system, 5 / CLOCK_TICKS)
+            self.assertEqual(cpu.iowait, 7 / CLOCK_TICKS)
             self.assertEqual(p.cpu_num(), 6)
 
     def test_status_file_parsing(self):
diff --git a/psutil/tests/test_process.py b/psutil/tests/test_process.py
index ae3388a1..24a29b5a 100755
--- a/psutil/tests/test_process.py
+++ b/psutil/tests/test_process.py
@@ -252,6 +252,8 @@ class TestProcess(unittest.TestCase):
         assert (times.user > 0.0) or (times.system > 0.0), times
         assert (times.children_user >= 0.0), times
         assert (times.children_system >= 0.0), times
+        if LINUX:
+            assert times.iowait >= 0.0, times
         # make sure returned values can be pretty printed with strftime
         for name in times._fields:
             time.strftime("%H:%M:%S", time.localtime(getattr(times, name)))
@@ -938,6 +940,8 @@ class TestProcess(unittest.TestCase):
         self.addCleanup(p.cpu_affinity, initial)
 
         # All possible CPU set combinations.
+        if len(initial) > 12:
+            initial = initial[:12]  # ...otherwise it will take forever
         combos = []
         for l in range(0, len(initial) + 1):
             for subset in itertools.combinations(initial, l):
diff --git a/psutil/tests/test_system.py b/psutil/tests/test_system.py
index 38843b0e..e04e120b 100755
--- a/psutil/tests/test_system.py
+++ b/psutil/tests/test_system.py
@@ -364,17 +364,16 @@ class TestSystemAPIs(unittest.TestCase):
         # Simulate some work load then make sure time have increased
         # between calls.
         tot1 = psutil.cpu_times(percpu=True)
-        stop_at = time.time() + 0.1
+        giveup_at = time.time() + 1
         while True:
-            if time.time() >= stop_at:
-                break
-        tot2 = psutil.cpu_times(percpu=True)
-        for t1, t2 in zip(tot1, tot2):
-            t1, t2 = sum(t1), sum(t2)
-            difference = t2 - t1
-            if difference >= 0.05:
-                return
-        self.fail()
+            if time.time() >= giveup_at:
+                return self.fail("timeout")
+            tot2 = psutil.cpu_times(percpu=True)
+            for t1, t2 in zip(tot1, tot2):
+                t1, t2 = psutil._cpu_busy_time(t1), psutil._cpu_busy_time(t2)
+                difference = t2 - t1
+                if difference >= 0.05:
+                    return
 
     def test_cpu_times_comparison(self):
         # Make sure the sum of all per cpu times is almost equal to
@@ -501,11 +500,8 @@ class TestSystemAPIs(unittest.TestCase):
                 # we cannot make any assumption about this, see:
                 # http://goo.gl/p9c43
                 disk.device
-            if SUNOS or TRAVIS:
-                # on solaris apparently mount points can also be files
-                assert os.path.exists(disk.mountpoint), disk
-            else:
-                assert os.path.isdir(disk.mountpoint), disk
+            # on modern systems mount points can also be files
+            assert os.path.exists(disk.mountpoint), disk
             assert disk.fstype, disk
 
         # all = True
diff --git a/psutil/tests/test_windows.py b/psutil/tests/test_windows.py
index 51b53f0e..1075efdd 100755
--- a/psutil/tests/test_windows.py
+++ b/psutil/tests/test_windows.py
@@ -517,6 +517,16 @@ class TestProcess(unittest.TestCase):
         psutil_value = psutil.Process(self.pid).num_handles()
         self.assertEqual(psutil_value, sys_value)
 
+    def test_error_partial_copy(self):
+        # https://github.com/giampaolo/psutil/issues/875
+        exc = WindowsError()
+        exc.winerror = 299
+        with mock.patch("psutil._psplatform.cext.proc_cwd", side_effect=exc):
+            with mock.patch("time.sleep") as m:
+                p = psutil.Process()
+                self.assertRaises(psutil.AccessDenied, p.cwd)
+        self.assertGreaterEqual(m.call_count, 5)
+
 
 @unittest.skipIf(not WINDOWS, "WINDOWS only")
 class TestProcessWMI(unittest.TestCase):