From: Oleg Broytman Date: Sun, 12 Nov 2023 14:23:26 +0000 (+0300) Subject: Fix(Py3): Fix `subproc.py` X-Git-Tag: 5.0.0~46 X-Git-Url: https://git.phdru.name/?a=commitdiff_plain;h=ac4b52039650cd5533912cda169d275ba8cb44d1;p=bookmarks_db.git Fix(Py3): Fix `subproc.py` Work with bytes. --- diff --git a/doc/TODO b/doc/TODO index 8848a10..47b3e59 100644 --- a/doc/TODO +++ b/doc/TODO @@ -1,5 +1,3 @@ -Replace subproc.py with some IPC. Or update for Python 3. - Python 3. Configuration file to configure defaults - global defaults for the system diff --git a/subproc.py b/subproc.py index 69bd13b..37cb253 100755 --- a/subproc.py +++ b/subproc.py @@ -1,4 +1,4 @@ -#! /usr/bin/env python +#! /usr/bin/env python3 """Run a subprocess and communicate with it via stdin, stdout, and stderr. @@ -80,7 +80,7 @@ class Subprocess: the subprocess stderr stream.""" pid = 0 - cmd = '' + cmd = b'' expire_noisily = 1 # Announce subproc destruction? pipefiles = [] readbuf = 0 # fork will assign to be a readbuf obj @@ -140,7 +140,7 @@ class Subprocess: else: ### PARENT ### noqa: E262 # Connect to the child's file descriptors, using our customized # fdopen: - self.toChild = os.fdopen(pWc, 'w') + self.toChild = os.fdopen(pWc, 'wb') self.toChild_fdlist = [pWc] self.readbuf = ReadBuf(pRc) self.errbuf = ReadBuf(pRe) @@ -184,9 +184,9 @@ class Subprocess: # XXX Can write-buffer full be handled better?? raise IOError("write to %s blocked" % self) # ===> - def writeline(self, line=''): + def writeline(self, line=b''): """Write STRING, with added newline termination, to subprocess.""" - self.write(line + '\n') + self.write(line + b'\n') ### Get output from subprocess ### noqa: E266 @@ -220,7 +220,7 @@ class Subprocess: """Read N chars, or all pending if no N specified.""" if n is None: return self.readPendingChars() - got = '' + got = b'' while n: got0 = self.readPendingChars(n) got = got + got0 @@ -384,7 +384,7 @@ class ReadBuf: raise ValueError self.fd = fd self.eof = 0 # May be set with stuff still in .buf - self.buf = '' + self.buf = b'' self.chunkSize = maxChunkSize # Biggest read chunk, default 1024. def fileno(self): @@ -398,7 +398,7 @@ class ReadBuf: return self.buf[0] # ===> if self.eof: - return '' # ===> + return b'' # ===> sel = select.select([self.fd], [], [self.fd], 0) if sel[2]: @@ -407,7 +407,7 @@ class ReadBuf: self.buf = os.read(self.fd, self.chunkSize) # ===> return self.buf[0] # Assume select don't lie. else: - return '' # ===> + return b'' # ===> def readPendingChar(self): """Consume first character of unconsumed output from file, or empty @@ -418,7 +418,7 @@ class ReadBuf: return got # ===> if self.eof: - return '' # ===> + return b'' # ===> sel = select.select([self.fd], [], [self.fd], 0) if sel[2]: @@ -426,23 +426,23 @@ class ReadBuf: if sel[0]: return os.read(self.fd, 1) # ===> else: - return '' # ===> + return b'' # ===> def readPendingChars(self, max=None): """Consume uncomsumed output from FILE, or empty string if nothing pending.""" - got = "" + got = b"" if self.buf: - if (max > 0) and (len(self.buf) > max): + if max and (len(self.buf) > max): got = self.buf[0:max] self.buf = self.buf[max:] else: - got, self.buf = self.buf, '' + got, self.buf = self.buf, b'' return got if self.eof: - return '' + return b'' sel = select.select([self.fd], [], [self.fd], 0) if sel[2]: @@ -451,7 +451,7 @@ class ReadBuf: got = got + os.read(self.fd, self.chunkSize) if max == 0: self.buf = got - return '' + return b'' elif max is None: return got elif len(got) > max: @@ -460,7 +460,7 @@ class ReadBuf: else: return got else: - return '' + return b'' def readPendingLine(self, block=0): """Return pending output from FILE, up to first newline (inclusive). @@ -471,15 +471,15 @@ class ReadBuf: any newline.""" if self.buf: - to = self.buf.find('\n') + to = self.buf.find(b'\n') if to != -1: got, self.buf = self.buf[:to+1], self.buf[to+1:] return got # ===> - got, self.buf = self.buf, '' + got, self.buf = self.buf, b'' else: if self.eof: - return '' # ===> - got = '' + return b'' # ===> + got = b'' # Herein, 'got' contains the (former) contents of the buffer, and it # doesn't include a newline. @@ -492,14 +492,14 @@ class ReadBuf: if sel[0]: got = got + os.read(self.fd, self.chunkSize) - to = got.find('\n') + to = got.find(b'\n') if to != -1: got, self.buf = got[:to+1], got[to+1:] return got # ===> if not block: return got # ===> if self.eof: - self.buf = '' # this is how an ordinary file acts... + self.buf = b'' # this is how an ordinary file acts... return got # otherwise - no newline, blocking requested, no eof - loop. # ==^ @@ -530,7 +530,7 @@ class RecordFile: def write_record(self, s): "Write so self.read knows exactly how much to read." f = self.__dict__['file'] - f.write("%s\n%s" % (len(s), s)) + f.write(b"%d\n%s" % (len(s), s)) if hasattr(f, 'flush'): f.flush() @@ -547,7 +547,7 @@ class RecordFile: return f.read(_l) else: # EOF. - return '' + return b'' def __getattr__(self, attr): """Implement characteristic file object attributes.""" @@ -609,7 +609,7 @@ class Ph: self.clear() - self.proc.writeline('query ' + q) + self.proc.writeline(b'query ' + q) got = [] it = {} while 1: @@ -626,8 +626,8 @@ class Ph: raise ValueError("ph failed match: '%s'" % response) # ===> for line in response: # convert to a dict: - line = line.split(':') - it[line.strip([0])] = (''.join(line[1:])).strip() + line = line.split(b':') + it[line.strip([0])] = (b''.join(line[1:])).strip() def getreply(self): """Consume next response from ph, returning list of lines or string @@ -641,20 +641,20 @@ class Ph: nextChar = self.proc.waitForPendingChar(60) if not nextChar: raise SubprocessError('ph subprocess not responding') # ===> - elif nextChar == '-': + elif nextChar == b'-': # dashed line - discard it, and continue reading: self.proc.readline() return self.getreply() # ===> - elif nextChar == 'p': + elif nextChar == b'p': # 'ph> ' prompt - don't think we should hit this, but what the hay: return '' # ===> - elif nextChar in '0123456789': + elif nextChar in b'0123456789': # Error notice - we're currently assuming single line errors: return self.proc.readline()[:-1] # ===> - elif nextChar in ' \t': + elif nextChar in b' \t': # Get content, up to next dashed line: got = [] - while nextChar != '-' and nextChar != '': + while nextChar != b'-' and nextChar != b'': got.append(self.proc.readline()[:-1]) nextChar = self.proc.peekPendingChar() return got @@ -668,13 +668,13 @@ class Ph: pause = .5 maxIter = 10 # 5 seconds to clear iterations = 0 - got = '' - self.proc.write('') + got = b'' + self.proc.write(b'') while iterations < maxIter: got = got + self.proc.readPendingChars() # Strip out all but the last incomplete line: - got = got.split('\n')[-1] - if got == 'ph> ': + got = got.split(b'\n')[-1] + if got == b'ph> ': return # Ok. ===> time.sleep(pause) raise SubprocessError('ph not responding within %s secs' % @@ -697,14 +697,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(b'first full line written\n') + p.write(b'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(b'first\n') + p.write(b'second\n') + p.write(b'third, (no cr)') print('\tFirst line via readline:') print(repr(p.readline())) print('\tRest via readPendingChars:') @@ -714,7 +714,7 @@ def test(p=0): print('\t** Stop seems to have failed!') else: print('\tWriting line while subprocess is paused...') - p.write('written while subprocess paused\n') + p.write(b'written while subprocess paused\n') print('\tNonblocking read of paused subprocess (should be empty):') print(p.readPendingChars()) print('\tContinuing subprocess (verbose):')