Advertisement
Guest User

Async subprocess for Linux and Windows, revisited

a guest
Mar 28th, 2014
471
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 2.71 KB | None | 0 0
  1.  
  2. '''
  3. Modern recipe for async subprocesses in Linux and Windows. Works in Python 3.3+.
  4. Written March 28, 2014 by Josiah Carlson
  5.  
  6. Released into the public domain.
  7.  
  8. From these two functions you can build buffered reads, writes, timeouts on
  9. reads or writes, readline, etc.
  10. '''
  11.  
  12. import errno
  13. import os
  14. import subprocess
  15. import time
  16.  
  17. if subprocess.mswindows:
  18.     from _winapi import PeekNamedPipe, ReadFile, WriteFile
  19.     from msvcrt import get_osfhandle
  20. else:
  21.     import fcntl
  22.     import select
  23.  
  24. def read(sp, stderr=False):
  25.     """
  26.    Reads all available data from the provided subprocess.
  27.  
  28.    Pass stderr=True if you want to read from stderr.
  29.    """
  30.    
  31.     pipe = sp.stderr if stderr else sp.stdout
  32.     if pipe.closed:
  33.         return b''
  34.  
  35.     flags = fcntl.fcntl(pipe, fcntl.F_GETFL)
  36.     fcntl.fcntl(pipe, fcntl.F_SETFL, flags | os.O_NONBLOCK)
  37.     ret = []
  38.     try:
  39.         while select.select([pipe], [], [], 0)[0]:
  40.             ret.append(pipe.read(4096))
  41.             if not ret[-1]:
  42.                 break
  43.         return b''.join(ret)
  44.     finally:
  45.         if not pipe.closed:
  46.             fcntl.fcntl(pipe, fcntl.F_SETFL, flags)
  47.  
  48. def write(sp, data):
  49.     """
  50.    Tries to write the data to the provided subprocess.
  51.  
  52.    Returns the number of bytes written.
  53.    """
  54.     if not select.select([], [sp.stdin], [], 0)[1]:
  55.         return 0
  56.  
  57.     try:
  58.         return os.write(sp.stdin.fileno(), data)
  59.     except OSError as why:
  60.         if why[0] == errno.EPIPE:
  61.             return 0
  62.         raise
  63.  
  64. if subprocess.mswindows:
  65.     def read(sp, stderr=False):
  66.         """
  67.        Reads all available data from the provided subprocess.
  68.        
  69.        Pass stderr=True if you want to read from stderr.
  70.        """
  71.         pipe = sp.stderr if stderr else sp.stdout
  72.         if pipe.closed:
  73.             return b''
  74.  
  75.         try:
  76.             handle = get_osfhandle(pipe.fileno())
  77.             avail = PeekNamedPipe(handle, 0)[0]
  78.             if avail > 0:
  79.                 return ReadFile(handle, avail)[0]
  80.             return b''
  81.         except ValueError:
  82.             return b''
  83.         except (subprocess.pywintypes.error, Exception) as why:
  84.             if why[0] in (109, errno.ESHUTDOWN):
  85.                 return b''
  86.             raise
  87.  
  88.     def write(sp, data):
  89.         """
  90.        Tries to write the data to the provided subprocess.
  91.  
  92.        Returns the number of bytes written.
  93.        """
  94.         try:
  95.             handle = get_osfhandle(sp.stdin.fileno())
  96.             return WriteFile(handle, data)[0]
  97.         except ValueError:
  98.             return 0
  99.         except (subprocess.pywintypes.error, Exception) as why:
  100.             if why[0] in (109, errno.ESHUTDOWN):
  101.                 return 0
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement