From a66745abb2ff9ec50535f608d1deb468bad4d85c Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 5 Oct 2017 19:22:08 +0300 Subject: [PATCH] Cleanup: Fix flake8 errors/warnings --- subproc.py | 143 +++++++++++++++++++++++++++++++++-------------------- 1 file changed, 90 insertions(+), 53 deletions(-) diff --git a/subproc.py b/subproc.py index b5944f9..886dc47 100755 --- a/subproc.py +++ b/subproc.py @@ -16,7 +16,7 @@ Subprocess class features: - Subprocess objects have nice, informative string rep (as every good object ought).""" -__version__ = "Revision: 1.15 " +__version__ = "Revision: 2.0 " # Id: subproc.py,v 1.15 1998/12/14 20:53:16 klm Exp # Originally by ken manheimer, ken.manheimer@nist.gov, jan 1995. @@ -46,18 +46,23 @@ __version__ = "Revision: 1.15 " # 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 os import select import signal +import string +import sys +import time 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 + class Subprocess: """Run and communicate asynchronously with a subprocess. @@ -94,8 +99,8 @@ class Subprocess: def fork(self, cmd=None): """Fork a subprocess with designated COMMAND (default, self.cmd).""" - if cmd: self.cmd = cmd - else: cmd = self.cmd + if cmd: + self.cmd = cmd cmd = string.split(self.cmd) pRc, cWp = os.pipe() # parent-read-child, child-write-parent cRp, pWc = os.pipe() # child-read-parent, parent-write-child @@ -104,8 +109,9 @@ class Subprocess: self.pid = os.fork() - if self.pid == 0: #### CHILD #### - parentErr = os.dup(self.in_fd) # Preserve handle on *parent* stderr + if self.pid == 0: #### CHILD #### noqa: E262 + # Preserve handle on *parent* stderr + parentErr = os.dup(self.in_fd) # Reopen stdin, out, err, on pipe ends: os.dup2(cRp, self.in_fd) # cRp = sys.stdin os.dup2(cWp, self.out_fd) # cWp = sys.stdout @@ -113,10 +119,12 @@ class Subprocess: os.dup2(cWe, self.err_fd) # cWe = sys.stderr # Ensure (within reason) stray file descriptors are closed: excludes = [self.in_fd, self.out_fd, self.err_fd] - for i in range(4,100): + for i in range(4, 100): if i not in excludes: - try: os.close(i) - except os.error: pass + try: + os.close(i) + except os.error: + pass try: os.execvp(cmd[0], cmd) @@ -130,7 +138,7 @@ class Subprocess: os._exit(1) os._exit(1) # Shouldn't get here. - else: ### PARENT ### + else: ### PARENT ### noqa: E262 # Connect to the child's file descriptors, using our customized # fdopen: self.toChild = os.fdopen(pWc, 'w') @@ -146,31 +154,31 @@ class Subprocess: self.pid = None raise SubprocessError("Subprocess '%s' failed." % self.cmd) self.pid = None - raise SubprocessError("Subprocess failed[%d]: %s" % (errno, msg)) + raise SubprocessError( + "Subprocess failed[%d]: %s" % (errno, msg)) if pid == self.pid: # child exited already - self.pid == None + self.pid = None sig = err & 0xff rc = (err & 0xff00) >> 8 if sig: raise SubprocessError( - "child killed by signal %d with a return code of %d" - % (sig, rc)) + "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 # anything more at this point. - ### Write input to subprocess ### + ### Write input to subprocess ### noqa: E266 def write(self, str): """Write a STRING to the subprocess.""" if not self.pid: raise SubprocessError("no child") # ===> - if select.select([],self.toChild_fdlist,[],0)[1]: + if select.select([], self.toChild_fdlist, [], 0)[1]: self.toChild.write(str) self.toChild.flush() else: @@ -181,13 +189,14 @@ class Subprocess: """Write STRING, with added newline termination, to subprocess.""" self.write(line + '\n') - ### Get output from subprocess ### + ### Get output from subprocess ### noqa: E266 def peekPendingChar(self): """Return, but (effectively) do not consume a single pending output char, or return null string if none pending.""" return self.readbuf.peekPendingChar() # ===> + def peekPendingErrChar(self): """Return, but (effectively) do not consume a single pending output char, or return null string if none pending.""" @@ -203,13 +212,14 @@ class Subprocess: accume = 0 while 1: nextChar = self.readbuf.peekPendingChar() - if nextChar or (accume > timeout): return nextChar + if nextChar or (accume > timeout): + return nextChar time.sleep(pollPause) accume = accume + pollPause def read(self, n=None): """Read N chars, or all pending if no N specified.""" - if n == None: + if n is None: return self.readPendingChars() got = '' while n: @@ -217,9 +227,11 @@ class Subprocess: got = got + got0 n = n - len(got0) return got + def readPendingChars(self, max=None): """Read all currently pending subprocess output as a single string.""" return self.readbuf.readPendingChars(max) + def readPendingErrChars(self): """Read all currently pending subprocess error output as a single string.""" @@ -232,6 +244,7 @@ class Subprocess: """Read currently pending subprocess output, up to a complete line (newline inclusive).""" return self.readbuf.readPendingLine() + def readPendingErrLine(self): """Read currently pending subprocess error output, up to a complete line (newline inclusive).""" @@ -244,6 +257,7 @@ class Subprocess: """Return next complete line of subprocess output, blocking until then.""" return self.readbuf.readline() + def readlineErr(self): """Return next complete line of subprocess error output, blocking until then.""" @@ -252,11 +266,12 @@ class Subprocess: else: raise SubprocessError("Haven't grabbed subprocess error stream.") - ### Subprocess Control ### + ### Subprocess Control ### noqa: E266 def active(self): """True if subprocess is alive and kicking.""" return self.status(boolean=1) + def status(self, boolean=0): """Return string indicating whether process is alive or dead.""" active = 0 @@ -281,9 +296,11 @@ class Subprocess: os.kill(self.pid, signal.SIGSTOP) except os.error: if verbose: - print("Stop failed for '%s' - '%s'" % (self.cmd, sys.exc_value)) + print( + "Stop failed for '%s' - '%s'" % (self.cmd, sys.exc_value)) return 0 - if verbose: print("Stopped '%s'" % self.cmd) + if verbose: + print("Stopped '%s'" % self.cmd) return 'stopped' def cont(self, verbose=0): @@ -296,7 +313,8 @@ class Subprocess: print(("Continue failed for '%s' - '%s'" % (self.cmd, sys.exc_value))) return 0 - if verbose: print("Continued '%s'" % self.cmd) + if verbose: + print("Continued '%s'" % self.cmd) return 'continued' def die(self): @@ -311,12 +329,11 @@ class Subprocess: raise SubprocessError("Can't signal subproc %s" % self) # ===> # Try sending first a TERM and then a KILL signal. - keep_trying = 1 sigs = [('TERMinated', signal.SIGTERM), ('KILLed', signal.SIGKILL)] for sig in sigs: try: os.kill(self.pid, sig[1]) - except posix.error: + except OSError: # keep trying pass # Try a couple or three times to reap the process with waitpid: @@ -329,7 +346,7 @@ class Subprocess: hex(id(self))[2:]))) for i in self.pipefiles: try: - fp = os.fdopen(i).close() + os.fdopen(i).close() except OSError: pass del self.pipefiles[:] @@ -339,7 +356,7 @@ class Subprocess: # Only got here if subprocess is not gone: raise SubprocessError( "Failed kill of subproc %d, '%s', with signals %s" % - (self.pid, self.cmd, map(lambda x: x[0], sigs))) + (self.pid, self.cmd, map(lambda x: x[0], sigs))) def __del__(self): """Terminate the subprocess""" @@ -350,9 +367,11 @@ class Subprocess: status = self.status() return '' -############################################################################# -##### Non-blocking read operations ##### -############################################################################# + +############################################################################## +##### Non-blocking read operations ##### noqa: E266 +############################################################################## + class ReadBuf: """Output buffer for non-blocking reads on selectable files like pipes and @@ -388,8 +407,8 @@ class ReadBuf: if sel[0]: self.buf = os.read(self.fd, self.chunkSize) # ===> return self.buf[0] # Assume select don't lie. - else: return '' # ===> - + else: + return '' # ===> def readPendingChar(self): """Consume first character of unconsumed output from file, or empty @@ -407,7 +426,8 @@ class ReadBuf: self.eof = 1 if sel[0]: return os.read(self.fd, 1) # ===> - else: return '' # ===> + else: + return '' # ===> def readPendingChars(self, max=None): """Consume uncomsumed output from FILE, or empty string if nothing @@ -433,14 +453,15 @@ class ReadBuf: if max == 0: self.buf = got return '' - elif max == None: + elif max is None: return got elif len(got) > max: self.buf = self.buf + got[max:] return got[:max] else: return got - else: return '' + else: + return '' def readPendingLine(self, block=0): """Return pending output from FILE, up to first newline (inclusive). @@ -490,11 +511,12 @@ class ReadBuf: ############################################################################# -##### Encapsulated reading and writing ##### +##### Encapsulated reading and writing ##### noqa: E266 ############################################################################# # Encapsulate messages so the end can be unambiguously identified, even # when they contain multiple, possibly empty lines. + class RecordFile: """Encapsulate stream object for record-oriented IO. @@ -522,7 +544,7 @@ class RecordFile: l = string.atoi(line) except ValueError: raise IOError(("corrupt %s file structure" - % self.__class__.__name__)) + % self.__class__.__name__)) return f.read(l) else: # EOF. @@ -541,6 +563,7 @@ class RecordFile: self.__dict__['file'], hex(id(self))[2:]) + def record_trial(s): """Exercise encapsulated write/read with an arbitrary string. @@ -555,10 +578,12 @@ def record_trial(s): if r != s: raise IOError("String distorted:\n%s" % show) + ############################################################################# -##### An example subprocess interfaces ##### +##### An example subprocess interfaces ##### noqa: E266 ############################################################################# + class Ph: """Convenient interface to CCSO 'ph' nameserver subprocess. @@ -576,7 +601,7 @@ class Ph: self.proc = Subprocess('ph', 1) except: raise SubprocessError('failure starting ph: %s' % # ===> - str(sys.exc_value)) + str(sys.exc_value)) def query(self, q): """Send a query and return a list of dicts for responses. @@ -586,7 +611,8 @@ class Ph: self.clear() self.proc.writeline('query ' + q) - got = []; it = {} + got = [] + it = {} while 1: response = self.getreply() # Should get null on new prompt. errs = self.proc.readPendingErrChars() @@ -597,7 +623,7 @@ class Ph: it = {} if not response: return got # ===> - elif type(response) == types.StringType: + elif isinstance(response, str): raise ValueError("ph failed match: '%s'" % response) # ===> for line in response: # convert to a dict: @@ -634,12 +660,15 @@ class Ph: got.append(self.proc.readline()[:-1]) nextChar = self.proc.peekPendingChar() return got + def __repr__(self): return "\n" % (self.proc.status(), - hex(id(self))[2:]) + hex(id(self))[2:]) + def clear(self): """Clear-out initial preface or residual subproc input and output.""" - pause = .5; maxIter = 10 # 5 seconds to clear + pause = .5 + maxIter = 10 # 5 seconds to clear iterations = 0 got = '' self.proc.write('') @@ -647,19 +676,22 @@ class Ph: got = got + self.proc.readPendingChars() # Strip out all but the last incomplete line: got = string.splitfields(got, '\n')[-1] - if got == 'ph> ': return # Ok. ===> + if got == 'ph> ': + return # Ok. ===> time.sleep(pause) raise SubprocessError('ph not responding within %s secs' % - pause * maxIter) + pause * maxIter) + + +############################################################################## +##### Test ##### noqa: E266 +############################################################################## -############################################################################# -##### Test ##### -############################################################################# def test(p=0): print("\tOpening bogus subprocess, should fail:") try: - b = Subprocess('/', 1) + Subprocess('/', 1) print("\tOops! Null-named subprocess startup *succeeded*?!?") except SubprocessError: print("\t...yep, it failed.") @@ -667,11 +699,14 @@ def test(p=0): 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') + p.write('first full line written\n') + p.write('second.\n') 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)') + p.write('first\n') + p.write('second\n') + p.write('third, (no cr)') print('\tFirst line via readline:') print(repr(p.readline())) print('\tRest via readPendingChars:') @@ -686,7 +721,8 @@ def test(p=0): print(p.readPendingChars()) print('\tContinuing subprocess (verbose):') if not p.cont(1): # verbose continue - print('\t** Continue seems to have failed! Probly lost subproc...') + print( + '\t** Continue seems to have failed! Probly lost subproc...') return p else: print('\tReading accumulated line, blocking read:') @@ -696,5 +732,6 @@ def test(p=0): print("\tDone.") return None + if __name__ == '__main__': test() -- 2.39.5