src/eric7/Debugger/DebuggerInterfacePython.py

branch
server
changeset 10561
be23a662d709
parent 10560
28b14d2df6a1
child 10564
0de57f082daa
equal deleted inserted replaced
10560:28b14d2df6a1 10561:be23a662d709
13 import os 13 import os
14 import shlex 14 import shlex
15 import struct 15 import struct
16 import zlib 16 import zlib
17 17
18 from PyQt6.QtCore import QObject, QProcess, QProcessEnvironment, QTimer 18 from PyQt6.QtCore import QObject, QProcess, QProcessEnvironment, QTimer, pyqtSlot
19 19
20 from eric7 import Preferences, Utilities 20 from eric7 import Preferences, Utilities
21 from eric7.EricWidgets import EricMessageBox 21 from eric7.EricWidgets import EricMessageBox
22 from eric7.EricWidgets.EricApplication import ericApp 22 from eric7.EricWidgets.EricApplication import ericApp
23 from eric7.Globals import getConfig 23 from eric7.Globals import getConfig
55 self.__ericServerDebuggerInterface = ericApp().getObject( 55 self.__ericServerDebuggerInterface = ericApp().getObject(
56 "EricServer" 56 "EricServer"
57 ).getServiceInterface("Debugger") 57 ).getServiceInterface("Debugger")
58 self.__ericServerDebuggerInterface.debugClientResponse.connect( 58 self.__ericServerDebuggerInterface.debugClientResponse.connect(
59 lambda jsonStr: self.handleJsonCommand(jsonStr, None) 59 lambda jsonStr: self.handleJsonCommand(jsonStr, None)
60 )
61 self.__ericServerDebuggerInterface.debugClientDisconnected.connect(
62 self.__handleServerDebugClientDisconnected
63 )
64 self.__ericServerDebuggerInterface.lastClientExited.connect(
65 self.__handleServerLastClientExited
60 ) 66 )
61 except KeyError: 67 except KeyError:
62 self.__ericServerDebuggerInterface = None 68 self.__ericServerDebuggerInterface = None
63 69
64 self.debugServer = debugServer 70 self.debugServer = debugServer
182 runInConsole, 188 runInConsole,
183 venvName, 189 venvName,
184 originalPathString, 190 originalPathString,
185 workingDir="", 191 workingDir="",
186 configOverride=None, 192 configOverride=None,
187 startRemote=False, 193 startRemote=None,
188 ): 194 ):
189 """ 195 """
190 Public method to start a remote Python interpreter. 196 Public method to start a remote Python interpreter.
191 197
192 @param port port number the debug server is listening on 198 @param port port number the debug server is listening on
202 @type str (optional) 208 @type str (optional)
203 @param configOverride dictionary containing the global config override data 209 @param configOverride dictionary containing the global config override data
204 (defaults to None) 210 (defaults to None)
205 @type dict (optional) 211 @type dict (optional)
206 @param startRemote flag indicating to start the client via an eric-ide server 212 @param startRemote flag indicating to start the client via an eric-ide server
207 (defaults to False) 213 (defaults to None)
208 @type bool (optional) 214 @type bool (optional)
209 @return client process object, a flag to indicate a network connection 215 @return client process object, a flag to indicate a network connection
210 and the name of the interpreter in case of a local execution 216 and the name of the interpreter in case of a local execution
211 @rtype tuple of (QProcess, bool, str) 217 @rtype tuple of (QProcess, bool, str)
212 """ 218 """
213 global origPathEnv 219 global origPathEnv
214 220
215 if startRemote or venvName == self.debugServer.getEricServerEnvironmentString(): 221 if (
222 (
223 startRemote is True
224 or (
225 startRemote is None and (
226 venvName == self.debugServer.getEricServerEnvironmentString()
227 or self.__ericServerDebugging
228 )
229 )
230 )
231 and ericApp().getObject("EricServer").isServerConnected()
232 ):
216 # TODO change this once server environment definitions are supported 233 # TODO change this once server environment definitions are supported
217 startRemote = True 234 startRemote = True
218 venvName = self.debugServer.getEricServerEnvironmentString() 235 venvName = self.debugServer.getEricServerEnvironmentString()
219 interpreter = "" 236 interpreter = ""
220 else: 237 else:
240 ) 257 )
241 return None, False, "" 258 return None, False, ""
242 259
243 self.__inShutdown = False 260 self.__inShutdown = False
244 261
262 self.__ericServerDebuggerInterface.stopClient()
245 self.__ericServerDebugging = False 263 self.__ericServerDebugging = False
246 self.__ericServerDebuggerInterface.stopClient()
247 self.__mainDebugger = None 264 self.__mainDebugger = None
248 265
249 redirect = ( 266 redirect = (
250 str(configOverride["redirect"]) 267 str(configOverride["redirect"])
251 if configOverride and configOverride["enable"] 268 if configOverride and configOverride["enable"]
332 ) 349 )
333 return None, False, "" 350 return None, False, ""
334 351
335 elif startRemote and self.__ericServerDebuggerInterface is not None: 352 elif startRemote and self.__ericServerDebuggerInterface is not None:
336 # debugging via an eric-ide server 353 # debugging via an eric-ide server
337 ##self.__ericServerDebuggerInterface.stopClient()
338 ##self.__mainDebugger = None
339 ##
340 self.translate = self.__ericServerTranslation 354 self.translate = self.__ericServerTranslation
341 self.__ericServerDebugging = True 355 self.__ericServerDebugging = True
342 356
343 args = [] 357 args = []
344 if noencoding: 358 if noencoding:
486 @type bool (optional) 500 @type bool (optional)
487 @return client process object, a flag to indicate a network connection 501 @return client process object, a flag to indicate a network connection
488 and the name of the interpreter in case of a local execution 502 and the name of the interpreter in case of a local execution
489 @rtype tuple of (QProcess, bool, str) 503 @rtype tuple of (QProcess, bool, str)
490 """ 504 """
505 # TODO: 'startRemoteForProject()' - implement the 'startRemote' logic like
506 # for 'startRemote'.
491 global origPathEnv 507 global origPathEnv
492 508
493 project = ericApp().getObject("Project") 509 project = ericApp().getObject("Project")
494 if not project.isDebugPropertiesLoaded(): 510 if not project.isDebugPropertiesLoaded():
495 return None, self.__isNetworked, "" 511 return None, self.__isNetworked, ""
526 ) 542 )
527 return None, self.__isNetworked, "" 543 return None, self.__isNetworked, ""
528 544
529 self.__inShutdown = False 545 self.__inShutdown = False
530 546
547 self.__ericServerDebuggerInterface.stopClient()
531 self.__ericServerDebugging = False 548 self.__ericServerDebugging = False
532 self.__ericServerDebuggerInterface.stopClient()
533 self.__mainDebugger = None 549 self.__mainDebugger = None
534 550
535 if project.getDebugProperty("REMOTEDEBUGGER"): 551 if project.getDebugProperty("REMOTEDEBUGGER"):
536 # remote debugging code 552 # remote debugging code
537 ipaddr = self.debugServer.getHostAddress(False) 553 ipaddr = self.debugServer.getHostAddress(False)
741 @type QTcpSocket 757 @type QTcpSocket
742 """ 758 """
743 for debuggerId in list(self.__connections): 759 for debuggerId in list(self.__connections):
744 if self.__connections[debuggerId] is sock: 760 if self.__connections[debuggerId] is sock:
745 del self.__connections[debuggerId] 761 del self.__connections[debuggerId]
746 if debuggerId == self.__mainDebugger: 762 self.__handleServerDebugClientDisconnected(debuggerId)
747 self.__mainDebugger = None
748 if debuggerId in self.__autoContinued:
749 self.__autoContinued.remove(debuggerId)
750 if not self.__inShutdown:
751 with contextlib.suppress(RuntimeError):
752 # can be ignored during a shutdown
753 self.debugServer.signalClientDisconnected(debuggerId)
754 break 763 break
755 else: 764 else:
756 if sock in self.__pendingConnections: 765 if sock in self.__pendingConnections:
757 self.__pendingConnections.remove(sock) 766 self.__pendingConnections.remove(sock)
758 767
759 if not self.__connections: 768 if not self.__connections:
760 # no active connections anymore 769 # no active connections anymore
770 self.__handleServerLastClientExited()
771
772 @pyqtSlot(str)
773 def __handleServerDebugClientDisconnected(self, debuggerId):
774 """
775 Private slot handling the disconnect of a debug client.
776
777 @param debuggerId ID of the disconnected debugger
778 @type str
779 """
780 if debuggerId == self.__mainDebugger:
781 self.__mainDebugger = None
782 if debuggerId in self.__autoContinued:
783 self.__autoContinued.remove(debuggerId)
784 if not self.__inShutdown:
761 with contextlib.suppress(RuntimeError): 785 with contextlib.suppress(RuntimeError):
762 # debug server object might have been deleted already 786 # can be ignored during a shutdown
763 # ignore this 787 self.debugServer.signalClientDisconnected(debuggerId)
764 self.debugServer.signalLastClientExited() 788
765 self.__autoContinued.clear() 789 @pyqtSlot()
766 if not self.__inShutdown: 790 def __handleServerLastClientExited(self):
767 self.debugServer.startClient() 791 """
792 Private slot to handle the exit of the last debug client connected.
793 """
794 with contextlib.suppress(RuntimeError):
795 # debug server object might have been deleted already
796 # ignore this
797 self.debugServer.signalLastClientExited()
798 self.__autoContinued.clear()
799 if not self.__inShutdown:
800 self.debugServer.startClient()
768 801
769 def getDebuggerIds(self): 802 def getDebuggerIds(self):
770 """ 803 """
771 Public method to return the IDs of the connected debugger backends. 804 Public method to return the IDs of the connected debugger backends.
772 805
888 @type bool 921 @type bool
889 @param reportAllExceptions flag indicating to report all exceptions 922 @param reportAllExceptions flag indicating to report all exceptions
890 instead of unhandled exceptions only 923 instead of unhandled exceptions only
891 @type bool 924 @type bool
892 """ 925 """
926 if FileSystemUtilities.isPlainFileName(fn):
927 fn = os.path.abspath(fn)
928
893 self.__autoContinue = autoContinue 929 self.__autoContinue = autoContinue
894 self.__scriptName = os.path.abspath(fn) 930 self.__scriptName = fn
895 self.__isStepCommand = False 931 self.__isStepCommand = False
896 932
897 wd = self.translate(wd, False) 933 wd = self.translate(wd, False)
898 fn = self.translate(os.path.abspath(fn), False) 934 fn = self.translate(fn, False)
899 self.__sendJsonCommand( 935 self.__sendJsonCommand(
900 "RequestLoad", 936 "RequestLoad",
901 { 937 {
902 "workdir": wd, 938 "workdir": wd,
903 "filename": fn, 939 "filename": fn,
1120 @param cond condition of the breakpoint 1156 @param cond condition of the breakpoint
1121 @type str 1157 @type str
1122 @param temp flag indicating a temporary breakpoint 1158 @param temp flag indicating a temporary breakpoint
1123 @type bool 1159 @type bool
1124 """ 1160 """
1125 debuggerList = [debuggerId] if debuggerId else list(self.__connections) 1161 if debuggerId:
1162 debuggerList = [debuggerId]
1163 elif self.__ericServerDebugging:
1164 debuggerList = ["<<all>>"]
1165 else:
1166 debuggerList = list(self.__connections)
1126 for debuggerId in debuggerList: 1167 for debuggerId in debuggerList:
1127 self.__sendJsonCommand( 1168 self.__sendJsonCommand(
1128 "RequestBreakpoint", 1169 "RequestBreakpoint",
1129 { 1170 {
1130 "filename": self.translate(fn, False), 1171 "filename": self.translate(fn, False),
1147 @param line line number of the breakpoint 1188 @param line line number of the breakpoint
1148 @type int 1189 @type int
1149 @param enable flag indicating enabling or disabling a breakpoint 1190 @param enable flag indicating enabling or disabling a breakpoint
1150 @type bool 1191 @type bool
1151 """ 1192 """
1152 debuggerList = [debuggerId] if debuggerId else list(self.__connections) 1193 if debuggerId:
1194 debuggerList = [debuggerId]
1195 elif self.__ericServerDebugging:
1196 debuggerList = ["<<all>>"]
1197 else:
1198 debuggerList = list(self.__connections)
1153 for debuggerId in debuggerList: 1199 for debuggerId in debuggerList:
1154 self.__sendJsonCommand( 1200 self.__sendJsonCommand(
1155 "RequestBreakpointEnable", 1201 "RequestBreakpointEnable",
1156 { 1202 {
1157 "filename": self.translate(fn, False), 1203 "filename": self.translate(fn, False),
1172 @param line line number of the breakpoint 1218 @param line line number of the breakpoint
1173 @type int 1219 @type int
1174 @param count number of occurrences to ignore 1220 @param count number of occurrences to ignore
1175 @type int 1221 @type int
1176 """ 1222 """
1177 debuggerList = [debuggerId] if debuggerId else list(self.__connections) 1223 if debuggerId:
1224 debuggerList = [debuggerId]
1225 elif self.__ericServerDebugging:
1226 debuggerList = ["<<all>>"]
1227 else:
1228 debuggerList = list(self.__connections)
1178 for debuggerId in debuggerList: 1229 for debuggerId in debuggerList:
1179 self.__sendJsonCommand( 1230 self.__sendJsonCommand(
1180 "RequestBreakpointIgnore", 1231 "RequestBreakpointIgnore",
1181 { 1232 {
1182 "filename": self.translate(fn, False), 1233 "filename": self.translate(fn, False),
1197 @param setWatch flag indicating setting or resetting a watch expression 1248 @param setWatch flag indicating setting or resetting a watch expression
1198 @type bool 1249 @type bool
1199 @param temp flag indicating a temporary watch expression 1250 @param temp flag indicating a temporary watch expression
1200 @type bool 1251 @type bool
1201 """ 1252 """
1202 debuggerList = [debuggerId] if debuggerId else list(self.__connections) 1253 if debuggerId:
1254 debuggerList = [debuggerId]
1255 elif self.__ericServerDebugging:
1256 debuggerList = ["<<all>>"]
1257 else:
1258 debuggerList = list(self.__connections)
1203 for debuggerId in debuggerList: 1259 for debuggerId in debuggerList:
1204 # cond is combination of cond and special (s. watch expression 1260 # cond is combination of cond and special (s. watch expression
1205 # viewer) 1261 # viewer)
1206 self.__sendJsonCommand( 1262 self.__sendJsonCommand(
1207 "RequestWatch", 1263 "RequestWatch",
1222 @param cond expression of the watch expression 1278 @param cond expression of the watch expression
1223 @type str 1279 @type str
1224 @param enable flag indicating enabling or disabling a watch expression 1280 @param enable flag indicating enabling or disabling a watch expression
1225 @type bool 1281 @type bool
1226 """ 1282 """
1227 debuggerList = [debuggerId] if debuggerId else list(self.__connections) 1283 if debuggerId:
1284 debuggerList = [debuggerId]
1285 elif self.__ericServerDebugging:
1286 debuggerList = ["<<all>>"]
1287 else:
1288 debuggerList = list(self.__connections)
1228 for debuggerId in debuggerList: 1289 for debuggerId in debuggerList:
1229 # cond is combination of cond and special (s. watch expression 1290 # cond is combination of cond and special (s. watch expression
1230 # viewer) 1291 # viewer)
1231 self.__sendJsonCommand( 1292 self.__sendJsonCommand(
1232 "RequestWatchEnable", 1293 "RequestWatchEnable",
1247 @param cond expression of the watch expression 1308 @param cond expression of the watch expression
1248 @type str 1309 @type str
1249 @param count number of occurrences to ignore 1310 @param count number of occurrences to ignore
1250 @type int 1311 @type int
1251 """ 1312 """
1252 debuggerList = [debuggerId] if debuggerId else list(self.__connections) 1313 if debuggerId:
1314 debuggerList = [debuggerId]
1315 elif self.__ericServerDebugging:
1316 debuggerList = ["<<all>>"]
1317 else:
1318 debuggerList = list(self.__connections)
1253 for debuggerId in debuggerList: 1319 for debuggerId in debuggerList:
1254 # cond is combination of cond and special (s. watch expression 1320 # cond is combination of cond and special (s. watch expression
1255 # viewer) 1321 # viewer)
1256 self.__sendJsonCommand( 1322 self.__sendJsonCommand(
1257 "RequestWatchIgnore", 1323 "RequestWatchIgnore",
1700 ) 1766 )
1701 1767
1702 elif method == "ResponseExit": 1768 elif method == "ResponseExit":
1703 self.__scriptName = "" 1769 self.__scriptName = ""
1704 self.debugServer.signalClientExit( 1770 self.debugServer.signalClientExit(
1705 params["program"], 1771 self.translate(params["program"], True),
1706 params["status"], 1772 params["status"],
1707 params["message"], 1773 params["message"],
1708 params["debuggerId"], 1774 params["debuggerId"],
1709 ) 1775 )
1710 if params["debuggerId"] == self.__mainDebugger: 1776 if params["debuggerId"] == self.__mainDebugger:

eric ide

mercurial