diff -r 28b14d2df6a1 -r be23a662d709 src/eric7/Debugger/DebuggerInterfacePython.py --- a/src/eric7/Debugger/DebuggerInterfacePython.py Sat Feb 10 11:28:58 2024 +0100 +++ b/src/eric7/Debugger/DebuggerInterfacePython.py Sun Feb 11 18:35:44 2024 +0100 @@ -15,7 +15,7 @@ import struct import zlib -from PyQt6.QtCore import QObject, QProcess, QProcessEnvironment, QTimer +from PyQt6.QtCore import QObject, QProcess, QProcessEnvironment, QTimer, pyqtSlot from eric7 import Preferences, Utilities from eric7.EricWidgets import EricMessageBox @@ -58,6 +58,12 @@ self.__ericServerDebuggerInterface.debugClientResponse.connect( lambda jsonStr: self.handleJsonCommand(jsonStr, None) ) + self.__ericServerDebuggerInterface.debugClientDisconnected.connect( + self.__handleServerDebugClientDisconnected + ) + self.__ericServerDebuggerInterface.lastClientExited.connect( + self.__handleServerLastClientExited + ) except KeyError: self.__ericServerDebuggerInterface = None @@ -184,7 +190,7 @@ originalPathString, workingDir="", configOverride=None, - startRemote=False, + startRemote=None, ): """ Public method to start a remote Python interpreter. @@ -204,7 +210,7 @@ (defaults to None) @type dict (optional) @param startRemote flag indicating to start the client via an eric-ide server - (defaults to False) + (defaults to None) @type bool (optional) @return client process object, a flag to indicate a network connection and the name of the interpreter in case of a local execution @@ -212,7 +218,18 @@ """ global origPathEnv - if startRemote or venvName == self.debugServer.getEricServerEnvironmentString(): + if ( + ( + startRemote is True + or ( + startRemote is None and ( + venvName == self.debugServer.getEricServerEnvironmentString() + or self.__ericServerDebugging + ) + ) + ) + and ericApp().getObject("EricServer").isServerConnected() + ): # TODO change this once server environment definitions are supported startRemote = True venvName = self.debugServer.getEricServerEnvironmentString() @@ -242,8 +259,8 @@ self.__inShutdown = False + self.__ericServerDebuggerInterface.stopClient() self.__ericServerDebugging = False - self.__ericServerDebuggerInterface.stopClient() self.__mainDebugger = None redirect = ( @@ -334,9 +351,6 @@ elif startRemote and self.__ericServerDebuggerInterface is not None: # debugging via an eric-ide server - ##self.__ericServerDebuggerInterface.stopClient() - ##self.__mainDebugger = None -## self.translate = self.__ericServerTranslation self.__ericServerDebugging = True @@ -488,6 +502,8 @@ and the name of the interpreter in case of a local execution @rtype tuple of (QProcess, bool, str) """ + # TODO: 'startRemoteForProject()' - implement the 'startRemote' logic like + # for 'startRemote'. global origPathEnv project = ericApp().getObject("Project") @@ -528,8 +544,8 @@ self.__inShutdown = False + self.__ericServerDebuggerInterface.stopClient() self.__ericServerDebugging = False - self.__ericServerDebuggerInterface.stopClient() self.__mainDebugger = None if project.getDebugProperty("REMOTEDEBUGGER"): @@ -743,14 +759,7 @@ for debuggerId in list(self.__connections): if self.__connections[debuggerId] is sock: del self.__connections[debuggerId] - if debuggerId == self.__mainDebugger: - self.__mainDebugger = None - if debuggerId in self.__autoContinued: - self.__autoContinued.remove(debuggerId) - if not self.__inShutdown: - with contextlib.suppress(RuntimeError): - # can be ignored during a shutdown - self.debugServer.signalClientDisconnected(debuggerId) + self.__handleServerDebugClientDisconnected(debuggerId) break else: if sock in self.__pendingConnections: @@ -758,13 +767,37 @@ if not self.__connections: # no active connections anymore + self.__handleServerLastClientExited() + + @pyqtSlot(str) + def __handleServerDebugClientDisconnected(self, debuggerId): + """ + Private slot handling the disconnect of a debug client. + + @param debuggerId ID of the disconnected debugger + @type str + """ + if debuggerId == self.__mainDebugger: + self.__mainDebugger = None + if debuggerId in self.__autoContinued: + self.__autoContinued.remove(debuggerId) + if not self.__inShutdown: with contextlib.suppress(RuntimeError): - # debug server object might have been deleted already - # ignore this - self.debugServer.signalLastClientExited() - self.__autoContinued.clear() - if not self.__inShutdown: - self.debugServer.startClient() + # can be ignored during a shutdown + self.debugServer.signalClientDisconnected(debuggerId) + + @pyqtSlot() + def __handleServerLastClientExited(self): + """ + Private slot to handle the exit of the last debug client connected. + """ + with contextlib.suppress(RuntimeError): + # debug server object might have been deleted already + # ignore this + self.debugServer.signalLastClientExited() + self.__autoContinued.clear() + if not self.__inShutdown: + self.debugServer.startClient() def getDebuggerIds(self): """ @@ -890,12 +923,15 @@ instead of unhandled exceptions only @type bool """ + if FileSystemUtilities.isPlainFileName(fn): + fn = os.path.abspath(fn) + self.__autoContinue = autoContinue - self.__scriptName = os.path.abspath(fn) + self.__scriptName = fn self.__isStepCommand = False wd = self.translate(wd, False) - fn = self.translate(os.path.abspath(fn), False) + fn = self.translate(fn, False) self.__sendJsonCommand( "RequestLoad", { @@ -1122,7 +1158,12 @@ @param temp flag indicating a temporary breakpoint @type bool """ - debuggerList = [debuggerId] if debuggerId else list(self.__connections) + if debuggerId: + debuggerList = [debuggerId] + elif self.__ericServerDebugging: + debuggerList = ["<<all>>"] + else: + debuggerList = list(self.__connections) for debuggerId in debuggerList: self.__sendJsonCommand( "RequestBreakpoint", @@ -1149,7 +1190,12 @@ @param enable flag indicating enabling or disabling a breakpoint @type bool """ - debuggerList = [debuggerId] if debuggerId else list(self.__connections) + if debuggerId: + debuggerList = [debuggerId] + elif self.__ericServerDebugging: + debuggerList = ["<<all>>"] + else: + debuggerList = list(self.__connections) for debuggerId in debuggerList: self.__sendJsonCommand( "RequestBreakpointEnable", @@ -1174,7 +1220,12 @@ @param count number of occurrences to ignore @type int """ - debuggerList = [debuggerId] if debuggerId else list(self.__connections) + if debuggerId: + debuggerList = [debuggerId] + elif self.__ericServerDebugging: + debuggerList = ["<<all>>"] + else: + debuggerList = list(self.__connections) for debuggerId in debuggerList: self.__sendJsonCommand( "RequestBreakpointIgnore", @@ -1199,7 +1250,12 @@ @param temp flag indicating a temporary watch expression @type bool """ - debuggerList = [debuggerId] if debuggerId else list(self.__connections) + if debuggerId: + debuggerList = [debuggerId] + elif self.__ericServerDebugging: + debuggerList = ["<<all>>"] + else: + debuggerList = list(self.__connections) for debuggerId in debuggerList: # cond is combination of cond and special (s. watch expression # viewer) @@ -1224,7 +1280,12 @@ @param enable flag indicating enabling or disabling a watch expression @type bool """ - debuggerList = [debuggerId] if debuggerId else list(self.__connections) + if debuggerId: + debuggerList = [debuggerId] + elif self.__ericServerDebugging: + debuggerList = ["<<all>>"] + else: + debuggerList = list(self.__connections) for debuggerId in debuggerList: # cond is combination of cond and special (s. watch expression # viewer) @@ -1249,7 +1310,12 @@ @param count number of occurrences to ignore @type int """ - debuggerList = [debuggerId] if debuggerId else list(self.__connections) + if debuggerId: + debuggerList = [debuggerId] + elif self.__ericServerDebugging: + debuggerList = ["<<all>>"] + else: + debuggerList = list(self.__connections) for debuggerId in debuggerList: # cond is combination of cond and special (s. watch expression # viewer) @@ -1702,7 +1768,7 @@ elif method == "ResponseExit": self.__scriptName = "" self.debugServer.signalClientExit( - params["program"], + self.translate(params["program"], True), params["status"], params["message"], params["debuggerId"],