Continued with the multiprocess debugger. multi_processing

Thu, 30 Jan 2020 19:37:03 +0100

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Thu, 30 Jan 2020 19:37:03 +0100
branch
multi_processing
changeset 7377
cc920e534ac0
parent 7376
21df384d6150
child 7379
72a72fd56494

Continued with the multiprocess debugger.

eric6/DebugClients/Python/AsyncFile.py file | annotate | diff | comparison | revisions
eric6/DebugClients/Python/DebugClientBase.py file | annotate | diff | comparison | revisions
eric6/Debugger/CallStackViewer.py file | annotate | diff | comparison | revisions
eric6/Debugger/DebugServer.py file | annotate | diff | comparison | revisions
eric6/Debugger/DebugUI.py file | annotate | diff | comparison | revisions
eric6/Debugger/DebugViewer.py file | annotate | diff | comparison | revisions
eric6/Debugger/DebuggerInterfacePython.py file | annotate | diff | comparison | revisions
eric6/UI/UserInterface.py file | annotate | diff | comparison | revisions
--- 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)

eric ide

mercurial