Sat, 11 Nov 2017 18:44:04 +0100
Fixed an issue in the debugger backend related to debugging threads.
--- a/APIs/Python3/eric6.api Thu Nov 09 18:31:34 2017 +0100 +++ b/APIs/Python3/eric6.api Sat Nov 11 18:44:04 2017 +0100 @@ -125,6 +125,7 @@ eric6.DebugClients.Python.AsyncFile.AsyncFile.maxtries?7 eric6.DebugClients.Python.AsyncFile.AsyncFile.pendingWrite?4() eric6.DebugClients.Python.AsyncFile.AsyncFile.read?4(size=-1) +eric6.DebugClients.Python.AsyncFile.AsyncFile.readCommand?4() eric6.DebugClients.Python.AsyncFile.AsyncFile.read_p?4(size=-1) eric6.DebugClients.Python.AsyncFile.AsyncFile.readable?4() eric6.DebugClients.Python.AsyncFile.AsyncFile.readline?4(sizehint=-1) @@ -217,7 +218,6 @@ eric6.DebugClients.Python.DebugClientBase.DebugClientBase.getCoding?4() eric6.DebugClients.Python.DebugClientBase.DebugClientBase.getRunning?4() eric6.DebugClients.Python.DebugClientBase.DebugClientBase.handleJsonCommand?4(jsonStr) -eric6.DebugClients.Python.DebugClientBase.DebugClientBase.handleLine?4(line) eric6.DebugClients.Python.DebugClientBase.DebugClientBase.input?4(prompt) eric6.DebugClients.Python.DebugClientBase.DebugClientBase.main?4() eric6.DebugClients.Python.DebugClientBase.DebugClientBase.progTerminated?4(status, message="")
--- a/DebugClients/Python/AsyncFile.py Thu Nov 09 18:31:34 2017 +0100 +++ b/DebugClients/Python/AsyncFile.py Sat Nov 11 18:44:04 2017 +0100 @@ -184,7 +184,25 @@ if size >= 0: buf = buf[:size] return buf - + + def readCommand(self): + """ + Public method to read a length prefixed command string. + + @return command string + @rtype str + """ + # The command string is prefixed by a 9 character long length field. + length = self.sock.recv(9) + length = int(length) + data = b'' + while len(data) < length: + newData = self.sock.recv(length - len(data)) + data += newData + + # step 2: convert the data + return data.decode('utf8', 'backslashreplace') + def readline_p(self, size=-1): """ Public method to read a line from this file.
--- a/DebugClients/Python/DebugBase.py Thu Nov 09 18:31:34 2017 +0100 +++ b/DebugClients/Python/DebugBase.py Sat Nov 11 18:44:04 2017 +0100 @@ -382,14 +382,14 @@ frame = sys._getframe().f_back # Skip set_trace method if sys.version_info[0] == 2: - stopOnHandleLine = self._dbgClient.handleLine.func_code + stopOnHandleCommand = self._dbgClient.handleJsonCommand.func_code else: - stopOnHandleLine = self._dbgClient.handleLine.__code__ + stopOnHandleCommand = self._dbgClient.handleJsonCommand.__code__ frame.f_trace = self.trace_dispatch while frame.f_back is not None: - # stop at erics debugger frame or a threading bootstrap - if (frame.f_back.f_code == stopOnHandleLine): + # stop at eric's debugger frame or a threading bootstrap + if (frame.f_back.f_code == stopOnHandleCommand): frame.f_trace = self.trace_dispatch break
--- a/DebugClients/Python/DebugClientBase.py Thu Nov 09 18:31:34 2017 +0100 +++ b/DebugClients/Python/DebugClientBase.py Sat Nov 11 18:44:04 2017 +0100 @@ -187,7 +187,6 @@ """ self.breakpoints = {} self.redirect = True - self.__receiveBuffer = "" # special objects representing the main scripts thread and frame self.mainThread = self @@ -355,23 +354,6 @@ return code - def handleLine(self, line): - """ - Public method to handle the receipt of a complete line. - - It first looks for a valid protocol token at the start of the line. - Thereafter it trys to execute the lines accumulated so far. - - @param line the received line - """ - # Remove any newline. - if line[-1] == '\n': - line = line[:-1] - -## printerr(line) ##debug - - self.handleJsonCommand(line) - def handleJsonCommand(self, jsonStr): """ Public method to handle a command serialized as a JSON string. @@ -379,9 +361,12 @@ @param jsonStr string containing the command received from the IDE @type str """ +## printerr(jsonStr) ##debug + try: commandDict = json.loads(jsonStr.strip()) except (TypeError, ValueError) as err: + printerr("Error handling command: " + jsonStr) printerr(str(err)) return @@ -1031,23 +1016,17 @@ @param stream file like object that has data to be written """ try: - got = stream.readline_p() + self.lockClient() + command = stream.readCommand() + self.unlockClient() except Exception: return - if len(got) == 0: + if len(command) == 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') + + self.handleJsonCommand(command) def writeReady(self, stream): """ @@ -2071,7 +2050,7 @@ redirect = True elif sys.argv[2] == "False": redirect = False - else: + else: try: redirect = int(sys.argv[2]) except (ValueError, IndexError):
--- a/Debugger/DebuggerInterfacePython.py Thu Nov 09 18:31:34 2017 +0100 +++ b/Debugger/DebuggerInterfacePython.py Sat Nov 11 18:44:04 2017 +0100 @@ -407,7 +407,7 @@ """ # Send commands that were waiting for the connection. for cmd in self.queue: - self.qsock.write(cmd.encode('utf8', 'backslashreplace')) + self.__writeJsonCommandToSocket(cmd) self.queue = [] @@ -1105,9 +1105,21 @@ } cmd = json.dumps(commandDict) + '\n' if self.qsock is not None: - self.qsock.write(cmd.encode('utf8', 'backslashreplace')) + self.__writeJsonCommandToSocket(cmd) else: self.queue.append(cmd) + + def __writeJsonCommandToSocket(self, cmd): + """ + Private method to write a JSON command to the socket. + + @param cmd JSON command to be sent + @type str + """ + data = cmd.encode('utf8', 'backslashreplace') + length = "{0:09d}".format(len(data)) + self.qsock.write(length.encode() + data) + self.qsock.flush() def createDebuggerInterfacePython2(debugServer, passive):
--- a/Documentation/Help/source.qhp Thu Nov 09 18:31:34 2017 +0100 +++ b/Documentation/Help/source.qhp Sat Nov 11 18:44:04 2017 +0100 @@ -1911,6 +1911,7 @@ <keyword name="AsyncFile.isatty" id="AsyncFile.isatty" ref="eric6.DebugClients.Python.AsyncFile.html#AsyncFile.isatty" /> <keyword name="AsyncFile.pendingWrite" id="AsyncFile.pendingWrite" ref="eric6.DebugClients.Python.AsyncFile.html#AsyncFile.pendingWrite" /> <keyword name="AsyncFile.read" id="AsyncFile.read" ref="eric6.DebugClients.Python.AsyncFile.html#AsyncFile.read" /> + <keyword name="AsyncFile.readCommand" id="AsyncFile.readCommand" ref="eric6.DebugClients.Python.AsyncFile.html#AsyncFile.readCommand" /> <keyword name="AsyncFile.read_p" id="AsyncFile.read_p" ref="eric6.DebugClients.Python.AsyncFile.html#AsyncFile.read_p" /> <keyword name="AsyncFile.readable" id="AsyncFile.readable" ref="eric6.DebugClients.Python.AsyncFile.html#AsyncFile.readable" /> <keyword name="AsyncFile.readline" id="AsyncFile.readline" ref="eric6.DebugClients.Python.AsyncFile.html#AsyncFile.readline" /> @@ -3429,7 +3430,6 @@ <keyword name="DebugClientBase.getCoding" id="DebugClientBase.getCoding" ref="eric6.DebugClients.Python.DebugClientBase.html#DebugClientBase.getCoding" /> <keyword name="DebugClientBase.getRunning" id="DebugClientBase.getRunning" ref="eric6.DebugClients.Python.DebugClientBase.html#DebugClientBase.getRunning" /> <keyword name="DebugClientBase.handleJsonCommand" id="DebugClientBase.handleJsonCommand" ref="eric6.DebugClients.Python.DebugClientBase.html#DebugClientBase.handleJsonCommand" /> - <keyword name="DebugClientBase.handleLine" id="DebugClientBase.handleLine" ref="eric6.DebugClients.Python.DebugClientBase.html#DebugClientBase.handleLine" /> <keyword name="DebugClientBase.input" id="DebugClientBase.input" ref="eric6.DebugClients.Python.DebugClientBase.html#DebugClientBase.input" /> <keyword name="DebugClientBase.main" id="DebugClientBase.main" ref="eric6.DebugClients.Python.DebugClientBase.html#DebugClientBase.main" /> <keyword name="DebugClientBase.progTerminated" id="DebugClientBase.progTerminated" ref="eric6.DebugClients.Python.DebugClientBase.html#DebugClientBase.progTerminated" /> @@ -3725,6 +3725,7 @@ <keyword name="DebuggerInterfacePython.__remoteTranslation" id="DebuggerInterfacePython.__remoteTranslation" ref="eric6.Debugger.DebuggerInterfacePython.html#DebuggerInterfacePython.__remoteTranslation" /> <keyword name="DebuggerInterfacePython.__sendJsonCommand" id="DebuggerInterfacePython.__sendJsonCommand" ref="eric6.Debugger.DebuggerInterfacePython.html#DebuggerInterfacePython.__sendJsonCommand" /> <keyword name="DebuggerInterfacePython.__startProcess" id="DebuggerInterfacePython.__startProcess" ref="eric6.Debugger.DebuggerInterfacePython.html#DebuggerInterfacePython.__startProcess" /> + <keyword name="DebuggerInterfacePython.__writeJsonCommandToSocket" id="DebuggerInterfacePython.__writeJsonCommandToSocket" ref="eric6.Debugger.DebuggerInterfacePython.html#DebuggerInterfacePython.__writeJsonCommandToSocket" /> <keyword name="DebuggerInterfacePython.flush" id="DebuggerInterfacePython.flush" ref="eric6.Debugger.DebuggerInterfacePython.html#DebuggerInterfacePython.flush" /> <keyword name="DebuggerInterfacePython.getClientCapabilities" id="DebuggerInterfacePython.getClientCapabilities" ref="eric6.Debugger.DebuggerInterfacePython.html#DebuggerInterfacePython.getClientCapabilities" /> <keyword name="DebuggerInterfacePython.isConnected" id="DebuggerInterfacePython.isConnected" ref="eric6.Debugger.DebuggerInterfacePython.html#DebuggerInterfacePython.isConnected" />
--- a/Documentation/Source/eric6.DebugClients.Python.AsyncFile.html Thu Nov 09 18:31:34 2017 +0100 +++ b/Documentation/Source/eric6.DebugClients.Python.AsyncFile.html Sat Nov 11 18:44:04 2017 +0100 @@ -85,6 +85,9 @@ <td><a href="#AsyncFile.read">read</a></td> <td>Public method to read bytes from this file.</td> </tr><tr> +<td><a href="#AsyncFile.readCommand">readCommand</a></td> +<td>Public method to read a length prefixed command string.</td> +</tr><tr> <td><a href="#AsyncFile.read_p">read_p</a></td> <td>Public method to read bytes from this file.</td> </tr><tr> @@ -243,6 +246,21 @@ <dd> str </dd> +</dl><a NAME="AsyncFile.readCommand" ID="AsyncFile.readCommand"></a> +<h4>AsyncFile.readCommand</h4> +<b>readCommand</b>(<i></i>) +<p> + Public method to read a length prefixed command string. +</p><dl> +<dt>Returns:</dt> +<dd> +command string +</dd> +</dl><dl> +<dt>Return Type:</dt> +<dd> +str +</dd> </dl><a NAME="AsyncFile.read_p" ID="AsyncFile.read_p"></a> <h4>AsyncFile.read_p</h4> <b>read_p</b>(<i>size=-1</i>)
--- a/Documentation/Source/eric6.DebugClients.Python.DebugClientBase.html Thu Nov 09 18:31:34 2017 +0100 +++ b/Documentation/Source/eric6.DebugClients.Python.DebugClientBase.html Sat Nov 11 18:44:04 2017 +0100 @@ -167,9 +167,6 @@ <td><a href="#DebugClientBase.handleJsonCommand">handleJsonCommand</a></td> <td>Public method to handle a command serialized as a JSON string.</td> </tr><tr> -<td><a href="#DebugClientBase.handleLine">handleLine</a></td> -<td>Public method to handle the receipt of a complete line.</td> -</tr><tr> <td><a href="#DebugClientBase.input">input</a></td> <td>Public method to implement input() (Python 2) using the event loop.</td> </tr><tr> @@ -630,19 +627,6 @@ <dd> string containing the command received from the IDE </dd> -</dl><a NAME="DebugClientBase.handleLine" ID="DebugClientBase.handleLine"></a> -<h4>DebugClientBase.handleLine</h4> -<b>handleLine</b>(<i>line</i>) -<p> - Public method to handle the receipt of a complete line. -</p><p> - It first looks for a valid protocol token at the start of the line. - Thereafter it trys to execute the lines accumulated so far. -</p><dl> -<dt><i>line</i></dt> -<dd> -the received line -</dd> </dl><a NAME="DebugClientBase.input" ID="DebugClientBase.input"></a> <h4>DebugClientBase.input</h4> <b>input</b>(<i>prompt</i>)
--- a/Documentation/Source/eric6.Debugger.DebuggerInterfacePython.html Thu Nov 09 18:31:34 2017 +0100 +++ b/Documentation/Source/eric6.Debugger.DebuggerInterfacePython.html Sat Nov 11 18:44:04 2017 +0100 @@ -91,6 +91,9 @@ <td><a href="#DebuggerInterfacePython.__startProcess">__startProcess</a></td> <td>Private method to start the debugger client process.</td> </tr><tr> +<td><a href="#DebuggerInterfacePython.__writeJsonCommandToSocket">__writeJsonCommandToSocket</a></td> +<td>Private method to write a JSON command to the socket.</td> +</tr><tr> <td><a href="#DebuggerInterfacePython.flush">flush</a></td> <td>Public slot to flush the queue.</td> </tr><tr> @@ -321,6 +324,16 @@ <dd> the process object (QProcess) or None </dd> +</dl><a NAME="DebuggerInterfacePython.__writeJsonCommandToSocket" ID="DebuggerInterfacePython.__writeJsonCommandToSocket"></a> +<h4>DebuggerInterfacePython.__writeJsonCommandToSocket</h4> +<b>__writeJsonCommandToSocket</b>(<i>cmd</i>) +<p> + Private method to write a JSON command to the socket. +</p><dl> +<dt><i>cmd</i> (str)</dt> +<dd> +JSON command to be sent +</dd> </dl><a NAME="DebuggerInterfacePython.flush" ID="DebuggerInterfacePython.flush"></a> <h4>DebuggerInterfacePython.flush</h4> <b>flush</b>(<i></i>)