From b0dfb659ded9ac9661041391ee03ffbf4276e348 Mon Sep 17 00:00:00 2001 From: Joseph Gardi Date: Tue, 11 Jun 2019 04:34:06 -0700 Subject: [PATCH] Added print and wait --- bash/__init__.py | 34 +++++++++++++++++++++++++++++++++- tests.py | 16 ++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/bash/__init__.py b/bash/__init__.py index d8da050..0cb47ef 100644 --- a/bash/__init__.py +++ b/bash/__init__.py @@ -1,4 +1,4 @@ -import sys +import sys, time from subprocess import PIPE, Popen SUBPROCESS_HAS_TIMEOUT = True if sys.version_info < (3, 0): @@ -39,6 +39,7 @@ def sync(self, timeout=None): self.code = self.p.returncode return self + def __repr__(self): return self.value() @@ -58,3 +59,34 @@ def value(self): if self.stdout: return self.stdout.strip().decode(encoding='UTF-8') return '' + + def print_and_wait(self): + """ + Continuously prints stdout and stderr of the subprocess to stdout in realtime + Returns the exit code of the subprocess once the process finishes running. + Note that if you do the following you will not see the stdout and stderr from the + subprocess until after the process completes, + process = bash('') + process.print_and_wait() + The process will finish synchronously when bash is called before print_and_wait gets called. + To see the output in realtime do the following, + process = bash('', sync=False) + process.print_and_wait() + """ + while True: + out_line = self.p.stdout.readline().decode() + err_line = self.p.stderr.readline().decode() + if len(out_line) > 0: + print(out_line) + elif len(err_line) > 0: + print(err_line) + elif self.p.poll() is None: + time.sleep(.05) + else: + break + + exit_code = self.p.poll() + print(f'exit code {exit_code} from subprocess') + return exit_code + + diff --git a/tests.py b/tests.py index 41263b4..9842a8e 100644 --- a/tests.py +++ b/tests.py @@ -1,5 +1,6 @@ from datetime import datetime import unittest +import io, sys try: from subprocess import TimeoutExpired @@ -66,3 +67,18 @@ def test_sync_false_does_not_wait(self): self.assertTrue((t2-t1).total_seconds() < 0.5) b.sync() self.assertEqual(b.stdout, b'1\n') + + def test_print_and_wait(self): + b = bash('echo hey', sync=False) + # with help from https://stackoverflow.com/a/35779140/3781537 + old_stdout = sys.stdout + sys.stdout = io.StringIO() + b.print_and_wait() + what_was_printed = sys.stdout.getvalue() + self.assertTrue('hey' in what_was_printed) + + sys.stdout = io.StringIO() + b = bash('./missing_command', sync=False) + b.print_and_wait() + self.assertTrue('No such file or directory' in sys.stdout.getvalue()) + sys.stdout = old_stdout