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.
12 __all__
= ["popen2", "popen3", "popen4"]
14 MAXFD
= 256 # Max number of file descriptors (os.getdtablesize()???)
19 for inst
in _active
[:]:
23 """Class representing a child process. Normally instances are created
24 by the factory functions popen2() and popen3()."""
26 sts
= -1 # Child not completed yet
28 def __init__(self
, cmd
, capturestderr
=0, bufsize
=-1):
29 """The parameter 'cmd' is the shell command to execute in a
30 sub-process. The 'capturestderr' flag, if true, specifies that
31 the object should capture standard error output of the child process.
32 The default is false. If the 'bufsize' parameter is specified, it
33 specifies the size of the I/O buffers to/from the child process."""
35 p2cread
, p2cwrite
= os
.pipe()
36 c2pread
, c2pwrite
= os
.pipe()
38 errout
, errin
= os
.pipe()
48 self
.tochild
= os
.fdopen(p2cwrite
, 'w', bufsize
)
50 self
.fromchild
= os
.fdopen(c2pread
, 'r', bufsize
)
53 self
.childerr
= os
.fdopen(errout
, 'r', bufsize
)
58 def _run_child(self
, cmd
):
59 if isinstance(cmd
, basestring
):
60 cmd
= ['/bin/sh', '-c', cmd
]
61 for i
in range(3, MAXFD
):
67 os
.execvp(cmd
[0], cmd
)
72 """Return the exit status of the child process if it has finished,
73 or -1 if it hasn't finished yet."""
76 pid
, sts
= os
.waitpid(self
.pid
, os
.WNOHANG
)
85 """Wait for and return the exit status of the child process."""
86 pid
, sts
= os
.waitpid(self
.pid
, 0)
96 def __init__(self
, cmd
, bufsize
=-1):
98 p2cread
, p2cwrite
= os
.pipe()
99 c2pread
, c2pwrite
= os
.pipe()
108 self
.tochild
= os
.fdopen(p2cwrite
, 'w', bufsize
)
110 self
.fromchild
= os
.fdopen(c2pread
, 'r', bufsize
)
114 if sys
.platform
[:3] == "win" or sys
.platform
== "os2emx":
115 # Some things don't make sense on non-Unix platforms.
118 def popen2(cmd
, bufsize
=-1, mode
='t'):
119 """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is
120 specified, it sets the buffer size for the I/O pipes. The file objects
121 (child_stdout, child_stdin) are returned."""
122 w
, r
= os
.popen2(cmd
, mode
, bufsize
)
125 def popen3(cmd
, bufsize
=-1, mode
='t'):
126 """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is
127 specified, it sets the buffer size for the I/O pipes. The file objects
128 (child_stdout, child_stdin, child_stderr) are returned."""
129 w
, r
, e
= os
.popen3(cmd
, mode
, bufsize
)
132 def popen4(cmd
, bufsize
=-1, mode
='t'):
133 """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is
134 specified, it sets the buffer size for the I/O pipes. The file objects
135 (child_stdout_stderr, child_stdin) are returned."""
136 w
, r
= os
.popen4(cmd
, mode
, bufsize
)
139 def popen2(cmd
, bufsize
=-1, mode
='t'):
140 """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is
141 specified, it sets the buffer size for the I/O pipes. The file objects
142 (child_stdout, child_stdin) are returned."""
143 inst
= Popen3(cmd
, 0, bufsize
)
144 return inst
.fromchild
, inst
.tochild
146 def popen3(cmd
, bufsize
=-1, mode
='t'):
147 """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is
148 specified, it sets the buffer size for the I/O pipes. The file objects
149 (child_stdout, child_stdin, child_stderr) are returned."""
150 inst
= Popen3(cmd
, 1, bufsize
)
151 return inst
.fromchild
, inst
.tochild
, inst
.childerr
153 def popen4(cmd
, bufsize
=-1, mode
='t'):
154 """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is
155 specified, it sets the buffer size for the I/O pipes. The file objects
156 (child_stdout_stderr, child_stdin) are returned."""
157 inst
= Popen4(cmd
, bufsize
)
158 return inst
.fromchild
, inst
.tochild
160 __all__
.extend(["Popen3", "Popen4"])
167 # "more" doesn't act the same way across Windows flavors,
168 # sometimes adding an extra newline at the start or the
169 # end. So we strip whitespace off both ends for comparison.
170 expected
= teststr
.strip()
171 print "testing popen2..."
176 if got
.strip() != expected
:
177 raise ValueError("wrote %s read %s" % (`teststr`
, `got`
))
178 print "testing popen3..."
180 r
, w
, e
= popen3([cmd
])
182 r
, w
, e
= popen3(cmd
)
186 if got
.strip() != expected
:
187 raise ValueError("wrote %s read %s" % (`teststr`
, `got`
))
190 raise ValueError("unexected %s on stderr" % `got`
)
191 for inst
in _active
[:]:
194 raise ValueError("_active not empty")
197 if __name__
== '__main__':