diff --git a/src/calibre/rpdb.py b/src/calibre/rpdb.py index 1a60f3b489..4243ce6fd3 100644 --- a/src/calibre/rpdb.py +++ b/src/calibre/rpdb.py @@ -6,10 +6,9 @@ __license__ = 'GPL v3' __copyright__ = '2014, Kovid Goyal ' import pdb, socket, inspect, sys, select, os, atexit, time +from contextlib import suppress -from calibre import prints from calibre.constants import cache_dir -from polyglot.builtins import range, raw_input as rinput PROMPT = '(debug) ' QUESTION = '\x00\x01\x02' @@ -18,24 +17,24 @@ QUESTION = '\x00\x01\x02' class RemotePdb(pdb.Pdb): def __init__(self, addr="127.0.0.1", port=4444, skip=None): - try: - prints("pdb is running on %s:%d" % (addr, port), file=sys.stderr) - except IOError: - pass - # Open a reusable socket to allow for reloads self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) self.sock.bind((addr, port)) self.sock.listen(1) + with suppress(OSError): + print("pdb is running on %s:%d" % (addr, port), file=sys.stderr) clientsocket, address = self.sock.accept() + clientsocket.setblocking(True) + self.clientsocket = clientsocket self.handle = clientsocket.makefile('rw') pdb.Pdb.__init__(self, completekey='tab', stdin=self.handle, stdout=self.handle, skip=skip) self.prompt = PROMPT def prints(self, *args, **kwargs): kwargs['file'] = self.handle - prints(*args, **kwargs) + kwargs['flush'] = True + print(*args, **kwargs) def ask_question(self, query): self.handle.write(QUESTION) @@ -47,7 +46,9 @@ class RemotePdb(pdb.Pdb): def end_session(self, *args): self.clear_all_breaks() self.reset() - del self.handle + self.handle.close() + self.clientsocket.shutdown(socket.SHUT_RDWR) + self.clientsocket.close() try: self.sock.shutdown(socket.SHUT_RDWR) self.sock.close() @@ -85,15 +86,15 @@ def set_trace(port=4444, skip=None): debugger = RemotePdb(port=port, skip=skip) debugger.set_trace(frame) except KeyboardInterrupt: - prints('Debugging aborted by keyboard interrupt') + print('Debugging aborted by keyboard interrupt') except Exception: - prints('Failed to run debugger') + print('Failed to run debugger') import traceback traceback.print_exc() def cli(port=4444): - prints('Connecting to remote debugger on port %d...' % port) + print('Connecting to remote debugger on port %d...' % port) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) for i in range(20): try: @@ -106,48 +107,51 @@ def cli(port=4444): try: sock.connect(('127.0.0.1', port)) except socket.error as err: - prints('Failed to connect to remote debugger:', err, file=sys.stderr) + print('Failed to connect to remote debugger:', err, file=sys.stderr) raise SystemExit(1) - prints('Connected to remote process') - import readline - histfile = os.path.join(cache_dir(), 'rpdb.history') + print('Connected to remote process', flush=True) try: - readline.read_history_file(histfile) - except IOError: + import readline + histfile = os.path.join(cache_dir(), 'rpdb.history') + try: + readline.read_history_file(histfile) + except IOError: + pass + atexit.register(readline.write_history_file, histfile) + p = pdb.Pdb() + readline.set_completer(p.complete) + readline.parse_and_bind("tab: complete") + except ImportError: pass - atexit.register(readline.write_history_file, histfile) - p = pdb.Pdb() - readline.set_completer(p.complete) - readline.parse_and_bind("tab: complete") - sockf = sock.makefile('rw') - - try: + sock.setblocking(True) + with suppress(KeyboardInterrupt): + end_of_input = PROMPT.encode('utf-8') while True: - recvd = '' - while not recvd.endswith(PROMPT) or select.select([sock], [], [], 0) == ([sock], [], []): - buf = sockf.read() + recvd = b'' + while select.select([sock], [], [], 0)[0] or not recvd.endswith(end_of_input): + buf = sock.recv(4096) if not buf: return recvd += buf + recvd = recvd.decode('utf-8', 'replace') recvd = recvd[:-len(PROMPT)] + raw = '' if recvd.startswith(QUESTION): recvd = recvd[len(QUESTION):] - sys.stdout.write(recvd) + print(recvd, end='', flush=True) raw = sys.stdin.readline() or 'n' else: - sys.stdout.write(recvd) - raw = '' + print(recvd, end='', flush=True) try: - raw = rinput(PROMPT.decode('utf-8')) + raw = input(PROMPT) except (EOFError, KeyboardInterrupt): pass else: raw += '\n' if not raw: raw = 'quit\n' - sockf.write(raw) - except KeyboardInterrupt: - pass + if raw: + sock.sendall(raw.encode('utf-8')) if __name__ == '__main__':