python-2.5.2/win32/Lib/popen2.py
changeset 0 ae805ac0140d
equal deleted inserted replaced
-1:000000000000 0:ae805ac0140d
       
     1 """Spawn a command with pipes to its stdin, stdout, and optionally stderr.
       
     2 
       
     3 The normal os.popen(cmd, mode) call spawns a shell command and provides a
       
     4 file interface to just the input or output of the process depending on
       
     5 whether mode is 'r' or 'w'.  This module provides the functions popen2(cmd)
       
     6 and popen3(cmd) which return two or three pipes to the spawned command.
       
     7 """
       
     8 
       
     9 import os
       
    10 import sys
       
    11 
       
    12 __all__ = ["popen2", "popen3", "popen4"]
       
    13 
       
    14 try:
       
    15     MAXFD = os.sysconf('SC_OPEN_MAX')
       
    16 except (AttributeError, ValueError):
       
    17     MAXFD = 256
       
    18 
       
    19 _active = []
       
    20 
       
    21 def _cleanup():
       
    22     for inst in _active[:]:
       
    23         if inst.poll(_deadstate=sys.maxint) >= 0:
       
    24             try:
       
    25                 _active.remove(inst)
       
    26             except ValueError:
       
    27                 # This can happen if two threads create a new Popen instance.
       
    28                 # It's harmless that it was already removed, so ignore.
       
    29                 pass
       
    30 
       
    31 class Popen3:
       
    32     """Class representing a child process.  Normally instances are created
       
    33     by the factory functions popen2() and popen3()."""
       
    34 
       
    35     sts = -1                    # Child not completed yet
       
    36 
       
    37     def __init__(self, cmd, capturestderr=False, bufsize=-1):
       
    38         """The parameter 'cmd' is the shell command to execute in a
       
    39         sub-process.  On UNIX, 'cmd' may be a sequence, in which case arguments
       
    40         will be passed directly to the program without shell intervention (as
       
    41         with os.spawnv()).  If 'cmd' is a string it will be passed to the shell
       
    42         (as with os.system()).   The 'capturestderr' flag, if true, specifies
       
    43         that the object should capture standard error output of the child
       
    44         process.  The default is false.  If the 'bufsize' parameter is
       
    45         specified, it specifies the size of the I/O buffers to/from the child
       
    46         process."""
       
    47         _cleanup()
       
    48         self.cmd = cmd
       
    49         p2cread, p2cwrite = os.pipe()
       
    50         c2pread, c2pwrite = os.pipe()
       
    51         if capturestderr:
       
    52             errout, errin = os.pipe()
       
    53         self.pid = os.fork()
       
    54         if self.pid == 0:
       
    55             # Child
       
    56             os.dup2(p2cread, 0)
       
    57             os.dup2(c2pwrite, 1)
       
    58             if capturestderr:
       
    59                 os.dup2(errin, 2)
       
    60             self._run_child(cmd)
       
    61         os.close(p2cread)
       
    62         self.tochild = os.fdopen(p2cwrite, 'w', bufsize)
       
    63         os.close(c2pwrite)
       
    64         self.fromchild = os.fdopen(c2pread, 'r', bufsize)
       
    65         if capturestderr:
       
    66             os.close(errin)
       
    67             self.childerr = os.fdopen(errout, 'r', bufsize)
       
    68         else:
       
    69             self.childerr = None
       
    70 
       
    71     def __del__(self):
       
    72         # In case the child hasn't been waited on, check if it's done.
       
    73         self.poll(_deadstate=sys.maxint)
       
    74         if self.sts < 0:
       
    75             if _active is not None:
       
    76                 # Child is still running, keep us alive until we can wait on it.
       
    77                 _active.append(self)
       
    78 
       
    79     def _run_child(self, cmd):
       
    80         if isinstance(cmd, basestring):
       
    81             cmd = ['/bin/sh', '-c', cmd]
       
    82         for i in xrange(3, MAXFD):
       
    83             try:
       
    84                 os.close(i)
       
    85             except OSError:
       
    86                 pass
       
    87         try:
       
    88             os.execvp(cmd[0], cmd)
       
    89         finally:
       
    90             os._exit(1)
       
    91 
       
    92     def poll(self, _deadstate=None):
       
    93         """Return the exit status of the child process if it has finished,
       
    94         or -1 if it hasn't finished yet."""
       
    95         if self.sts < 0:
       
    96             try:
       
    97                 pid, sts = os.waitpid(self.pid, os.WNOHANG)
       
    98                 # pid will be 0 if self.pid hasn't terminated
       
    99                 if pid == self.pid:
       
   100                     self.sts = sts
       
   101             except os.error:
       
   102                 if _deadstate is not None:
       
   103                     self.sts = _deadstate
       
   104         return self.sts
       
   105 
       
   106     def wait(self):
       
   107         """Wait for and return the exit status of the child process."""
       
   108         if self.sts < 0:
       
   109             pid, sts = os.waitpid(self.pid, 0)
       
   110             # This used to be a test, but it is believed to be
       
   111             # always true, so I changed it to an assertion - mvl
       
   112             assert pid == self.pid
       
   113             self.sts = sts
       
   114         return self.sts
       
   115 
       
   116 
       
   117 class Popen4(Popen3):
       
   118     childerr = None
       
   119 
       
   120     def __init__(self, cmd, bufsize=-1):
       
   121         _cleanup()
       
   122         self.cmd = cmd
       
   123         p2cread, p2cwrite = os.pipe()
       
   124         c2pread, c2pwrite = os.pipe()
       
   125         self.pid = os.fork()
       
   126         if self.pid == 0:
       
   127             # Child
       
   128             os.dup2(p2cread, 0)
       
   129             os.dup2(c2pwrite, 1)
       
   130             os.dup2(c2pwrite, 2)
       
   131             self._run_child(cmd)
       
   132         os.close(p2cread)
       
   133         self.tochild = os.fdopen(p2cwrite, 'w', bufsize)
       
   134         os.close(c2pwrite)
       
   135         self.fromchild = os.fdopen(c2pread, 'r', bufsize)
       
   136 
       
   137 
       
   138 if sys.platform[:3] == "win" or sys.platform == "os2emx":
       
   139     # Some things don't make sense on non-Unix platforms.
       
   140     del Popen3, Popen4
       
   141 
       
   142     def popen2(cmd, bufsize=-1, mode='t'):
       
   143         """Execute the shell command 'cmd' in a sub-process. On UNIX, 'cmd' may
       
   144         be a sequence, in which case arguments will be passed directly to the
       
   145         program without shell intervention (as with os.spawnv()). If 'cmd' is a
       
   146         string it will be passed to the shell (as with os.system()). If
       
   147         'bufsize' is specified, it sets the buffer size for the I/O pipes. The
       
   148         file objects (child_stdout, child_stdin) are returned."""
       
   149         w, r = os.popen2(cmd, mode, bufsize)
       
   150         return r, w
       
   151 
       
   152     def popen3(cmd, bufsize=-1, mode='t'):
       
   153         """Execute the shell command 'cmd' in a sub-process. On UNIX, 'cmd' may
       
   154         be a sequence, in which case arguments will be passed directly to the
       
   155         program without shell intervention (as with os.spawnv()). If 'cmd' is a
       
   156         string it will be passed to the shell (as with os.system()). If
       
   157         'bufsize' is specified, it sets the buffer size for the I/O pipes. The
       
   158         file objects (child_stdout, child_stdin, child_stderr) are returned."""
       
   159         w, r, e = os.popen3(cmd, mode, bufsize)
       
   160         return r, w, e
       
   161 
       
   162     def popen4(cmd, bufsize=-1, mode='t'):
       
   163         """Execute the shell command 'cmd' in a sub-process. On UNIX, 'cmd' may
       
   164         be a sequence, in which case arguments will be passed directly to the
       
   165         program without shell intervention (as with os.spawnv()). If 'cmd' is a
       
   166         string it will be passed to the shell (as with os.system()). If
       
   167         'bufsize' is specified, it sets the buffer size for the I/O pipes. The
       
   168         file objects (child_stdout_stderr, child_stdin) are returned."""
       
   169         w, r = os.popen4(cmd, mode, bufsize)
       
   170         return r, w
       
   171 else:
       
   172     def popen2(cmd, bufsize=-1, mode='t'):
       
   173         """Execute the shell command 'cmd' in a sub-process. On UNIX, 'cmd' may
       
   174         be a sequence, in which case arguments will be passed directly to the
       
   175         program without shell intervention (as with os.spawnv()). If 'cmd' is a
       
   176         string it will be passed to the shell (as with os.system()). If
       
   177         'bufsize' is specified, it sets the buffer size for the I/O pipes. The
       
   178         file objects (child_stdout, child_stdin) are returned."""
       
   179         inst = Popen3(cmd, False, bufsize)
       
   180         return inst.fromchild, inst.tochild
       
   181 
       
   182     def popen3(cmd, bufsize=-1, mode='t'):
       
   183         """Execute the shell command 'cmd' in a sub-process. On UNIX, 'cmd' may
       
   184         be a sequence, in which case arguments will be passed directly to the
       
   185         program without shell intervention (as with os.spawnv()). If 'cmd' is a
       
   186         string it will be passed to the shell (as with os.system()). If
       
   187         'bufsize' is specified, it sets the buffer size for the I/O pipes. The
       
   188         file objects (child_stdout, child_stdin, child_stderr) are returned."""
       
   189         inst = Popen3(cmd, True, bufsize)
       
   190         return inst.fromchild, inst.tochild, inst.childerr
       
   191 
       
   192     def popen4(cmd, bufsize=-1, mode='t'):
       
   193         """Execute the shell command 'cmd' in a sub-process. On UNIX, 'cmd' may
       
   194         be a sequence, in which case arguments will be passed directly to the
       
   195         program without shell intervention (as with os.spawnv()). If 'cmd' is a
       
   196         string it will be passed to the shell (as with os.system()). If
       
   197         'bufsize' is specified, it sets the buffer size for the I/O pipes. The
       
   198         file objects (child_stdout_stderr, child_stdin) are returned."""
       
   199         inst = Popen4(cmd, bufsize)
       
   200         return inst.fromchild, inst.tochild
       
   201 
       
   202     __all__.extend(["Popen3", "Popen4"])
       
   203 
       
   204 def _test():
       
   205     # When the test runs, there shouldn't be any open pipes
       
   206     _cleanup()
       
   207     assert not _active, "Active pipes when test starts " + repr([c.cmd for c in _active])
       
   208     cmd  = "cat"
       
   209     teststr = "ab cd\n"
       
   210     if os.name == "nt":
       
   211         cmd = "more"
       
   212     # "more" doesn't act the same way across Windows flavors,
       
   213     # sometimes adding an extra newline at the start or the
       
   214     # end.  So we strip whitespace off both ends for comparison.
       
   215     expected = teststr.strip()
       
   216     print "testing popen2..."
       
   217     r, w = popen2(cmd)
       
   218     w.write(teststr)
       
   219     w.close()
       
   220     got = r.read()
       
   221     if got.strip() != expected:
       
   222         raise ValueError("wrote %r read %r" % (teststr, got))
       
   223     print "testing popen3..."
       
   224     try:
       
   225         r, w, e = popen3([cmd])
       
   226     except:
       
   227         r, w, e = popen3(cmd)
       
   228     w.write(teststr)
       
   229     w.close()
       
   230     got = r.read()
       
   231     if got.strip() != expected:
       
   232         raise ValueError("wrote %r read %r" % (teststr, got))
       
   233     got = e.read()
       
   234     if got:
       
   235         raise ValueError("unexpected %r on stderr" % (got,))
       
   236     for inst in _active[:]:
       
   237         inst.wait()
       
   238     _cleanup()
       
   239     if _active:
       
   240         raise ValueError("_active not empty")
       
   241     print "All OK"
       
   242 
       
   243 if __name__ == '__main__':
       
   244     _test()