Its right now.
[python.git] / Lib / popen2.py
blob54543bed0f8d355c72ec37a09b0dbb2ede7b45fd
1 """Spawn a command with pipes to its stdin, stdout, and optionally stderr.
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 """
9 import os
10 import sys
12 __all__ = ["popen2", "popen3", "popen4"]
14 try:
15 MAXFD = os.sysconf('SC_OPEN_MAX')
16 except (AttributeError, ValueError):
17 MAXFD = 256
19 _active = []
21 def _cleanup():
22 for inst in _active[:]:
23 inst.poll()
25 class Popen3:
26 """Class representing a child process. Normally instances are created
27 by the factory functions popen2() and popen3()."""
29 sts = -1 # Child not completed yet
31 def __init__(self, cmd, capturestderr=False, bufsize=-1):
32 """The parameter 'cmd' is the shell command to execute in a
33 sub-process. On UNIX, 'cmd' may be a sequence, in which case arguments
34 will be passed directly to the program without shell intervention (as
35 with os.spawnv()). If 'cmd' is a string it will be passed to the shell
36 (as with os.system()). The 'capturestderr' flag, if true, specifies
37 that the object should capture standard error output of the child
38 process. The default is false. If the 'bufsize' parameter is
39 specified, it specifies the size of the I/O buffers to/from the child
40 process."""
41 _cleanup()
42 p2cread, p2cwrite = os.pipe()
43 c2pread, c2pwrite = os.pipe()
44 if capturestderr:
45 errout, errin = os.pipe()
46 self.pid = os.fork()
47 if self.pid == 0:
48 # Child
49 os.dup2(p2cread, 0)
50 os.dup2(c2pwrite, 1)
51 if capturestderr:
52 os.dup2(errin, 2)
53 self._run_child(cmd)
54 os.close(p2cread)
55 self.tochild = os.fdopen(p2cwrite, 'w', bufsize)
56 os.close(c2pwrite)
57 self.fromchild = os.fdopen(c2pread, 'r', bufsize)
58 if capturestderr:
59 os.close(errin)
60 self.childerr = os.fdopen(errout, 'r', bufsize)
61 else:
62 self.childerr = None
63 _active.append(self)
65 def _run_child(self, cmd):
66 if isinstance(cmd, basestring):
67 cmd = ['/bin/sh', '-c', cmd]
68 for i in range(3, MAXFD):
69 try:
70 os.close(i)
71 except OSError:
72 pass
73 try:
74 os.execvp(cmd[0], cmd)
75 finally:
76 os._exit(1)
78 def poll(self):
79 """Return the exit status of the child process if it has finished,
80 or -1 if it hasn't finished yet."""
81 if self.sts < 0:
82 try:
83 pid, sts = os.waitpid(self.pid, os.WNOHANG)
84 if pid == self.pid:
85 self.sts = sts
86 _active.remove(self)
87 except os.error:
88 pass
89 return self.sts
91 def wait(self):
92 """Wait for and return the exit status of the child process."""
93 if self.sts < 0:
94 pid, sts = os.waitpid(self.pid, 0)
95 if pid == self.pid:
96 self.sts = sts
97 _active.remove(self)
98 return self.sts
101 class Popen4(Popen3):
102 childerr = None
104 def __init__(self, cmd, bufsize=-1):
105 _cleanup()
106 p2cread, p2cwrite = os.pipe()
107 c2pread, c2pwrite = os.pipe()
108 self.pid = os.fork()
109 if self.pid == 0:
110 # Child
111 os.dup2(p2cread, 0)
112 os.dup2(c2pwrite, 1)
113 os.dup2(c2pwrite, 2)
114 self._run_child(cmd)
115 os.close(p2cread)
116 self.tochild = os.fdopen(p2cwrite, 'w', bufsize)
117 os.close(c2pwrite)
118 self.fromchild = os.fdopen(c2pread, 'r', bufsize)
119 _active.append(self)
122 if sys.platform[:3] == "win" or sys.platform == "os2emx":
123 # Some things don't make sense on non-Unix platforms.
124 del Popen3, Popen4
126 def popen2(cmd, bufsize=-1, mode='t'):
127 """Execute the shell command 'cmd' in a sub-process. On UNIX, 'cmd' may
128 be a sequence, in which case arguments will be passed directly to the
129 program without shell intervention (as with os.spawnv()). If 'cmd' is a
130 string it will be passed to the shell (as with os.system()). If
131 'bufsize' is specified, it sets the buffer size for the I/O pipes. The
132 file objects (child_stdout, child_stdin) are returned."""
133 w, r = os.popen2(cmd, mode, bufsize)
134 return r, w
136 def popen3(cmd, bufsize=-1, mode='t'):
137 """Execute the shell command 'cmd' in a sub-process. On UNIX, 'cmd' may
138 be a sequence, in which case arguments will be passed directly to the
139 program without shell intervention (as with os.spawnv()). If 'cmd' is a
140 string it will be passed to the shell (as with os.system()). If
141 'bufsize' is specified, it sets the buffer size for the I/O pipes. The
142 file objects (child_stdout, child_stdin, child_stderr) are returned."""
143 w, r, e = os.popen3(cmd, mode, bufsize)
144 return r, w, e
146 def popen4(cmd, bufsize=-1, mode='t'):
147 """Execute the shell command 'cmd' in a sub-process. On UNIX, 'cmd' may
148 be a sequence, in which case arguments will be passed directly to the
149 program without shell intervention (as with os.spawnv()). If 'cmd' is a
150 string it will be passed to the shell (as with os.system()). If
151 'bufsize' is specified, it sets the buffer size for the I/O pipes. The
152 file objects (child_stdout_stderr, child_stdin) are returned."""
153 w, r = os.popen4(cmd, mode, bufsize)
154 return r, w
155 else:
156 def popen2(cmd, bufsize=-1, mode='t'):
157 """Execute the shell command 'cmd' in a sub-process. On UNIX, 'cmd' may
158 be a sequence, in which case arguments will be passed directly to the
159 program without shell intervention (as with os.spawnv()). If 'cmd' is a
160 string it will be passed to the shell (as with os.system()). If
161 'bufsize' is specified, it sets the buffer size for the I/O pipes. The
162 file objects (child_stdout, child_stdin) are returned."""
163 inst = Popen3(cmd, False, bufsize)
164 return inst.fromchild, inst.tochild
166 def popen3(cmd, bufsize=-1, mode='t'):
167 """Execute the shell command 'cmd' in a sub-process. On UNIX, 'cmd' may
168 be a sequence, in which case arguments will be passed directly to the
169 program without shell intervention (as with os.spawnv()). If 'cmd' is a
170 string it will be passed to the shell (as with os.system()). If
171 'bufsize' is specified, it sets the buffer size for the I/O pipes. The
172 file objects (child_stdout, child_stdin, child_stderr) are returned."""
173 inst = Popen3(cmd, True, bufsize)
174 return inst.fromchild, inst.tochild, inst.childerr
176 def popen4(cmd, bufsize=-1, mode='t'):
177 """Execute the shell command 'cmd' in a sub-process. On UNIX, 'cmd' may
178 be a sequence, in which case arguments will be passed directly to the
179 program without shell intervention (as with os.spawnv()). If 'cmd' is a
180 string it will be passed to the shell (as with os.system()). If
181 'bufsize' is specified, it sets the buffer size for the I/O pipes. The
182 file objects (child_stdout_stderr, child_stdin) are returned."""
183 inst = Popen4(cmd, bufsize)
184 return inst.fromchild, inst.tochild
186 __all__.extend(["Popen3", "Popen4"])
188 def _test():
189 cmd = "cat"
190 teststr = "ab cd\n"
191 if os.name == "nt":
192 cmd = "more"
193 # "more" doesn't act the same way across Windows flavors,
194 # sometimes adding an extra newline at the start or the
195 # end. So we strip whitespace off both ends for comparison.
196 expected = teststr.strip()
197 print "testing popen2..."
198 r, w = popen2(cmd)
199 w.write(teststr)
200 w.close()
201 got = r.read()
202 if got.strip() != expected:
203 raise ValueError("wrote %r read %r" % (teststr, got))
204 print "testing popen3..."
205 try:
206 r, w, e = popen3([cmd])
207 except:
208 r, w, e = popen3(cmd)
209 w.write(teststr)
210 w.close()
211 got = r.read()
212 if got.strip() != expected:
213 raise ValueError("wrote %r read %r" % (teststr, got))
214 got = e.read()
215 if got:
216 raise ValueError("unexpected %r on stderr" % (got,))
217 for inst in _active[:]:
218 inst.wait()
219 if _active:
220 raise ValueError("_active not empty")
221 print "All OK"
223 if __name__ == '__main__':
224 _test()