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 |
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 |
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: |
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 |
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 |