+#! /usr/bin/env python
+
"""Run a subprocess and communicate with it via stdin, stdout, and stderr.
Requires that platform supports, eg, posix-style 'os.pipe' and 'os.fork'
__version__ = "Revision: 1.15 "
-# Id: subproc.py,v 1.15 1998/12/14 20:53:16 klm Exp
+# Id: subproc.py,v 1.15 1998/12/14 20:53:16 klm Exp
# Originally by ken manheimer, ken.manheimer@nist.gov, jan 1995.
# Prior art: Initially based python code examples demonstrating usage of pipes
#
# ken.manheimer@nist.gov
+# This is a modified version by Oleg Broytman <phd@phdru.name>.
+# The original version is still preserved at
+# https://www.python.org/ftp/python/contrib-09-Dec-1999/System/subproc.tar.gz
import sys, os, string, time, types
import select
import signal
-SubprocessError = 'SubprocessError'
+class SubprocessError(Exception):
+ pass
+
# You may need to increase execvp_grace_seconds, if you have a large or slow
# path to search:
execvp_grace_seconds = 0.5
except os.error as error:
errno, msg = error
if errno == 10:
+ self.pid = None
raise SubprocessError("Subprocess '%s' failed." % self.cmd)
+ self.pid = None
raise SubprocessError("Subprocess failed[%d]: %s" % (errno, msg))
if pid == self.pid:
# child exited already
"child killed by signal %d with a return code of %d"
% (sig, rc))
if rc:
+ self.pid = None
raise SubprocessError(
"child exited with return code %d" % rc)
# Child may have exited, but not in error, so we won't say
got0 = self.readPendingChars(n)
got = got + got0
n = n - len(got0)
- return got
+ return got
def readPendingChars(self, max=None):
"""Read all currently pending subprocess output as a single string."""
return self.readbuf.readPendingChars(max)
(sig[0], self.pid, self.cmd,
hex(id(self))[2:])))
for i in self.pipefiles:
- os.close(i)
+ try:
+ fp = os.fdopen(i).close()
+ except OSError:
+ pass
+ del self.pipefiles[:]
self.pid = 0
return None # ===>
time.sleep(.1)
got = ""
if self.buf:
- if (max > 0) and (len(self.buf) > max):
- got = self.buf[0:max]
- self.buf = self.buf[max:]
- else:
- got, self.buf = self.buf, ''
- return got
+ if (max > 0) and (len(self.buf) > max):
+ got = self.buf[0:max]
+ self.buf = self.buf[max:]
+ else:
+ got, self.buf = self.buf, ''
+ return got
if self.eof:
- return ''
+ return ''
sel = select.select([self.fd], [], [self.fd], 0)
if sel[2]:
c.write(s)
c.seek(0)
r = c.read()
- show = " start:\t %s\n end:\t %s\n" % (`s`, `r`)
+ show = " start:\t %s\n end:\t %s\n" % (repr(s), repr(r))
if r != s:
raise IOError("String distorted:\n%s" % show)
line = string.splitfields(line, ':')
it[string.strip(line[0])] = (
string.strip(string.join(line[1:])))
-
+
def getreply(self):
"""Consume next response from ph, returning list of lines or string
err."""
#############################################################################
def test(p=0):
- print("\tOpening subprocess:")
- p = Subprocess('cat', 1) # set to expire noisily...
- print(p)
print("\tOpening bogus subprocess, should fail:")
try:
b = Subprocess('/', 1)
print("\tOops! Null-named subprocess startup *succeeded*?!?")
except SubprocessError:
print("\t...yep, it failed.")
+ print("\tOpening cat subprocess:")
+ p = Subprocess('cat', 1) # set to expire noisily...
+ print(p)
print('\tWrite, then read, two newline-teriminated lines, using readline:')
p.write('first full line written\n'); p.write('second.\n')
- print(`p.readline()`)
- print(`p.readline()`)
+ print(repr(p.readline()))
+ print(repr(p.readline()))
print('\tThree lines, last sans newline, read using combination:')
p.write('first\n'); p.write('second\n'); p.write('third, (no cr)')
print('\tFirst line via readline:')
- print(`p.readline()`)
+ print(repr(p.readline()))
print('\tRest via readPendingChars:')
print(p.readPendingChars())
print("\tStopping then continuing subprocess (verbose):")
del p
print("\tDone.")
return None
+
+if __name__ == '__main__':
+ test()