''' Modern recipe for async subprocesses in Linux and Windows. Works in Python 3.3+. Written March 28, 2014 by Josiah Carlson Released into the public domain. From these two functions you can build buffered reads, writes, timeouts on reads or writes, readline, etc. ''' import errno import os import subprocess import time if subprocess.mswindows: from _winapi import PeekNamedPipe, ReadFile, WriteFile from msvcrt import get_osfhandle else: import fcntl import select def read(sp, stderr=False): """ Reads all available data from the provided subprocess. Pass stderr=True if you want to read from stderr. """ pipe = sp.stderr if stderr else sp.stdout if pipe.closed: return b'' flags = fcntl.fcntl(pipe, fcntl.F_GETFL) fcntl.fcntl(pipe, fcntl.F_SETFL, flags | os.O_NONBLOCK) ret = [] try: while select.select([pipe], [], [], 0)[0]: ret.append(pipe.read(4096)) if not ret[-1]: break return b''.join(ret) finally: if not pipe.closed: fcntl.fcntl(pipe, fcntl.F_SETFL, flags) def write(sp, data): """ Tries to write the data to the provided subprocess. Returns the number of bytes written. """ if not select.select([], [sp.stdin], [], 0)[1]: return 0 try: return os.write(sp.stdin.fileno(), data) except OSError as why: if why[0] == errno.EPIPE: return 0 raise if subprocess.mswindows: def read(sp, stderr=False): """ Reads all available data from the provided subprocess. Pass stderr=True if you want to read from stderr. """ pipe = sp.stderr if stderr else sp.stdout if pipe.closed: return b'' try: handle = get_osfhandle(pipe.fileno()) avail = PeekNamedPipe(handle, 0)[0] if avail > 0: return ReadFile(handle, avail)[0] return b'' except ValueError: return b'' except (subprocess.pywintypes.error, Exception) as why: if why[0] in (109, errno.ESHUTDOWN): return b'' raise def write(sp, data): """ Tries to write the data to the provided subprocess. Returns the number of bytes written. """ try: handle = get_osfhandle(sp.stdin.fileno()) return WriteFile(handle, data)[0] except ValueError: return 0 except (subprocess.pywintypes.error, Exception) as why: if why[0] in (109, errno.ESHUTDOWN): return 0