summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGiampaolo Rodola <g.rodola@gmail.com>2020-04-30 15:12:45 -0700
committerGiampaolo Rodola <g.rodola@gmail.com>2020-04-30 15:12:45 -0700
commitd59992759f56969ec2f7a8e0c6ac6f7ad81f8fcb (patch)
tree37e59c1731b45e8d04d5ce66f5f0322da0e4ff64
parent3480e1b05f3e98744a1b6aa6fe286caac86e6bbd (diff)
downloadpsutil-d59992759f56969ec2f7a8e0c6ac6f7ad81f8fcb.tar.gz
revert #1736 (make psutil.Popen inherit from subprocess)
-rw-r--r--HISTORY.rst4
-rw-r--r--docs/index.rst47
-rw-r--r--psutil/__init__.py69
3 files changed, 42 insertions, 78 deletions
diff --git a/HISTORY.rst b/HISTORY.rst
index c375934c..6f8087db 100644
--- a/HISTORY.rst
+++ b/HISTORY.rst
@@ -7,9 +7,7 @@ XXXX-XX-XX
**Enhancements**
-- 1729_: parallel tests on UNIX (make test-parallel).
-- 1736_: psutil.Popen now inherits from subprocess.Popen instead of
- psutil.Process. Also, wait(timeout=...) parameter is backported to Python 2.7.
+- 1729_: parallel tests on UNIX (make test-parallel). They're twice as fast!
- 1741_: "make build/install" is now run in parallel and it's about 15% faster
on UNIX.
diff --git a/docs/index.rst b/docs/index.rst
index 08a69555..133e69fe 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -1959,24 +1959,18 @@ Process class
>>> p.terminate()
>>> p.wait()
-Popen class
------------
-
.. class:: Popen(*args, **kwargs)
- A more convenient interface to stdlib `subprocess.Popen`_.
- It starts a sub process and you deal with it exactly as when using
- `subprocess.Popen`_, but in addition it also provides all the methods of
- :class:`psutil.Process` class as a unified interface.
-
- .. note::
-
- Unlike `subprocess.Popen`_ this class preemptively checks whether PID has
- been reused on
- :meth:`send_signal() <psutil.Process.send_signal()>`,
- :meth:`terminate() <psutil.Process.terminate()>` and
- :meth:`kill() <psutil.Process.kill()>`
- so that you can't accidentally terminate another process, fixing `BPO-6973`_.
+ Starts a sub-process via `subprocess.Popen`_, and in addition it provides
+ all the methods of :class:`psutil.Process` in a single class.
+ For method names common to both classes such as
+ :meth:`send_signal() <psutil.Process.send_signal()>`,
+ :meth:`terminate() <psutil.Process.terminate()>`,
+ :meth:`kill() <psutil.Process.kill()>` and
+ :meth:`wait() <psutil.Process.wait()>`
+ :class:`psutil.Process` implementation takes precedence.
+ This may have some advantages, like making sure PID has not been reused,
+ fixing `BPO-6973`_.
>>> import psutil
>>> from subprocess import PIPE
@@ -1992,25 +1986,10 @@ Popen class
0
>>>
- *timeout* parameter of `subprocess.Popen.wait`_ is backported for Python < 3.3.
- :class:`psutil.Popen` objects are supported as context managers via the with
- statement (added to Python 3.2). On exit, standard file descriptors are
- closed, and the process is waited for. This is supported on all Python
- versions.
-
- >>> import psutil, subprocess
- >>> with psutil.Popen(["ifconfig"], stdout=subprocess.PIPE) as proc:
- >>> log.write(proc.stdout.read())
-
-
- .. versionchanged:: 4.4.0 added context manager support.
-
- .. versionchanged:: 5.7.1 inherit from `subprocess.Popen`_ instead of
- :class:`psutil.Process`.
-
- .. versionchanged:: 5.7.1 backporint `subprocess.Popen.wait`_ **timeout**
- parameter on old Python versions.
+ .. versionchanged:: 4.4.0 added context manager support
+ .. versionchanged:: 5.7.1 wait() invokes :meth:`wait() <psutil.Process.wait()>`
+ instead of `subprocess.Popen.wait`_.
Windows services
================
diff --git a/psutil/__init__.py b/psutil/__init__.py
index 028ab049..eb6d6c1b 100644
--- a/psutil/__init__.py
+++ b/psutil/__init__.py
@@ -1289,12 +1289,12 @@ _as_dict_attrnames = set(
# =====================================================================
-class Popen(subprocess.Popen):
+class Popen(Process):
"""A more convenient interface to stdlib subprocess.Popen class.
It starts a sub process and deals with it exactly as when using
- subprocess.Popen class, but in addition it also provides all the
- methods of psutil.Process class as a unified interface:
-
+ subprocess.Popen class but in addition also provides all the
+ properties and methods of psutil.Process class as a unified
+ interface:
>>> import psutil
>>> from subprocess import PIPE
>>> p = psutil.Popen(["python", "-c", "print 'hi'"], stdout=PIPE)
@@ -1310,16 +1310,12 @@ class Popen(subprocess.Popen):
>>> p.wait(timeout=2)
0
>>>
-
- In addition, it backports the following functionality:
- * "with" statement (Python 3.2)
- * wait(timeout=...) parameter (Python 3.3)
-
+ For method names common to both classes such as kill(), terminate()
+ and wait(), psutil.Process implementation takes precedence.
Unlike subprocess.Popen this class pre-emptively checks whether PID
- has been reused on send_signal(), terminate() and kill(), so that
+ has been reused on send_signal(), terminate() and kill() so that
you don't accidentally terminate another process, fixing
http://bugs.python.org/issue6973.
-
For a complete documentation refer to:
http://docs.python.org/3/library/subprocess.html
"""
@@ -1328,21 +1324,21 @@ class Popen(subprocess.Popen):
# Explicitly avoid to raise NoSuchProcess in case the process
# spawned by subprocess.Popen terminates too quickly, see:
# https://github.com/giampaolo/psutil/issues/193
- self.__psproc = None
- subprocess.Popen.__init__(self, *args, **kwargs)
- self.__psproc = Process(self.pid)
- self.__psproc._init(self.pid, _ignore_nsp=True)
+ self.__subproc = subprocess.Popen(*args, **kwargs)
+ self._init(self.__subproc.pid, _ignore_nsp=True)
def __dir__(self):
- return sorted(set(dir(subprocess.Popen) + dir(Process)))
+ return sorted(set(dir(Popen) + dir(subprocess.Popen)))
- # Introduced in Python 3.2.
- if not hasattr(subprocess.Popen, '__enter__'):
+ def __enter__(self):
+ if hasattr(self.__subproc, '__enter__'):
+ self.__subproc.__enter__()
+ return self
- def __enter__(self):
- return self
-
- def __exit__(self, *args, **kwargs):
+ def __exit__(self, *args, **kwargs):
+ if hasattr(self.__subproc, '__exit__'):
+ return self.__subproc.__exit__(*args, **kwargs)
+ else:
if self.stdout:
self.stdout.close()
if self.stderr:
@@ -1360,30 +1356,21 @@ class Popen(subprocess.Popen):
return object.__getattribute__(self, name)
except AttributeError:
try:
- return object.__getattribute__(self.__psproc, name)
+ return object.__getattribute__(self.__subproc, name)
except AttributeError:
raise AttributeError("%s instance has no attribute '%s'"
% (self.__class__.__name__, name))
- def send_signal(self, sig):
- return self.__psproc.send_signal(sig)
-
- def terminate(self):
- return self.__psproc.terminate()
-
- def kill(self):
- return self.__psproc.kill()
-
def wait(self, timeout=None):
- if sys.version_info < (3, 3):
- # backport of timeout parameter
- if self.returncode is not None:
- return self.returncode
- ret = self.__psproc.wait(timeout)
- self.returncode = ret
- return ret
- else:
- return super(Popen, self).wait(timeout)
+ if self.__subproc.returncode is not None:
+ return self.__subproc.returncode
+ # Note: using psutil's wait() on UNIX should make no difference.
+ # On Windows it does, because PID can still be alive (see
+ # _pswindows.py counterpart addressing this). On Python 2.7 we don't
+ # have timeout arg, so this acts as a backport.
+ ret = Process.wait(self, timeout)
+ self.__subproc.returncode = ret
+ return ret
# =====================================================================