eric6/Debugger/DebuggerInterfacePython.py

branch
multi_processing
changeset 7379
72a72fd56494
parent 7377
cc920e534ac0
child 7389
770ffcb88be5
diff -r cc920e534ac0 -r 72a72fd56494 eric6/Debugger/DebuggerInterfacePython.py
--- a/eric6/Debugger/DebuggerInterfacePython.py	Thu Jan 30 19:37:03 2020 +0100
+++ b/eric6/Debugger/DebuggerInterfacePython.py	Sat Feb 01 19:48:21 2020 +0100
@@ -58,8 +58,8 @@
         self.__variant = pythonVariant
         self.__startedVenv = ""
         
-        self.qsock = None
         self.queue = []
+        self.__master = None
         self.__connections = {}
         self.__pendingConnections = []
         
@@ -487,7 +487,7 @@
             self.__startedVenv = venvName
         
         return process, self.__isNetworked, interpreter
-
+    
     def getClientCapabilities(self):
         """
         Public method to retrieve the debug clients capabilities.
@@ -500,19 +500,16 @@
         """
         Public slot to handle a new connection.
         
-        @param sock reference to the socket object (QTcpSocket)
-        @return flag indicating success (boolean)
+        @param sock reference to the socket object
+        @type QTcpSocket
+        @return flag indicating success
+        @rtype bool
         """
-        sock.disconnected.connect(self.debugServer.startClient)
-        sock.readyRead.connect(lambda: self.__parseClientLine(sock))
-        
-        if self.qsock is None:
-            # first connection is the main one
-            self.qsock = sock
         self.__pendingConnections.append(sock)
         
-        # Get the remote clients capabilities
-        self.remoteCapabilities()
+        sock.readyRead.connect(lambda: self.__parseClientLine(sock))
+        sock.disconnected.connect(lambda: self.__socketDisconnected(sock))
+        
         return True
     
     def __assignDebuggerId(self, sock, debuggerId):
@@ -529,8 +526,38 @@
             self.__connections[debuggerId] = sock
             self.__pendingConnections.remove(sock)
             
+            if self.__master is None:
+                self.__master = debuggerId
+                # Get the remote clients capabilities
+                self.remoteCapabilities()
+            
             self.debugServer.signalClientDebuggerIds(
                 sorted(self.__connections.keys()))
+            
+            if debuggerId == self.__master:
+                self.__flush()
+                self.debugServer.masterClientConnected()
+            
+            self.debugServer.initializeClient(debuggerId)
+    
+    def __socketDisconnected(self, sock):
+        """
+        Private slot handling a socket disconnecting.
+        
+        @param sock reference to the disconnected socket
+        @type QTcpSocket
+        """
+        for debuggerId in self.__connections:
+            if self.__connections[debuggerId] is sock:
+                del self.__connections[debuggerId]
+                break
+        else:
+            if sock in self.__pendingConnections:
+                self.__pendingConnections.remove(sock)
+        
+        if not self.__connections:
+            # no active connections anymore => restart the backend
+            self.debugServer.startClient()
     
     def getDebuggerIds(self):
         """
@@ -541,14 +568,15 @@
         """
         return sorted(self.__connections.keys())
     
-    def flush(self):
+    def __flush(self):
         """
-        Public slot to flush the queue.
+        Private slot to flush the queue.
         """
-        if self.qsock:
+        if self.__master:
             # Send commands that were waiting for the connection.
             for cmd in self.queue:
-                self.__writeJsonCommandToSocket(cmd, self.qsock)
+                self.__writeJsonCommandToSocket(
+                    cmd, self.__connections[self.__master])
         
         self.queue = []
     
@@ -556,38 +584,53 @@
         """
         Public method to cleanly shut down.
         
-        It closes our socket and shuts down
-        the debug client. (Needed on Win OS)
+        It closes our sockets and shuts down the debug clients.
+        (Needed on Win OS)
         """
-        if self.qsock is None:
+        if not self.__master:
             return
         
-        for sock in (
-            list(self.__connections.values()) + self.__pendingConnections
-        ):
-            # do not want any slots called during shutdown
-            sock.disconnected.disconnect()
-            sock.readyRead.disconnect()
+        while self.__connections:
+            debuggerId, sock = self.__connections.popitem()
+            self.__shutdownSocket(sock)
         
-            # close down socket, and shut down client as well.
-            self.__sendJsonCommand("RequestShutdown", {}, sock=sock)
-            sock.flush()
-            sock.close()
+        while self.__pendingConnections:
+            sock = self.__pendingConnections.pop()
+            self.__shutdownSocket(sock)
         
         # reinitialize
-        self.qsock = None
         self.queue = []
         
-        self.__pendingConnections = []
-        self.__connections = {}
+        self.__master = None
+
+    def __shutdownSocket(self, sock):
+        """
+        Private slot to shut down a socket.
+        
+        @param sock reference to the socket
+        @type QTcpSocket
+        """
+        # do not want any slots called during shutdown
+        sock.readyRead.disconnect()
+        sock.disconnected.disconnect()
+
+        # close down socket, and shut down client as well.
+        self.__sendJsonCommand("RequestShutdown", {}, sock=sock)
+        sock.flush()
+        sock.close()
+        
+        sock.setParent(None)
+        sock.deleteLater()
+        del sock
     
     def isConnected(self):
         """
         Public method to test, if a debug client has connected.
         
-        @return flag indicating the connection status (boolean)
+        @return flag indicating the connection status
+        @rtype bool
         """
-        return self.qsock is not None
+        return bool(self.__connections)
     
     def remoteEnvironment(self, env):
         """
@@ -595,7 +638,9 @@
         
         @param env environment settings (dictionary)
         """
-        self.__sendJsonCommand("RequestEnvironment", {"environment": env})
+        if self.__master:
+            self.__sendJsonCommand("RequestEnvironment", {"environment": env},
+                                   self.__master)
     
     def remoteLoad(self, fn, argv, wd, traceInterpreter=False,
                    autoContinue=True, autoFork=False, forkChild=False):
@@ -625,7 +670,7 @@
             "traceInterpreter": traceInterpreter,
             "autofork": autoFork,
             "forkChild": forkChild,
-        })
+        }, self.__master)
     
     def remoteRun(self, fn, argv, wd, autoFork=False, forkChild=False):
         """
@@ -648,7 +693,7 @@
             "argv": Utilities.parseOptionString(argv),
             "autofork": autoFork,
             "forkChild": forkChild,
-        })
+        }, self.__master)
     
     def remoteCoverage(self, fn, argv, wd, erase=False):
         """
@@ -669,7 +714,7 @@
             "filename": fn,
             "argv": Utilities.parseOptionString(argv),
             "erase": erase,
-        })
+        }, self.__master)
 
     def remoteProfile(self, fn, argv, wd, erase=False):
         """
@@ -690,155 +735,236 @@
             "filename": fn,
             "argv": Utilities.parseOptionString(argv),
             "erase": erase,
-        })
-
-    def remoteStatement(self, stmt):
+        }, self.__master)
+    
+    def remoteStatement(self, debuggerId, stmt):
         """
         Public method to execute a Python statement.
         
-        @param stmt the Python statement to execute (string). It
-              should not have a trailing newline.
+        @param debuggerId ID of the debugger backend
+        @type str
+        @param stmt the Python statement to execute.
+        @type str
         """
         self.__sendJsonCommand("ExecuteStatement", {
             "statement": stmt,
-        })
-
-    def remoteStep(self):
+        }, debuggerId)
+    
+    def remoteStep(self, debuggerId):
         """
         Public method to single step the debugged program.
+        
+        @param debuggerId ID of the debugger backend
+        @type str
         """
-        self.__sendJsonCommand("RequestStep", {})
-
-    def remoteStepOver(self):
+        self.__sendJsonCommand("RequestStep", {}, debuggerId)
+    
+    def remoteStepOver(self, debuggerId):
         """
         Public method to step over the debugged program.
+        
+        @param debuggerId ID of the debugger backend
+        @type str
         """
-        self.__sendJsonCommand("RequestStepOver", {})
-
-    def remoteStepOut(self):
+        self.__sendJsonCommand("RequestStepOver", {}, debuggerId)
+    
+    def remoteStepOut(self, debuggerId):
         """
         Public method to step out the debugged program.
+        
+        @param debuggerId ID of the debugger backend
+        @type str
         """
-        self.__sendJsonCommand("RequestStepOut", {})
-
-    def remoteStepQuit(self):
+        self.__sendJsonCommand("RequestStepOut", {}, debuggerId)
+    
+    def remoteStepQuit(self, debuggerId):
         """
         Public method to stop the debugged program.
+        
+        @param debuggerId ID of the debugger backend
+        @type str
         """
-        self.__sendJsonCommand("RequestStepQuit", {})
-
-    def remoteContinue(self, special=False):
+        self.__sendJsonCommand("RequestStepQuit", {}, debuggerId)
+    
+    def remoteContinue(self, debuggerId, special=False):
         """
         Public method to continue the debugged program.
         
+        @param debuggerId ID of the debugger backend
+        @type str
         @param special flag indicating a special continue operation
+        @type bool
         """
         self.__sendJsonCommand("RequestContinue", {
             "special": special,
-        })
-
-    def remoteMoveIP(self, line):
+        }, debuggerId)
+    
+    def remoteMoveIP(self, debuggerId, line):
         """
         Public method to move the instruction pointer to a different line.
         
+        @param debuggerId ID of the debugger backend
+        @type str
         @param line the new line, where execution should be continued
+        @type int
         """
         self.__sendJsonCommand("RequestMoveIP", {
             "newLine": line,
-        })
-
-    def remoteBreakpoint(self, fn, line, setBreakpoint, cond=None, temp=False):
+        }, debuggerId)
+    
+    def remoteBreakpoint(self, debuggerId, fn, line, setBreakpoint, cond=None,
+                         temp=False):
         """
         Public method to set or clear a breakpoint.
         
-        @param fn filename the breakpoint belongs to (string)
-        @param line linenumber of the breakpoint (int)
-        @param setBreakpoint flag indicating setting or resetting a
-            breakpoint (boolean)
-        @param cond condition of the breakpoint (string)
-        @param temp flag indicating a temporary breakpoint (boolean)
+        @param debuggerId ID of the debugger backend
+        @type str
+        @param fn filename the breakpoint belongs to
+        @type str
+        @param line linenumber of the breakpoint
+        @type int
+        @param setBreakpoint flag indicating setting or resetting a breakpoint
+        @type bool
+        @param cond condition of the breakpoint
+        @type str
+        @param temp flag indicating a temporary breakpoint
+        @type bool
         """
-        self.__sendJsonCommand("RequestBreakpoint", {
-            "filename": self.translate(fn, False),
-            "line": line,
-            "temporary": temp,
-            "setBreakpoint": setBreakpoint,
-            "condition": cond,
-        })
+        if debuggerId:
+            debuggerList = [debuggerId]
+        else:
+            debuggerList = list(self.__connections.keys())
+        for debuggerId in debuggerList:
+            self.__sendJsonCommand("RequestBreakpoint", {
+                "filename": self.translate(fn, False),
+                "line": line,
+                "temporary": temp,
+                "setBreakpoint": setBreakpoint,
+                "condition": cond,
+            }, debuggerId)
     
-    def remoteBreakpointEnable(self, fn, line, enable):
+    def remoteBreakpointEnable(self, debuggerId, fn, line, enable):
         """
         Public method to enable or disable a breakpoint.
         
-        @param fn filename the breakpoint belongs to (string)
-        @param line linenumber of the breakpoint (int)
+        @param debuggerId ID of the debugger backend
+        @type str
+        @param fn filename the breakpoint belongs to
+        @type str
+        @param line linenumber of the breakpoint
+        @type int
         @param enable flag indicating enabling or disabling a breakpoint
-            (boolean)
+        @type bool
         """
-        self.__sendJsonCommand("RequestBreakpointEnable", {
-            "filename": self.translate(fn, False),
-            "line": line,
-            "enable": enable,
-        })
+        if debuggerId:
+            debuggerList = [debuggerId]
+        else:
+            debuggerList = list(self.__connections.keys())
+        for debuggerId in debuggerList:
+            self.__sendJsonCommand("RequestBreakpointEnable", {
+                "filename": self.translate(fn, False),
+                "line": line,
+                "enable": enable,
+            }, debuggerId)
     
-    def remoteBreakpointIgnore(self, fn, line, count):
+    def remoteBreakpointIgnore(self, debuggerId, fn, line, count):
         """
         Public method to ignore a breakpoint the next couple of occurrences.
         
-        @param fn filename the breakpoint belongs to (string)
-        @param line linenumber of the breakpoint (int)
-        @param count number of occurrences to ignore (int)
+        @param debuggerId ID of the debugger backend
+        @type str
+        @param fn filename the breakpoint belongs to
+        @type str
+        @param line linenumber of the breakpoint
+        @type int
+        @param count number of occurrences to ignore
+        @type int
         """
-        self.__sendJsonCommand("RequestBreakpointIgnore", {
-            "filename": self.translate(fn, False),
-            "line": line,
-            "count": count,
-        })
+        if debuggerId:
+            debuggerList = [debuggerId]
+        else:
+            debuggerList = list(self.__connections.keys())
+        for debuggerId in debuggerList:
+            self.__sendJsonCommand("RequestBreakpointIgnore", {
+                "filename": self.translate(fn, False),
+                "line": line,
+                "count": count,
+            }, debuggerId)
     
-    def remoteWatchpoint(self, cond, setWatch, temp=False):
+    def remoteWatchpoint(self, debuggerId, cond, setWatch, temp=False):
         """
         Public method to set or clear a watch expression.
         
-        @param cond expression of the watch expression (string)
+        @param debuggerId ID of the debugger backend
+        @type str
+        @param cond expression of the watch expression
+        @type str
         @param setWatch flag indicating setting or resetting a watch expression
-            (boolean)
-        @param temp flag indicating a temporary watch expression (boolean)
+        @type bool
+        @param temp flag indicating a temporary watch expression
+        @type bool
         """
-        # cond is combination of cond and special (s. watch expression viewer)
-        self.__sendJsonCommand("RequestWatch", {
-            "temporary": temp,
-            "setWatch": setWatch,
-            "condition": cond,
-        })
+        if debuggerId:
+            debuggerList = [debuggerId]
+        else:
+            debuggerList = list(self.__connections.keys())
+        for debuggerId in debuggerList:
+            # cond is combination of cond and special (s. watch expression
+            # viewer)
+            self.__sendJsonCommand("RequestWatch", {
+                "temporary": temp,
+                "setWatch": setWatch,
+                "condition": cond,
+            }, debuggerId)
     
-    def remoteWatchpointEnable(self, cond, enable):
+    def remoteWatchpointEnable(self, debuggerId, cond, enable):
         """
         Public method to enable or disable a watch expression.
         
-        @param cond expression of the watch expression (string)
+        @param debuggerId ID of the debugger backend
+        @type str
+        @param cond expression of the watch expression
+        @type str
         @param enable flag indicating enabling or disabling a watch expression
-            (boolean)
+        @type bool
         """
-        # cond is combination of cond and special (s. watch expression viewer)
-        self.__sendJsonCommand("RequestWatchEnable", {
-            "condition": cond,
-            "enable": enable,
-        })
+        if debuggerId:
+            debuggerList = [debuggerId]
+        else:
+            debuggerList = list(self.__connections.keys())
+        for debuggerId in debuggerList:
+            # cond is combination of cond and special (s. watch expression
+            # viewer)
+            self.__sendJsonCommand("RequestWatchEnable", {
+                "condition": cond,
+                "enable": enable,
+            }, debuggerId)
     
-    def remoteWatchpointIgnore(self, cond, count):
+    def remoteWatchpointIgnore(self, debuggerId, cond, count):
         """
         Public method to ignore a watch expression the next couple of
         occurrences.
         
-        @param cond expression of the watch expression (string)
-        @param count number of occurrences to ignore (int)
+        @param debuggerId ID of the debugger backend
+        @type str
+        @param cond expression of the watch expression
+        @type str
+        @param count number of occurrences to ignore
+        @type int
         """
-        # cond is combination of cond and special (s. watch expression viewer)
-        self.__sendJsonCommand("RequestWatchIgnore", {
-            "condition": cond,
-            "count": count,
-        })
+        if debuggerId:
+            debuggerList = [debuggerId]
+        else:
+            debuggerList = list(self.__connections.keys())
+        for debuggerId in debuggerList:
+            # cond is combination of cond and special (s. watch expression
+            # viewer)
+            self.__sendJsonCommand("RequestWatchIgnore", {
+                "condition": cond,
+                "count": count,
+            }, debuggerId)
     
+    # TODO: add debuggerId
     def remoteRawInput(self, s):
         """
         Public method to send the raw input to the debugged program.
@@ -849,42 +975,44 @@
             "input": s,
         })
     
-    def remoteThreadList(self, debuggerId=""):
+    def remoteThreadList(self, debuggerId):
         """
         Public method to request the list of threads from the client.
         
         @param debuggerId ID of the debugger backend
         @type str
         """
-        self.__sendJsonCommand("RequestThreadList", {}, debuggerId=debuggerId)
+        self.__sendJsonCommand("RequestThreadList", {}, debuggerId)
         
-    def remoteSetThread(self, tid, debuggerId=""):
+    def remoteSetThread(self, debuggerId, tid):
         """
         Public method to request to set the given thread as current thread.
         
+        @param debuggerId ID of the debugger backend
+        @type str
         @param tid id of the thread
         @type int
-        @param debuggerId ID of the debugger backend
-        @type str
         """
         self.__sendJsonCommand("RequestThreadSet", {
             "threadID": tid,
-        }, debuggerId=debuggerId)
+        }, debuggerId)
     
-    def remoteClientStack(self, debuggerId=""):
+    def remoteClientStack(self, debuggerId):
         """
         Public method to request the stack of the main thread.
         
         @param debuggerId ID of the debugger backend
         @type str
         """
-        self.__sendJsonCommand("RequestStack", {}, debuggerId=debuggerId)
+        self.__sendJsonCommand("RequestStack", {}, debuggerId)
     
-    def remoteClientVariables(self, scope, filterList, framenr=0, maxSize=0,
-                              debuggerId=""):
+    def remoteClientVariables(self, debuggerId, scope, filterList, framenr=0,
+                              maxSize=0):
         """
         Public method to request the variables of the debugged program.
         
+        @param debuggerId ID of the debugger backend
+        @type str
         @param scope the scope of the variables (0 = local, 1 = global)
         @type int
         @param filterList list of variable types to filter out
@@ -895,21 +1023,21 @@
             be shown. If it is bigger than that, a 'too big' indication will
             be given (@@TOO_BIG_TO_SHOW@@).
         @type int
-        @param debuggerId ID of the debugger backend
-        @type str
         """
         self.__sendJsonCommand("RequestVariables", {
             "frameNumber": framenr,
             "scope": scope,
             "filters": filterList,
             "maxSize": maxSize,
-        }, debuggerId=debuggerId)
+        }, debuggerId)
     
-    def remoteClientVariable(self, scope, filterList, var, framenr=0,
-                             maxSize=0):
+    def remoteClientVariable(self, debuggerId, scope, filterList, var,
+                             framenr=0, maxSize=0):
         """
         Public method to request the variables of the debugged program.
         
+        @param debuggerId ID of the debugger backend
+        @type str
         @param scope the scope of the variables (0 = local, 1 = global)
         @type int
         @param filterList list of variable types to filter out
@@ -929,8 +1057,9 @@
             "scope": scope,
             "filters": filterList,
             "maxSize": maxSize,
-        })
+        }, debuggerId)
     
+    # TODO: add debuggerId
     def remoteClientSetFilter(self, scope, filterStr):
         """
         Public method to set a variables filter list.
@@ -944,15 +1073,18 @@
             "filter": filterStr,
         })
     
-    def setCallTraceEnabled(self, on):
+    def setCallTraceEnabled(self, debuggerId, on):
         """
         Public method to set the call trace state.
         
-        @param on flag indicating to enable the call trace function (boolean)
+        @param debuggerId ID of the debugger backend
+        @type str
+        @param on flag indicating to enable the call trace function
+        @type bool
         """
         self.__sendJsonCommand("RequestCallTrace", {
             "enable": on,
-        })
+        }, debuggerId)
     
     def remoteBanner(self):
         """
@@ -960,11 +1092,14 @@
         """
         self.__sendJsonCommand("RequestBanner", {})
     
-    def remoteCapabilities(self):
+    def remoteCapabilities(self, debuggerId):
         """
         Public slot to get the debug clients capabilities.
+        
+        @param debuggerId ID of the debugger backend
+        @type str
         """
-        self.__sendJsonCommand("RequestCapabilities", {})
+        self.__sendJsonCommand("RequestCapabilities", {}, debuggerId)
     
     def remoteCompletion(self, text):
         """
@@ -1159,14 +1294,15 @@
             # Check if obsolet thread was clicked
             if params["stack"] == []:
                 # Request updated list
-                self.remoteThreadList()
+                self.remoteThreadList(params["debuggerId"])
                 return
             for s in params["stack"]:
                 s[0] = self.translate(s[0], True)
             cf = params["stack"][0]
             if self.__autoContinue:
                 self.__autoContinue = False
-                QTimer.singleShot(0, self.remoteContinue)
+                QTimer.singleShot(
+                    0, lambda: self.remoteContinue(params["debuggerId"]))
             else:
                 self.debugServer.signalClientLine(
                     cf[0], int(cf[1]), params["debuggerId"],
@@ -1183,15 +1319,17 @@
                 fromInfo["filename"], str(fromInfo["linenumber"]),
                 fromInfo["codename"],
                 toInfo["filename"], str(toInfo["linenumber"]),
-                toInfo["codename"])
+                toInfo["codename"],
+                params["debuggerId"])
         
         elif method == "ResponseVariables":
             self.debugServer.signalClientVariables(
-                params["scope"], params["variables"])
+                params["scope"], params["variables"], params["debuggerId"])
         
         elif method == "ResponseVariable":
             self.debugServer.signalClientVariable(
-                params["scope"], [params["variable"]] + params["variables"])
+                params["scope"], [params["variable"]] + params["variables"],
+                params["debuggerId"])
         
         elif method == "ResponseThreadList":
             self.debugServer.signalClientThreadList(
@@ -1199,94 +1337,106 @@
                 params["debuggerId"])
         
         elif method == "ResponseThreadSet":
-            self.debugServer.signalClientThreadSet()
+            self.debugServer.signalClientThreadSet(params["debuggerId"])
         
         elif method == "ResponseCapabilities":
             self.clientCapabilities = params["capabilities"]
-            self.debugServer.signalClientCapabilities(
-                params["capabilities"],
-                params["clientType"],
-                self.__startedVenv,
-            )
+            if params["debuggerId"] == self.__master:
+                # signal only for the master connection
+                self.debugServer.signalClientCapabilities(
+                    params["capabilities"],
+                    params["clientType"],
+                    self.__startedVenv,
+                )
         
         elif method == "ResponseBanner":
-            self.debugServer.signalClientBanner(
-                params["version"],
-                params["platform"],
-                params["dbgclient"],
-                self.__startedVenv,
-            )
+            if params["debuggerId"] == self.__master:
+                # signal only for the master connection
+                self.debugServer.signalClientBanner(
+                    params["version"],
+                    params["platform"],
+                    params["dbgclient"],
+                    self.__startedVenv,
+                )
         
         elif method == "ResponseOK":
-            self.debugServer.signalClientStatement(False)
+            self.debugServer.signalClientStatement(False, params["debuggerId"])
         
         elif method == "ResponseContinue":
-            self.debugServer.signalClientStatement(True)
+            self.debugServer.signalClientStatement(True, params["debuggerId"])
         
+        # TODO: add debuggerId
         elif method == "RequestRaw":
             self.debugServer.signalClientRawInput(
                 params["prompt"], params["echo"])
         
+        # TODO: add debuggerId
         elif method == "ResponseBPConditionError":
             fn = self.translate(params["filename"], True)
             self.debugServer.signalClientBreakConditionError(
                 fn, params["line"])
         
+        # TODO: add debuggerId
         elif method == "ResponseClearBreakpoint":
             fn = self.translate(params["filename"], True)
             self.debugServer.signalClientClearBreak(fn, params["line"])
         
+        # TODO: add debuggerId
         elif method == "ResponseWatchConditionError":
             self.debugServer.signalClientWatchConditionError(
                 params["condition"])
         
+        # TODO: add debuggerId
         elif method == "ResponseClearWatch":
             self.debugServer.signalClientClearWatch(params["condition"])
         
         elif method == "ResponseException":
-            if params:
-                exctype = params["type"]
-                excmessage = params["message"]
-                stack = params["stack"]
-                if stack:
+            exctype = params["type"]
+            excmessage = params["message"]
+            stack = params["stack"]
+            if stack:
+                for stackEntry in stack:
+                    stackEntry[0] = self.translate(stackEntry[0], True)
+                if stack[0] and stack[0][0] == "<string>":
                     for stackEntry in stack:
-                        stackEntry[0] = self.translate(stackEntry[0], True)
-                    if stack[0] and stack[0][0] == "<string>":
-                        for stackEntry in stack:
-                            if stackEntry[0] == "<string>":
-                                stackEntry[0] = self.__scriptName
-                            else:
-                                break
-            else:
-                exctype = ''
-                excmessage = ''
-                stack = []
+                        if stackEntry[0] == "<string>":
+                            stackEntry[0] = self.__scriptName
+                        else:
+                            break
             
             self.debugServer.signalClientException(
-                exctype, excmessage, stack)
+                exctype, excmessage, stack, params["debuggerId"])
         
         elif method == "ResponseSyntax":
             self.debugServer.signalClientSyntaxError(
                 params["message"], self.translate(params["filename"], True),
-                params["linenumber"], params["characternumber"])
+                params["linenumber"], params["characternumber"],
+                params["debuggerId"])
         
         elif method == "ResponseSignal":
             self.debugServer.signalClientSignal(
                 params["message"], self.translate(params["filename"], True),
-                params["linenumber"], params["function"], params["arguments"])
+                params["linenumber"], params["function"], params["arguments"],
+                params["debuggerId"])
         
         elif method == "ResponseExit":
             self.__scriptName = ""
             self.debugServer.signalClientExit(
-                params["status"], params["message"])
+                params["status"], params["message"], params["debuggerId"])
         
         elif method == "PassiveStartup":
             self.debugServer.passiveStartUp(
                 self.translate(params["filename"], True), params["exceptions"])
         
         elif method == "ResponseCompletion":
-            self.debugServer.signalClientCompletionList(
-                params["completions"], params["text"])
+            if params["debuggerId"] == self.__master:
+                # signal only for the master connection
+                self.debugServer.signalClientCompletionList(
+                    params["completions"], params["text"])
+        
+        ###################################################################
+        ## Unit test related stuff is not done with multi processing
+        ###################################################################
         
         elif method == "ResponseUTDiscover":
             self.debugServer.clientUtDiscovered(
@@ -1327,6 +1477,7 @@
             self.debugServer.clientUtTestSucceededUnexpected(
                 params["testname"], params["id"])
         
+        # TODO: add debuggerId
         elif method == "RequestForkTo":
             self.__askForkTo()
     
@@ -1355,8 +1506,8 @@
         
         if debuggerId and debuggerId in self.__connections:
             sock = self.__connections[debuggerId]
-        elif sock is None and self.qsock is not None:
-            sock = self.qsock
+        elif sock is None and self.__master is not None:
+            sock = self.__connections[self.__master]
         if sock is not None:
             self.__writeJsonCommandToSocket(cmd, sock)
         else:

eric ide

mercurial