diff options
| author | Giampaolo Rodola <g.rodola@gmail.com> | 2020-05-01 02:20:52 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-05-01 11:20:52 +0200 |
| commit | 8d8a7804d159e5b80378000b57bbfbaf63ce6e8f (patch) | |
| tree | f8a0b45d618ef69faca670bdde8077bb0c20d427 /psutil | |
| parent | 3480e1b05f3e98744a1b6aa6fe286caac86e6bbd (diff) | |
| download | psutil-8d8a7804d159e5b80378000b57bbfbaf63ce6e8f.tar.gz | |
Revert #1736: Popen inheriting from subprocess (#1744)
Diffstat (limited to 'psutil')
| -rw-r--r-- | psutil/__init__.py | 69 | ||||
| -rw-r--r-- | psutil/tests/__init__.py | 21 | ||||
| -rwxr-xr-x | psutil/tests/runner.py | 40 |
3 files changed, 55 insertions, 75 deletions
diff --git a/psutil/__init__.py b/psutil/__init__.py index 028ab049..acf5ee79 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). Python 2.7 doesn't + # have timeout arg, so this acts as a backport. + ret = Process.wait(self, timeout) + self.__subproc.returncode = ret + return ret # ===================================================================== diff --git a/psutil/tests/__init__.py b/psutil/tests/__init__.py index 8ce76304..6cdf3bc8 100644 --- a/psutil/tests/__init__.py +++ b/psutil/tests/__init__.py @@ -486,21 +486,12 @@ def terminate(proc_or_pid, sig=signal.SIGTERM, wait_timeout=GLOBAL_TIMEOUT): from psutil._psposix import wait_pid def wait(proc, timeout): - if sys.version_info < (3, 3) and \ - isinstance(proc, subprocess.Popen) and \ - not isinstance(proc, psutil.Popen): - # subprocess.Popen instance: emulate missing timeout arg. - ret = None - try: - ret = psutil.Process(proc.pid).wait(timeout) - except psutil.NoSuchProcess: - # Needed to kill zombies. - if POSIX: - ret = wait_pid(proc.pid, timeout) - proc.returncode = ret - return ret - else: - return proc.wait(timeout) + try: + return psutil.Process(proc.pid).wait(timeout) + except psutil.NoSuchProcess: + # Needed to kill zombies. + if POSIX: + return wait_pid(proc.pid, timeout) def term_subproc(proc, timeout): try: diff --git a/psutil/tests/runner.py b/psutil/tests/runner.py index ef135c8d..a7f74964 100755 --- a/psutil/tests/runner.py +++ b/psutil/tests/runner.py @@ -53,11 +53,21 @@ from psutil.tests import TOX VERBOSITY = 1 if TOX else 2 FAILED_TESTS_FNAME = '.failed-tests.txt' NWORKERS = psutil.cpu_count() or 1 +USE_COLORS = term_supports_colors() and not APPVEYOR HERE = os.path.abspath(os.path.dirname(__file__)) loadTestsFromTestCase = unittest.defaultTestLoader.loadTestsFromTestCase +def cprint(msg, color, bold=False, file=None): + if file is None: + file = sys.stderr if color == 'red' else sys.stdout + if USE_COLORS: + print_color(msg, color, bold=bold, file=file) + else: + print(msg, file=file) + + class TestLoader: testdir = HERE @@ -110,24 +120,21 @@ class TestLoader: class ColouredResult(unittest.TextTestResult): - def _print_color(self, s, color, bold=False): - print_color(s, color, bold=bold, file=self.stream) - def addSuccess(self, test): unittest.TestResult.addSuccess(self, test) - self._print_color("OK", "green") + cprint("OK", "green") def addError(self, test, err): unittest.TestResult.addError(self, test, err) - self._print_color("ERROR", "red", bold=True) + cprint("ERROR", "red", bold=True) def addFailure(self, test, err): unittest.TestResult.addFailure(self, test, err) - self._print_color("FAIL", "red") + cprint("FAIL", "red") def addSkip(self, test, reason): unittest.TestResult.addSkip(self, test, reason) - self._print_color("skipped: %s" % reason.strip(), "brown") + cprint("skipped: %s" % reason.strip(), "brown") def printErrorList(self, flavour, errors): flavour = hilite(flavour, "red", bold=flavour == 'ERROR') @@ -139,11 +146,7 @@ class ColouredTextRunner(unittest.TextTestRunner): A coloured text runner which also prints failed tests on KeyboardInterrupt and save failed tests in a file so that they can be re-run. """ - - if term_supports_colors() and not APPVEYOR: - resultclass = ColouredResult - else: - resultclass = unittest.TextTestResult + resultclass = ColouredResult if USE_COLORS else unittest.TextTestResult def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -180,11 +183,11 @@ class ColouredTextRunner(unittest.TextTestRunner): def _exit(self, success): if success: - print_color("SUCCESS", "green", bold=True) + cprint("SUCCESS", "green", bold=True) safe_rmpath(FAILED_TESTS_FNAME) sys.exit(0) else: - print_color("FAILED", "red", bold=True) + cprint("FAILED", "red", bold=True) self._write_last_failed() sys.exit(1) @@ -228,8 +231,8 @@ class ParallelRunner(ColouredTextRunner): par_suite = self._parallelize(par_suite) # run parallel - print_color("starting parallel tests using %s workers" % NWORKERS, - "green", bold=True) + cprint("starting parallel tests using %s workers" % NWORKERS, + "green", bold=True) t = time.time() par = self._run(par_suite) par_elapsed = time.time() - t @@ -239,7 +242,7 @@ class ParallelRunner(ColouredTextRunner): orphans = psutil.Process().children() gone, alive = psutil.wait_procs(orphans, timeout=1) if alive: - print_color("alive processes %s" % alive, "red") + cprint("alive processes %s" % alive, "red") reap_children() # run serial @@ -274,8 +277,7 @@ class ParallelRunner(ColouredTextRunner): def get_runner(parallel=False): def warn(msg): - print_color(msg + " Running serial tests instead.", - "red", file=sys.stderr) + cprint(msg + " Running serial tests instead.", "red") if parallel: if psutil.WINDOWS: warn("Can't run parallel tests on Windows.") |
