diff -r eb1b3e0577e4 -r b6cbdba69967 DebugClients/Python3/DebugClientBase.py --- a/DebugClients/Python3/DebugClientBase.py Thu Sep 01 20:03:50 2016 +0200 +++ b/DebugClients/Python3/DebugClientBase.py Fri Sep 02 19:14:41 2016 +0200 @@ -20,7 +20,7 @@ import signal -import DebugProtocol +##import DebugProtocol import DebugClientCapabilities from DebugBase import setRecursionLimit, printerr # __IGNORE_WARNING__ from AsyncFile import AsyncFile, AsyncPendingWrite @@ -160,6 +160,7 @@ """ self.breakpoints = {} self.redirect = True + self.__receiveBuffer = "" # The next couple of members are needed for the threaded version. # For this base class they contain static values for the non threaded @@ -188,7 +189,7 @@ self.globalsFilterObjects = [] self.localsFilterObjects = [] - self.pendingResponse = DebugProtocol.ResponseOK +## self.pendingResponse = DebugProtocol.ResponseOK self._fncache = {} self.dircache = [] ## self.inRawMode = False @@ -304,7 +305,7 @@ ## self.write("{0}{1!r}\n".format(DebugProtocol.ResponseThreadList, ## (currentId, threadList))) - self.__sendJsonCommand("ResponseThreadList", { + self.sendJsonCommand("ResponseThreadList", { "currentID": currentId, "threadList": threadList, }) @@ -319,7 +320,7 @@ """ ## self.write("{0}{1!r}\n".format( ## DebugProtocol.ResponseRaw, (prompt, echo))) - self.__sendJsonCommand("RequestRaw", { + self.sendJsonCommand("RequestRaw", { "prompt": prompt, "echo": echo, }) @@ -327,15 +328,15 @@ self.eventLoop(True) return self.rawLine - def __exceptionRaised(self): - """ - Private method called in the case of an exception. - - It ensures that the debug server is informed of the raised exception. - """ -## self.pendingResponse = DebugProtocol.ResponseException - self.__sendJsonCommand("ResponseException", {}) - +## def __exceptionRaised(self): +## """ +## Private method called in the case of an exception. +## +## It ensures that the debug server is informed of the raised exception. +## """ +#### self.pendingResponse = DebugProtocol.ResponseException +## self.sendJsonCommand("ResponseException", {}) +## def sessionClose(self, exit=True): """ Public method to close the session with the debugger and optionally @@ -348,8 +349,8 @@ except Exception: pass - # clean up asyncio. - self.disconnect() +## # clean up asyncio. +## self.disconnect() self.debugging = False # make sure we close down our end of the socket @@ -408,16 +409,16 @@ ## printerr(line) ##debug - if "jsonrpc" in line: + if line.startswith("{") and "jsonrpc" in line: return self.handleJsonCommand(line) - - eoc = line.find('<') - - if eoc >= 0 and line[0] == '>': - # Get the command part and any argument. - cmd = line[:eoc + 1] - arg = line[eoc + 1:] - +## +## eoc = line.find('<') +## +## if eoc >= 0 and line[0] == '>': +## # Get the command part and any argument. +## cmd = line[:eoc + 1] +## arg = line[eoc + 1:] +## ## if cmd == DebugProtocol.RequestVariables: ## frmnr, scope, filter = eval(arg.replace("u'", "'")) ## self.__dumpVariables(int(frmnr), int(scope), filter) @@ -912,32 +913,32 @@ ## str((self.test.countTestCases(), "", "")))) ## return ## - if cmd == DebugProtocol.RequestUTRun: - from DCTestResult import DCTestResult - self.testResult = DCTestResult(self) - if self.cover: - self.cover.start() - self.test.run(self.testResult) - if self.cover: - self.cover.stop() - self.cover.save() - self.write('{0}\n'.format(DebugProtocol.ResponseUTFinished)) - return - - if cmd == DebugProtocol.RequestUTStop: - self.testResult.stop() - return - - if cmd == DebugProtocol.ResponseForkTo: - # this results from a separate event loop - self.fork_child = (arg == 'child') - self.eventExit = True - return - - if cmd == DebugProtocol.RequestForkMode: - self.fork_auto, self.fork_child = eval(arg) - return - +## if cmd == DebugProtocol.RequestUTRun: +## from DCTestResult import DCTestResult +## self.testResult = DCTestResult(self) +## if self.cover: +## self.cover.start() +## self.test.run(self.testResult) +## if self.cover: +## self.cover.stop() +## self.cover.save() +## self.write('{0}\n'.format(DebugProtocol.ResponseUTFinished)) +## return +## +## if cmd == DebugProtocol.RequestUTStop: +## self.testResult.stop() +## return +## +## if cmd == DebugProtocol.ResponseForkTo: +## # this results from a separate event loop +## self.fork_child = (arg == 'child') +## self.eventExit = True +## return +## +## if cmd == DebugProtocol.RequestForkMode: +## self.fork_auto, self.fork_child = eval(arg) +## return +## ## # If we are handling raw mode input then reset the mode and break out ## # of the current event loop. ## if self.inRawMode: @@ -1046,56 +1047,48 @@ if method == "RequestVariables": self.__dumpVariables( params["frameNumber"], params["scope"], params["filters"]) - return - if method == "RequestVariable": + elif method == "RequestVariable": self.__dumpVariable( params["variable"], params["frameNumber"], params["scope"], params["filters"]) - return - if method == "RequestThreadList": + elif method == "RequestThreadList": self.__dumpThreadList() - return - if method == "RequestThreadSet": + elif method == "RequestThreadSet": if params["threadID"] in self.threads: self.setCurrentThread(params["threadID"]) - self.__sendJsonCommand("ResponseThreadSet", {}) + self.sendJsonCommand("ResponseThreadSet", {}) stack = self.currentThread.getStack() - self.__sendJsonCommand("ResponseStack", { + self.sendJsonCommand("ResponseStack", { "stack": stack, }) - return - if method == "RequestCapabilities": - self.__sendJsonCommand("ResponseCapabilities", { + elif method == "RequestCapabilities": + self.sendJsonCommand("ResponseCapabilities", { "capabilities": self.__clientCapabilities(), "clientType": "Python3" }) - return - if method == "RequestBanner": - self.__sendJsonCommand("ResponseBanner", { + elif method == "RequestBanner": + self.sendJsonCommand("ResponseBanner", { "version": "Python {0}".format(sys.version), "platform": socket.gethostname(), "dbgclient": self.variant, }) - return - if method == "RequestSetFilter": + elif method == "RequestSetFilter": self.__generateFilterObjects(params["scope"], params["filter"]) - return - if method == "RequestCallTrace": + elif method == "RequestCallTrace": if self.debugging: self.callTraceEnabled = params["enable"] else: self.__newCallTraceEnabled = params["enable"] # remember for later - return - if method == "RequestEnvironment": + elif method == "RequestEnvironment": for key, value in params["environment"].items(): if key.endswith("+"): if key[:-1] in os.environ: @@ -1104,9 +1097,8 @@ os.environ[key[:-1]] = value else: os.environ[key] = value - return - if method == "RequestLoad": + elif method == "RequestLoad": self._fncache = {} self.dircache = [] sys.argv = [] @@ -1149,9 +1141,8 @@ self.callTraceEnabled = self.__newCallTraceEnabled res = self.mainThread.run(code, self.debugMod.__dict__) self.progTerminated(res) - return - if method == "RequestRun": + elif method == "RequestRun": sys.argv = [] self.__setCoding(params["filename"]) sys.argv.append(params["filename"]) @@ -1192,9 +1183,8 @@ atexit._run_exitfuncs() self.writestream.flush() self.progTerminated(res) - return - if method == "RequestCoverage": + elif method == "RequestCoverage": from coverage import coverage sys.argv = [] self.__setCoding(params["filename"]) @@ -1242,9 +1232,8 @@ self.cover.save() self.writestream.flush() self.progTerminated(res) - return - if method == "RequestProfile": + elif method == "RequestProfile": sys.setprofile(None) import PyProfile sys.argv = [] @@ -1287,9 +1276,8 @@ self.prof.save() self.writestream.flush() self.progTerminated(res) - return - if method == "ExecuteStatement": + elif method == "ExecuteStatement": if self.buffer: self.buffer = self.buffer + '\n' + params["statement"] else: @@ -1301,13 +1289,17 @@ # Report the exception sys.last_type, sys.last_value, sys.last_traceback = \ sys.exc_info() - for l in traceback.format_exception_only( - sys.last_type, sys.last_value): - self.write(l) +## for l in traceback.format_exception_only( +## sys.last_type, sys.last_value): +## self.write(l) + self.sendJsonCommand("ClientOutput", { + "text": "".join(traceback.format_exception_only( + sys.last_type, sys.last_value)) + }) self.buffer = '' else: if code is None: - self.__sendJsonCommand("ResponseContinue", {}) + self.sendJsonCommand("ResponseContinue", {}) return else: self.buffer = '' @@ -1357,6 +1349,7 @@ self.progTerminated(exc.code) except Exception: # Report the exception and the traceback + tlist = [] try: exc_type, exc_value, exc_tb = sys.exc_info() sys.last_type = exc_type @@ -1364,57 +1357,54 @@ sys.last_traceback = exc_tb tblist = traceback.extract_tb(exc_tb) del tblist[:1] - list = traceback.format_list(tblist) - if list: - list.insert(0, "Traceback (innermost last):\n") - list[len(list):] = \ + tlist = traceback.format_list(tblist) + if tlist: + tlist.insert( + 0, "Traceback (innermost last):\n") + tlist[len(tlist):] = \ traceback.format_exception_only( exc_type, exc_value) finally: tblist = exc_tb = None - for l in list: - self.write(l) +## for l in list: +## self.write(l) + self.sendJsonCommand("ClientOutput", { + "text": "".join(tlist) + }) - self.__sendJsonCommand("ResponseOK", {}) - return + self.sendJsonCommand("ResponseOK", {}) - if method == "RequestStep": + elif method == "RequestStep": self.currentThread.step(True) self.eventExit = True - return - if method == "RequestStepOver": + elif method == "RequestStepOver": self.currentThread.step(False) self.eventExit = True - return - if method == "RequestStepOut": + elif method == "RequestStepOut": self.currentThread.stepOut() self.eventExit = True - return - if method == "RequestStepQuit": + elif method == "RequestStepQuit": if self.passive: self.progTerminated(42) else: self.set_quit() self.eventExit = True - return - if method == "RequestContinue": + elif method == "RequestContinue": self.currentThread.go(params["special"]) self.eventExit = True - return - if method == "RawInput": + elif method == "RawInput": # If we are handling raw mode input then break out of the current # event loop. self.rawLine = params["input"] self.eventExit = True - return - if method == "RequestBreakpoint": + elif method == "RequestBreakpoint": if params["setBreakpoint"]: if params["condition"] in ['None', '']: params["condition"] = None @@ -1422,7 +1412,7 @@ try: compile(params["condition"], '<string>', 'eval') except SyntaxError: - self.__sendJsonCommand("ResponseBPConditionError", { + self.sendJsonCommand("ResponseBPConditionError", { "filename": params["filename"], "line": params["line"], }) @@ -1432,32 +1422,28 @@ params["condition"]) else: self.mainThread.clear_break(params["filename"], params["line"]) - - return - if method == "RequestBreakpointEnable": + elif method == "RequestBreakpointEnable": bp = self.mainThread.get_break(params["filename"], params["line"]) if bp is not None: if params["enable"]: bp.enable() else: bp.disable() - return - if method == "RequestBreakpointIgnore": + elif method == "RequestBreakpointIgnore": bp = self.mainThread.get_break(params["filename"], params["line"]) if bp is not None: bp.ignore = params["count"] - return - if method == "RequestWatch": + elif method == "RequestWatch": if params["setWatch"]: if not params["condition"].endswith( ('??created??', '??changed??')): try: compile(params["condition"], '<string>', 'eval') except SyntaxError: - self.__sendJsonCommand("ResponseWatchConditionError", { + self.sendJsonCommand("ResponseWatchConditionError", { "condition": params["condition"], }) return @@ -1465,37 +1451,28 @@ params["condition"], params["temporary"]) else: self.mainThread.clear_watch(params["condition"]) - return - if method == "RequestWatchEnable": + elif method == "RequestWatchEnable": wp = self.mainThread.get_watch(params["condition"]) if wp is not None: if params["enable"]: wp.enable() else: wp.disable() - return - if method == "RequestWatchIgnore": + elif method == "RequestWatchIgnore": wp = self.mainThread.get_watch(params["condition"]) if wp is not None: wp.ignore = params["count"] return - if method == "RequestShutdown": + elif method == "RequestShutdown": self.sessionClose() - return - if method == "RequestCompletion": + elif method == "RequestCompletion": self.__completionList(params["text"]) - return - if method == "RequestUTPrepare": -## fn, tn, tfn, failed, cov, covname, erase = arg.split('|') -## sys.path.insert(0, os.path.dirname(os.path.abspath(fn))) -## os.chdir(sys.path[0]) -## failed = eval(failed) -## + elif method == "RequestUTPrepare": # set the system exception handling function to ensure, that # we report on all unhandled exceptions sys.excepthook = self.__unhandled_exception @@ -1518,15 +1495,12 @@ .loadTestsFromModule(utModule) except Exception: exc_type, exc_value, exc_tb = sys.exc_info() -## self.write('{0}{1}\n'.format( -## DebugProtocol.ResponseUTPrepared, -## str((0, str(exc_type), str(exc_value))))) - self.__sendJsonCommand("ResponseUTPrepared", { + self.sendJsonCommand("ResponseUTPrepared", { "count": 0, "exception": exc_type.__name__, "message": str(exc_value), }) - self.__exceptionRaised() +## self.__exceptionRaised() return # generate a coverage object @@ -1541,19 +1515,34 @@ else: self.cover = None -## self.write('{0}{1}\n'.format( -## DebugProtocol.ResponseUTPrepared, -## str((self.test.countTestCases(), "", "")))) - self.__sendJsonCommand("ResponseUTPrepared", { + self.sendJsonCommand("ResponseUTPrepared", { "count": self.test.countTestCases(), "exception": "", "message": "", }) - return + + elif method == "RequestUTRun": + from DCTestResult import DCTestResult + self.testResult = DCTestResult(self) + if self.cover: + self.cover.start() + self.test.run(self.testResult) + if self.cover: + self.cover.stop() + self.cover.save() + self.sendJsonCommand("ResponseUTFinished", {}) + + elif method == "RequestUTStop": + self.testResult.stop() + + elif method == "ResponseForkTo": + # this results from a separate event loop + self.fork_child = (params["target"] == 'child') + self.eventExit = True - def __sendJsonCommand(self, command, params): + def sendJsonCommand(self, command, params): """ - Private method to send a single command to the client. + Public method to send a single command to the client. @param command command name to be sent @type str @@ -1568,7 +1557,9 @@ "params": params, } cmd = json.dumps(commandDict) + '\n' - self.write(cmd) + + self.writestream.write_p(cmd) + self.writestream.flush() def sendClearTemporaryBreakpoint(self, filename, lineno): """ @@ -1579,7 +1570,7 @@ @param lineno linenumber of the bp @type int """ - self.__sendJsonCommand("ResponseClearBreakpoint", { + self.sendJsonCommand("ResponseClearBreakpoint", { "filename": filename, "line": lineno }) @@ -1591,7 +1582,7 @@ @param condition condition of the watch expression to be cleared @type str """ - self.__sendJsonCommand("ResponseClearWatch", { + self.sendJsonCommand("ResponseClearWatch", { "condition": condition, }) @@ -1602,7 +1593,7 @@ @param stack call stack @type list """ - self.__sendJsonCommand("ResponseLine", { + self.sendJsonCommand("ResponseLine", { "stack": stack, }) @@ -1617,7 +1608,7 @@ @param toStr pre-formatted target info @type str """ - self.__sendJsonCommand("CallTrace", { + self.sendJsonCommand("CallTrace", { "event": event[0], "from": fromStr, "to": toStr, @@ -1634,7 +1625,7 @@ @param stack stack trace information @param list """ - self.__sendJsonCommand("ResponseException", { + self.sendJsonCommand("ResponseException", { "type": exceptionType, "message": exceptionMessage, "stack": stack, @@ -1653,7 +1644,7 @@ @param charno character number info @tyoe int """ - self.__sendJsonCommand("ResponseSyntax", { + self.sendJsonCommand("ResponseSyntax", { "message": message, "filename": filename, "linenumber": lineno, @@ -1669,7 +1660,7 @@ @param exceptions flag to enable exception reporting of the IDE @type bool """ - self.__sendJsonCommand("PassiveStartup", { + self.sendJsonCommand("PassiveStartup", { "filename": filename, "exceptions": exceptions, }) @@ -1691,23 +1682,58 @@ return ( self.clientCapabilities & ~DebugClientCapabilities.HasProfiler) - def write(self, s): +## def write(self, s): +## """ +## Public method to write data to the output stream. +## +## @param s data to be written (string) +## """ +## self.writestream.write_p(s) +## self.writestream.flush() +## + def readReady(self, stream): """ - Public method to write data to the output stream. + Public method called when there is data ready to be read. - @param s data to be written (string) + @param fd file descriptor of the file that has data to be read (int) """ - self.writestream.write(s) - self.writestream.flush() + try: + got = stream.readline_p() + except Exception: + return + + if len(got) == 0: + self.sessionClose() + return + + self.__receiveBuffer = self.__receiveBuffer + got + # Call handleLine for the line if it is complete. + eol = self.__receiveBuffer.find('\n') + while eol >= 0: + line = self.__receiveBuffer[:eol + 1] + self.__receiveBuffer = self.__receiveBuffer[eol + 1:] + self.handleLine(line) + eol = self.__receiveBuffer.find('\n') + + def writeReady(self, stream): + """ + Public method called when we are ready to write data. + + @param fd file descriptor of the file that has data to be written (int) + """ + stream.write_p("") + stream.flush() + def __interact(self): """ Private method to interact with the debugger. """ global DebugClientInstance - self.setDescriptors(self.readstream, self.writestream) +## self.setDescriptors(self.readstream, self.writestream) DebugClientInstance = self + self.__receiveBuffer = "" if not self.passive: # At this point simulate an event loop. @@ -1742,13 +1768,13 @@ continue if self.readstream in rrdy: - self.readReady(self.readstream.fileno()) + self.readReady(self.readstream) if self.writestream in wrdy: - self.writeReady(self.writestream.fileno()) + self.writeReady(self.writestream) if self.errorstream in wrdy: - self.writeReady(self.errorstream.fileno()) + self.writeReady(self.errorstream) self.eventExit = None self.pollingDisabled = False @@ -1786,10 +1812,10 @@ self.readReady(self.readstream.fileno()) if self.writestream in wrdy: - self.writeReady(self.writestream.fileno()) + self.writeReady(self.writestream) if self.errorstream in wrdy: - self.writeReady(self.errorstream.fileno()) + self.writeReady(self.errorstream) def connectDebugger(self, port, remoteAddress=None, redirect=True): """ @@ -1888,7 +1914,7 @@ ## siglist = [message, [filename, linenr, ffunc, fargs]] ## ## self.write("{0}{1}".format(DebugProtocol.ResponseSignal, str(siglist))) - self.__sendJsonCommand("ResponseSignal", { + self.sendJsonCommand("ResponseSignal", { "message": message, "filename": filename, "linenumber": linenr, @@ -1969,12 +1995,14 @@ """ return self.running - def progTerminated(self, status): + def progTerminated(self, status, message=""): """ Public method to tell the debugger that the program has terminated. @param status return status @type int + @param message status message + @type str """ if status is None: status = 0 @@ -1988,8 +2016,9 @@ self.set_quit() self.running = None ## self.write('{0}{1:d}\n'.format(DebugProtocol.ResponseExit, status)) - self.__sendJsonCommand("ResponseExit", { + self.sendJsonCommand("ResponseExit", { "status": status, + "message": message, }) # reset coding @@ -2039,7 +2068,7 @@ ## self.write('{0}{1}\n'.format( ## DebugProtocol.ResponseVariables, str(varlist))) - self.__sendJsonCommand("ResponseVariables", { + self.sendJsonCommand("ResponseVariables", { "scope": scope, "variables": varlist, }) @@ -2328,7 +2357,7 @@ ## self.write('{0}{1}\n'.format( ## DebugProtocol.ResponseVariable, str(varlist))) - self.__sendJsonCommand("ResponseVariable", { + self.sendJsonCommand("ResponseVariable", { "scope": scope, "variable": var, "variables": varlist, @@ -2630,7 +2659,7 @@ ## self.write("{0}{1}||{2}\n".format(DebugProtocol.ResponseCompletion, ## str(list(completions)), text)) - self.__sendJsonCommand("ResponseCompletion", { + self.sendJsonCommand("ResponseCompletion", { "completions": list(completions), "text": text, }) @@ -2914,7 +2943,8 @@ @return process ID (integer) """ if not self.fork_auto: - self.write(DebugProtocol.RequestForkTo + '\n') +## self.write(DebugProtocol.RequestForkTo + '\n') + self.sendJsonCommand("RequestForkTo", {}) self.eventLoop(True) pid = DebugClientOrigFork() if pid == 0: