import select import os def proc_communicate(proc, stdin=None, stdout=None, stderr=None): """ Run the given process, piping input/output/errors to the given file-like objects (which need not be actual file objects, unlike the arguments passed to Popen). Wait for process to terminate. Note: this is taken from the posix version of subprocess.Popen.communicate, but made more general through the use of file-like objects. """ read_set = [] write_set = [] input_buffer = '' trans_nl = proc.universal_newlines and hasattr(open, 'newlines') if proc.stdin: # Flush stdio buffer. This might block, if the user has # been writing to .stdin in an uncontrolled fashion. proc.stdin.flush() if input: write_set.append(proc.stdin) else: proc.stdin.close() else: assert stdin is None if proc.stdout: read_set.append(proc.stdout) else: assert stdout is None if proc.stderr: read_set.append(proc.stderr) else: assert stderr is None while read_set or write_set: rlist, wlist, xlist = select.select(read_set, write_set, []) if proc.stdin in wlist: # When select has indicated that the file is writable, # we can write up to PIPE_BUF bytes without risk # blocking. POSIX defines PIPE_BUF >= 512 next, input_buffer = input_buffer, '' next_len = 512-len(next) if next_len: next += stdin.read(next_len) if not next: proc.stdin.close() write_set.remove(proc.stdin) else: bytes_written = os.write(proc.stdin.fileno(), next) if bytes_written < len(next): input_buffer = next[bytes_written:] if proc.stdout in rlist: data = os.read(proc.stdout.fileno(), 1024) if data == "": proc.stdout.close() read_set.remove(proc.stdout) if trans_nl: data = proc._translate_newlines(data) stdout.write(data) if proc.stderr in rlist: data = os.read(proc.stderr.fileno(), 1024) if data == "": proc.stderr.close() read_set.remove(proc.stderr) if trans_nl: data = proc._translate_newlines(data) stderr.write(data) proc.wait()