diff --git a/subprocess2.py b/subprocess2.py index c6ff24f6b..c9057ac6a 100644 --- a/subprocess2.py +++ b/subprocess2.py @@ -19,6 +19,9 @@ import threading # Constants forwarded from subprocess. PIPE = subprocess.PIPE STDOUT = subprocess.STDOUT +# Sends stdout or stderr to os.devnull. +VOID = '/dev/null' + # Globals. # Set to True if you somehow need to disable this hack. @@ -123,13 +126,15 @@ def get_english_env(env): def Popen(args, **kwargs): """Wraps subprocess.Popen(). - Forces English output since it's easier to parse the stdout if it is always in - English. + Returns a subprocess.Popen object. - Sets shell=True on windows by default. You can override this by forcing shell - parameter to a value. + - Forces English output since it's easier to parse the stdout if it is always + in English. + - Sets shell=True on windows by default. You can override this by forcing + shell parameter to a value. + - Adds support for VOID to not buffer when not needed. - Popen() can throw OSError when cwd or args[0] doesn't exist. + Note: Popen() can throw OSError when cwd or args[0] doesn't exist. """ # Make sure we hack subprocess if necessary. hack_subprocess() @@ -149,17 +154,22 @@ def Popen(args, **kwargs): if kwargs.get('cwd', None): tmp_str += '; cwd=%s' % kwargs['cwd'] logging.debug(tmp_str) + + # Replaces VOID with handle to /dev/null. + if kwargs.get('stdout') in (VOID, os.devnull): + kwargs['stdout'] = open(os.devnull, 'w') + if kwargs.get('stderr') in (VOID, os.devnull): + kwargs['stderr'] = open(os.devnull, 'w') return subprocess.Popen(args, **kwargs) def call(args, timeout=None, **kwargs): """Wraps subprocess.Popen().communicate(). - The process will be kill with error code -9 after |timeout| seconds if set. - - Automatically passes stdin content as input so do not specify stdin=PIPE. + Returns ((stdout, stderr), returncode). - Returns both communicate() tuple and return code wrapped in a tuple. + - The process will be kill with error code -9 after |timeout| seconds if set. + - Automatically passes stdin content as input so do not specify stdin=PIPE. """ stdin = kwargs.pop('stdin', None) if stdin is not None: @@ -204,13 +214,9 @@ def call(args, timeout=None, **kwargs): def check_call(args, **kwargs): - """Similar to subprocess.check_call() but use call() instead. + """Improved version of subprocess.check_call(). - This permits to include more details in CalledProcessError(). - - Runs a command and throws an exception if the command failed. - - Returns communicate() tuple. + Returns (stdout, stderr), unlike subprocess.check_call(). """ out, returncode = call(args, **kwargs) if returncode: @@ -222,9 +228,10 @@ def check_call(args, **kwargs): def capture(args, **kwargs): """Captures stdout of a process call and returns it. - Similar to check_output() excepts that it discards return code. + Returns stdout. - Discards communicate()[1]. By default sets stderr=STDOUT. + - Discards returncode. + - Discards stderr. By default sets stderr=STDOUT. """ if kwargs.get('stderr') is None: kwargs['stderr'] = STDOUT @@ -234,11 +241,11 @@ def capture(args, **kwargs): def check_output(args, **kwargs): """Captures stdout of a process call and returns it. - Discards communicate()[1]. By default sets stderr=STDOUT. - - Throws if return code is not 0. + Returns stdout. - Works even prior to python 2.7. + - Discards stderr. By default sets stderr=STDOUT. + - Throws if return code is not 0. + - Works even prior to python 2.7. """ if kwargs.get('stderr') is None: kwargs['stderr'] = STDOUT diff --git a/tests/local_rietveld.py b/tests/local_rietveld.py index d14da5628..b2efb3ff6 100755 --- a/tests/local_rietveld.py +++ b/tests/local_rietveld.py @@ -58,8 +58,6 @@ class LocalRietveld(object): self.rietveld = os.path.join(self.base_dir, 'tests', 'rietveld') self.test_server = None self.port = None - self.out = None - self.err = None def install_prerequisites(self): # First, verify the Google AppEngine SDK is available. @@ -87,11 +85,9 @@ class LocalRietveld(object): self.install_prerequisites() self.port = find_free_port() if verbose: - self.out = None - self.err = None + pipe = None else: - self.out = open(os.devnull, 'w') - self.err = open(os.devnull, 'w') + pipe = subprocess2.VOID cmd = [ self.dev_app, '--skip_sdk_update_check', @@ -100,7 +96,7 @@ class LocalRietveld(object): '--datastore_path=' + os.path.join(self.rietveld, 'tmp.db'), '-c'] self.test_server = subprocess2.Popen( - cmd, stdout=self.out, stderr=self.err, cwd=self.rietveld) + cmd, stdout=pipe, stderr=pipe, cwd=self.rietveld) # Loop until port 127.0.0.1:port opens or the process dies. while not test_port(self.port): self.test_server.poll() @@ -116,12 +112,6 @@ class LocalRietveld(object): self.test_server.wait() self.test_server = None self.port = None - if self.out: - self.out.close() - self.out = None - if self.err: - self.err.close() - self.err = None def main():