Thu, 30 Jan 2020 19:37:03 +0100
Continued with the multiprocess debugger.
--- a/eric6/DebugClients/Python/AsyncFile.py Wed Jan 29 19:38:13 2020 +0100 +++ b/eric6/DebugClients/Python/AsyncFile.py Thu Jan 30 19:37:03 2020 +0100 @@ -345,6 +345,7 @@ cmd = prepareJsonCommand("ClientOutput", { "text": s, + "debuggerId": "", }) self.wpending.append(cmd) self.flush()
--- a/eric6/DebugClients/Python/DebugClientBase.py Wed Jan 29 19:38:13 2020 +0100 +++ b/eric6/DebugClients/Python/DebugClientBase.py Thu Jan 30 19:37:03 2020 +0100 @@ -2210,7 +2210,6 @@ self.startOptions = ( wd, host, port, exceptions, tracePython, redirect, self.noencoding, self.fork_auto, self.fork_child, - self.pids ) if not self.noencoding: self.__coding = self.defaultCoding @@ -2261,7 +2260,6 @@ self.startOptions = ( '', remoteAddress, port, True, False, redirect, self.noencoding, self.fork_auto, self.fork_child, - self.pids ) if not self.noencoding: self.__coding = self.defaultCoding
--- a/eric6/Debugger/CallStackViewer.py Wed Jan 29 19:38:13 2020 +0100 +++ b/eric6/Debugger/CallStackViewer.py Thu Jan 30 19:37:03 2020 +0100 @@ -105,6 +105,7 @@ @param stack list of tuples with call stack data (file name, line number, function name, formatted argument/values list) + @type list of tuples of (str, str, str, str) """ self.clear() for fname, fline, ffunc, fargs in stack:
--- a/eric6/Debugger/DebugServer.py Wed Jan 29 19:38:13 2020 +0100 +++ b/eric6/Debugger/DebugServer.py Thu Jan 30 19:37:03 2020 +0100 @@ -44,12 +44,12 @@ @signal clientOutput(str) emitted after the client has sent some output @signal clientRawInputSent() emitted after the data was sent to the debug client - @signal clientLine(filename, lineno, forStack) emitted after the - debug client has executed a line of code - @signal clientStack(stack) emitted after the debug client has executed a - line of code - @signal clientThreadList(currentId, threadList) emitted after a thread list - has been received + @signal clientLine(filename, lineno, debuggerId, forStack) emitted after + the debug client has executed a line of code + @signal clientStack(stack, debuggerId) emitted after the debug client has + executed a line of code + @signal clientThreadList(currentId, threadList, debuggerId) emitted after + a thread list has been received @signal clientThreadSet() emitted after the client has acknowledged the change of the current thread @signal clientVariables(scope, variables) emitted after a variables dump @@ -124,9 +124,9 @@ clientProcessStderr = pyqtSignal(str) clientRawInputSent = pyqtSignal() clientOutput = pyqtSignal(str) - clientLine = pyqtSignal(str, int, bool) - clientStack = pyqtSignal(list) - clientThreadList = pyqtSignal('PyQt_PyObject', list) + clientLine = pyqtSignal(str, int, str, bool) + clientStack = pyqtSignal(list, str) + clientThreadList = pyqtSignal(int, list, str) clientThreadSet = pyqtSignal() clientVariables = pyqtSignal(int, list) clientVariable = pyqtSignal(int, list) @@ -1462,42 +1462,59 @@ """ self.debuggerInterface.remoteUTStop() - def signalClientOutput(self, line): + def signalClientOutput(self, line, debuggerId): """ Public method to process a line of client output. - @param line client output (string) + @param line client output + @type str + @param debuggerId ID of the debugger backend + @type str """ - self.clientOutput.emit(line) + if debuggerId: + self.clientOutput.emit("{0}: {1}".format(debuggerId, line)) + else: + self.clientOutput.emit(line) - def signalClientLine(self, filename, lineno, forStack=False): + def signalClientLine(self, filename, lineno, debuggerId, forStack=False): """ Public method to process client position feedback. - @param filename name of the file currently being executed (string) - @param lineno line of code currently being executed (integer) - @param forStack flag indicating this is for a stack dump (boolean) + @param filename name of the file currently being executed + @type str + @param lineno line of code currently being executed + @type int + @param debuggerId ID of the debugger backend + @type str + @param forStack flag indicating this is for a stack dump + @type bool """ - self.clientLine.emit(filename, lineno, forStack) + self.clientLine.emit(filename, lineno, debuggerId, forStack) - def signalClientStack(self, stack): + def signalClientStack(self, stack, debuggerId): """ Public method to process a client's stack information. @param stack list of stack entries. Each entry is a tuple of three values giving the filename, linenumber and method - (list of lists of (string, integer, string)) + @type list of lists of (string, integer, string) + @param debuggerId ID of the debugger backend + @type str """ - self.clientStack.emit(stack) + self.clientStack.emit(stack, debuggerId) - def signalClientThreadList(self, currentId, threadList): + def signalClientThreadList(self, currentId, threadList, debuggerId): """ Public method to process the client thread list info. - @param currentId id of the current thread (integer) + @param currentId id of the current thread + @type int @param threadList list of dictionaries containing the thread data + @type list of dict + @param debuggerId ID of the debugger backend + @type str """ - self.clientThreadList.emit(currentId, threadList) + self.clientThreadList.emit(currentId, threadList, debuggerId) def signalClientThreadSet(self): """
--- a/eric6/Debugger/DebugUI.py Wed Jan 29 19:38:13 2020 +0100 +++ b/eric6/Debugger/DebugUI.py Thu Jan 30 19:37:03 2020 +0100 @@ -34,7 +34,8 @@ """ Class implementing the debugger part of the UI. - @signal clientStack(stack) emitted at breaking after a reported exception + @signal clientStack(stack, debuggerId) emitted at breaking after a reported + exception @signal compileForms() emitted if changed project forms should be compiled @signal compileResources() emitted if changed project resources should be compiled @@ -48,7 +49,7 @@ @signal appendStdout(msg) emitted when the client program has terminated and the display of the termination dialog is suppressed """ - clientStack = pyqtSignal(list) + clientStack = pyqtSignal(list, str) resetUI = pyqtSignal() exceptionInterrupt = pyqtSignal() compileForms = pyqtSignal() @@ -137,9 +138,6 @@ debugServer.passiveDebugStarted.connect(self.__passiveDebugStarted) debugServer.clientThreadSet.connect(self.__clientThreadSet) - debugServer.clientThreadList.connect(debugViewer.showThreadList) - debugServer.clientDebuggerIds.connect(debugViewer.showDebuggersList) - # Connect the signals emitted by the viewmanager vm.editorOpened.connect(self.__editorOpened) vm.lastEditorClosed.connect(self.__lastEditorClosed) @@ -996,13 +994,18 @@ self.stopAct.setEnabled(False) self.resetUI.emit() - def __clientLine(self, fn, line, forStack): + def __clientLine(self, fn, line, debuggerId, forStack): """ Private method to handle a change to the current line. - @param fn filename (string) - @param line linenumber (int) - @param forStack flag indicating this is for a stack dump (boolean) + @param fn filename + @type str + @param line linenumber + @type int + @param debuggerId ID of the debugger backend + @type str + @param forStack flag indicating this is for a stack dump + @type bool """ self.ui.raise_() self.ui.activateWindow() @@ -1126,13 +1129,19 @@ '</p>') .format(filename, message, lineNo, characterNo)) - def __clientException(self, exceptionType, exceptionMessage, stackTrace): + def __clientException(self, exceptionType, exceptionMessage, stackTrace, + debuggerId=""): """ Private method to handle an exception of the debugged program. - @param exceptionType type of exception raised (string) - @param exceptionMessage message given by the exception (string) - @param stackTrace list of stack entries (list of string) + @param exceptionType type of exception raised + @type str + @param exceptionMessage message given by the exception + @type (str + @param stackTrace list of stack entries + @type list of str + @param debuggerId ID of the debugger backend + @type str """ self.ui.raise_() QApplication.processEvents() @@ -1216,7 +1225,7 @@ stack = [] for fn, ln, func, args in stackTrace: stack.append((fn, ln, func, args)) - self.clientStack.emit(stack) + self.clientStack.emit(stack, debuggerId) self.__getClientVariables() self.ui.setDebugProfile() self.debugActGrp.setEnabled(True) @@ -2251,6 +2260,7 @@ self.lastAction = 0 self.__enterRemote() self.debugServer.remoteContinue() + self.__getThreadList() def __specialContinue(self): """ @@ -2259,6 +2269,7 @@ self.lastAction = 2 self.__enterRemote() self.debugServer.remoteContinue(1) + self.__getThreadList() def __step(self): """ @@ -2275,6 +2286,7 @@ self.lastAction = 2 self.__enterRemote() self.debugServer.remoteStepOver() + self.__getThreadList() def __stepOut(self): """ @@ -2283,6 +2295,7 @@ self.lastAction = 3 self.__enterRemote() self.debugServer.remoteStepOut() + self.__getThreadList() def __stepQuit(self): """ @@ -2304,6 +2317,7 @@ self.debugServer.remoteBreakpoint( aw.getFileName(), line, 1, None, 1) self.debugServer.remoteContinue() + self.__getThreadList() def __moveInstructionPointer(self): """
--- a/eric6/Debugger/DebugViewer.py Wed Jan 29 19:38:13 2020 +0100 +++ b/eric6/Debugger/DebugViewer.py Thu Jan 30 19:37:03 2020 +0100 @@ -23,7 +23,7 @@ import os -from PyQt5.QtCore import pyqtSignal +from PyQt5.QtCore import pyqtSignal, Qt from PyQt5.QtWidgets import ( QWidget, QVBoxLayout, QHBoxLayout, QLineEdit, QSizePolicy, QPushButton, QComboBox, QLabel, QTreeWidget, QTreeWidgetItem, QHeaderView, QFrame @@ -69,7 +69,7 @@ self.setLayout(self.__mainLayout) # add the viewer showing the connected debug backends - self.__debuggersLayout = QHBoxLayout(self) + self.__debuggersLayout = QHBoxLayout() self.__debuggersLayout.addWidget(QLabel(self.tr("Debuggers:"))) self.__debuggersCombo = QComboBox(self) self.__debuggersCombo.setSizePolicy( @@ -77,7 +77,7 @@ self.__debuggersLayout.addWidget(self.__debuggersCombo) self.__mainLayout.addLayout(self.__debuggersLayout) - self.__debuggersCombo.currentTextChanged.connect( + self.__debuggersCombo.currentIndexChanged[str].connect( self.__debuggerSelected) # add a line to separate debugger selector from debugger specific parts @@ -264,11 +264,29 @@ self.currentStack = None self.framenr = 0 - self.debugServer.clientStack.connect(self.handleClientStack) - self.__autoViewSource = Preferences.getDebugger("AutoViewSourceCode") self.sourceButton.setVisible(not self.__autoViewSource) + # connect somer debug server signals + self.debugServer.clientStack.connect( + self.handleClientStack) + self.debugServer.clientThreadList.connect( + self.showThreadList) + self.debugServer.clientDebuggerIds.connect( + self.showDebuggersList) + self.debugServer.passiveDebugStarted.connect( + self.handleDebuggingStarted) + self.debugServer.clientLine.connect( + self.__clientLine) + + self.debugServer.clientException.connect( + self.exceptionLogger.addException) + self.debugServer.passiveDebugStarted.connect( + self.exceptionLogger.debuggingStarted) + + self.debugServer.clientLine.connect( + self.breakpointViewer.highlightBreakpoint) + def handlePreferencesChanged(self): """ Public slot to handle the preferencesChanged signal. @@ -283,9 +301,15 @@ @param debugUI reference to the DebugUI object (DebugUI) """ self.debugUI = debugUI - self.debugUI.clientStack.connect(self.handleClientStack) self.callStackViewer.setDebugger(debugUI) + # connect some debugUI signals + self.debugUI.clientStack.connect(self.handleClientStack) + self.debugUI.debuggingStarted.connect( + self.exceptionLogger.debuggingStarted) + self.debugUI.debuggingStarted.connect( + self.handleDebuggingStarted) + def handleResetUI(self): """ Public method to reset the SBVviewer. @@ -371,24 +395,45 @@ else: self.__tabWidget.setCurrentWidget(self.lvWidget) - def handleClientStack(self, stack): + def handleClientStack(self, stack, debuggerId): """ Public slot to show the call stack of the program being debugged. @param stack list of tuples with call stack data (file name, line number, function name, formatted argument/values list) + @type list of tuples of (str, str, str, str) + @param debuggerId ID of the debugger backend + @type str """ - block = self.stackComboBox.blockSignals(True) - self.framenr = 0 - self.stackComboBox.clear() - self.currentStack = stack - self.sourceButton.setEnabled(len(stack) > 0) - for s in stack: - # just show base filename to make it readable - s = (os.path.basename(s[0]), s[1], s[2]) - self.stackComboBox.addItem('{0}:{1}:{2}'.format(*s)) - self.stackComboBox.blockSignals(block) + if debuggerId == self.__debuggersCombo.currentText(): + block = self.stackComboBox.blockSignals(True) + self.framenr = 0 + self.stackComboBox.clear() + self.currentStack = stack + self.sourceButton.setEnabled(len(stack) > 0) + for s in stack: + # just show base filename to make it readable + s = (os.path.basename(s[0]), s[1], s[2]) + self.stackComboBox.addItem('{0}:{1}:{2}'.format(*s)) + self.stackComboBox.blockSignals(block) + + def __clientLine(self, fn, line, debuggerId): + """ + Private method to handle a change to the current line. + @param fn filename + @type str + @param line linenumber + @type int + @param debuggerId ID of the debugger backend + @type str + """ + if debuggerId: + index = self.__debuggersCombo.findText(debuggerId, Qt.MatchExactly) + if index >= 0: + self.__debuggersCombo.setItemIcon( + index, UI.PixmapCache.getIcon("exceptions.png")) + def setVariablesFilter(self, globalsFilter, localsFilter): """ Public slot to set the local variables filter. @@ -471,41 +516,68 @@ """ self.__tabWidget.setCurrentWidget(widget) - def showThreadList(self, currentID, threadList): + def showThreadList(self, currentID, threadList, debuggerId): """ Public method to show the thread list. - @param currentID id of the current thread (integer) + @param currentID id of the current thread + @type int @param threadList list of dictionaries containing the thread data + @type list of dict + @param debuggerId ID of the debugger backend + @type str """ - citm = None + debugStatus = -1 # i.e. running - self.__threadList.clear() - for thread in threadList: - if thread.get('except', False): - state = self.tr("waiting at exception") - icon = "exceptions.png" - elif thread['broken']: - state = self.tr("waiting at breakpoint") - icon = "mediaPlaybackPause.png" - else: - state = self.tr("running") - icon = "mediaPlaybackStart.png" - itm = QTreeWidgetItem(self.__threadList, - ["{0:d}".format(thread['id']), - thread['name'], state]) - itm.setIcon(0, UI.PixmapCache.getIcon(icon)) - if thread['id'] == currentID: - citm = itm + if debuggerId == self.__debuggersCombo.currentText(): + citm = None + + self.__threadList.clear() + for thread in threadList: + if thread.get('except', False): + state = self.tr("waiting at exception") + icon = "exceptions.png" + debugStatus = 1 + elif thread['broken']: + state = self.tr("waiting at breakpoint") + icon = "mediaPlaybackPause.png" + if debugStatus < 1: + debugStatus = 0 + else: + state = self.tr("running") + icon = "mediaPlaybackStart.png" + itm = QTreeWidgetItem(self.__threadList, + ["{0:d}".format(thread['id']), + thread['name'], state]) + itm.setIcon(0, UI.PixmapCache.getIcon(icon)) + if thread['id'] == currentID: + citm = itm + + self.__threadList.header().resizeSections( + QHeaderView.ResizeToContents) + self.__threadList.header().setStretchLastSection(True) + + if citm: + self.__doThreadListUpdate = False + self.__threadList.setCurrentItem(citm) + self.__doThreadListUpdate = True + else: + for thread in threadList: + if thread.get('except', False): + debugStatus = 1 + elif thread['broken']: + if debugStatus < 1: + debugStatus = 0 - self.__threadList.header().resizeSections(QHeaderView.ResizeToContents) - self.__threadList.header().setStretchLastSection(True) - - if citm: - self.__doThreadListUpdate = False - self.__threadList.setCurrentItem(citm) - self.__doThreadListUpdate = True - + if debugStatus == -1: + icon = "mediaPlaybackStart.png" + elif debugStatus == 0: + icon = "mediaPlaybackPause.png" + else: + icon = "exceptions.png" + self.__debuggersCombo.setItemIcon(self.__debuggersCombo.currentIndex(), + UI.PixmapCache.getIcon(icon)) + def __threadSelected(self, current, previous): """ Private slot to handle the selection of a thread in the thread list.
--- a/eric6/Debugger/DebuggerInterfacePython.py Wed Jan 29 19:38:13 2020 +0100 +++ b/eric6/Debugger/DebuggerInterfacePython.py Thu Jan 30 19:37:03 2020 +0100 @@ -1152,7 +1152,8 @@ self.__assignDebuggerId(sock, params["debuggerId"]) elif method == "ClientOutput": - self.debugServer.signalClientOutput(params["text"]) + self.debugServer.signalClientOutput( + params["text"], params["debuggerId"]) elif method in ["ResponseLine", "ResponseStack"]: # Check if obsolet thread was clicked @@ -1168,9 +1169,10 @@ QTimer.singleShot(0, self.remoteContinue) else: self.debugServer.signalClientLine( - cf[0], int(cf[1]), + cf[0], int(cf[1]), params["debuggerId"], method == "ResponseStack") - self.debugServer.signalClientStack(params["stack"]) + self.debugServer.signalClientStack( + params["stack"], params["debuggerId"]) elif method == "CallTrace": isCall = params["event"].lower() == "c" @@ -1193,7 +1195,8 @@ elif method == "ResponseThreadList": self.debugServer.signalClientThreadList( - params["currentID"], params["threadList"]) + params["currentID"], params["threadList"], + params["debuggerId"]) elif method == "ResponseThreadSet": self.debugServer.signalClientThreadSet()
--- a/eric6/UI/UserInterface.py Wed Jan 29 19:38:13 2020 +0100 +++ b/eric6/UI/UserInterface.py Thu Jan 30 19:37:03 2020 +0100 @@ -427,10 +427,6 @@ self.debuggerUI.resetUI.connect(self.viewmanager.handleResetUI) self.debuggerUI.resetUI.connect(self.debugViewer.handleResetUI) self.debuggerUI.resetUI.connect(self.__debuggingDone) - self.debuggerUI.debuggingStarted.connect( - self.debugViewer.exceptionLogger.debuggingStarted) - self.debuggerUI.debuggingStarted.connect( - self.debugViewer.handleDebuggingStarted) self.debuggerUI.debuggingStarted.connect(self.__programChange) self.debuggerUI.debuggingStarted.connect(self.__debuggingStarted) self.debuggerUI.compileForms.connect( @@ -440,14 +436,6 @@ self.debuggerUI.executeMake.connect(self.project.executeMake) self.debuggerUI.appendStdout.connect(self.appendToStdout) - debugServer.passiveDebugStarted.connect( - self.debugViewer.exceptionLogger.debuggingStarted) - debugServer.passiveDebugStarted.connect( - self.debugViewer.handleDebuggingStarted) - debugServer.clientException.connect( - self.debugViewer.exceptionLogger.addException) - debugServer.clientLine.connect( - self.debugViewer.breakpointViewer.highlightBreakpoint) debugServer.clientProcessStdout.connect(self.appendToStdout) debugServer.clientProcessStderr.connect(self.appendToStderr) debugServer.appendStdout.connect(self.appendToStdout)