src/eric7/Debugger/DebuggerInterfacePython.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9264
18a7312cfdb3
child 9320
22eef25d2956
equal deleted inserted replaced
9220:e9e7eca7efee 9221:bf71ee032bb4
11 import os 11 import os
12 import logging 12 import logging
13 import shlex 13 import shlex
14 import contextlib 14 import contextlib
15 15
16 from PyQt6.QtCore import ( 16 from PyQt6.QtCore import QObject, QProcess, QProcessEnvironment, QTimer
17 QObject, QProcess, QProcessEnvironment, QTimer
18 )
19 17
20 from EricWidgets.EricApplication import ericApp 18 from EricWidgets.EricApplication import ericApp
21 from EricWidgets import EricMessageBox 19 from EricWidgets import EricMessageBox
22 20
23 from . import DebugClientCapabilities 21 from . import DebugClientCapabilities
35 class DebuggerInterfacePython(QObject): 33 class DebuggerInterfacePython(QObject):
36 """ 34 """
37 Class implementing the debugger interface for the debug server for 35 Class implementing the debugger interface for the debug server for
38 Python 3. 36 Python 3.
39 """ 37 """
38
40 def __init__(self, debugServer, passive): 39 def __init__(self, debugServer, passive):
41 """ 40 """
42 Constructor 41 Constructor
43 42
44 @param debugServer reference to the debug server 43 @param debugServer reference to the debug server
45 @type DebugServer 44 @type DebugServer
46 @param passive flag indicating passive connection mode 45 @param passive flag indicating passive connection mode
47 @type bool 46 @type bool
48 """ 47 """
49 super().__init__() 48 super().__init__()
50 49
51 self.__isNetworked = True 50 self.__isNetworked = True
52 self.__autoContinue = False 51 self.__autoContinue = False
53 self.__autoContinued = [] 52 self.__autoContinued = []
54 self.__isStepCommand = False 53 self.__isStepCommand = False
55 54
56 self.debugServer = debugServer 55 self.debugServer = debugServer
57 self.passive = passive 56 self.passive = passive
58 self.process = None 57 self.process = None
59 self.__startedVenv = "" 58 self.__startedVenv = ""
60 59
61 self.queue = [] 60 self.queue = []
62 self.__master = None 61 self.__master = None
63 self.__connections = {} 62 self.__connections = {}
64 self.__pendingConnections = [] 63 self.__pendingConnections = []
65 self.__inShutdown = False 64 self.__inShutdown = False
66 65
67 # set default values for capabilities of clients 66 # set default values for capabilities of clients
68 self.clientCapabilities = ClientDefaultCapabilities 67 self.clientCapabilities = ClientDefaultCapabilities
69 68
70 # set translation function 69 # set translation function
71 self.translate = self.__identityTranslation 70 self.translate = self.__identityTranslation
72 71
73 if passive: 72 if passive:
74 # set translation function 73 # set translation function
75 if Preferences.getDebugger("PathTranslation"): 74 if Preferences.getDebugger("PathTranslation"):
76 self.translateRemote = Preferences.getDebugger( 75 self.translateRemote = Preferences.getDebugger("PathTranslationRemote")
77 "PathTranslationRemote")
78 self.translateRemoteWindows = "\\" in self.translateRemote 76 self.translateRemoteWindows = "\\" in self.translateRemote
79 self.translateLocal = Preferences.getDebugger( 77 self.translateLocal = Preferences.getDebugger("PathTranslationLocal")
80 "PathTranslationLocal")
81 self.translateLocalWindows = "\\" in self.translateLocal 78 self.translateLocalWindows = "\\" in self.translateLocal
82 self.translate = self.__remoteTranslation 79 self.translate = self.__remoteTranslation
83 else: 80 else:
84 self.translate = self.__identityTranslation 81 self.translate = self.__identityTranslation
85 82
86 # attribute to remember the name of the executed script 83 # attribute to remember the name of the executed script
87 self.__scriptName = "" 84 self.__scriptName = ""
88 85
89 def __identityTranslation(self, fn, remote2local=True): 86 def __identityTranslation(self, fn, remote2local=True):
90 """ 87 """
91 Private method to perform the identity path translation. 88 Private method to perform the identity path translation.
92 89
93 @param fn filename to be translated 90 @param fn filename to be translated
94 @type str 91 @type str
95 @param remote2local flag indicating the direction of translation 92 @param remote2local flag indicating the direction of translation
96 (False = local to remote, True = remote to local [default]) 93 (False = local to remote, True = remote to local [default])
97 @type bool 94 @type bool
98 @return translated filename 95 @return translated filename
99 @rtype str 96 @rtype str
100 """ 97 """
101 return fn 98 return fn
102 99
103 def __remoteTranslation(self, fn, remote2local=True): 100 def __remoteTranslation(self, fn, remote2local=True):
104 """ 101 """
105 Private method to perform the path translation. 102 Private method to perform the path translation.
106 103
107 @param fn filename to be translated 104 @param fn filename to be translated
108 @type str 105 @type str
109 @param remote2local flag indicating the direction of translation 106 @param remote2local flag indicating the direction of translation
110 (False = local to remote, True = remote to local [default]) 107 (False = local to remote, True = remote to local [default])
111 @type bool 108 @type bool
118 path = path.replace("/", "\\") 115 path = path.replace("/", "\\")
119 else: 116 else:
120 path = fn.replace(self.translateLocal, self.translateRemote) 117 path = fn.replace(self.translateLocal, self.translateRemote)
121 if not self.translateRemoteWindows: 118 if not self.translateRemoteWindows:
122 path = path.replace("\\", "/") 119 path = path.replace("\\", "/")
123 120
124 return path 121 return path
125 122
126 def __startProcess(self, program, arguments, environment=None, 123 def __startProcess(self, program, arguments, environment=None, workingDir=None):
127 workingDir=None):
128 """ 124 """
129 Private method to start the debugger client process. 125 Private method to start the debugger client process.
130 126
131 @param program name of the executable to start 127 @param program name of the executable to start
132 @type str 128 @type str
133 @param arguments arguments to be passed to the program 129 @param arguments arguments to be passed to the program
134 @type list of str 130 @type list of str
135 @param environment dictionary of environment settings to pass 131 @param environment dictionary of environment settings to pass
149 if workingDir: 145 if workingDir:
150 proc.setWorkingDirectory(workingDir) 146 proc.setWorkingDirectory(workingDir)
151 proc.start(program, args) 147 proc.start(program, args)
152 if not proc.waitForStarted(10000): 148 if not proc.waitForStarted(10000):
153 proc = None 149 proc = None
154 150
155 return proc 151 return proc
156 152
157 def startRemote(self, port, runInConsole, venvName, originalPathString, 153 def startRemote(
158 workingDir=None, configOverride=None): 154 self,
155 port,
156 runInConsole,
157 venvName,
158 originalPathString,
159 workingDir=None,
160 configOverride=None,
161 ):
159 """ 162 """
160 Public method to start a remote Python interpreter. 163 Public method to start a remote Python interpreter.
161 164
162 @param port port number the debug server is listening on 165 @param port port number the debug server is listening on
163 @type int 166 @type int
164 @param runInConsole flag indicating to start the debugger in a 167 @param runInConsole flag indicating to start the debugger in a
165 console window 168 console window
166 @type bool 169 @type bool
176 @return client process object, a flag to indicate a network connection 179 @return client process object, a flag to indicate a network connection
177 and the name of the interpreter in case of a local execution 180 and the name of the interpreter in case of a local execution
178 @rtype tuple of (QProcess, bool, str) 181 @rtype tuple of (QProcess, bool, str)
179 """ 182 """
180 global origPathEnv 183 global origPathEnv
181 184
182 if not venvName: 185 if not venvName:
183 venvName = Preferences.getDebugger("Python3VirtualEnv") 186 venvName = Preferences.getDebugger("Python3VirtualEnv")
184 venvManager = ericApp().getObject("VirtualEnvManager") 187 venvManager = ericApp().getObject("VirtualEnvManager")
185 interpreter = venvManager.getVirtualenvInterpreter(venvName) 188 interpreter = venvManager.getVirtualenvInterpreter(venvName)
186 execPath = venvManager.getVirtualenvExecPath(venvName) 189 execPath = venvManager.getVirtualenvExecPath(venvName)
189 interpreter = Globals.getPythonExecutable() 192 interpreter = Globals.getPythonExecutable()
190 if interpreter == "": 193 if interpreter == "":
191 EricMessageBox.critical( 194 EricMessageBox.critical(
192 None, 195 None,
193 self.tr("Start Debugger"), 196 self.tr("Start Debugger"),
194 self.tr( 197 self.tr("""<p>No suitable Python3 environment configured.</p>"""),
195 """<p>No suitable Python3 environment configured.</p>""")
196 ) 198 )
197 return None, False, "" 199 return None, False, ""
198 200
199 self.__inShutdown = False 201 self.__inShutdown = False
200 202
201 debugClientType = Preferences.getDebugger("DebugClientType3") 203 debugClientType = Preferences.getDebugger("DebugClientType3")
202 if debugClientType == "standard": 204 if debugClientType == "standard":
203 debugClient = os.path.join(getConfig('ericDir'), 205 debugClient = os.path.join(
204 "DebugClients", "Python", 206 getConfig("ericDir"), "DebugClients", "Python", "DebugClient.py"
205 "DebugClient.py") 207 )
206 else: 208 else:
207 debugClient = Preferences.getDebugger("DebugClient3") 209 debugClient = Preferences.getDebugger("DebugClient3")
208 if debugClient == "": 210 if debugClient == "":
209 debugClient = os.path.join(sys.path[0], 211 debugClient = os.path.join(
210 "DebugClients", "Python", 212 sys.path[0], "DebugClients", "Python", "DebugClient.py"
211 "DebugClient.py") 213 )
212 214
213 redirect = ( 215 redirect = (
214 str(configOverride["redirect"]) 216 str(configOverride["redirect"])
215 if configOverride and configOverride["enable"] else 217 if configOverride and configOverride["enable"]
216 str(Preferences.getDebugger("Python3Redirect")) 218 else str(Preferences.getDebugger("Python3Redirect"))
217 ) 219 )
218 noencoding = (Preferences.getDebugger("Python3NoEncoding") and 220 noencoding = (
219 '--no-encoding' or '') 221 Preferences.getDebugger("Python3NoEncoding") and "--no-encoding" or ""
222 )
220 multiprocessEnabled = ( 223 multiprocessEnabled = (
221 '--multiprocess' if Preferences.getDebugger("MultiProcessEnabled") 224 "--multiprocess" if Preferences.getDebugger("MultiProcessEnabled") else ""
222 else '' 225 )
223 ) 226
224
225 if Preferences.getDebugger("RemoteDbgEnabled"): 227 if Preferences.getDebugger("RemoteDbgEnabled"):
226 ipaddr = self.debugServer.getHostAddress(False) 228 ipaddr = self.debugServer.getHostAddress(False)
227 rexec = Preferences.getDebugger("RemoteExecution") 229 rexec = Preferences.getDebugger("RemoteExecution")
228 rhost = Preferences.getDebugger("RemoteHost") 230 rhost = Preferences.getDebugger("RemoteHost")
229 if rhost == "": 231 if rhost == "":
230 rhost = "localhost" 232 rhost = "localhost"
231 if rexec: 233 if rexec:
232 args = Utilities.parseOptionString(rexec) + [ 234 args = Utilities.parseOptionString(rexec) + [
233 rhost, interpreter, debugClient] 235 rhost,
236 interpreter,
237 debugClient,
238 ]
234 if noencoding: 239 if noencoding:
235 args.append(noencoding) 240 args.append(noencoding)
236 if multiprocessEnabled: 241 if multiprocessEnabled:
237 args.append(multiprocessEnabled) 242 args.append(multiprocessEnabled)
238 args.extend([str(port), redirect, ipaddr]) 243 args.extend([str(port), redirect, ipaddr])
243 if prog: 248 if prog:
244 args[0] = prog 249 args[0] = prog
245 break 250 break
246 else: 251 else:
247 args[0] = Utilities.getExecutablePath(args[0]) 252 args[0] = Utilities.getExecutablePath(args[0])
248 process = self.__startProcess(args[0], args[1:], 253 process = self.__startProcess(args[0], args[1:], workingDir=workingDir)
249 workingDir=workingDir)
250 if process is None: 254 if process is None:
251 EricMessageBox.critical( 255 EricMessageBox.critical(
252 None, 256 None,
253 self.tr("Start Debugger"), 257 self.tr("Start Debugger"),
254 self.tr( 258 self.tr(
255 """<p>The debugger backend could not be""" 259 """<p>The debugger backend could not be"""
256 """ started.</p>""")) 260 """ started.</p>"""
257 261 ),
262 )
263
258 # set translation function 264 # set translation function
259 if Preferences.getDebugger("PathTranslation"): 265 if Preferences.getDebugger("PathTranslation"):
260 self.translateRemote = Preferences.getDebugger( 266 self.translateRemote = Preferences.getDebugger(
261 "PathTranslationRemote") 267 "PathTranslationRemote"
268 )
262 self.translateRemoteWindows = "\\" in self.translateRemote 269 self.translateRemoteWindows = "\\" in self.translateRemote
263 self.translateLocal = Preferences.getDebugger( 270 self.translateLocal = Preferences.getDebugger(
264 "PathTranslationLocal") 271 "PathTranslationLocal"
272 )
265 self.translate = self.__remoteTranslation 273 self.translate = self.__remoteTranslation
266 self.translateLocalWindows = "\\" in self.translateLocal 274 self.translateLocalWindows = "\\" in self.translateLocal
267 else: 275 else:
268 self.translate = self.__identityTranslation 276 self.translate = self.__identityTranslation
269 return process, self.__isNetworked, "" 277 return process, self.__isNetworked, ""
270 278
271 # set translation function 279 # set translation function
272 self.translate = self.__identityTranslation 280 self.translate = self.__identityTranslation
273 281
274 # setup the environment for the debugger 282 # setup the environment for the debugger
275 if Preferences.getDebugger("DebugEnvironmentReplace"): 283 if Preferences.getDebugger("DebugEnvironmentReplace"):
276 clientEnv = {} 284 clientEnv = {}
277 else: 285 else:
278 clientEnv = os.environ.copy() 286 clientEnv = os.environ.copy()
279 if originalPathString: 287 if originalPathString:
280 clientEnv["PATH"] = originalPathString 288 clientEnv["PATH"] = originalPathString
281 envlist = shlex.split( 289 envlist = shlex.split(Preferences.getDebugger("DebugEnvironment"))
282 Preferences.getDebugger("DebugEnvironment"))
283 for el in envlist: 290 for el in envlist:
284 with contextlib.suppress(ValueError): 291 with contextlib.suppress(ValueError):
285 key, value = el.split('=', 1) 292 key, value = el.split("=", 1)
286 clientEnv[str(key)] = str(value) 293 clientEnv[str(key)] = str(value)
287 if execPath: 294 if execPath:
288 if "PATH" in clientEnv: 295 if "PATH" in clientEnv:
289 clientEnv["PATH"] = os.pathsep.join( 296 clientEnv["PATH"] = os.pathsep.join([execPath, clientEnv["PATH"]])
290 [execPath, clientEnv["PATH"]])
291 else: 297 else:
292 clientEnv["PATH"] = execPath 298 clientEnv["PATH"] = execPath
293 299
294 ipaddr = self.debugServer.getHostAddress(True) 300 ipaddr = self.debugServer.getHostAddress(True)
295 if runInConsole or Preferences.getDebugger("ConsoleDbgEnabled"): 301 if runInConsole or Preferences.getDebugger("ConsoleDbgEnabled"):
296 ccmd = Preferences.getDebugger("ConsoleDbgCommand") 302 ccmd = Preferences.getDebugger("ConsoleDbgCommand")
297 if ccmd: 303 if ccmd:
298 args = Utilities.parseOptionString(ccmd) + [ 304 args = Utilities.parseOptionString(ccmd) + [
299 interpreter, os.path.abspath(debugClient)] 305 interpreter,
306 os.path.abspath(debugClient),
307 ]
300 if noencoding: 308 if noencoding:
301 args.append(noencoding) 309 args.append(noencoding)
302 if multiprocessEnabled: 310 if multiprocessEnabled:
303 args.append(multiprocessEnabled) 311 args.append(multiprocessEnabled)
304 args.extend([str(port), '0', ipaddr]) 312 args.extend([str(port), "0", ipaddr])
305 args[0] = Utilities.getExecutablePath(args[0]) 313 args[0] = Utilities.getExecutablePath(args[0])
306 process = self.__startProcess(args[0], args[1:], clientEnv, 314 process = self.__startProcess(
307 workingDir=workingDir) 315 args[0], args[1:], clientEnv, workingDir=workingDir
316 )
308 if process is None: 317 if process is None:
309 EricMessageBox.critical( 318 EricMessageBox.critical(
310 None, 319 None,
311 self.tr("Start Debugger"), 320 self.tr("Start Debugger"),
312 self.tr( 321 self.tr(
313 """<p>The debugger backend could not be""" 322 """<p>The debugger backend could not be"""
314 """ started.</p>""")) 323 """ started.</p>"""
324 ),
325 )
315 return process, self.__isNetworked, interpreter 326 return process, self.__isNetworked, interpreter
316 327
317 args = [debugClient] 328 args = [debugClient]
318 if noencoding: 329 if noencoding:
319 args.append(noencoding) 330 args.append(noencoding)
320 if multiprocessEnabled: 331 if multiprocessEnabled:
321 args.append(multiprocessEnabled) 332 args.append(multiprocessEnabled)
322 args.extend([str(port), redirect, ipaddr]) 333 args.extend([str(port), redirect, ipaddr])
323 process = self.__startProcess(interpreter, args, clientEnv, 334 process = self.__startProcess(
324 workingDir=workingDir) 335 interpreter, args, clientEnv, workingDir=workingDir
336 )
325 if process is None: 337 if process is None:
326 self.__startedVenv = "" 338 self.__startedVenv = ""
327 EricMessageBox.critical( 339 EricMessageBox.critical(
328 None, 340 None,
329 self.tr("Start Debugger"), 341 self.tr("Start Debugger"),
330 self.tr( 342 self.tr("""<p>The debugger backend could not be started.</p>"""),
331 """<p>The debugger backend could not be started.</p>""")) 343 )
332 else: 344 else:
333 self.__startedVenv = venvName 345 self.__startedVenv = venvName
334 346
335 return process, self.__isNetworked, interpreter 347 return process, self.__isNetworked, interpreter
336 348
337 def startRemoteForProject(self, port, runInConsole, venvName, 349 def startRemoteForProject(
338 originalPathString, workingDir=None, 350 self,
339 configOverride=None): 351 port,
352 runInConsole,
353 venvName,
354 originalPathString,
355 workingDir=None,
356 configOverride=None,
357 ):
340 """ 358 """
341 Public method to start a remote Python interpreter for a project. 359 Public method to start a remote Python interpreter for a project.
342 360
343 @param port port number the debug server is listening on 361 @param port port number the debug server is listening on
344 @type int 362 @type int
345 @param runInConsole flag indicating to start the debugger in a 363 @param runInConsole flag indicating to start the debugger in a
346 console window 364 console window
347 @type bool 365 @type bool
357 @return client process object, a flag to indicate a network connection 375 @return client process object, a flag to indicate a network connection
358 and the name of the interpreter in case of a local execution 376 and the name of the interpreter in case of a local execution
359 @rtype tuple of (QProcess, bool, str) 377 @rtype tuple of (QProcess, bool, str)
360 """ 378 """
361 global origPathEnv 379 global origPathEnv
362 380
363 project = ericApp().getObject("Project") 381 project = ericApp().getObject("Project")
364 if not project.isDebugPropertiesLoaded(): 382 if not project.isDebugPropertiesLoaded():
365 return None, self.__isNetworked, "" 383 return None, self.__isNetworked, ""
366 384
367 # start debugger with project specific settings 385 # start debugger with project specific settings
368 debugClient = project.getDebugProperty("DEBUGCLIENT") 386 debugClient = project.getDebugProperty("DEBUGCLIENT")
369 387
370 redirect = ( 388 redirect = (
371 str(configOverride["redirect"]) 389 str(configOverride["redirect"])
372 if configOverride and configOverride["enable"] else 390 if configOverride and configOverride["enable"]
373 str(project.getDebugProperty("REDIRECT")) 391 else str(project.getDebugProperty("REDIRECT"))
374 ) 392 )
375 noencoding = ( 393 noencoding = "--no-encoding" if project.getDebugProperty("NOENCODING") else ""
376 '--no-encoding' if project.getDebugProperty("NOENCODING") else ''
377 )
378 multiprocessEnabled = ( 394 multiprocessEnabled = (
379 '--multiprocess' if Preferences.getDebugger("MultiProcessEnabled") 395 "--multiprocess" if Preferences.getDebugger("MultiProcessEnabled") else ""
380 else '' 396 )
381 ) 397
382
383 if venvName: 398 if venvName:
384 venvManager = ericApp().getObject("VirtualEnvManager") 399 venvManager = ericApp().getObject("VirtualEnvManager")
385 interpreter = venvManager.getVirtualenvInterpreter(venvName) 400 interpreter = venvManager.getVirtualenvInterpreter(venvName)
386 execPath = venvManager.getVirtualenvExecPath(venvName) 401 execPath = venvManager.getVirtualenvExecPath(venvName)
387 else: 402 else:
390 interpreter = project.getProjectInterpreter() 405 interpreter = project.getProjectInterpreter()
391 if interpreter == "": 406 if interpreter == "":
392 EricMessageBox.critical( 407 EricMessageBox.critical(
393 None, 408 None,
394 self.tr("Start Debugger"), 409 self.tr("Start Debugger"),
395 self.tr( 410 self.tr("""<p>No suitable Python3 environment configured.</p>"""),
396 """<p>No suitable Python3 environment configured.</p>""")
397 ) 411 )
398 return None, self.__isNetworked, "" 412 return None, self.__isNetworked, ""
399 413
400 self.__inShutdown = False 414 self.__inShutdown = False
401 415
402 if project.getDebugProperty("REMOTEDEBUGGER"): 416 if project.getDebugProperty("REMOTEDEBUGGER"):
403 ipaddr = self.debugServer.getHostAddress(False) 417 ipaddr = self.debugServer.getHostAddress(False)
404 rexec = project.getDebugProperty("REMOTECOMMAND") 418 rexec = project.getDebugProperty("REMOTECOMMAND")
405 rhost = project.getDebugProperty("REMOTEHOST") 419 rhost = project.getDebugProperty("REMOTEHOST")
406 if rhost == "": 420 if rhost == "":
407 rhost = "localhost" 421 rhost = "localhost"
408 if rexec: 422 if rexec:
409 args = Utilities.parseOptionString(rexec) + [ 423 args = Utilities.parseOptionString(rexec) + [
410 rhost, interpreter, debugClient] 424 rhost,
425 interpreter,
426 debugClient,
427 ]
411 if noencoding: 428 if noencoding:
412 args.append(noencoding) 429 args.append(noencoding)
413 if multiprocessEnabled: 430 if multiprocessEnabled:
414 args.append(multiprocessEnabled) 431 args.append(multiprocessEnabled)
415 args.extend([str(port), redirect, ipaddr]) 432 args.extend([str(port), redirect, ipaddr])
420 if prog: 437 if prog:
421 args[0] = prog 438 args[0] = prog
422 break 439 break
423 else: 440 else:
424 args[0] = Utilities.getExecutablePath(args[0]) 441 args[0] = Utilities.getExecutablePath(args[0])
425 process = self.__startProcess(args[0], args[1:], 442 process = self.__startProcess(args[0], args[1:], workingDir=workingDir)
426 workingDir=workingDir)
427 if process is None: 443 if process is None:
428 EricMessageBox.critical( 444 EricMessageBox.critical(
429 None, 445 None,
430 self.tr("Start Debugger"), 446 self.tr("Start Debugger"),
431 self.tr( 447 self.tr(
432 """<p>The debugger backend could not be""" 448 """<p>The debugger backend could not be"""
433 """ started.</p>""")) 449 """ started.</p>"""
450 ),
451 )
434 # set translation function 452 # set translation function
435 if project.getDebugProperty("PATHTRANSLATION"): 453 if project.getDebugProperty("PATHTRANSLATION"):
436 self.translateRemote = project.getDebugProperty( 454 self.translateRemote = project.getDebugProperty("REMOTEPATH")
437 "REMOTEPATH")
438 self.translateRemoteWindows = "\\" in self.translateRemote 455 self.translateRemoteWindows = "\\" in self.translateRemote
439 self.translateLocal = project.getDebugProperty("LOCALPATH") 456 self.translateLocal = project.getDebugProperty("LOCALPATH")
440 self.translateLocalWindows = "\\" in self.translateLocal 457 self.translateLocalWindows = "\\" in self.translateLocal
441 self.translate = self.__remoteTranslation 458 self.translate = self.__remoteTranslation
442 else: 459 else:
443 self.translate = self.__identityTranslation 460 self.translate = self.__identityTranslation
444 return process, self.__isNetworked, "" 461 return process, self.__isNetworked, ""
445 else: 462 else:
446 # remote shell command is missing 463 # remote shell command is missing
447 return None, self.__isNetworked, "" 464 return None, self.__isNetworked, ""
448 465
449 # set translation function 466 # set translation function
450 self.translate = self.__identityTranslation 467 self.translate = self.__identityTranslation
451 468
452 # setup the environment for the debugger 469 # setup the environment for the debugger
453 if project.getDebugProperty("ENVIRONMENTOVERRIDE"): 470 if project.getDebugProperty("ENVIRONMENTOVERRIDE"):
454 clientEnv = {} 471 clientEnv = {}
455 else: 472 else:
456 clientEnv = os.environ.copy() 473 clientEnv = os.environ.copy()
457 if originalPathString: 474 if originalPathString:
458 clientEnv["PATH"] = originalPathString 475 clientEnv["PATH"] = originalPathString
459 envlist = shlex.split( 476 envlist = shlex.split(project.getDebugProperty("ENVIRONMENTSTRING"))
460 project.getDebugProperty("ENVIRONMENTSTRING"))
461 for el in envlist: 477 for el in envlist:
462 with contextlib.suppress(ValueError): 478 with contextlib.suppress(ValueError):
463 key, value = el.split('=', 1) 479 key, value = el.split("=", 1)
464 clientEnv[str(key)] = str(value) 480 clientEnv[str(key)] = str(value)
465 if execPath: 481 if execPath:
466 if "PATH" in clientEnv: 482 if "PATH" in clientEnv:
467 clientEnv["PATH"] = os.pathsep.join( 483 clientEnv["PATH"] = os.pathsep.join([execPath, clientEnv["PATH"]])
468 [execPath, clientEnv["PATH"]])
469 else: 484 else:
470 clientEnv["PATH"] = execPath 485 clientEnv["PATH"] = execPath
471 486
472 ipaddr = self.debugServer.getHostAddress(True) 487 ipaddr = self.debugServer.getHostAddress(True)
473 if runInConsole or project.getDebugProperty("CONSOLEDEBUGGER"): 488 if runInConsole or project.getDebugProperty("CONSOLEDEBUGGER"):
474 ccmd = (project.getDebugProperty("CONSOLECOMMAND") or 489 ccmd = project.getDebugProperty(
475 Preferences.getDebugger("ConsoleDbgCommand")) 490 "CONSOLECOMMAND"
491 ) or Preferences.getDebugger("ConsoleDbgCommand")
476 if ccmd: 492 if ccmd:
477 args = Utilities.parseOptionString(ccmd) + [ 493 args = Utilities.parseOptionString(ccmd) + [
478 interpreter, os.path.abspath(debugClient)] 494 interpreter,
495 os.path.abspath(debugClient),
496 ]
479 if noencoding: 497 if noencoding:
480 args.append(noencoding) 498 args.append(noencoding)
481 if multiprocessEnabled: 499 if multiprocessEnabled:
482 args.append(multiprocessEnabled) 500 args.append(multiprocessEnabled)
483 args.extend([str(port), '0', ipaddr]) 501 args.extend([str(port), "0", ipaddr])
484 args[0] = Utilities.getExecutablePath(args[0]) 502 args[0] = Utilities.getExecutablePath(args[0])
485 process = self.__startProcess(args[0], args[1:], clientEnv, 503 process = self.__startProcess(
486 workingDir=workingDir) 504 args[0], args[1:], clientEnv, workingDir=workingDir
505 )
487 if process is None: 506 if process is None:
488 EricMessageBox.critical( 507 EricMessageBox.critical(
489 None, 508 None,
490 self.tr("Start Debugger"), 509 self.tr("Start Debugger"),
491 self.tr( 510 self.tr(
492 """<p>The debugger backend could not be""" 511 """<p>The debugger backend could not be"""
493 """ started.</p>""")) 512 """ started.</p>"""
513 ),
514 )
494 return process, self.__isNetworked, interpreter 515 return process, self.__isNetworked, interpreter
495 516
496 args = [debugClient] 517 args = [debugClient]
497 if noencoding: 518 if noencoding:
498 args.append(noencoding) 519 args.append(noencoding)
499 if multiprocessEnabled: 520 if multiprocessEnabled:
500 args.append(multiprocessEnabled) 521 args.append(multiprocessEnabled)
501 args.extend([str(port), redirect, ipaddr]) 522 args.extend([str(port), redirect, ipaddr])
502 process = self.__startProcess(interpreter, args, clientEnv, 523 process = self.__startProcess(
503 workingDir=workingDir) 524 interpreter, args, clientEnv, workingDir=workingDir
525 )
504 if process is None: 526 if process is None:
505 self.__startedVenv = "" 527 self.__startedVenv = ""
506 EricMessageBox.critical( 528 EricMessageBox.critical(
507 None, 529 None,
508 self.tr("Start Debugger"), 530 self.tr("Start Debugger"),
509 self.tr( 531 self.tr("""<p>The debugger backend could not be started.</p>"""),
510 """<p>The debugger backend could not be started.</p>""")) 532 )
511 else: 533 else:
512 self.__startedVenv = venvName 534 self.__startedVenv = venvName
513 535
514 return process, self.__isNetworked, interpreter 536 return process, self.__isNetworked, interpreter
515 537
516 def getClientCapabilities(self): 538 def getClientCapabilities(self):
517 """ 539 """
518 Public method to retrieve the debug clients capabilities. 540 Public method to retrieve the debug clients capabilities.
519 541
520 @return debug client capabilities 542 @return debug client capabilities
521 @rtype int 543 @rtype int
522 """ 544 """
523 return self.clientCapabilities 545 return self.clientCapabilities
524 546
525 def newConnection(self, sock): 547 def newConnection(self, sock):
526 """ 548 """
527 Public slot to handle a new connection. 549 Public slot to handle a new connection.
528 550
529 @param sock reference to the socket object 551 @param sock reference to the socket object
530 @type QTcpSocket 552 @type QTcpSocket
531 @return flag indicating success 553 @return flag indicating success
532 @rtype bool 554 @rtype bool
533 """ 555 """
534 self.__pendingConnections.append(sock) 556 self.__pendingConnections.append(sock)
535 557
536 sock.readyRead.connect(lambda: self.__parseClientLine(sock)) 558 sock.readyRead.connect(lambda: self.__parseClientLine(sock))
537 sock.disconnected.connect(lambda: self.__socketDisconnected(sock)) 559 sock.disconnected.connect(lambda: self.__socketDisconnected(sock))
538 560
539 return True 561 return True
540 562
541 def __assignDebuggerId(self, sock, debuggerId): 563 def __assignDebuggerId(self, sock, debuggerId):
542 """ 564 """
543 Private method to set the debugger id for a recent debugger connection 565 Private method to set the debugger id for a recent debugger connection
544 attempt. 566 attempt.
545 567
546 @param sock reference to the socket object 568 @param sock reference to the socket object
547 @type QTcpSocket 569 @type QTcpSocket
548 @param debuggerId id of the connected debug client 570 @param debuggerId id of the connected debug client
549 @type str 571 @type str
550 """ 572 """
551 if sock in self.__pendingConnections: 573 if sock in self.__pendingConnections:
552 self.__connections[debuggerId] = sock 574 self.__connections[debuggerId] = sock
553 self.__pendingConnections.remove(sock) 575 self.__pendingConnections.remove(sock)
554 576
555 if self.__master is None: 577 if self.__master is None:
556 self.__master = debuggerId 578 self.__master = debuggerId
557 # Get the remote clients capabilities 579 # Get the remote clients capabilities
558 self.remoteCapabilities(debuggerId) 580 self.remoteCapabilities(debuggerId)
559 581
560 self.debugServer.signalClientDebuggerId(debuggerId) 582 self.debugServer.signalClientDebuggerId(debuggerId)
561 583
562 if debuggerId == self.__master: 584 if debuggerId == self.__master:
563 self.__flush() 585 self.__flush()
564 self.debugServer.masterClientConnected() 586 self.debugServer.masterClientConnected()
565 587
566 self.debugServer.initializeClient(debuggerId) 588 self.debugServer.initializeClient(debuggerId)
567 589
568 # perform auto-continue except for master 590 # perform auto-continue except for master
569 if ( 591 if (
570 debuggerId != self.__master and 592 debuggerId != self.__master
571 self.__autoContinue and 593 and self.__autoContinue
572 not self.__isStepCommand 594 and not self.__isStepCommand
573 ): 595 ):
574 self.__autoContinued.append(debuggerId) 596 self.__autoContinued.append(debuggerId)
575 QTimer.singleShot( 597 QTimer.singleShot(0, lambda: self.remoteContinue(debuggerId))
576 0, lambda: self.remoteContinue(debuggerId)) 598
577
578 def __socketDisconnected(self, sock): 599 def __socketDisconnected(self, sock):
579 """ 600 """
580 Private slot handling a socket disconnecting. 601 Private slot handling a socket disconnecting.
581 602
582 @param sock reference to the disconnected socket 603 @param sock reference to the disconnected socket
583 @type QTcpSocket 604 @type QTcpSocket
584 """ 605 """
585 for debuggerId in self.__connections: 606 for debuggerId in self.__connections:
586 if self.__connections[debuggerId] is sock: 607 if self.__connections[debuggerId] is sock:
595 self.debugServer.signalClientDisconnected(debuggerId) 616 self.debugServer.signalClientDisconnected(debuggerId)
596 break 617 break
597 else: 618 else:
598 if sock in self.__pendingConnections: 619 if sock in self.__pendingConnections:
599 self.__pendingConnections.remove(sock) 620 self.__pendingConnections.remove(sock)
600 621
601 if not self.__connections: 622 if not self.__connections:
602 # no active connections anymore 623 # no active connections anymore
603 with contextlib.suppress(RuntimeError): 624 with contextlib.suppress(RuntimeError):
604 self.debugServer.signalLastClientExited() 625 self.debugServer.signalLastClientExited()
605 # debug server object might have been deleted already 626 # debug server object might have been deleted already
606 # ignore this 627 # ignore this
607 self.__autoContinued.clear() 628 self.__autoContinued.clear()
608 self.debugServer.startClient() 629 self.debugServer.startClient()
609 630
610 def getDebuggerIds(self): 631 def getDebuggerIds(self):
611 """ 632 """
612 Public method to return the IDs of the connected debugger backends. 633 Public method to return the IDs of the connected debugger backends.
613 634
614 @return list of connected debugger backend IDs 635 @return list of connected debugger backend IDs
615 @rtype list of str 636 @rtype list of str
616 """ 637 """
617 return sorted(self.__connections.keys()) 638 return sorted(self.__connections.keys())
618 639
619 def __flush(self): 640 def __flush(self):
620 """ 641 """
621 Private slot to flush the queue. 642 Private slot to flush the queue.
622 """ 643 """
623 if self.__master: 644 if self.__master:
624 # Send commands that were waiting for the connection. 645 # Send commands that were waiting for the connection.
625 for cmd in self.queue: 646 for cmd in self.queue:
626 self.__writeJsonCommandToSocket( 647 self.__writeJsonCommandToSocket(cmd, self.__connections[self.__master])
627 cmd, self.__connections[self.__master]) 648
628
629 self.queue = [] 649 self.queue = []
630 650
631 def shutdown(self): 651 def shutdown(self):
632 """ 652 """
633 Public method to cleanly shut down. 653 Public method to cleanly shut down.
634 654
635 It closes our sockets and shuts down the debug clients. 655 It closes our sockets and shuts down the debug clients.
636 (Needed on Win OS) 656 (Needed on Win OS)
637 """ 657 """
638 if not self.__master: 658 if not self.__master:
639 return 659 return
640 660
641 self.__inShutdown = True 661 self.__inShutdown = True
642 662
643 while self.__connections: 663 while self.__connections:
644 debuggerId, sock = self.__connections.popitem() 664 debuggerId, sock = self.__connections.popitem()
645 self.__shutdownSocket(sock) 665 self.__shutdownSocket(sock)
646 666
647 while self.__pendingConnections: 667 while self.__pendingConnections:
648 sock = self.__pendingConnections.pop() 668 sock = self.__pendingConnections.pop()
649 self.__shutdownSocket(sock) 669 self.__shutdownSocket(sock)
650 670
651 # reinitialize 671 # reinitialize
652 self.queue = [] 672 self.queue = []
653 673
654 self.__master = None 674 self.__master = None
655 675
656 def __shutdownSocket(self, sock): 676 def __shutdownSocket(self, sock):
657 """ 677 """
658 Private slot to shut down a socket. 678 Private slot to shut down a socket.
659 679
660 @param sock reference to the socket 680 @param sock reference to the socket
661 @type QTcpSocket 681 @type QTcpSocket
662 """ 682 """
663 # do not want any slots called during shutdown 683 # do not want any slots called during shutdown
664 sock.readyRead.disconnect() 684 sock.readyRead.disconnect()
666 686
667 # close down socket, and shut down client as well. 687 # close down socket, and shut down client as well.
668 self.__sendJsonCommand("RequestShutdown", {}, sock=sock) 688 self.__sendJsonCommand("RequestShutdown", {}, sock=sock)
669 sock.flush() 689 sock.flush()
670 sock.close() 690 sock.close()
671 691
672 sock.setParent(None) 692 sock.setParent(None)
673 sock.deleteLater() 693 sock.deleteLater()
674 del sock 694 del sock
675 695
676 def isConnected(self): 696 def isConnected(self):
677 """ 697 """
678 Public method to test, if a debug client has connected. 698 Public method to test, if a debug client has connected.
679 699
680 @return flag indicating the connection status 700 @return flag indicating the connection status
681 @rtype bool 701 @rtype bool
682 """ 702 """
683 return bool(self.__connections) 703 return bool(self.__connections)
684 704
685 def remoteEnvironment(self, env): 705 def remoteEnvironment(self, env):
686 """ 706 """
687 Public method to set the environment for a program to debug, run, ... 707 Public method to set the environment for a program to debug, run, ...
688 708
689 @param env environment settings 709 @param env environment settings
690 @type dict 710 @type dict
691 """ 711 """
692 self.__sendJsonCommand("RequestEnvironment", {"environment": env}, 712 self.__sendJsonCommand(
693 self.__master) 713 "RequestEnvironment", {"environment": env}, self.__master
694 714 )
695 def remoteLoad(self, fn, argv, wd, traceInterpreter=False, 715
696 autoContinue=True, enableMultiprocess=False): 716 def remoteLoad(
717 self,
718 fn,
719 argv,
720 wd,
721 traceInterpreter=False,
722 autoContinue=True,
723 enableMultiprocess=False,
724 ):
697 """ 725 """
698 Public method to load a new program to debug. 726 Public method to load a new program to debug.
699 727
700 @param fn the filename to debug 728 @param fn the filename to debug
701 @type str 729 @type str
702 @param argv the commandline arguments to pass to the program 730 @param argv the commandline arguments to pass to the program
703 @type str 731 @type str
704 @param wd the working directory for the program 732 @param wd the working directory for the program
714 @type bool 742 @type bool
715 """ 743 """
716 self.__autoContinue = autoContinue 744 self.__autoContinue = autoContinue
717 self.__scriptName = os.path.abspath(fn) 745 self.__scriptName = os.path.abspath(fn)
718 self.__isStepCommand = False 746 self.__isStepCommand = False
719 747
720 wd = self.translate(wd, False) 748 wd = self.translate(wd, False)
721 fn = self.translate(os.path.abspath(fn), False) 749 fn = self.translate(os.path.abspath(fn), False)
722 self.__sendJsonCommand("RequestLoad", { 750 self.__sendJsonCommand(
723 "workdir": wd, 751 "RequestLoad",
724 "filename": fn, 752 {
725 "argv": Utilities.parseOptionString(argv), 753 "workdir": wd,
726 "traceInterpreter": traceInterpreter, 754 "filename": fn,
727 "multiprocess": enableMultiprocess, 755 "argv": Utilities.parseOptionString(argv),
728 }, self.__master) 756 "traceInterpreter": traceInterpreter,
729 757 "multiprocess": enableMultiprocess,
758 },
759 self.__master,
760 )
761
730 def remoteRun(self, fn, argv, wd): 762 def remoteRun(self, fn, argv, wd):
731 """ 763 """
732 Public method to load a new program to run. 764 Public method to load a new program to run.
733 765
734 @param fn the filename to run 766 @param fn the filename to run
735 @type str 767 @type str
736 @param argv the commandline arguments to pass to the program 768 @param argv the commandline arguments to pass to the program
737 @type str 769 @type str
738 @param wd the working directory for the program 770 @param wd the working directory for the program
739 @type str 771 @type str
740 """ 772 """
741 self.__scriptName = os.path.abspath(fn) 773 self.__scriptName = os.path.abspath(fn)
742 774
743 wd = self.translate(wd, False) 775 wd = self.translate(wd, False)
744 fn = self.translate(os.path.abspath(fn), False) 776 fn = self.translate(os.path.abspath(fn), False)
745 self.__sendJsonCommand("RequestRun", { 777 self.__sendJsonCommand(
746 "workdir": wd, 778 "RequestRun",
747 "filename": fn, 779 {
748 "argv": Utilities.parseOptionString(argv), 780 "workdir": wd,
749 }, self.__master) 781 "filename": fn,
750 782 "argv": Utilities.parseOptionString(argv),
783 },
784 self.__master,
785 )
786
751 def remoteCoverage(self, fn, argv, wd, erase=False): 787 def remoteCoverage(self, fn, argv, wd, erase=False):
752 """ 788 """
753 Public method to load a new program to collect coverage data. 789 Public method to load a new program to collect coverage data.
754 790
755 @param fn the filename to run 791 @param fn the filename to run
756 @type str 792 @type str
757 @param argv the commandline arguments to pass to the program 793 @param argv the commandline arguments to pass to the program
758 @type str 794 @type str
759 @param wd the working directory for the program 795 @param wd the working directory for the program
761 @param erase flag indicating that coverage info should be 797 @param erase flag indicating that coverage info should be
762 cleared first 798 cleared first
763 @type bool 799 @type bool
764 """ 800 """
765 self.__scriptName = os.path.abspath(fn) 801 self.__scriptName = os.path.abspath(fn)
766 802
767 wd = self.translate(wd, False) 803 wd = self.translate(wd, False)
768 fn = self.translate(os.path.abspath(fn), False) 804 fn = self.translate(os.path.abspath(fn), False)
769 self.__sendJsonCommand("RequestCoverage", { 805 self.__sendJsonCommand(
770 "workdir": wd, 806 "RequestCoverage",
771 "filename": fn, 807 {
772 "argv": Utilities.parseOptionString(argv), 808 "workdir": wd,
773 "erase": erase, 809 "filename": fn,
774 }, self.__master) 810 "argv": Utilities.parseOptionString(argv),
775 811 "erase": erase,
812 },
813 self.__master,
814 )
815
776 def remoteProfile(self, fn, argv, wd, erase=False): 816 def remoteProfile(self, fn, argv, wd, erase=False):
777 """ 817 """
778 Public method to load a new program to collect profiling data. 818 Public method to load a new program to collect profiling data.
779 819
780 @param fn the filename to run 820 @param fn the filename to run
781 @type str 821 @type str
782 @param argv the commandline arguments to pass to the program 822 @param argv the commandline arguments to pass to the program
783 @type str 823 @type str
784 @param wd the working directory for the program 824 @param wd the working directory for the program
786 @param erase flag indicating that timing info should be cleared 826 @param erase flag indicating that timing info should be cleared
787 first 827 first
788 @type bool 828 @type bool
789 """ 829 """
790 self.__scriptName = os.path.abspath(fn) 830 self.__scriptName = os.path.abspath(fn)
791 831
792 wd = self.translate(wd, False) 832 wd = self.translate(wd, False)
793 fn = self.translate(os.path.abspath(fn), False) 833 fn = self.translate(os.path.abspath(fn), False)
794 self.__sendJsonCommand("RequestProfile", { 834 self.__sendJsonCommand(
795 "workdir": wd, 835 "RequestProfile",
796 "filename": fn, 836 {
797 "argv": Utilities.parseOptionString(argv), 837 "workdir": wd,
798 "erase": erase, 838 "filename": fn,
799 }, self.__master) 839 "argv": Utilities.parseOptionString(argv),
800 840 "erase": erase,
841 },
842 self.__master,
843 )
844
801 def remoteStatement(self, debuggerId, stmt): 845 def remoteStatement(self, debuggerId, stmt):
802 """ 846 """
803 Public method to execute a Python statement. 847 Public method to execute a Python statement.
804 848
805 @param debuggerId ID of the debugger backend 849 @param debuggerId ID of the debugger backend
806 @type str 850 @type str
807 @param stmt the Python statement to execute. 851 @param stmt the Python statement to execute.
808 @type str 852 @type str
809 """ 853 """
810 self.__sendJsonCommand("ExecuteStatement", { 854 self.__sendJsonCommand(
811 "statement": stmt, 855 "ExecuteStatement",
812 }, debuggerId) 856 {
813 857 "statement": stmt,
858 },
859 debuggerId,
860 )
861
814 def remoteStep(self, debuggerId): 862 def remoteStep(self, debuggerId):
815 """ 863 """
816 Public method to single step the debugged program. 864 Public method to single step the debugged program.
817 865
818 @param debuggerId ID of the debugger backend 866 @param debuggerId ID of the debugger backend
819 @type str 867 @type str
820 """ 868 """
821 self.__isStepCommand = True 869 self.__isStepCommand = True
822 self.__sendJsonCommand("RequestStep", {}, debuggerId) 870 self.__sendJsonCommand("RequestStep", {}, debuggerId)
823 871
824 def remoteStepOver(self, debuggerId): 872 def remoteStepOver(self, debuggerId):
825 """ 873 """
826 Public method to step over the debugged program. 874 Public method to step over the debugged program.
827 875
828 @param debuggerId ID of the debugger backend 876 @param debuggerId ID of the debugger backend
829 @type str 877 @type str
830 """ 878 """
831 self.__isStepCommand = True 879 self.__isStepCommand = True
832 self.__sendJsonCommand("RequestStepOver", {}, debuggerId) 880 self.__sendJsonCommand("RequestStepOver", {}, debuggerId)
833 881
834 def remoteStepOut(self, debuggerId): 882 def remoteStepOut(self, debuggerId):
835 """ 883 """
836 Public method to step out the debugged program. 884 Public method to step out the debugged program.
837 885
838 @param debuggerId ID of the debugger backend 886 @param debuggerId ID of the debugger backend
839 @type str 887 @type str
840 """ 888 """
841 self.__isStepCommand = True 889 self.__isStepCommand = True
842 self.__sendJsonCommand("RequestStepOut", {}, debuggerId) 890 self.__sendJsonCommand("RequestStepOut", {}, debuggerId)
843 891
844 def remoteStepQuit(self, debuggerId): 892 def remoteStepQuit(self, debuggerId):
845 """ 893 """
846 Public method to stop the debugged program. 894 Public method to stop the debugged program.
847 895
848 @param debuggerId ID of the debugger backend 896 @param debuggerId ID of the debugger backend
849 @type str 897 @type str
850 """ 898 """
851 self.__isStepCommand = True 899 self.__isStepCommand = True
852 self.__sendJsonCommand("RequestStepQuit", {}, debuggerId) 900 self.__sendJsonCommand("RequestStepQuit", {}, debuggerId)
853 901
854 def remoteContinue(self, debuggerId, special=False): 902 def remoteContinue(self, debuggerId, special=False):
855 """ 903 """
856 Public method to continue the debugged program. 904 Public method to continue the debugged program.
857 905
858 @param debuggerId ID of the debugger backend 906 @param debuggerId ID of the debugger backend
859 @type str 907 @type str
860 @param special flag indicating a special continue operation 908 @param special flag indicating a special continue operation
861 @type bool 909 @type bool
862 """ 910 """
863 self.__isStepCommand = False 911 self.__isStepCommand = False
864 self.__sendJsonCommand("RequestContinue", { 912 self.__sendJsonCommand(
865 "special": special, 913 "RequestContinue",
866 }, debuggerId) 914 {
867 915 "special": special,
916 },
917 debuggerId,
918 )
919
868 def remoteContinueUntil(self, debuggerId, line): 920 def remoteContinueUntil(self, debuggerId, line):
869 """ 921 """
870 Public method to continue the debugged program to the given line 922 Public method to continue the debugged program to the given line
871 or until returning from the current frame. 923 or until returning from the current frame.
872 924
873 @param debuggerId ID of the debugger backend 925 @param debuggerId ID of the debugger backend
874 @type str 926 @type str
875 @param line the new line, where execution should be continued to 927 @param line the new line, where execution should be continued to
876 @type int 928 @type int
877 """ 929 """
878 self.__isStepCommand = False 930 self.__isStepCommand = False
879 self.__sendJsonCommand("RequestContinueUntil", { 931 self.__sendJsonCommand(
880 "newLine": line, 932 "RequestContinueUntil",
881 }, debuggerId) 933 {
882 934 "newLine": line,
935 },
936 debuggerId,
937 )
938
883 def remoteMoveIP(self, debuggerId, line): 939 def remoteMoveIP(self, debuggerId, line):
884 """ 940 """
885 Public method to move the instruction pointer to a different line. 941 Public method to move the instruction pointer to a different line.
886 942
887 @param debuggerId ID of the debugger backend 943 @param debuggerId ID of the debugger backend
888 @type str 944 @type str
889 @param line the new line, where execution should be continued 945 @param line the new line, where execution should be continued
890 @type int 946 @type int
891 """ 947 """
892 self.__sendJsonCommand("RequestMoveIP", { 948 self.__sendJsonCommand(
893 "newLine": line, 949 "RequestMoveIP",
894 }, debuggerId) 950 {
895 951 "newLine": line,
896 def remoteBreakpoint(self, debuggerId, fn, line, setBreakpoint, cond=None, 952 },
897 temp=False): 953 debuggerId,
954 )
955
956 def remoteBreakpoint(
957 self, debuggerId, fn, line, setBreakpoint, cond=None, temp=False
958 ):
898 """ 959 """
899 Public method to set or clear a breakpoint. 960 Public method to set or clear a breakpoint.
900 961
901 @param debuggerId ID of the debugger backend 962 @param debuggerId ID of the debugger backend
902 @type str 963 @type str
903 @param fn filename the breakpoint belongs to 964 @param fn filename the breakpoint belongs to
904 @type str 965 @type str
905 @param line linenumber of the breakpoint 966 @param line linenumber of the breakpoint
909 @param cond condition of the breakpoint 970 @param cond condition of the breakpoint
910 @type str 971 @type str
911 @param temp flag indicating a temporary breakpoint 972 @param temp flag indicating a temporary breakpoint
912 @type bool 973 @type bool
913 """ 974 """
914 debuggerList = ([debuggerId] if debuggerId 975 debuggerList = [debuggerId] if debuggerId else list(self.__connections.keys())
915 else list(self.__connections.keys()))
916 for debuggerId in debuggerList: 976 for debuggerId in debuggerList:
917 self.__sendJsonCommand("RequestBreakpoint", { 977 self.__sendJsonCommand(
918 "filename": self.translate(fn, False), 978 "RequestBreakpoint",
919 "line": line, 979 {
920 "temporary": temp, 980 "filename": self.translate(fn, False),
921 "setBreakpoint": setBreakpoint, 981 "line": line,
922 "condition": cond, 982 "temporary": temp,
923 }, debuggerId) 983 "setBreakpoint": setBreakpoint,
924 984 "condition": cond,
985 },
986 debuggerId,
987 )
988
925 def remoteBreakpointEnable(self, debuggerId, fn, line, enable): 989 def remoteBreakpointEnable(self, debuggerId, fn, line, enable):
926 """ 990 """
927 Public method to enable or disable a breakpoint. 991 Public method to enable or disable a breakpoint.
928 992
929 @param debuggerId ID of the debugger backend 993 @param debuggerId ID of the debugger backend
930 @type str 994 @type str
931 @param fn filename the breakpoint belongs to 995 @param fn filename the breakpoint belongs to
932 @type str 996 @type str
933 @param line linenumber of the breakpoint 997 @param line linenumber of the breakpoint
934 @type int 998 @type int
935 @param enable flag indicating enabling or disabling a breakpoint 999 @param enable flag indicating enabling or disabling a breakpoint
936 @type bool 1000 @type bool
937 """ 1001 """
938 debuggerList = ([debuggerId] if debuggerId 1002 debuggerList = [debuggerId] if debuggerId else list(self.__connections.keys())
939 else list(self.__connections.keys()))
940 for debuggerId in debuggerList: 1003 for debuggerId in debuggerList:
941 self.__sendJsonCommand("RequestBreakpointEnable", { 1004 self.__sendJsonCommand(
942 "filename": self.translate(fn, False), 1005 "RequestBreakpointEnable",
943 "line": line, 1006 {
944 "enable": enable, 1007 "filename": self.translate(fn, False),
945 }, debuggerId) 1008 "line": line,
946 1009 "enable": enable,
1010 },
1011 debuggerId,
1012 )
1013
947 def remoteBreakpointIgnore(self, debuggerId, fn, line, count): 1014 def remoteBreakpointIgnore(self, debuggerId, fn, line, count):
948 """ 1015 """
949 Public method to ignore a breakpoint the next couple of occurrences. 1016 Public method to ignore a breakpoint the next couple of occurrences.
950 1017
951 @param debuggerId ID of the debugger backend 1018 @param debuggerId ID of the debugger backend
952 @type str 1019 @type str
953 @param fn filename the breakpoint belongs to 1020 @param fn filename the breakpoint belongs to
954 @type str 1021 @type str
955 @param line linenumber of the breakpoint 1022 @param line linenumber of the breakpoint
956 @type int 1023 @type int
957 @param count number of occurrences to ignore 1024 @param count number of occurrences to ignore
958 @type int 1025 @type int
959 """ 1026 """
960 debuggerList = ([debuggerId] if debuggerId 1027 debuggerList = [debuggerId] if debuggerId else list(self.__connections.keys())
961 else list(self.__connections.keys()))
962 for debuggerId in debuggerList: 1028 for debuggerId in debuggerList:
963 self.__sendJsonCommand("RequestBreakpointIgnore", { 1029 self.__sendJsonCommand(
964 "filename": self.translate(fn, False), 1030 "RequestBreakpointIgnore",
965 "line": line, 1031 {
966 "count": count, 1032 "filename": self.translate(fn, False),
967 }, debuggerId) 1033 "line": line,
968 1034 "count": count,
1035 },
1036 debuggerId,
1037 )
1038
969 def remoteWatchpoint(self, debuggerId, cond, setWatch, temp=False): 1039 def remoteWatchpoint(self, debuggerId, cond, setWatch, temp=False):
970 """ 1040 """
971 Public method to set or clear a watch expression. 1041 Public method to set or clear a watch expression.
972 1042
973 @param debuggerId ID of the debugger backend 1043 @param debuggerId ID of the debugger backend
974 @type str 1044 @type str
975 @param cond expression of the watch expression 1045 @param cond expression of the watch expression
976 @type str 1046 @type str
977 @param setWatch flag indicating setting or resetting a watch expression 1047 @param setWatch flag indicating setting or resetting a watch expression
978 @type bool 1048 @type bool
979 @param temp flag indicating a temporary watch expression 1049 @param temp flag indicating a temporary watch expression
980 @type bool 1050 @type bool
981 """ 1051 """
982 debuggerList = ([debuggerId] if debuggerId 1052 debuggerList = [debuggerId] if debuggerId else list(self.__connections.keys())
983 else list(self.__connections.keys()))
984 for debuggerId in debuggerList: 1053 for debuggerId in debuggerList:
985 # cond is combination of cond and special (s. watch expression 1054 # cond is combination of cond and special (s. watch expression
986 # viewer) 1055 # viewer)
987 self.__sendJsonCommand("RequestWatch", { 1056 self.__sendJsonCommand(
988 "temporary": temp, 1057 "RequestWatch",
989 "setWatch": setWatch, 1058 {
990 "condition": cond, 1059 "temporary": temp,
991 }, debuggerId) 1060 "setWatch": setWatch,
992 1061 "condition": cond,
1062 },
1063 debuggerId,
1064 )
1065
993 def remoteWatchpointEnable(self, debuggerId, cond, enable): 1066 def remoteWatchpointEnable(self, debuggerId, cond, enable):
994 """ 1067 """
995 Public method to enable or disable a watch expression. 1068 Public method to enable or disable a watch expression.
996 1069
997 @param debuggerId ID of the debugger backend 1070 @param debuggerId ID of the debugger backend
998 @type str 1071 @type str
999 @param cond expression of the watch expression 1072 @param cond expression of the watch expression
1000 @type str 1073 @type str
1001 @param enable flag indicating enabling or disabling a watch expression 1074 @param enable flag indicating enabling or disabling a watch expression
1002 @type bool 1075 @type bool
1003 """ 1076 """
1004 debuggerList = ([debuggerId] if debuggerId 1077 debuggerList = [debuggerId] if debuggerId else list(self.__connections.keys())
1005 else list(self.__connections.keys()))
1006 for debuggerId in debuggerList: 1078 for debuggerId in debuggerList:
1007 # cond is combination of cond and special (s. watch expression 1079 # cond is combination of cond and special (s. watch expression
1008 # viewer) 1080 # viewer)
1009 self.__sendJsonCommand("RequestWatchEnable", { 1081 self.__sendJsonCommand(
1010 "condition": cond, 1082 "RequestWatchEnable",
1011 "enable": enable, 1083 {
1012 }, debuggerId) 1084 "condition": cond,
1013 1085 "enable": enable,
1086 },
1087 debuggerId,
1088 )
1089
1014 def remoteWatchpointIgnore(self, debuggerId, cond, count): 1090 def remoteWatchpointIgnore(self, debuggerId, cond, count):
1015 """ 1091 """
1016 Public method to ignore a watch expression the next couple of 1092 Public method to ignore a watch expression the next couple of
1017 occurrences. 1093 occurrences.
1018 1094
1019 @param debuggerId ID of the debugger backend 1095 @param debuggerId ID of the debugger backend
1020 @type str 1096 @type str
1021 @param cond expression of the watch expression 1097 @param cond expression of the watch expression
1022 @type str 1098 @type str
1023 @param count number of occurrences to ignore 1099 @param count number of occurrences to ignore
1024 @type int 1100 @type int
1025 """ 1101 """
1026 debuggerList = ([debuggerId] if debuggerId 1102 debuggerList = [debuggerId] if debuggerId else list(self.__connections.keys())
1027 else list(self.__connections.keys()))
1028 for debuggerId in debuggerList: 1103 for debuggerId in debuggerList:
1029 # cond is combination of cond and special (s. watch expression 1104 # cond is combination of cond and special (s. watch expression
1030 # viewer) 1105 # viewer)
1031 self.__sendJsonCommand("RequestWatchIgnore", { 1106 self.__sendJsonCommand(
1032 "condition": cond, 1107 "RequestWatchIgnore",
1033 "count": count, 1108 {
1034 }, debuggerId) 1109 "condition": cond,
1035 1110 "count": count,
1111 },
1112 debuggerId,
1113 )
1114
1036 def remoteRawInput(self, debuggerId, inputString): 1115 def remoteRawInput(self, debuggerId, inputString):
1037 """ 1116 """
1038 Public method to send the raw input to the debugged program. 1117 Public method to send the raw input to the debugged program.
1039 1118
1040 @param debuggerId ID of the debugger backend 1119 @param debuggerId ID of the debugger backend
1041 @type str 1120 @type str
1042 @param inputString the raw input 1121 @param inputString the raw input
1043 @type str 1122 @type str
1044 """ 1123 """
1045 self.__sendJsonCommand("RawInput", { 1124 self.__sendJsonCommand(
1046 "input": inputString, 1125 "RawInput",
1047 }, debuggerId) 1126 {
1048 1127 "input": inputString,
1128 },
1129 debuggerId,
1130 )
1131
1049 def remoteThreadList(self, debuggerId): 1132 def remoteThreadList(self, debuggerId):
1050 """ 1133 """
1051 Public method to request the list of threads from the client. 1134 Public method to request the list of threads from the client.
1052 1135
1053 @param debuggerId ID of the debugger backend 1136 @param debuggerId ID of the debugger backend
1054 @type str 1137 @type str
1055 """ 1138 """
1056 self.__sendJsonCommand("RequestThreadList", {}, debuggerId) 1139 self.__sendJsonCommand("RequestThreadList", {}, debuggerId)
1057 1140
1058 def remoteSetThread(self, debuggerId, tid): 1141 def remoteSetThread(self, debuggerId, tid):
1059 """ 1142 """
1060 Public method to request to set the given thread as current thread. 1143 Public method to request to set the given thread as current thread.
1061 1144
1062 @param debuggerId ID of the debugger backend 1145 @param debuggerId ID of the debugger backend
1063 @type str 1146 @type str
1064 @param tid id of the thread 1147 @param tid id of the thread
1065 @type int 1148 @type int
1066 """ 1149 """
1067 self.__sendJsonCommand("RequestThreadSet", { 1150 self.__sendJsonCommand(
1068 "threadID": tid, 1151 "RequestThreadSet",
1069 }, debuggerId) 1152 {
1070 1153 "threadID": tid,
1154 },
1155 debuggerId,
1156 )
1157
1071 def remoteClientStack(self, debuggerId): 1158 def remoteClientStack(self, debuggerId):
1072 """ 1159 """
1073 Public method to request the stack of the main thread. 1160 Public method to request the stack of the main thread.
1074 1161
1075 @param debuggerId ID of the debugger backend 1162 @param debuggerId ID of the debugger backend
1076 @type str 1163 @type str
1077 """ 1164 """
1078 self.__sendJsonCommand("RequestStack", {}, debuggerId) 1165 self.__sendJsonCommand("RequestStack", {}, debuggerId)
1079 1166
1080 def remoteClientVariables(self, debuggerId, scope, filterList, framenr=0, 1167 def remoteClientVariables(
1081 maxSize=0): 1168 self, debuggerId, scope, filterList, framenr=0, maxSize=0
1169 ):
1082 """ 1170 """
1083 Public method to request the variables of the debugged program. 1171 Public method to request the variables of the debugged program.
1084 1172
1085 @param debuggerId ID of the debugger backend 1173 @param debuggerId ID of the debugger backend
1086 @type str 1174 @type str
1087 @param scope the scope of the variables (0 = local, 1 = global) 1175 @param scope the scope of the variables (0 = local, 1 = global)
1088 @type int 1176 @type int
1089 @param filterList list of variable types to filter out 1177 @param filterList list of variable types to filter out
1093 @param maxSize maximum size the formatted value of a variable will 1181 @param maxSize maximum size the formatted value of a variable will
1094 be shown. If it is bigger than that, a 'too big' indication will 1182 be shown. If it is bigger than that, a 'too big' indication will
1095 be given (@@TOO_BIG_TO_SHOW@@). 1183 be given (@@TOO_BIG_TO_SHOW@@).
1096 @type int 1184 @type int
1097 """ 1185 """
1098 self.__sendJsonCommand("RequestVariables", { 1186 self.__sendJsonCommand(
1099 "frameNumber": framenr, 1187 "RequestVariables",
1100 "scope": scope, 1188 {
1101 "filters": filterList, 1189 "frameNumber": framenr,
1102 "maxSize": maxSize, 1190 "scope": scope,
1103 }, debuggerId) 1191 "filters": filterList,
1104 1192 "maxSize": maxSize,
1105 def remoteClientVariable(self, debuggerId, scope, filterList, var, 1193 },
1106 framenr=0, maxSize=0): 1194 debuggerId,
1195 )
1196
1197 def remoteClientVariable(
1198 self, debuggerId, scope, filterList, var, framenr=0, maxSize=0
1199 ):
1107 """ 1200 """
1108 Public method to request the variables of the debugged program. 1201 Public method to request the variables of the debugged program.
1109 1202
1110 @param debuggerId ID of the debugger backend 1203 @param debuggerId ID of the debugger backend
1111 @type str 1204 @type str
1112 @param scope the scope of the variables (0 = local, 1 = global) 1205 @param scope the scope of the variables (0 = local, 1 = global)
1113 @type int 1206 @type int
1114 @param filterList list of variable types to filter out 1207 @param filterList list of variable types to filter out
1120 @param maxSize maximum size the formatted value of a variable will 1213 @param maxSize maximum size the formatted value of a variable will
1121 be shown. If it is bigger than that, a 'too big' indication will 1214 be shown. If it is bigger than that, a 'too big' indication will
1122 be given (@@TOO_BIG_TO_SHOW@@). 1215 be given (@@TOO_BIG_TO_SHOW@@).
1123 @type int 1216 @type int
1124 """ 1217 """
1125 self.__sendJsonCommand("RequestVariable", { 1218 self.__sendJsonCommand(
1126 "variable": var, 1219 "RequestVariable",
1127 "frameNumber": framenr, 1220 {
1128 "scope": scope, 1221 "variable": var,
1129 "filters": filterList, 1222 "frameNumber": framenr,
1130 "maxSize": maxSize, 1223 "scope": scope,
1131 }, debuggerId) 1224 "filters": filterList,
1132 1225 "maxSize": maxSize,
1226 },
1227 debuggerId,
1228 )
1229
1133 def remoteClientDisassembly(self, debuggerId): 1230 def remoteClientDisassembly(self, debuggerId):
1134 """ 1231 """
1135 Public method to ask the client for the latest traceback disassembly. 1232 Public method to ask the client for the latest traceback disassembly.
1136 1233
1137 @param debuggerId ID of the debugger backend 1234 @param debuggerId ID of the debugger backend
1138 @type str 1235 @type str
1139 """ 1236 """
1140 self.__sendJsonCommand("RequestDisassembly", {}, debuggerId) 1237 self.__sendJsonCommand("RequestDisassembly", {}, debuggerId)
1141 1238
1142 def remoteClientSetFilter(self, debuggerId, scope, filterStr): 1239 def remoteClientSetFilter(self, debuggerId, scope, filterStr):
1143 """ 1240 """
1144 Public method to set a variables filter list. 1241 Public method to set a variables filter list.
1145 1242
1146 @param debuggerId ID of the debugger backend 1243 @param debuggerId ID of the debugger backend
1147 @type str 1244 @type str
1148 @param scope the scope of the variables (0 = local, 1 = global) 1245 @param scope the scope of the variables (0 = local, 1 = global)
1149 @type int 1246 @type int
1150 @param filterStr regexp string for variable names to filter out 1247 @param filterStr regexp string for variable names to filter out
1151 @type str 1248 @type str
1152 """ 1249 """
1153 self.__sendJsonCommand("RequestSetFilter", { 1250 self.__sendJsonCommand(
1154 "scope": scope, 1251 "RequestSetFilter",
1155 "filter": filterStr, 1252 {
1156 }, debuggerId) 1253 "scope": scope,
1157 1254 "filter": filterStr,
1255 },
1256 debuggerId,
1257 )
1258
1158 def setCallTraceEnabled(self, debuggerId, on): 1259 def setCallTraceEnabled(self, debuggerId, on):
1159 """ 1260 """
1160 Public method to set the call trace state. 1261 Public method to set the call trace state.
1161 1262
1162 @param debuggerId ID of the debugger backend 1263 @param debuggerId ID of the debugger backend
1163 @type str 1264 @type str
1164 @param on flag indicating to enable the call trace function 1265 @param on flag indicating to enable the call trace function
1165 @type bool 1266 @type bool
1166 """ 1267 """
1167 self.__sendJsonCommand("RequestCallTrace", { 1268 self.__sendJsonCommand(
1168 "enable": on, 1269 "RequestCallTrace",
1169 }, debuggerId) 1270 {
1170 1271 "enable": on,
1272 },
1273 debuggerId,
1274 )
1275
1171 def remoteNoDebugList(self, debuggerId, noDebugList): 1276 def remoteNoDebugList(self, debuggerId, noDebugList):
1172 """ 1277 """
1173 Public method to set a list of programs not to be debugged. 1278 Public method to set a list of programs not to be debugged.
1174 1279
1175 The programs given in the list will not be run under the control 1280 The programs given in the list will not be run under the control
1176 of the multi process debugger. 1281 of the multi process debugger.
1177 1282
1178 @param debuggerId ID of the debugger backend 1283 @param debuggerId ID of the debugger backend
1179 @type str 1284 @type str
1180 @param noDebugList list of Python programs not to be debugged 1285 @param noDebugList list of Python programs not to be debugged
1181 @type list of str 1286 @type list of str
1182 """ 1287 """
1183 self.__sendJsonCommand("RequestSetNoDebugList", { 1288 self.__sendJsonCommand(
1184 "noDebug": noDebugList, 1289 "RequestSetNoDebugList",
1185 }, debuggerId) 1290 {
1186 1291 "noDebug": noDebugList,
1292 },
1293 debuggerId,
1294 )
1295
1187 def remoteBanner(self): 1296 def remoteBanner(self):
1188 """ 1297 """
1189 Public slot to get the banner info of the remote client. 1298 Public slot to get the banner info of the remote client.
1190 """ 1299 """
1191 self.__sendJsonCommand("RequestBanner", {}) 1300 self.__sendJsonCommand("RequestBanner", {})
1192 1301
1193 def remoteCapabilities(self, debuggerId): 1302 def remoteCapabilities(self, debuggerId):
1194 """ 1303 """
1195 Public slot to get the debug clients capabilities. 1304 Public slot to get the debug clients capabilities.
1196 1305
1197 @param debuggerId ID of the debugger backend 1306 @param debuggerId ID of the debugger backend
1198 @type str 1307 @type str
1199 """ 1308 """
1200 self.__sendJsonCommand("RequestCapabilities", {}, debuggerId) 1309 self.__sendJsonCommand("RequestCapabilities", {}, debuggerId)
1201 1310
1202 def remoteCompletion(self, debuggerId, text): 1311 def remoteCompletion(self, debuggerId, text):
1203 """ 1312 """
1204 Public slot to get the a list of possible commandline completions 1313 Public slot to get the a list of possible commandline completions
1205 from the remote client. 1314 from the remote client.
1206 1315
1207 @param debuggerId ID of the debugger backend 1316 @param debuggerId ID of the debugger backend
1208 @type str 1317 @type str
1209 @param text the text to be completed 1318 @param text the text to be completed
1210 @type str 1319 @type str
1211 """ 1320 """
1212 self.__sendJsonCommand("RequestCompletion", { 1321 self.__sendJsonCommand(
1213 "text": text, 1322 "RequestCompletion",
1214 }, debuggerId) 1323 {
1215 1324 "text": text,
1325 },
1326 debuggerId,
1327 )
1328
1216 def __parseClientLine(self, sock): 1329 def __parseClientLine(self, sock):
1217 """ 1330 """
1218 Private method to handle data from the client. 1331 Private method to handle data from the client.
1219 1332
1220 @param sock reference to the socket to read data from 1333 @param sock reference to the socket to read data from
1221 @type QTcpSocket 1334 @type QTcpSocket
1222 """ 1335 """
1223 while sock and sock.canReadLine(): 1336 while sock and sock.canReadLine():
1224 qs = sock.readLine() 1337 qs = sock.readLine()
1225 line = bytes(qs).decode( 1338 line = bytes(qs).decode(encoding=Preferences.getSystem("StringEncoding"))
1226 encoding=Preferences.getSystem("StringEncoding")) 1339
1227
1228 logging.debug("<Debug-Server> %s", line) 1340 logging.debug("<Debug-Server> %s", line)
1229 ## print("Server: ", line) ## debug # __IGNORE_WARNING_M891__ 1341 ##print("Server: ", line) ## debug # __IGNORE_WARNING_M891__
1230 1342
1231 self.__handleJsonCommand(line, sock) 1343 self.__handleJsonCommand(line, sock)
1232 1344
1233 def __handleJsonCommand(self, jsonStr, sock): 1345 def __handleJsonCommand(self, jsonStr, sock):
1234 """ 1346 """
1235 Private method to handle a command or response serialized as a 1347 Private method to handle a command or response serialized as a
1236 JSON string. 1348 JSON string.
1237 1349
1238 @param jsonStr string containing the command or response received 1350 @param jsonStr string containing the command or response received
1239 from the debug backend 1351 from the debug backend
1240 @type str 1352 @type str
1241 @param sock reference to the socket the data was received from 1353 @param sock reference to the socket the data was received from
1242 @type QTcpSocket 1354 @type QTcpSocket
1243 """ 1355 """
1244 import json 1356 import json
1245 1357
1246 try: 1358 try:
1247 commandDict = json.loads(jsonStr.strip()) 1359 commandDict = json.loads(jsonStr.strip())
1248 except (TypeError, ValueError) as err: 1360 except (TypeError, ValueError) as err:
1249 EricMessageBox.critical( 1361 EricMessageBox.critical(
1250 None, 1362 None,
1251 self.tr("Debug Protocol Error"), 1363 self.tr("Debug Protocol Error"),
1252 self.tr("""<p>The response received from the debugger""" 1364 self.tr(
1253 """ backend could not be decoded. Please report""" 1365 """<p>The response received from the debugger"""
1254 """ this issue with the received data to the""" 1366 """ backend could not be decoded. Please report"""
1255 """ eric bugs email address.</p>""" 1367 """ this issue with the received data to the"""
1256 """<p>Error: {0}</p>""" 1368 """ eric bugs email address.</p>"""
1257 """<p>Data:<br/>{1}</p>""").format( 1369 """<p>Error: {0}</p>"""
1258 str(err), Utilities.html_encode(jsonStr.strip())), 1370 """<p>Data:<br/>{1}</p>"""
1259 EricMessageBox.Ok) 1371 ).format(str(err), Utilities.html_encode(jsonStr.strip())),
1372 EricMessageBox.Ok,
1373 )
1260 return 1374 return
1261 1375
1262 method = commandDict["method"] 1376 method = commandDict["method"]
1263 params = commandDict["params"] 1377 params = commandDict["params"]
1264 1378
1265 if method == "DebuggerId": 1379 if method == "DebuggerId":
1266 self.__assignDebuggerId(sock, params["debuggerId"]) 1380 self.__assignDebuggerId(sock, params["debuggerId"])
1267 1381
1268 elif method == "ClientOutput": 1382 elif method == "ClientOutput":
1269 self.debugServer.signalClientOutput( 1383 self.debugServer.signalClientOutput(params["text"], params["debuggerId"])
1270 params["text"], params["debuggerId"]) 1384
1271
1272 elif method in ["ResponseLine", "ResponseStack"]: 1385 elif method in ["ResponseLine", "ResponseStack"]:
1273 # Check if obsolete thread was clicked 1386 # Check if obsolete thread was clicked
1274 if params["stack"] == []: 1387 if params["stack"] == []:
1275 # Request updated list 1388 # Request updated list
1276 self.remoteThreadList(params["debuggerId"]) 1389 self.remoteThreadList(params["debuggerId"])
1277 return 1390 return
1278 for s in params["stack"]: 1391 for s in params["stack"]:
1279 s[0] = self.translate(s[0], True) 1392 s[0] = self.translate(s[0], True)
1280 cf = params["stack"][0] 1393 cf = params["stack"][0]
1281 if ( 1394 if self.__autoContinue and params["debuggerId"] not in self.__autoContinued:
1282 self.__autoContinue and
1283 params["debuggerId"] not in self.__autoContinued
1284 ):
1285 self.__autoContinued.append(params["debuggerId"]) 1395 self.__autoContinued.append(params["debuggerId"])
1286 QTimer.singleShot( 1396 QTimer.singleShot(0, lambda: self.remoteContinue(params["debuggerId"]))
1287 0, lambda: self.remoteContinue(params["debuggerId"]))
1288 else: 1397 else:
1289 self.debugServer.signalClientLine( 1398 self.debugServer.signalClientLine(
1290 cf[0], int(cf[1]), params["debuggerId"], 1399 cf[0],
1291 method == "ResponseStack", threadName=params["threadName"]) 1400 int(cf[1]),
1401 params["debuggerId"],
1402 method == "ResponseStack",
1403 threadName=params["threadName"],
1404 )
1292 self.debugServer.signalClientStack( 1405 self.debugServer.signalClientStack(
1293 params["stack"], params["debuggerId"], 1406 params["stack"],
1294 threadName=params["threadName"]) 1407 params["debuggerId"],
1295 1408 threadName=params["threadName"],
1409 )
1410
1296 elif method == "CallTrace": 1411 elif method == "CallTrace":
1297 isCall = params["event"].lower() == "c" 1412 isCall = params["event"].lower() == "c"
1298 fromInfo = params["from"] 1413 fromInfo = params["from"]
1299 toInfo = params["to"] 1414 toInfo = params["to"]
1300 self.debugServer.signalClientCallTrace( 1415 self.debugServer.signalClientCallTrace(
1301 isCall, 1416 isCall,
1302 fromInfo["filename"], str(fromInfo["linenumber"]), 1417 fromInfo["filename"],
1418 str(fromInfo["linenumber"]),
1303 fromInfo["codename"], 1419 fromInfo["codename"],
1304 toInfo["filename"], str(toInfo["linenumber"]), 1420 toInfo["filename"],
1421 str(toInfo["linenumber"]),
1305 toInfo["codename"], 1422 toInfo["codename"],
1306 params["debuggerId"]) 1423 params["debuggerId"],
1307 1424 )
1425
1308 elif method == "ResponseVariables": 1426 elif method == "ResponseVariables":
1309 self.debugServer.signalClientVariables( 1427 self.debugServer.signalClientVariables(
1310 params["scope"], params["variables"], params["debuggerId"]) 1428 params["scope"], params["variables"], params["debuggerId"]
1311 1429 )
1430
1312 elif method == "ResponseVariable": 1431 elif method == "ResponseVariable":
1313 self.debugServer.signalClientVariable( 1432 self.debugServer.signalClientVariable(
1314 params["scope"], [params["variable"]] + params["variables"], 1433 params["scope"],
1315 params["debuggerId"]) 1434 [params["variable"]] + params["variables"],
1316 1435 params["debuggerId"],
1436 )
1437
1317 elif method == "ResponseThreadList": 1438 elif method == "ResponseThreadList":
1318 self.debugServer.signalClientThreadList( 1439 self.debugServer.signalClientThreadList(
1319 params["currentID"], params["threadList"], 1440 params["currentID"], params["threadList"], params["debuggerId"]
1320 params["debuggerId"]) 1441 )
1321 1442
1322 elif method == "ResponseThreadSet": 1443 elif method == "ResponseThreadSet":
1323 self.debugServer.signalClientThreadSet(params["debuggerId"]) 1444 self.debugServer.signalClientThreadSet(params["debuggerId"])
1324 1445
1325 elif method == "ResponseCapabilities": 1446 elif method == "ResponseCapabilities":
1326 self.clientCapabilities = params["capabilities"] 1447 self.clientCapabilities = params["capabilities"]
1327 if params["debuggerId"] == self.__master: 1448 if params["debuggerId"] == self.__master:
1328 # signal only for the master connection 1449 # signal only for the master connection
1329 self.debugServer.signalClientCapabilities( 1450 self.debugServer.signalClientCapabilities(
1330 params["capabilities"], 1451 params["capabilities"],
1331 params["clientType"], 1452 params["clientType"],
1332 self.__startedVenv, 1453 self.__startedVenv,
1333 ) 1454 )
1334 1455
1335 elif method == "ResponseBanner": 1456 elif method == "ResponseBanner":
1336 if params["debuggerId"] == self.__master: 1457 if params["debuggerId"] == self.__master:
1337 # signal only for the master connection 1458 # signal only for the master connection
1338 self.debugServer.signalClientBanner( 1459 self.debugServer.signalClientBanner(
1339 params["version"], 1460 params["version"],
1340 params["platform"], 1461 params["platform"],
1341 self.__startedVenv, 1462 self.__startedVenv,
1342 ) 1463 )
1343 1464
1344 elif method == "ResponseOK": 1465 elif method == "ResponseOK":
1345 self.debugServer.signalClientStatement(False, params["debuggerId"]) 1466 self.debugServer.signalClientStatement(False, params["debuggerId"])
1346 1467
1347 elif method == "ResponseContinue": 1468 elif method == "ResponseContinue":
1348 self.debugServer.signalClientStatement(True, params["debuggerId"]) 1469 self.debugServer.signalClientStatement(True, params["debuggerId"])
1349 1470
1350 elif method == "RequestRaw": 1471 elif method == "RequestRaw":
1351 self.debugServer.signalClientRawInput( 1472 self.debugServer.signalClientRawInput(
1352 params["prompt"], params["echo"], params["debuggerId"]) 1473 params["prompt"], params["echo"], params["debuggerId"]
1353 1474 )
1475
1354 elif method == "ResponseBPConditionError": 1476 elif method == "ResponseBPConditionError":
1355 fn = self.translate(params["filename"], True) 1477 fn = self.translate(params["filename"], True)
1356 self.debugServer.signalClientBreakConditionError( 1478 self.debugServer.signalClientBreakConditionError(
1357 fn, params["line"], params["debuggerId"]) 1479 fn, params["line"], params["debuggerId"]
1358 1480 )
1481
1359 elif method == "ResponseClearBreakpoint": 1482 elif method == "ResponseClearBreakpoint":
1360 fn = self.translate(params["filename"], True) 1483 fn = self.translate(params["filename"], True)
1361 self.debugServer.signalClientClearBreak( 1484 self.debugServer.signalClientClearBreak(
1362 fn, params["line"], params["debuggerId"]) 1485 fn, params["line"], params["debuggerId"]
1363 1486 )
1487
1364 elif method == "ResponseWatchConditionError": 1488 elif method == "ResponseWatchConditionError":
1365 self.debugServer.signalClientWatchConditionError( 1489 self.debugServer.signalClientWatchConditionError(
1366 params["condition"], params["debuggerId"]) 1490 params["condition"], params["debuggerId"]
1367 1491 )
1492
1368 elif method == "ResponseClearWatch": 1493 elif method == "ResponseClearWatch":
1369 self.debugServer.signalClientClearWatch( 1494 self.debugServer.signalClientClearWatch(
1370 params["condition"], params["debuggerId"]) 1495 params["condition"], params["debuggerId"]
1371 1496 )
1497
1372 elif method == "ResponseDisassembly": 1498 elif method == "ResponseDisassembly":
1373 self.debugServer.signalClientDisassembly( 1499 self.debugServer.signalClientDisassembly(
1374 params["disassembly"], params["debuggerId"]) 1500 params["disassembly"], params["debuggerId"]
1375 1501 )
1502
1376 elif method == "ResponseException": 1503 elif method == "ResponseException":
1377 exctype = params["type"] 1504 exctype = params["type"]
1378 excmessage = params["message"] 1505 excmessage = params["message"]
1379 stack = params["stack"] 1506 stack = params["stack"]
1380 if stack: 1507 if stack:
1384 for stackEntry in stack: 1511 for stackEntry in stack:
1385 if stackEntry[0] == "<string>": 1512 if stackEntry[0] == "<string>":
1386 stackEntry[0] = self.__scriptName 1513 stackEntry[0] = self.__scriptName
1387 else: 1514 else:
1388 break 1515 break
1389 1516
1390 self.debugServer.signalClientException( 1517 self.debugServer.signalClientException(
1391 exctype, excmessage, stack, params["debuggerId"], 1518 exctype, excmessage, stack, params["debuggerId"], params["threadName"]
1392 params["threadName"]) 1519 )
1393 1520
1394 elif method == "ResponseSyntax": 1521 elif method == "ResponseSyntax":
1395 self.debugServer.signalClientSyntaxError( 1522 self.debugServer.signalClientSyntaxError(
1396 params["message"], self.translate(params["filename"], True), 1523 params["message"],
1397 params["linenumber"], params["characternumber"], 1524 self.translate(params["filename"], True),
1398 params["debuggerId"], params["threadName"]) 1525 params["linenumber"],
1399 1526 params["characternumber"],
1527 params["debuggerId"],
1528 params["threadName"],
1529 )
1530
1400 elif method == "ResponseSignal": 1531 elif method == "ResponseSignal":
1401 self.debugServer.signalClientSignal( 1532 self.debugServer.signalClientSignal(
1402 params["message"], self.translate(params["filename"], True), 1533 params["message"],
1403 params["linenumber"], params["function"], params["arguments"], 1534 self.translate(params["filename"], True),
1404 params["debuggerId"]) 1535 params["linenumber"],
1405 1536 params["function"],
1537 params["arguments"],
1538 params["debuggerId"],
1539 )
1540
1406 elif method == "ResponseExit": 1541 elif method == "ResponseExit":
1407 self.__scriptName = "" 1542 self.__scriptName = ""
1408 self.debugServer.signalClientExit( 1543 self.debugServer.signalClientExit(
1409 params["program"], params["status"], params["message"], 1544 params["program"],
1410 params["debuggerId"]) 1545 params["status"],
1546 params["message"],
1547 params["debuggerId"],
1548 )
1411 if params["debuggerId"] == self.__master: 1549 if params["debuggerId"] == self.__master:
1412 self.debugServer.signalMainClientExit() 1550 self.debugServer.signalMainClientExit()
1413 1551
1414 elif method == "PassiveStartup": 1552 elif method == "PassiveStartup":
1415 self.debugServer.passiveStartUp( 1553 self.debugServer.passiveStartUp(
1416 self.translate(params["filename"], True), params["exceptions"], 1554 self.translate(params["filename"], True),
1417 params["debuggerId"]) 1555 params["exceptions"],
1418 1556 params["debuggerId"],
1557 )
1558
1419 elif method == "ResponseCompletion": 1559 elif method == "ResponseCompletion":
1420 self.debugServer.signalClientCompletionList( 1560 self.debugServer.signalClientCompletionList(
1421 params["completions"], params["text"], params["debuggerId"]) 1561 params["completions"], params["text"], params["debuggerId"]
1422 1562 )
1563
1423 def __sendJsonCommand(self, command, params, debuggerId="", sock=None): 1564 def __sendJsonCommand(self, command, params, debuggerId="", sock=None):
1424 """ 1565 """
1425 Private method to send a single command to the client. 1566 Private method to send a single command to the client.
1426 1567
1427 @param command command name to be sent 1568 @param command command name to be sent
1428 @type str 1569 @type str
1429 @param params dictionary of named parameters for the command 1570 @param params dictionary of named parameters for the command
1430 @type dict 1571 @type dict
1431 @param debuggerId id of the debug client to send the command to 1572 @param debuggerId id of the debug client to send the command to
1433 @param sock reference to the socket object to be used (only used if 1574 @param sock reference to the socket object to be used (only used if
1434 debuggerId is not given) 1575 debuggerId is not given)
1435 @type QTcpSocket 1576 @type QTcpSocket
1436 """ 1577 """
1437 import json 1578 import json
1438 1579
1439 commandDict = { 1580 commandDict = {
1440 "jsonrpc": "2.0", 1581 "jsonrpc": "2.0",
1441 "method": command, 1582 "method": command,
1442 "params": params, 1583 "params": params,
1443 } 1584 }
1444 cmd = json.dumps(commandDict) + '\n' 1585 cmd = json.dumps(commandDict) + "\n"
1445 1586
1446 if debuggerId and debuggerId in self.__connections: 1587 if debuggerId and debuggerId in self.__connections:
1447 sock = self.__connections[debuggerId] 1588 sock = self.__connections[debuggerId]
1448 elif sock is None and self.__master is not None: 1589 elif sock is None and self.__master is not None:
1449 sock = self.__connections[self.__master] 1590 sock = self.__connections[self.__master]
1450 if sock is not None: 1591 if sock is not None:
1451 self.__writeJsonCommandToSocket(cmd, sock) 1592 self.__writeJsonCommandToSocket(cmd, sock)
1452 else: 1593 else:
1453 self.queue.append(cmd) 1594 self.queue.append(cmd)
1454 1595
1455 def __writeJsonCommandToSocket(self, cmd, sock): 1596 def __writeJsonCommandToSocket(self, cmd, sock):
1456 """ 1597 """
1457 Private method to write a JSON command to the socket. 1598 Private method to write a JSON command to the socket.
1458 1599
1459 @param cmd JSON command to be sent 1600 @param cmd JSON command to be sent
1460 @type str 1601 @type str
1461 @param sock reference to the socket to write to 1602 @param sock reference to the socket to write to
1462 @type QTcpSocket 1603 @type QTcpSocket
1463 """ 1604 """
1464 data = cmd.encode('utf8', 'backslashreplace') 1605 data = cmd.encode("utf8", "backslashreplace")
1465 length = "{0:09d}".format(len(data)) 1606 length = "{0:09d}".format(len(data))
1466 sock.write(length.encode() + data) 1607 sock.write(length.encode() + data)
1467 sock.flush() 1608 sock.flush()
1468 1609
1469 1610
1470 def createDebuggerInterfacePython3(debugServer, passive): 1611 def createDebuggerInterfacePython3(debugServer, passive):
1471 """ 1612 """
1472 Module function to create a debugger interface instance. 1613 Module function to create a debugger interface instance.
1473 1614
1474 1615
1475 @param debugServer reference to the debug server 1616 @param debugServer reference to the debug server
1476 @type DebugServer 1617 @type DebugServer
1477 @param passive flag indicating passive connection mode 1618 @param passive flag indicating passive connection mode
1478 @type bool 1619 @type bool
1479 @return instantiated debugger interface 1620 @return instantiated debugger interface
1484 1625
1485 def getRegistryData(): 1626 def getRegistryData():
1486 """ 1627 """
1487 Module function to get characterizing data for the supported debugger 1628 Module function to get characterizing data for the supported debugger
1488 interfaces. 1629 interfaces.
1489 1630
1490 @return list of tuples containing the client type, the client capabilities, 1631 @return list of tuples containing the client type, the client capabilities,
1491 the client file type associations and a reference to the creation 1632 the client file type associations and a reference to the creation
1492 function 1633 function
1493 @rtype list of tuple of (str, int, list of str, function) 1634 @rtype list of tuple of (str, int, list of str, function)
1494 """ 1635 """
1496 for ext in Preferences.getDebugger("Python3Extensions").split(): 1637 for ext in Preferences.getDebugger("Python3Extensions").split():
1497 if ext.startswith("."): 1638 if ext.startswith("."):
1498 py3Exts.append(ext) 1639 py3Exts.append(ext)
1499 else: 1640 else:
1500 py3Exts.append(".{0}".format(ext)) 1641 py3Exts.append(".{0}".format(ext))
1501 1642
1502 registryData = [] 1643 registryData = []
1503 if py3Exts: 1644 if py3Exts:
1504 registryData.append( 1645 registryData.append(
1505 ("Python3", ClientDefaultCapabilities, py3Exts, 1646 (
1506 createDebuggerInterfacePython3) 1647 "Python3",
1507 ) 1648 ClientDefaultCapabilities,
1508 1649 py3Exts,
1650 createDebuggerInterfacePython3,
1651 )
1652 )
1653
1509 return registryData 1654 return registryData

eric ide

mercurial