Home | History | Annotate | Download | only in Lib
      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 import warnings
     12 warnings.warn("The popen2 module is deprecated.  Use the subprocess module.",
     13               DeprecationWarning, stacklevel=2)
     14 
     15 __all__ = ["popen2", "popen3", "popen4"]
     16 
     17 try:
     18     MAXFD = os.sysconf('SC_OPEN_MAX')
     19 except (AttributeError, ValueError):
     20     MAXFD = 256
     21 
     22 _active = []
     23 
     24 def _cleanup():
     25     for inst in _active[:]:
     26         if inst.poll(_deadstate=sys.maxint) >= 0:
     27             try:
     28                 _active.remove(inst)
     29             except ValueError:
     30                 # This can happen if two threads create a new Popen instance.

     31                 # It's harmless that it was already removed, so ignore.

     32                 pass
     33 
     34 class Popen3:
     35     """Class representing a child process.  Normally, instances are created
     36     internally by the functions popen2() and popen3()."""
     37 
     38     sts = -1                    # Child not completed yet

     39 
     40     def __init__(self, cmd, capturestderr=False, bufsize=-1):
     41         """The parameter 'cmd' is the shell command to execute in a
     42         sub-process.  On UNIX, 'cmd' may be a sequence, in which case arguments
     43         will be passed directly to the program without shell intervention (as
     44         with os.spawnv()).  If 'cmd' is a string it will be passed to the shell
     45         (as with os.system()).   The 'capturestderr' flag, if true, specifies
     46         that the object should capture standard error output of the child
     47         process.  The default is false.  If the 'bufsize' parameter is
     48         specified, it specifies the size of the I/O buffers to/from the child
     49         process."""
     50         _cleanup()
     51         self.cmd = cmd
     52         p2cread, p2cwrite = os.pipe()
     53         c2pread, c2pwrite = os.pipe()
     54         if capturestderr:
     55             errout, errin = os.pipe()
     56         self.pid = os.fork()
     57         if self.pid == 0:
     58             # Child

     59             os.dup2(p2cread, 0)
     60             os.dup2(c2pwrite, 1)
     61             if capturestderr:
     62                 os.dup2(errin, 2)
     63             self._run_child(cmd)
     64         os.close(p2cread)
     65         self.tochild = os.fdopen(p2cwrite, 'w', bufsize)
     66         os.close(c2pwrite)
     67         self.fromchild = os.fdopen(c2pread, 'r', bufsize)
     68         if capturestderr:
     69             os.close(errin)
     70             self.childerr = os.fdopen(errout, 'r', bufsize)
     71         else:
     72             self.childerr = None
     73 
     74     def __del__(self):
     75         # In case the child hasn't been waited on, check if it's done.

     76         self.poll(_deadstate=sys.maxint)
     77         if self.sts < 0:
     78             if _active is not None:
     79                 # Child is still running, keep us alive until we can wait on it.

     80                 _active.append(self)
     81 
     82     def _run_child(self, cmd):
     83         if isinstance(cmd, basestring):
     84             cmd = ['/bin/sh', '-c', cmd]
     85         os.closerange(3, MAXFD)
     86         try:
     87             os.execvp(cmd[0], cmd)
     88         finally:
     89             os._exit(1)
     90 
     91     def poll(self, _deadstate=None):
     92         """Return the exit status of the child process if it has finished,
     93         or -1 if it hasn't finished yet."""
     94         if self.sts < 0:
     95             try:
     96                 pid, sts = os.waitpid(self.pid, os.WNOHANG)
     97                 # pid will be 0 if self.pid hasn't terminated

     98                 if pid == self.pid:
     99                     self.sts = sts
    100             except os.error:
    101                 if _deadstate is not None:
    102                     self.sts = _deadstate
    103         return self.sts
    104 
    105     def wait(self):
    106         """Wait for and return the exit status of the child process."""
    107         if self.sts < 0:
    108             pid, sts = os.waitpid(self.pid, 0)
    109             # This used to be a test, but it is believed to be

    110             # always true, so I changed it to an assertion - mvl

    111             assert pid == self.pid
    112             self.sts = sts
    113         return self.sts
    114 
    115 
    116 class Popen4(Popen3):
    117     childerr = None
    118 
    119     def __init__(self, cmd, bufsize=-1):
    120         _cleanup()
    121         self.cmd = cmd
    122         p2cread, p2cwrite = os.pipe()
    123         c2pread, c2pwrite = os.pipe()
    124         self.pid = os.fork()
    125         if self.pid == 0:
    126             # Child

    127             os.dup2(p2cread, 0)
    128             os.dup2(c2pwrite, 1)
    129             os.dup2(c2pwrite, 2)
    130             self._run_child(cmd)
    131         os.close(p2cread)
    132         self.tochild = os.fdopen(p2cwrite, 'w', bufsize)
    133         os.close(c2pwrite)
    134         self.fromchild = os.fdopen(c2pread, 'r', bufsize)
    135 
    136 
    137 if sys.platform[:3] == "win" or sys.platform == "os2emx":
    138     # Some things don't make sense on non-Unix platforms.

    139     del Popen3, Popen4
    140 
    141     def popen2(cmd, bufsize=-1, mode='t'):
    142         """Execute the shell command 'cmd' in a sub-process. On UNIX, 'cmd' may
    143         be a sequence, in which case arguments will be passed directly to the
    144         program without shell intervention (as with os.spawnv()). If 'cmd' is a
    145         string it will be passed to the shell (as with os.system()). If
    146         'bufsize' is specified, it sets the buffer size for the I/O pipes. The
    147         file objects (child_stdout, child_stdin) are returned."""
    148         w, r = os.popen2(cmd, mode, bufsize)
    149         return r, w
    150 
    151     def popen3(cmd, bufsize=-1, mode='t'):
    152         """Execute the shell command 'cmd' in a sub-process. On UNIX, 'cmd' may
    153         be a sequence, in which case arguments will be passed directly to the
    154         program without shell intervention (as with os.spawnv()). If 'cmd' is a
    155         string it will be passed to the shell (as with os.system()). If
    156         'bufsize' is specified, it sets the buffer size for the I/O pipes. The
    157         file objects (child_stdout, child_stdin, child_stderr) are returned."""
    158         w, r, e = os.popen3(cmd, mode, bufsize)
    159         return r, w, e
    160 
    161     def popen4(cmd, bufsize=-1, mode='t'):
    162         """Execute the shell command 'cmd' in a sub-process. On UNIX, 'cmd' may
    163         be a sequence, in which case arguments will be passed directly to the
    164         program without shell intervention (as with os.spawnv()). If 'cmd' is a
    165         string it will be passed to the shell (as with os.system()). If
    166         'bufsize' is specified, it sets the buffer size for the I/O pipes. The
    167         file objects (child_stdout_stderr, child_stdin) are returned."""
    168         w, r = os.popen4(cmd, mode, bufsize)
    169         return r, w
    170 else:
    171     def popen2(cmd, bufsize=-1, mode='t'):
    172         """Execute the shell command 'cmd' in a sub-process. On UNIX, 'cmd' may
    173         be a sequence, in which case arguments will be passed directly to the
    174         program without shell intervention (as with os.spawnv()). If 'cmd' is a
    175         string it will be passed to the shell (as with os.system()). If
    176         'bufsize' is specified, it sets the buffer size for the I/O pipes. The
    177         file objects (child_stdout, child_stdin) are returned."""
    178         inst = Popen3(cmd, False, bufsize)
    179         return inst.fromchild, inst.tochild
    180 
    181     def popen3(cmd, bufsize=-1, mode='t'):
    182         """Execute the shell command 'cmd' in a sub-process. On UNIX, 'cmd' may
    183         be a sequence, in which case arguments will be passed directly to the
    184         program without shell intervention (as with os.spawnv()). If 'cmd' is a
    185         string it will be passed to the shell (as with os.system()). If
    186         'bufsize' is specified, it sets the buffer size for the I/O pipes. The
    187         file objects (child_stdout, child_stdin, child_stderr) are returned."""
    188         inst = Popen3(cmd, True, bufsize)
    189         return inst.fromchild, inst.tochild, inst.childerr
    190 
    191     def popen4(cmd, bufsize=-1, mode='t'):
    192         """Execute the shell command 'cmd' in a sub-process. On UNIX, 'cmd' may
    193         be a sequence, in which case arguments will be passed directly to the
    194         program without shell intervention (as with os.spawnv()). If 'cmd' is a
    195         string it will be passed to the shell (as with os.system()). If
    196         'bufsize' is specified, it sets the buffer size for the I/O pipes. The
    197         file objects (child_stdout_stderr, child_stdin) are returned."""
    198         inst = Popen4(cmd, bufsize)
    199         return inst.fromchild, inst.tochild
    200 
    201     __all__.extend(["Popen3", "Popen4"])
    202