1# -*- coding: utf-8 -*- 2 3# Copyright (c) 2007 - 2021 Detlev Offenbach <detlev@die-offenbachs.de> 4# 5 6""" 7Module implementing the debug server. 8""" 9 10import os 11import shlex 12import contextlib 13 14from PyQt5.QtCore import pyqtSignal, pyqtSlot, QModelIndex 15from PyQt5.QtNetwork import ( 16 QTcpServer, QHostAddress, QHostInfo, QNetworkInterface 17) 18 19from E5Gui.E5Application import e5App 20from E5Gui import E5MessageBox 21 22from .BreakPointModel import BreakPointModel 23from .WatchPointModel import WatchPointModel 24from . import DebugClientCapabilities 25 26import Preferences 27 28 29DebuggerInterfaces = { 30 "Python": "DebuggerInterfacePython", 31 "None": "DebuggerInterfaceNone", 32} 33 34 35class DebugServer(QTcpServer): 36 """ 37 Class implementing the debug server embedded within the IDE. 38 39 @signal clientProcessStdout(str) emitted after the client has sent some 40 output via stdout 41 @signal clientProcessStderr(str) emitted after the client has sent some 42 output via stderr 43 @signal clientOutput(str) emitted after the client has sent some output 44 @signal clientRawInputSent(debuggerId) emitted after the data was sent 45 to the indicated debug client 46 @signal clientLine(filename, lineno, debuggerId, threadName, forStack) 47 emitted after the debug client has executed a line of code 48 @signal clientStack(stack, debuggerId, threadName) emitted after the 49 debug client has executed a line of code 50 @signal clientThreadList(currentId, threadList, debuggerId) emitted after 51 a thread list has been received 52 @signal clientThreadSet(debuggerId) emitted after the client has 53 acknowledged the change of the current thread 54 @signal clientVariables(scope, variables, debuggerId) emitted after a 55 variables dump has been received 56 @signal clientVariable(scope, variables, debuggerId) emitted after a dump 57 for one class variable has been received 58 @signal clientStatement(continue, debuggerId) emitted after an interactive 59 command has been executed. The parameter is False to indicate that the 60 command is complete and True if it needs more input. 61 @signal clientDisassembly(disassembly, debuggerId) emitted after the client 62 has sent a disassembly of the code raising an exception 63 @signal clientException(exceptionType, exceptionMessage, stackTrace, 64 debuggerId, threadName) emitted after an exception occured on the 65 client side 66 @signal clientSyntaxError(message, filename, linenumber, characternumber, 67 debuggerId, threadName) emitted after a syntax error has been detected 68 on the client side 69 @signal clientSignal(message, filename, linenumber, function name, 70 function arguments, debuggerId) emitted after a signal has been 71 generated on the client side 72 @signal clientDisconnected(str) emitted after a debug client has 73 disconnected (i.e. closed the network socket) 74 @signal clientExit(str, int, str, bool, str) emitted after the client has 75 exited giving the program name, the exit status, an exit message, an 76 indication to be quiet and the ID of the exited client 77 @signal mainClientExit() emitted to indicate that the main client process 78 has exited 79 @signal lastClientExited() emitted to indicate that the last connected 80 debug client has terminated 81 @signal clientClearBreak(filename, lineno, debuggerId) emitted after the 82 debug client has decided to clear a temporary breakpoint 83 @signal clientBreakConditionError(fn, lineno, debuggerId) emitted after the 84 client has signaled a syntax error in a breakpoint condition 85 @signal clientClearWatch(condition, debuggerId) emitted after the debug 86 client has decided to clear a temporary watch expression 87 @signal clientWatchConditionError(condition, debuggerId) emitted after the 88 client has signaled a syntax error in a watch expression 89 @signal clientRawInput(prompt, echo, debuggerId) emitted after a raw input 90 request was received 91 @signal clientBanner(version, platform, venvname) emitted after 92 the client banner data was received 93 @signal clientCapabilities(capabilities, cltype, venvname) emitted after 94 the clients capabilities were received 95 @signal clientCompletionList(completionList, text) emitted after the 96 commandline completion list and the reworked search string was 97 received from the client 98 @signal passiveDebugStarted(str, bool) emitted after the debug client has 99 connected in passive debug mode 100 @signal clientGone(bool) emitted if the client went away (planned or 101 unplanned) 102 @signal clientInterpreterChanged(str) emitted to signal a change of the 103 client interpreter 104 @signal utDiscovered(testCases, exc_type, exc_value) emitted after the 105 client has performed a test case discovery action 106 @signal utPrepared(nrTests, exc_type, exc_value) emitted after the client 107 has loaded a unittest suite 108 @signal utFinished() emitted after the client signalled the end of the 109 unittest 110 @signal utStartTest(testname, testdocu) emitted after the client has 111 started a test 112 @signal utStopTest() emitted after the client has finished a test 113 @signal utTestFailed(testname, exc_info, id) emitted after the client 114 reported a failed test 115 @signal utTestErrored(testname, exc_info, id) emitted after the client 116 reported an errored test 117 @signal utTestSkipped(testname, reason, id) emitted after the client 118 reported a skipped test 119 @signal utTestFailedExpected(testname, exc_info, id) emitted after the 120 client reported an expected test failure 121 @signal utTestSucceededUnexpected(testname, id) emitted after the client 122 reported an unexpected test success 123 @signal callTraceInfo emitted after the client reported the call trace 124 data (isCall, fromFile, fromLine, fromFunction, toFile, toLine, 125 toFunction, debuggerId) 126 @signal appendStdout(msg) emitted when a passive debug connection is 127 established or lost 128 @signal clientDebuggerId(debuggerId) emitted to indicate a newly connected 129 debugger backend 130 """ 131 clientClearBreak = pyqtSignal(str, int, str) 132 clientClearWatch = pyqtSignal(str, str) 133 clientGone = pyqtSignal(bool) 134 clientProcessStdout = pyqtSignal(str) 135 clientProcessStderr = pyqtSignal(str) 136 clientRawInputSent = pyqtSignal(str) 137 clientOutput = pyqtSignal(str) 138 clientLine = pyqtSignal(str, int, str, str, bool) 139 clientStack = pyqtSignal(list, str, str) 140 clientThreadList = pyqtSignal('PyQt_PyObject', list, str) 141 clientThreadSet = pyqtSignal(str) 142 clientVariables = pyqtSignal(int, list, str) 143 clientVariable = pyqtSignal(int, list, str) 144 clientStatement = pyqtSignal(bool, str) 145 clientDisassembly = pyqtSignal(dict, str) 146 clientException = pyqtSignal(str, str, list, str, str) 147 clientSyntaxError = pyqtSignal(str, str, int, int, str, str) 148 clientSignal = pyqtSignal(str, str, int, str, str, str) 149 clientDisconnected = pyqtSignal(str) 150 clientExit = pyqtSignal(str, int, str, bool, str) 151 mainClientExit = pyqtSignal() 152 lastClientExited = pyqtSignal() 153 clientBreakConditionError = pyqtSignal(str, int, str) 154 clientWatchConditionError = pyqtSignal(str, str) 155 clientRawInput = pyqtSignal(str, bool, str) 156 clientBanner = pyqtSignal(str, str, str) 157 clientCapabilities = pyqtSignal(int, str, str) 158 clientCompletionList = pyqtSignal(list, str) 159 clientInterpreterChanged = pyqtSignal(str) 160 clientDebuggerId = pyqtSignal(str) 161 utDiscovered = pyqtSignal(list, str, str) 162 utPrepared = pyqtSignal(int, str, str) 163 utStartTest = pyqtSignal(str, str) 164 utStopTest = pyqtSignal() 165 utTestFailed = pyqtSignal(str, str, str) 166 utTestErrored = pyqtSignal(str, str, str) 167 utTestSkipped = pyqtSignal(str, str, str) 168 utTestFailedExpected = pyqtSignal(str, str, str) 169 utTestSucceededUnexpected = pyqtSignal(str, str) 170 utFinished = pyqtSignal() 171 passiveDebugStarted = pyqtSignal(str, bool) 172 callTraceInfo = pyqtSignal(bool, str, str, str, str, str, str, str) 173 appendStdout = pyqtSignal(str) 174 175 def __init__(self, originalPathString, preventPassiveDebugging=False, 176 project=None, parent=None): 177 """ 178 Constructor 179 180 @param originalPathString original PATH environment variable 181 @type str 182 @param preventPassiveDebugging flag overriding the PassiveDbgEnabled 183 setting (defaults to False) 184 @type bool (optional) 185 @param project reference to the project object (defaults to None) 186 @type Project (optional) 187 @param parent reference to the parent object 188 @type QObject 189 """ 190 super().__init__(parent) 191 192 self.__originalPathString = originalPathString 193 194 self.__debuggerInterfaces = {} 195 # the interface name is the key, a function to get the 196 # registration data is the value 197 self.__debuggerInterfaceRegistry = {} 198 # the client language is the key, a list containing the client 199 # capabilities, a list of associated file extensions, a 200 # function reference to create the debugger interface (see 201 # __createDebuggerInterface() below) and the interface name is 202 # the value 203 204 # create our models 205 self.breakpointModel = BreakPointModel(project, self) 206 self.watchpointModel = WatchPointModel(self) 207 self.watchSpecialCreated = self.tr( 208 "created", "must be same as in EditWatchpointDialog") 209 self.watchSpecialChanged = self.tr( 210 "changed", "must be same as in EditWatchpointDialog") 211 212 # arrays to track already reported issues 213 self.__reportedBreakpointIssues = [] 214 self.__reportedWatchpointIssues = [] 215 216 self.networkInterface = Preferences.getDebugger("NetworkInterface") 217 if self.networkInterface == "all": 218 hostAddress = QHostAddress("0.0.0.0") 219 # QHostAddress.SpecialAddress.Any) # secok 220 elif self.networkInterface == "allv6": 221 hostAddress = QHostAddress("::") 222 # QHostAddress.SpecialAddress.AnyIPv6) 223 else: 224 hostAddress = QHostAddress(self.networkInterface) 225 self.networkInterfaceName, self.networkInterfaceIndex = ( 226 self.__getNetworkInterfaceAndIndex(self.networkInterface)) 227 228 if (not preventPassiveDebugging and 229 Preferences.getDebugger("PassiveDbgEnabled")): 230 sock = Preferences.getDebugger("PassiveDbgPort") # default: 42424 231 self.listen(hostAddress, sock) 232 self.passive = True 233 self.passiveClientExited = False 234 else: 235 if hostAddress.toString().lower().startswith("fe80"): 236 hostAddress.setScopeId(self.networkInterfaceName) 237 self.listen(hostAddress) 238 self.passive = False 239 240 self.debuggerInterface = None 241 self.debugging = False 242 self.running = False 243 self.clientProcess = None 244 self.clientInterpreter = "" 245 self.clientType = Preferences.Prefs.settings.value('DebugClient/Type') 246 if self.clientType is None: 247 self.clientType = 'Python3' 248 249 self.lastClientType = '' 250 self.__autoClearShell = False 251 self.__forProject = False 252 253 self.clientClearBreak.connect(self.__clientClearBreakPoint) 254 self.clientClearWatch.connect(self.__clientClearWatchPoint) 255 self.newConnection.connect(self.__newConnection) 256 257 self.breakpointModel.rowsAboutToBeRemoved.connect( 258 self.__deleteBreakPoints) 259 self.breakpointModel.dataAboutToBeChanged.connect( 260 self.__breakPointDataAboutToBeChanged) 261 self.breakpointModel.dataChanged.connect(self.__changeBreakPoints) 262 self.breakpointModel.rowsInserted.connect(self.__addBreakPoints) 263 264 self.watchpointModel.rowsAboutToBeRemoved.connect( 265 self.__deleteWatchPoints) 266 self.watchpointModel.dataAboutToBeChanged.connect( 267 self.__watchPointDataAboutToBeChanged) 268 self.watchpointModel.dataChanged.connect(self.__changeWatchPoints) 269 self.watchpointModel.rowsInserted.connect(self.__addWatchPoints) 270 271 self.__maxVariableSize = Preferences.getDebugger("MaxVariableSize") 272 273 self.__multiprocessNoDebugList = [] 274 275 self.__registerDebuggerInterfaces() 276 277 def getHostAddress(self, localhost): 278 """ 279 Public method to get the IP address or hostname the debug server is 280 listening. 281 282 @param localhost flag indicating to return the address for localhost 283 @type bool 284 @return IP address or hostname 285 @rtype str 286 """ 287 if self.networkInterface == "all": 288 if localhost: 289 return "127.0.0.1" 290 else: 291 return "{0}@@v4".format(QHostInfo.localHostName()) 292 elif self.networkInterface == "allv6": 293 if localhost: 294 return "::1" 295 else: 296 return "{0}@@v6".format(QHostInfo.localHostName()) 297 else: 298 return "{0}@@i{1}".format(self.networkInterface, 299 self.networkInterfaceIndex) 300 301 def __getNetworkInterfaceAndIndex(self, address): 302 """ 303 Private method to determine the network interface and the interface 304 index. 305 306 @param address address to determine the info for 307 @type str 308 @return tuple of network interface name and index 309 @rtype tuple of (str, int) 310 """ 311 if address not in ["all", "allv6"]: 312 for networkInterface in QNetworkInterface.allInterfaces(): 313 addressEntries = networkInterface.addressEntries() 314 if len(addressEntries) > 0: 315 for addressEntry in addressEntries: 316 if (addressEntry.ip().toString().lower() == 317 address.lower()): 318 return (networkInterface.humanReadableName(), 319 networkInterface.index()) 320 321 return "", 0 322 323 def preferencesChanged(self): 324 """ 325 Public slot to handle the preferencesChanged signal. 326 """ 327 registeredInterfaces = {} 328 for interfaceName in self.__debuggerInterfaces: 329 registeredInterfaces[interfaceName] = ( 330 self.__debuggerInterfaces[interfaceName]) 331 332 self.__debuggerInterfaceRegistry = {} 333 for interfaceName, getRegistryData in registeredInterfaces.items(): 334 self.registerDebuggerInterface(interfaceName, getRegistryData, 335 reregister=True) 336 337 self.__maxVariableSize = Preferences.getDebugger("MaxVariableSize") 338 339 def registerDebuggerInterface(self, interfaceName, getRegistryData, 340 reregister=False): 341 """ 342 Public method to register a debugger interface. 343 344 @param interfaceName name of the debugger interface 345 @type str 346 @param getRegistryData reference to a function to be called 347 to get the debugger interface details. This method shall 348 return the client language, the client capabilities, the 349 list of associated file extensions and a function reference 350 to create the debugger interface (see __createDebuggerInterface()) 351 @type function 352 @param reregister flag indicating to re-register the interface 353 @type bool 354 """ 355 if interfaceName in self.__debuggerInterfaces and not reregister: 356 E5MessageBox.warning( 357 None, 358 self.tr("Register Debugger Interface"), 359 self.tr("""<p>The debugger interface <b>{0}</b> has already""" 360 """ been registered. Ignoring this request.</p>""")) 361 return 362 363 if not reregister: 364 self.__debuggerInterfaces[interfaceName] = getRegistryData 365 registryDataList = getRegistryData() 366 if registryDataList: 367 for (clientLanguage, clientCapabilities, clientExtensions, 368 interfaceCreator) in registryDataList: 369 self.__debuggerInterfaceRegistry[clientLanguage] = [ 370 clientCapabilities, clientExtensions, interfaceCreator, 371 interfaceName] 372 373 def unregisterDebuggerInterface(self, interfaceName): 374 """ 375 Public method to unregister a debugger interface. 376 377 @param interfaceName interfaceName of the debugger interface 378 @type str 379 """ 380 if interfaceName in self.__debuggerInterfaces: 381 clientLanguages = [] 382 for clientLanguage, registryData in ( 383 self.__debuggerInterfaceRegistry.items()): 384 if interfaceName == registryData[-1]: 385 clientLanguages.append(clientLanguage) 386 for clientLanguage in clientLanguages: 387 del self.__debuggerInterfaceRegistry[clientLanguage] 388 del self.__debuggerInterfaces[interfaceName] 389 390 def __findLanguageForExtension(self, ext): 391 """ 392 Private method to get the language associated with a file extension. 393 394 @param ext file extension 395 @type str 396 @return associated language 397 @rtype str 398 """ 399 for language in self.__debuggerInterfaceRegistry: 400 if ext in self.__debuggerInterfaceRegistry[language][1]: 401 return language 402 403 return "" 404 405 def __registerDebuggerInterfaces(self): 406 """ 407 Private method to register the available internal debugger interfaces. 408 """ 409 for name, interface in DebuggerInterfaces.items(): 410 modName = "Debugger.{0}".format(interface) 411 mod = __import__(modName) 412 components = modName.split('.') 413 for comp in components[1:]: 414 mod = getattr(mod, comp) 415 416 self.registerDebuggerInterface(name, mod.getRegistryData) 417 418 def getSupportedLanguages(self, shellOnly=False): 419 """ 420 Public slot to return the supported programming languages. 421 422 @param shellOnly flag indicating only languages supporting an 423 interactive shell should be returned 424 @type bool 425 @return list of supported languages 426 @rtype list of str 427 """ 428 languages = list(self.__debuggerInterfaceRegistry.keys()) 429 with contextlib.suppress(ValueError): 430 languages.remove("None") 431 432 if shellOnly: 433 languages = [lang for lang in languages 434 if self.__debuggerInterfaceRegistry[lang][0] & 435 DebugClientCapabilities.HasShell] 436 437 return languages[:] 438 439 def getExtensions(self, language): 440 """ 441 Public slot to get the extensions associated with the given language. 442 443 @param language language to get extensions for 444 @type str 445 @return tuple of extensions associated with the language 446 @rtype tuple of str 447 """ 448 if language in self.__debuggerInterfaceRegistry: 449 return tuple(self.__debuggerInterfaceRegistry[language][1]) 450 else: 451 return () 452 453 def __createDebuggerInterface(self, clientType=None): 454 """ 455 Private slot to create the debugger interface object. 456 457 @param clientType type of the client interface to be created 458 @type str 459 """ 460 if self.lastClientType != self.clientType or clientType is not None: 461 if clientType is None: 462 clientType = self.clientType 463 if clientType in self.__debuggerInterfaceRegistry: 464 self.debuggerInterface = ( 465 self.__debuggerInterfaceRegistry[clientType][2]( 466 self, self.passive)) 467 else: 468 self.debuggerInterface = ( 469 self.__debuggerInterfaceRegistry["None"][2]( 470 self, self.passive)) 471 self.clientType = "None" 472 473 def __setClientType(self, clType): 474 """ 475 Private method to set the client type. 476 477 @param clType type of client to be started 478 @type str 479 """ 480 if clType is not None and clType in self.getSupportedLanguages(): 481 self.clientType = clType 482 Preferences.Prefs.settings.setValue( 483 'DebugClient/Type', self.clientType) 484 485 def startClient(self, unplanned=True, clType=None, forProject=False, 486 runInConsole=False, venvName="", workingDir=None, 487 configOverride=None): 488 """ 489 Public method to start a debug client. 490 491 @param unplanned flag indicating that the client has died 492 @type bool 493 @param clType type of client to be started 494 @type str 495 @param forProject flag indicating a project related action 496 @type bool 497 @param runInConsole flag indicating to start the debugger in a 498 console window 499 @type bool 500 @param venvName name of the virtual environment to be used 501 @type str 502 @param workingDir directory to start the debugger client in 503 @type str 504 @param configOverride dictionary containing the global config override 505 data 506 @type dict 507 """ 508 self.running = False 509 510 if ( 511 (not self.passive or not self.passiveClientExited) and 512 self.debuggerInterface and 513 self.debuggerInterface.isConnected() 514 ): 515 self.shutdownServer() 516 self.debugging = False 517 self.clientGone.emit(unplanned and self.debugging) 518 519 if clType: 520 if clType not in self.getSupportedLanguages(): 521 # a not supported client language was requested 522 return 523 524 self.__setClientType(clType) 525 526 # only start the client, if we are not in passive mode 527 if not self.passive: 528 if self.clientProcess: 529 self.clientProcess.kill() 530 self.clientProcess.waitForFinished(1000) 531 self.clientProcess.deleteLater() 532 self.clientProcess = None 533 534 self.__forProject = forProject 535 self.__createDebuggerInterface() 536 if forProject: 537 project = e5App().getObject("Project") 538 if not project.isDebugPropertiesLoaded(): 539 self.clientProcess, isNetworked, clientInterpreter = ( 540 self.debuggerInterface.startRemote( 541 self.serverPort(), runInConsole, venvName, 542 self.__originalPathString, workingDir=workingDir, 543 configOverride=configOverride)) 544 else: 545 self.clientProcess, isNetworked, clientInterpreter = ( 546 self.debuggerInterface.startRemoteForProject( 547 self.serverPort(), runInConsole, venvName, 548 self.__originalPathString, workingDir=workingDir, 549 configOverride=configOverride)) 550 else: 551 self.clientProcess, isNetworked, clientInterpreter = ( 552 self.debuggerInterface.startRemote( 553 self.serverPort(), runInConsole, venvName, 554 self.__originalPathString, workingDir=workingDir, 555 configOverride=configOverride)) 556 557 if self.clientProcess: 558 self.clientProcess.readyReadStandardError.connect( 559 self.__clientProcessError) 560 self.clientProcess.readyReadStandardOutput.connect( 561 self.__clientProcessOutput) 562 563 # Perform actions necessary, if client type has changed 564 if self.lastClientType != self.clientType: 565 self.lastClientType = self.clientType 566 self.remoteBanner() 567 elif self.__autoClearShell: 568 self.__autoClearShell = False 569 self.remoteBanner() 570 else: 571 if clType and self.lastClientType: 572 self.__setClientType(self.lastClientType) 573 else: 574 self.__createDebuggerInterface("None") 575 clientInterpreter = "" 576 577 if clientInterpreter != self.clientInterpreter: 578 self.clientInterpreter = clientInterpreter 579 self.clientInterpreterChanged.emit(clientInterpreter) 580 581 def __clientProcessOutput(self): 582 """ 583 Private slot to process client output received via stdout. 584 """ 585 output = str(self.clientProcess.readAllStandardOutput(), 586 Preferences.getSystem("IOEncoding"), 587 'replace') 588 self.clientProcessStdout.emit(output) 589 590 def __clientProcessError(self): 591 """ 592 Private slot to process client output received via stderr. 593 """ 594 error = str(self.clientProcess.readAllStandardError(), 595 Preferences.getSystem("IOEncoding"), 596 'replace') 597 self.clientProcessStderr.emit(error) 598 599 @pyqtSlot(str, int) 600 def __clientClearBreakPoint(self, fn, lineno): 601 """ 602 Private slot to handle the clientClearBreak signal. 603 604 @param fn filename of breakpoint to clear 605 @type str 606 @param lineno line number of breakpoint to clear 607 @type int 608 """ 609 if self.debugging: 610 index = self.breakpointModel.getBreakPointIndex(fn, lineno) 611 self.breakpointModel.deleteBreakPointByIndex(index) 612 if (fn, lineno) in self.__reportedBreakpointIssues: 613 self.__reportedBreakpointIssues.remove((fn, lineno)) 614 615 def __deleteBreakPoints(self, parentIndex, start, end): 616 """ 617 Private slot to delete breakpoints. 618 619 @param parentIndex index of parent item 620 @type QModelIndex 621 @param start start row 622 @type int 623 @param end end row 624 @type int 625 """ 626 if self.debugging: 627 for row in range(start, end + 1): 628 index = self.breakpointModel.index(row, 0, parentIndex) 629 fn, lineno = ( 630 self.breakpointModel.getBreakPointByIndex(index)[0:2]) 631 # delete the breakpoints of all connected backends 632 self.remoteBreakpoint("", fn, lineno, False) 633 if (fn, lineno) in self.__reportedBreakpointIssues: 634 self.__reportedBreakpointIssues.remove((fn, lineno)) 635 636 def __changeBreakPoints(self, startIndex, endIndex): 637 """ 638 Private slot to set changed breakpoints. 639 640 @param startIndex starting index of the change breakpoins 641 @type QModelIndex 642 @param endIndex ending index of the change breakpoins 643 @type QModelIndex 644 """ 645 if self.debugging: 646 self.__addBreakPoints( 647 QModelIndex(), startIndex.row(), endIndex.row()) 648 649 def __breakPointDataAboutToBeChanged(self, startIndex, endIndex): 650 """ 651 Private slot to handle the dataAboutToBeChanged signal of the 652 breakpoint model. 653 654 @param startIndex start index of the rows to be changed 655 @type QModelIndex 656 @param endIndex end index of the rows to be changed 657 @type QModelIndex 658 """ 659 if self.debugging: 660 self.__deleteBreakPoints( 661 QModelIndex(), startIndex.row(), endIndex.row()) 662 663 def __addBreakPoints(self, parentIndex, start, end, debuggerId=""): 664 """ 665 Private slot to add breakpoints. 666 667 @param parentIndex index of parent item 668 @type QModelIndex 669 @param start start row 670 @type int 671 @param end end row 672 @type int 673 @param debuggerId ID of the debugger backend to send to. If this is 674 empty, they will be broadcast to all connected backends. 675 @type str 676 """ 677 if self.debugging: 678 for row in range(start, end + 1): 679 index = self.breakpointModel.index(row, 0, parentIndex) 680 fn, lineno, cond, temp, enabled, ignorecount = ( 681 self.breakpointModel.getBreakPointByIndex(index)[:6]) 682 683 if (fn, lineno) in self.__reportedBreakpointIssues: 684 self.__reportedBreakpointIssues.remove((fn, lineno)) 685 686 self.remoteBreakpoint(debuggerId, fn, lineno, True, cond, temp) 687 if not enabled: 688 self.__remoteBreakpointEnable( 689 debuggerId, fn, lineno, False) 690 if ignorecount: 691 self.__remoteBreakpointIgnore( 692 debuggerId, fn, lineno, ignorecount) 693 694 def __makeWatchCondition(self, cond, special): 695 """ 696 Private method to construct the condition string. 697 698 @param cond condition 699 @type str 700 @param special special condition 701 @type str 702 @return condition string 703 @rtype str 704 """ 705 if special == "": 706 _cond = cond 707 else: 708 if special == self.watchSpecialCreated: 709 _cond = "{0} ??created??".format(cond) 710 elif special == self.watchSpecialChanged: 711 _cond = "{0} ??changed??".format(cond) 712 return _cond 713 714 def __splitWatchCondition(self, cond): 715 """ 716 Private method to split a remote watch expression. 717 718 @param cond remote expression 719 @type str 720 @return tuple of local expression (string) and special condition 721 @rtype str 722 """ 723 if cond.endswith(" ??created??"): 724 cond, special = cond.split() 725 special = self.watchSpecialCreated 726 elif cond.endswith(" ??changed??"): 727 cond, special = cond.split() 728 special = self.watchSpecialChanged 729 else: 730 cond = cond 731 special = "" 732 733 return cond, special 734 735 @pyqtSlot(str) 736 def __clientClearWatchPoint(self, condition): 737 """ 738 Private slot to handle the clientClearWatch signal. 739 740 @param condition expression of watch expression to clear 741 @type str 742 """ 743 if self.debugging: 744 cond, special = self.__splitWatchCondition(condition) 745 index = self.watchpointModel.getWatchPointIndex(cond, special) 746 self.watchpointModel.deleteWatchPointByIndex(index) 747 if condition in self.__reportedWatchpointIssues: 748 self.__reportedWatchpointIssues.remove(condition) 749 750 def __deleteWatchPoints(self, parentIndex, start, end): 751 """ 752 Private slot to delete watch expressions. 753 754 @param parentIndex index of parent item 755 @type QModelIndex 756 @param start start row 757 @type int 758 @param end end row 759 @type int 760 """ 761 if self.debugging: 762 for row in range(start, end + 1): 763 index = self.watchpointModel.index(row, 0, parentIndex) 764 cond, special = ( 765 self.watchpointModel.getWatchPointByIndex(index)[0:2]) 766 cond = self.__makeWatchCondition(cond, special) 767 self.__remoteWatchpoint("", cond, False) 768 if cond in self.__reportedWatchpointIssues: 769 self.__reportedWatchpointIssues.remove(cond) 770 771 def __watchPointDataAboutToBeChanged(self, startIndex, endIndex): 772 """ 773 Private slot to handle the dataAboutToBeChanged signal of the 774 watch expression model. 775 776 @param startIndex start index of the rows to be changed 777 @type QModelIndex 778 @param endIndex end index of the rows to be changed 779 @type QModelIndex 780 """ 781 if self.debugging: 782 self.__deleteWatchPoints( 783 QModelIndex(), startIndex.row(), endIndex.row()) 784 785 def __addWatchPoints(self, parentIndex, start, end, debuggerId=""): 786 """ 787 Private slot to set a watch expression. 788 789 @param parentIndex index of parent item 790 @type QModelIndex 791 @param start start row 792 @type int 793 @param end end row 794 @type int 795 @param debuggerId ID of the debugger backend to send to. If this is 796 empty, they will be broadcast to all connected backends. 797 @type str 798 """ 799 if self.debugging: 800 for row in range(start, end + 1): 801 index = self.watchpointModel.index(row, 0, parentIndex) 802 cond, special, temp, enabled, ignorecount = ( 803 self.watchpointModel.getWatchPointByIndex(index)[:5]) 804 cond = self.__makeWatchCondition(cond, special) 805 806 if cond in self.__reportedWatchpointIssues: 807 self.__reportedWatchpointIssues.remove(cond) 808 809 self.__remoteWatchpoint(debuggerId, cond, True, temp) 810 if not enabled: 811 self.__remoteWatchpointEnable(debuggerId, cond, False) 812 if ignorecount: 813 self.__remoteWatchpointIgnore(debuggerId, cond, 814 ignorecount) 815 816 def __changeWatchPoints(self, startIndex, endIndex): 817 """ 818 Private slot to set changed watch expressions. 819 820 @param startIndex start index of the rows to be changed 821 @type QModelIndex 822 @param endIndex end index of the rows to be changed 823 @type QModelIndex 824 """ 825 if self.debugging: 826 self.__addWatchPoints( 827 QModelIndex(), startIndex.row(), endIndex.row()) 828 829 def getClientCapabilities(self, clientType): 830 """ 831 Public method to retrieve the debug clients capabilities. 832 833 @param clientType debug client type 834 @type str 835 @return debug client capabilities 836 @rtype int 837 """ 838 try: 839 return self.__debuggerInterfaceRegistry[clientType][0] 840 except KeyError: 841 return 0 # no capabilities 842 843 def getClientInterpreter(self): 844 """ 845 Public method to get the interpreter of the debug client. 846 847 @return interpreter of the debug client 848 @rtype str 849 """ 850 return self.clientInterpreter 851 852 def getClientType(self): 853 """ 854 Public method to get the currently running debug client type. 855 856 @return debug client type 857 @rtype str 858 """ 859 return self.clientType 860 861 def isClientProcessUp(self): 862 """ 863 Public method to check, if the debug client process is up. 864 865 @return flag indicating a running debug client process 866 @rtype bool 867 """ 868 return self.clientProcess is not None 869 870 def __newConnection(self): 871 """ 872 Private slot to handle a new connection. 873 """ 874 sock = self.nextPendingConnection() 875 peerAddress = sock.peerAddress().toString() 876 if peerAddress not in Preferences.getDebugger("AllowedHosts"): 877 # the peer is not allowed to connect 878 res = E5MessageBox.yesNo( 879 None, 880 self.tr("Connection from illegal host"), 881 self.tr( 882 """<p>A connection was attempted by the illegal host""" 883 """ <b>{0}</b>. Accept this connection?</p>""") 884 .format(peerAddress), 885 icon=E5MessageBox.Warning) 886 if not res: 887 sock.abort() 888 return 889 else: 890 allowedHosts = Preferences.getDebugger("AllowedHosts") 891 allowedHosts.append(peerAddress) 892 Preferences.setDebugger("AllowedHosts", allowedHosts) 893 894 if self.passive: 895 self.__createDebuggerInterface( 896 Preferences.getDebugger("PassiveDbgType")) 897 898 self.debuggerInterface.newConnection(sock) 899 900 def masterClientConnected(self): 901 """ 902 Public method to perform actions after the master client has finally 903 established the connection. 904 """ 905 # Perform actions necessary, if client type has changed 906 if self.lastClientType != self.clientType: 907 self.lastClientType = self.clientType 908 self.remoteBanner() 909 elif self.__autoClearShell: 910 self.__autoClearShell = False 911 self.remoteBanner() 912 elif self.passive: 913 self.remoteBanner() 914 915 def shutdownServer(self): 916 """ 917 Public method to cleanly shut down. 918 919 It closes our socket and shuts down 920 the debug client. (Needed on Win OS) 921 """ 922 if self.debuggerInterface is not None: 923 self.debuggerInterface.shutdown() 924 925 def remoteEnvironment(self, env): 926 """ 927 Public method to set the environment for a program to debug, run, ... 928 929 @param env environment settings 930 @type str 931 """ 932 envlist = shlex.split(env) 933 envdict = {} 934 for el in envlist: 935 if '=' in el: 936 key, value = el.split('=', 1) 937 envdict[key] = value 938 else: 939 envdict[el] = "" 940 self.debuggerInterface.remoteEnvironment(envdict) 941 942 def remoteLoad(self, venvName, fn, argv, wd, env, autoClearShell=True, 943 tracePython=False, autoContinue=True, forProject=False, 944 runInConsole=False, clientType="", enableCallTrace=False, 945 enableMultiprocess=False, multiprocessNoDebug="", 946 configOverride=None): 947 """ 948 Public method to load a new program to debug. 949 950 @param venvName name of the virtual environment to be used 951 @type str 952 @param fn the filename to debug 953 @type str 954 @param argv the command line arguments to pass to the program 955 @type str 956 @param wd the working directory for the program 957 @type str 958 @param env environment parameter settings 959 @type str 960 @param autoClearShell flag indicating, that the interpreter window 961 should be cleared 962 @type bool 963 @param tracePython flag indicating if the Python library should be 964 traced as well 965 @type bool 966 @param autoContinue flag indicating, that the debugger should not 967 stop at the first executable line 968 @type bool 969 @param forProject flag indicating a project related action 970 @type bool 971 @param runInConsole flag indicating to start the debugger in a 972 console window 973 @type bool 974 @param clientType client type to be used 975 @type str 976 @param enableCallTrace flag indicating to enable the call trace 977 function 978 @type bool 979 @param enableMultiprocess flag indicating to perform multiprocess 980 debugging 981 @type bool 982 @param multiprocessNoDebug space separated list of programs not to be 983 debugged 984 @type str 985 @param configOverride dictionary containing the global config override 986 data 987 @type dict 988 """ 989 self.__autoClearShell = autoClearShell 990 self.__multiprocessNoDebugList = [ 991 s.strip() for s in multiprocessNoDebug.split(os.pathsep) 992 ] 993 994 if clientType not in self.getSupportedLanguages(): 995 # a not supported client language was requested 996 E5MessageBox.critical( 997 None, 998 self.tr("Start Debugger"), 999 self.tr( 1000 """<p>The debugger type <b>{0}</b> is not supported""" 1001 """ or not configured.</p>""").format(clientType) 1002 ) 1003 return 1004 1005 # Restart the client 1006 try: 1007 if clientType: 1008 self.__setClientType(clientType) 1009 else: 1010 self.__setClientType( 1011 self.__findLanguageForExtension(os.path.splitext(fn)[1])) 1012 except KeyError: 1013 self.__setClientType('Python3') # assume it is a Python3 file 1014 self.startClient(False, forProject=forProject, 1015 runInConsole=runInConsole, venvName=venvName, 1016 configOverride=configOverride) 1017 1018 self.setCallTraceEnabled("", enableCallTrace) 1019 self.remoteEnvironment(env) 1020 1021 self.debuggerInterface.remoteLoad( 1022 fn, argv, wd, tracePython, autoContinue, 1023 enableMultiprocess=enableMultiprocess 1024 ) 1025 self.debugging = True 1026 self.running = True 1027 self.__restoreBreakpoints() 1028 self.__restoreWatchpoints() 1029 self.__restoreNoDebugList() 1030 1031 def remoteRun(self, venvName, fn, argv, wd, env, autoClearShell=True, 1032 forProject=False, runInConsole=False, clientType="", 1033 configOverride=None): 1034 """ 1035 Public method to load a new program to run. 1036 1037 @param venvName name of the virtual environment to be used 1038 @type str 1039 @param fn the filename to debug 1040 @type str 1041 @param argv the command line arguments to pass to the program 1042 @type str 1043 @param wd the working directory for the program 1044 @type str 1045 @param env environment parameter settings 1046 @type str 1047 @param autoClearShell flag indicating, that the interpreter window 1048 should be cleared 1049 @type bool 1050 @param forProject flag indicating a project related action 1051 @type bool 1052 @param runInConsole flag indicating to start the debugger in a 1053 console window 1054 @type bool 1055 @param clientType client type to be used 1056 @type str 1057 @param configOverride dictionary containing the global config override 1058 data 1059 @type dict 1060 """ 1061 self.__autoClearShell = autoClearShell 1062 1063 if clientType not in self.getSupportedLanguages(): 1064 E5MessageBox.critical( 1065 None, 1066 self.tr("Start Debugger"), 1067 self.tr( 1068 """<p>The debugger type <b>{0}</b> is not supported""" 1069 """ or not configured.</p>""").format(clientType) 1070 ) 1071 # a not supported client language was requested 1072 return 1073 1074 # Restart the client 1075 try: 1076 if clientType: 1077 self.__setClientType(clientType) 1078 else: 1079 self.__setClientType( 1080 self.__findLanguageForExtension(os.path.splitext(fn)[1])) 1081 except KeyError: 1082 self.__setClientType('Python3') # assume it is a Python3 file 1083 self.startClient(False, forProject=forProject, 1084 runInConsole=runInConsole, venvName=venvName, 1085 configOverride=configOverride) 1086 1087 self.remoteEnvironment(env) 1088 1089 self.debuggerInterface.remoteRun(fn, argv, wd) 1090 self.debugging = False 1091 self.running = True 1092 1093 def remoteCoverage(self, venvName, fn, argv, wd, env, 1094 autoClearShell=True, erase=False, forProject=False, 1095 runInConsole=False, clientType="", configOverride=None): 1096 """ 1097 Public method to load a new program to collect coverage data. 1098 1099 @param venvName name of the virtual environment to be used 1100 @type str 1101 @param fn the filename to debug 1102 @type str 1103 @param argv the command line arguments to pass to the program 1104 @type str 1105 @param wd the working directory for the program 1106 @type str 1107 @param env environment parameter settings 1108 @type str 1109 @param autoClearShell flag indicating, that the interpreter window 1110 should be cleared 1111 @type bool 1112 @param erase flag indicating that coverage info should be 1113 cleared first 1114 @type bool 1115 @param forProject flag indicating a project related action 1116 @type bool 1117 @param runInConsole flag indicating to start the debugger in a 1118 console window 1119 @type bool 1120 @param clientType client type to be used 1121 @type str 1122 @param configOverride dictionary containing the global config override 1123 data 1124 @type dict 1125 """ 1126 self.__autoClearShell = autoClearShell 1127 1128 if clientType not in self.getSupportedLanguages(): 1129 # a not supported client language was requested 1130 E5MessageBox.critical( 1131 None, 1132 self.tr("Start Debugger"), 1133 self.tr( 1134 """<p>The debugger type <b>{0}</b> is not supported""" 1135 """ or not configured.</p>""").format(clientType) 1136 ) 1137 return 1138 1139 # Restart the client 1140 try: 1141 if clientType: 1142 self.__setClientType(clientType) 1143 else: 1144 self.__setClientType( 1145 self.__findLanguageForExtension(os.path.splitext(fn)[1])) 1146 except KeyError: 1147 self.__setClientType('Python3') # assume it is a Python3 file 1148 self.startClient(False, forProject=forProject, 1149 runInConsole=runInConsole, venvName=venvName, 1150 configOverride=configOverride) 1151 1152 self.remoteEnvironment(env) 1153 1154 self.debuggerInterface.remoteCoverage(fn, argv, wd, erase) 1155 self.debugging = False 1156 self.running = True 1157 1158 def remoteProfile(self, venvName, fn, argv, wd, env, 1159 autoClearShell=True, erase=False, forProject=False, 1160 runInConsole=False, clientType="", configOverride=None): 1161 """ 1162 Public method to load a new program to collect profiling data. 1163 1164 @param venvName name of the virtual environment to be used 1165 @type str 1166 @param fn the filename to debug 1167 @type str 1168 @param argv the command line arguments to pass to the program 1169 @type str 1170 @param wd the working directory for the program 1171 @type str 1172 @param env environment parameter settings 1173 @type str 1174 @param autoClearShell flag indicating, that the interpreter window 1175 should be cleared 1176 @type bool 1177 @param erase flag indicating that coverage info should be 1178 cleared first 1179 @type bool 1180 @param forProject flag indicating a project related action 1181 @type bool 1182 @param runInConsole flag indicating to start the debugger in a 1183 console window 1184 @type bool 1185 @param clientType client type to be used 1186 @type str 1187 @param configOverride dictionary containing the global config override 1188 data 1189 @type dict 1190 """ 1191 self.__autoClearShell = autoClearShell 1192 1193 if clientType not in self.getSupportedLanguages(): 1194 # a not supported client language was requested 1195 E5MessageBox.critical( 1196 None, 1197 self.tr("Start Debugger"), 1198 self.tr( 1199 """<p>The debugger type <b>{0}</b> is not supported""" 1200 """ or not configured.</p>""").format(clientType) 1201 ) 1202 return 1203 1204 # Restart the client 1205 try: 1206 if clientType: 1207 self.__setClientType(clientType) 1208 else: 1209 self.__setClientType( 1210 self.__findLanguageForExtension(os.path.splitext(fn)[1])) 1211 except KeyError: 1212 self.__setClientType('Python3') # assume it is a Python3 file 1213 self.startClient(False, forProject=forProject, 1214 runInConsole=runInConsole, venvName=venvName, 1215 configOverride=configOverride) 1216 1217 self.remoteEnvironment(env) 1218 1219 self.debuggerInterface.remoteProfile(fn, argv, wd, erase) 1220 self.debugging = False 1221 self.running = True 1222 1223 def remoteStatement(self, debuggerId, stmt): 1224 """ 1225 Public method to execute a Python statement. 1226 1227 @param debuggerId ID of the debugger backend 1228 @type str 1229 @param stmt the Python statement to execute. 1230 @type str 1231 """ 1232 self.debuggerInterface.remoteStatement(debuggerId, stmt.rstrip()) 1233 1234 def remoteStep(self, debuggerId): 1235 """ 1236 Public method to single step the debugged program. 1237 1238 @param debuggerId ID of the debugger backend 1239 @type str 1240 """ 1241 self.debuggerInterface.remoteStep(debuggerId) 1242 1243 def remoteStepOver(self, debuggerId): 1244 """ 1245 Public method to step over the debugged program. 1246 1247 @param debuggerId ID of the debugger backend 1248 @type str 1249 """ 1250 self.debuggerInterface.remoteStepOver(debuggerId) 1251 1252 def remoteStepOut(self, debuggerId): 1253 """ 1254 Public method to step out the debugged program. 1255 1256 @param debuggerId ID of the debugger backend 1257 @type str 1258 """ 1259 self.debuggerInterface.remoteStepOut(debuggerId) 1260 1261 def remoteStepQuit(self, debuggerId): 1262 """ 1263 Public method to stop the debugged program. 1264 1265 @param debuggerId ID of the debugger backend 1266 @type str 1267 """ 1268 self.debuggerInterface.remoteStepQuit(debuggerId) 1269 1270 def remoteContinue(self, debuggerId, special=False): 1271 """ 1272 Public method to continue the debugged program. 1273 1274 @param debuggerId ID of the debugger backend 1275 @type str 1276 @param special flag indicating a special continue operation 1277 """ 1278 self.debuggerInterface.remoteContinue(debuggerId, special) 1279 1280 def remoteContinueUntil(self, debuggerId, line): 1281 """ 1282 Public method to continue the debugged program to the given line 1283 or until returning from the current frame. 1284 1285 @param debuggerId ID of the debugger backend 1286 @type str 1287 @param line the new line, where execution should be continued to 1288 @type int 1289 """ 1290 self.debuggerInterface.remoteContinueUntil(debuggerId, line) 1291 1292 def remoteMoveIP(self, debuggerId, line): 1293 """ 1294 Public method to move the instruction pointer to a different line. 1295 1296 @param debuggerId ID of the debugger backend 1297 @type str 1298 @param line the new line, where execution should be continued 1299 @type int 1300 """ 1301 self.debuggerInterface.remoteMoveIP(debuggerId, line) 1302 1303 def remoteBreakpoint(self, debuggerId, fn, line, setBreakpoint, cond=None, 1304 temp=False): 1305 """ 1306 Public method to set or clear a breakpoint. 1307 1308 @param debuggerId ID of the debugger backend 1309 @type str 1310 @param fn filename the breakpoint belongs to 1311 @type str 1312 @param line linenumber of the breakpoint 1313 @type int 1314 @param setBreakpoint flag indicating setting or resetting a breakpoint 1315 @type bool 1316 @param cond condition of the breakpoint 1317 @type str 1318 @param temp flag indicating a temporary breakpoint 1319 @type bool 1320 """ 1321 self.debuggerInterface.remoteBreakpoint( 1322 debuggerId, fn, line, setBreakpoint, cond, temp) 1323 1324 def __remoteBreakpointEnable(self, debuggerId, fn, line, enable): 1325 """ 1326 Private method to enable or disable a breakpoint. 1327 1328 @param debuggerId ID of the debugger backend 1329 @type str 1330 @param fn filename the breakpoint belongs to 1331 @type str 1332 @param line linenumber of the breakpoint 1333 @type int 1334 @param enable flag indicating enabling or disabling a breakpoint 1335 @type bool 1336 """ 1337 self.debuggerInterface.remoteBreakpointEnable( 1338 debuggerId, fn, line, enable) 1339 1340 def __remoteBreakpointIgnore(self, debuggerId, fn, line, count): 1341 """ 1342 Private method to ignore a breakpoint the next couple of occurrences. 1343 1344 @param debuggerId ID of the debugger backend 1345 @type str 1346 @param fn filename the breakpoint belongs to 1347 @type str 1348 @param line linenumber of the breakpoint 1349 @type int 1350 @param count number of occurrences to ignore 1351 @type int 1352 """ 1353 self.debuggerInterface.remoteBreakpointIgnore( 1354 debuggerId, fn, line, count) 1355 1356 def __remoteWatchpoint(self, debuggerId, cond, setWatch, temp=False): 1357 """ 1358 Private method to set or clear a watch expression. 1359 1360 @param debuggerId ID of the debugger backend 1361 @type str 1362 @param cond expression of the watch expression 1363 @type str 1364 @param setWatch flag indicating setting or resetting a watch expression 1365 @type bool 1366 @param temp flag indicating a temporary watch expression 1367 @type bool 1368 """ 1369 # cond is combination of cond and special (s. watch expression viewer) 1370 self.debuggerInterface.remoteWatchpoint(debuggerId, cond, setWatch, 1371 temp) 1372 1373 def __remoteWatchpointEnable(self, debuggerId, cond, enable): 1374 """ 1375 Private method to enable or disable a watch expression. 1376 1377 @param debuggerId ID of the debugger backend 1378 @type str 1379 @param cond expression of the watch expression 1380 @type str 1381 @param enable flag indicating enabling or disabling a watch expression 1382 @type bool 1383 """ 1384 # cond is combination of cond and special (s. watch expression viewer) 1385 self.debuggerInterface.remoteWatchpointEnable(debuggerId, cond, enable) 1386 1387 def __remoteWatchpointIgnore(self, debuggerId, cond, count): 1388 """ 1389 Private method to ignore a watch expression the next couple of 1390 occurrences. 1391 1392 @param debuggerId ID of the debugger backend 1393 @type str 1394 @param cond expression of the watch expression 1395 @type str 1396 @param count number of occurrences to ignore 1397 @type int 1398 """ 1399 # cond is combination of cond and special (s. watch expression viewer) 1400 self.debuggerInterface.remoteWatchpointIgnore(debuggerId, cond, count) 1401 1402 def remoteRawInput(self, debuggerId, inputString): 1403 """ 1404 Public method to send the raw input to the debugged program. 1405 1406 @param debuggerId ID of the debugger backend 1407 @type str 1408 @param inputString the raw input 1409 @type str 1410 """ 1411 self.debuggerInterface.remoteRawInput(debuggerId, inputString) 1412 self.clientRawInputSent.emit(debuggerId) 1413 1414 def remoteThreadList(self, debuggerId): 1415 """ 1416 Public method to request the list of threads from the client. 1417 1418 @param debuggerId ID of the debugger backend 1419 @type str 1420 """ 1421 self.debuggerInterface.remoteThreadList(debuggerId) 1422 1423 def remoteSetThread(self, debuggerId, tid): 1424 """ 1425 Public method to request to set the given thread as current thread. 1426 1427 @param debuggerId ID of the debugger backend 1428 @type str 1429 @param tid id of the thread 1430 @type int 1431 """ 1432 self.debuggerInterface.remoteSetThread(debuggerId, tid) 1433 1434 def remoteClientStack(self, debuggerId): 1435 """ 1436 Public method to request the stack of the main thread. 1437 1438 @param debuggerId ID of the debugger backend 1439 @type str 1440 """ 1441 self.debuggerInterface.remoteClientStack(debuggerId) 1442 1443 def remoteClientVariables(self, debuggerId, scope, filterList, framenr=0): 1444 """ 1445 Public method to request the variables of the debugged program. 1446 1447 @param debuggerId ID of the debugger backend 1448 @type str 1449 @param scope the scope of the variables (0 = local, 1 = global) 1450 @type int 1451 @param filterList list of variable types to filter out 1452 @type list of str 1453 @param framenr framenumber of the variables to retrieve 1454 @type int 1455 """ 1456 self.debuggerInterface.remoteClientVariables( 1457 debuggerId, scope, filterList, framenr, self.__maxVariableSize) 1458 1459 def remoteClientVariable(self, debuggerId, scope, filterList, var, 1460 framenr=0, maxSize=0): 1461 """ 1462 Public method to request the variables of the debugged program. 1463 1464 @param debuggerId ID of the debugger backend 1465 @type str 1466 @param scope the scope of the variables (0 = local, 1 = global) 1467 @type int 1468 @param filterList list of variable types to filter out 1469 @type list of str 1470 @param var list encoded name of variable to retrieve 1471 @type list of str 1472 @param framenr framenumber of the variables to retrieve 1473 @type int 1474 @param maxSize maximum size the formatted value of a variable will 1475 be shown. If it is bigger than that, a 'too big' indication will 1476 be given (@@TOO_BIG_TO_SHOW@@). 1477 @type int 1478 """ 1479 self.debuggerInterface.remoteClientVariable( 1480 debuggerId, scope, filterList, var, framenr, 1481 self.__maxVariableSize) 1482 1483 def remoteClientDisassembly(self, debuggerId): 1484 """ 1485 Public method to ask the client for the latest traceback disassembly. 1486 1487 @param debuggerId ID of the debugger backend 1488 @type str 1489 """ 1490 with contextlib.suppress(AttributeError): 1491 self.debuggerInterface.remoteClientDisassembly(debuggerId) 1492 1493 def remoteClientSetFilter(self, debuggerId, scope, filterStr): 1494 """ 1495 Public method to set a variables filter list. 1496 1497 @param debuggerId ID of the debugger backend 1498 @type str 1499 @param scope the scope of the variables (0 = local, 1 = global) 1500 @type int 1501 @param filterStr regexp string for variable names to filter out 1502 @type str 1503 """ 1504 self.debuggerInterface.remoteClientSetFilter( 1505 debuggerId, scope, filterStr) 1506 1507 def setCallTraceEnabled(self, debuggerId, on): 1508 """ 1509 Public method to set the call trace state. 1510 1511 @param debuggerId ID of the debugger backend 1512 @type str 1513 @param on flag indicating to enable the call trace function 1514 @type bool 1515 """ 1516 self.debuggerInterface.setCallTraceEnabled(debuggerId, on) 1517 1518 def remoteBanner(self): 1519 """ 1520 Public slot to get the banner info of the remote client. 1521 """ 1522 self.debuggerInterface.remoteBanner() 1523 1524 def remoteCapabilities(self): 1525 """ 1526 Public slot to get the debug clients capabilities. 1527 """ 1528 self.debuggerInterface.remoteCapabilities() 1529 1530 def remoteCompletion(self, debuggerId, text): 1531 """ 1532 Public slot to get the a list of possible commandline completions 1533 from the remote client. 1534 1535 @param debuggerId ID of the debugger backend 1536 @type str 1537 @param text the text to be completed 1538 @type str 1539 """ 1540 self.debuggerInterface.remoteCompletion(debuggerId, text) 1541 1542 def remoteUTDiscover(self, clientType, forProject, venvName, syspath, 1543 workdir, discoveryStart): 1544 """ 1545 Public method to perform a test case discovery. 1546 1547 @param clientType client type to be used 1548 @type str 1549 @param forProject flag indicating a project related action 1550 @type bool 1551 @param venvName name of a virtual environment 1552 @type str 1553 @param syspath list of directories to be added to sys.path on the 1554 remote side 1555 @type list of str 1556 @param workdir path name of the working directory 1557 @type str 1558 @param discoveryStart directory to start auto-discovery at 1559 @type str 1560 """ 1561 if clientType and clientType not in self.getSupportedLanguages(): 1562 # a not supported client language was requested 1563 E5MessageBox.critical( 1564 None, 1565 self.tr("Start Debugger"), 1566 self.tr( 1567 """<p>The debugger type <b>{0}</b> is not supported""" 1568 """ or not configured.</p>""").format(clientType) 1569 ) 1570 return 1571 1572 # Restart the client if there is already a program loaded. 1573 try: 1574 if clientType: 1575 self.__setClientType(clientType) 1576 except KeyError: 1577 self.__setClientType('Python3') # assume it is a Python3 file 1578 self.startClient(False, forProject=forProject, venvName=venvName) 1579 1580 self.debuggerInterface.remoteUTDiscover( 1581 syspath, workdir, discoveryStart) 1582 1583 def remoteUTPrepare(self, fn, tn, tfn, failed, cov, covname, coverase, 1584 clientType="", forProject=False, venvName="", 1585 syspath=None, workdir="", discover=False, 1586 discoveryStart="", testCases=None, debug=False): 1587 """ 1588 Public method to prepare a new unittest run. 1589 1590 @param fn the filename to load 1591 @type str 1592 @param tn the testname to load 1593 @type str 1594 @param tfn the test function name to load tests from 1595 @type str 1596 @param failed list of failed test, if only failed test should be run 1597 @type list of str 1598 @param cov flag indicating collection of coverage data is requested 1599 @type bool 1600 @param covname filename to be used to assemble the coverage caches 1601 filename 1602 @type str 1603 @param coverase flag indicating erasure of coverage data is requested 1604 @type bool 1605 @param clientType client type to be used 1606 @type str 1607 @param forProject flag indicating a project related action 1608 @type bool 1609 @param venvName name of a virtual environment 1610 @type str 1611 @param syspath list of directories to be added to sys.path on the 1612 remote side 1613 @type list of str 1614 @param workdir path name of the working directory 1615 @type str 1616 @param discover flag indicating to discover the tests automatically 1617 @type bool 1618 @param discoveryStart directory to start auto-discovery at 1619 @type str 1620 @param testCases list of test cases to be loaded 1621 @type list of str 1622 @param debug flag indicating to run unittest with debugging 1623 @type bool 1624 """ 1625 if clientType and clientType not in self.getSupportedLanguages(): 1626 # a not supported client language was requested 1627 E5MessageBox.critical( 1628 None, 1629 self.tr("Start Debugger"), 1630 self.tr( 1631 """<p>The debugger type <b>{0}</b> is not supported""" 1632 """ or not configured.</p>""").format(clientType) 1633 ) 1634 return 1635 1636 # Restart the client if there is already a program loaded. 1637 try: 1638 if clientType: 1639 self.__setClientType(clientType) 1640 else: 1641 self.__setClientType( 1642 self.__findLanguageForExtension(os.path.splitext(fn)[1])) 1643 except KeyError: 1644 self.__setClientType('Python3') # assume it is a Python3 file 1645 self.startClient(False, forProject=forProject, venvName=venvName) 1646 1647 self.debuggerInterface.remoteUTPrepare( 1648 fn, tn, tfn, failed, cov, covname, coverase, syspath, workdir, 1649 discover, discoveryStart, testCases, debug) 1650 self.running = True 1651 self.debugging = debug 1652 if debug: 1653 self.__restoreBreakpoints() 1654 self.__restoreWatchpoints() 1655 1656 def remoteUTRun(self, debug=False, failfast=False): 1657 """ 1658 Public method to start a unittest run. 1659 1660 @param debug flag indicating to run unittest with debugging 1661 @type bool 1662 @param failfast flag indicating to stop at the first error 1663 @type bool 1664 """ 1665 self.debuggerInterface.remoteUTRun(debug, failfast) 1666 1667 def remoteUTStop(self): 1668 """ 1669 public method to stop a unittest run. 1670 """ 1671 self.debuggerInterface.remoteUTStop() 1672 1673 def signalClientOutput(self, line, debuggerId): 1674 """ 1675 Public method to process a line of client output. 1676 1677 @param line client output 1678 @type str 1679 @param debuggerId ID of the debugger backend 1680 @type str 1681 """ 1682 if debuggerId: 1683 self.clientOutput.emit("{0}: {1}".format(debuggerId, line)) 1684 else: 1685 self.clientOutput.emit(line) 1686 1687 def signalClientLine(self, filename, lineno, debuggerId, forStack=False, 1688 threadName=""): 1689 """ 1690 Public method to process client position feedback. 1691 1692 @param filename name of the file currently being executed 1693 @type str 1694 @param lineno line of code currently being executed 1695 @type int 1696 @param debuggerId ID of the debugger backend 1697 @type str 1698 @param forStack flag indicating this is for a stack dump 1699 @type bool 1700 @param threadName name of the thread signaling the event 1701 @type str 1702 """ 1703 self.clientLine.emit(filename, lineno, debuggerId, threadName, 1704 forStack) 1705 1706 def signalClientStack(self, stack, debuggerId, threadName=""): 1707 """ 1708 Public method to process a client's stack information. 1709 1710 @param stack list of stack entries. Each entry is a tuple of three 1711 values giving the filename, linenumber and method 1712 @type list of lists of (string, integer, string) 1713 @param debuggerId ID of the debugger backend 1714 @type str 1715 @param threadName name of the thread signaling the event 1716 @type str 1717 """ 1718 self.clientStack.emit(stack, debuggerId, threadName) 1719 1720 def signalClientThreadList(self, currentId, threadList, debuggerId): 1721 """ 1722 Public method to process the client thread list info. 1723 1724 @param currentId id of the current thread 1725 @type int 1726 @param threadList list of dictionaries containing the thread data 1727 @type list of dict 1728 @param debuggerId ID of the debugger backend 1729 @type str 1730 """ 1731 self.clientThreadList.emit(currentId, threadList, debuggerId) 1732 1733 def signalClientThreadSet(self, debuggerId): 1734 """ 1735 Public method to handle the change of the client thread. 1736 1737 @param debuggerId ID of the debugger backend 1738 @type str 1739 """ 1740 self.clientThreadSet.emit(debuggerId) 1741 1742 def signalClientVariables(self, scope, variables, debuggerId): 1743 """ 1744 Public method to process the client variables info. 1745 1746 @param scope scope of the variables 1747 (-2 = no frame found, -1 = empty locals, 1 = global, 0 = local) 1748 @type int 1749 @param variables the list of variables from the client 1750 @type list 1751 @param debuggerId ID of the debugger backend 1752 @type str 1753 """ 1754 self.clientVariables.emit(scope, variables, debuggerId) 1755 1756 def signalClientVariable(self, scope, variables, debuggerId): 1757 """ 1758 Public method to process the client variable info. 1759 1760 @param scope scope of the variables (-1 = empty global, 1 = global, 1761 0 = local) 1762 @type int 1763 @param variables the list of members of a classvariable from the client 1764 @type list 1765 @param debuggerId ID of the debugger backend 1766 @type str 1767 """ 1768 self.clientVariable.emit(scope, variables, debuggerId) 1769 1770 def signalClientStatement(self, more, debuggerId): 1771 """ 1772 Public method to process the input response from the client. 1773 1774 @param more flag indicating that more user input is required 1775 @type bool 1776 @param debuggerId ID of the debugger backend 1777 @type str 1778 """ 1779 self.clientStatement.emit(more, debuggerId) 1780 1781 def signalClientDisassembly(self, disassembly, debuggerId): 1782 """ 1783 Public method to process the disassembly info from the client. 1784 1785 @param disassembly dictionary containing the disassembly information 1786 @type dict 1787 @param debuggerId ID of the debugger backend 1788 @type str 1789 """ 1790 if self.running: 1791 self.clientDisassembly.emit(disassembly, debuggerId) 1792 1793 def signalClientException(self, exceptionType, exceptionMessage, 1794 stackTrace, debuggerId, threadName=""): 1795 """ 1796 Public method to process the exception info from the client. 1797 1798 @param exceptionType type of exception raised 1799 @type str 1800 @param exceptionMessage message given by the exception 1801 @type str 1802 @param stackTrace list of stack entries with the exception position 1803 first. Each stack entry is a list giving the filename and the 1804 linenumber. 1805 @type list 1806 @param debuggerId ID of the debugger backend 1807 @type str 1808 @param threadName name of the thread signaling the event 1809 @type str 1810 """ 1811 if self.running: 1812 self.clientException.emit(exceptionType, exceptionMessage, 1813 stackTrace, debuggerId, threadName) 1814 1815 def signalClientSyntaxError(self, message, filename, lineNo, characterNo, 1816 debuggerId, threadName=""): 1817 """ 1818 Public method to process a syntax error info from the client. 1819 1820 @param message message of the syntax error 1821 @type str 1822 @param filename translated filename of the syntax error position 1823 @type str 1824 @param lineNo line number of the syntax error position 1825 @type int 1826 @param characterNo character number of the syntax error position 1827 @type int 1828 @param debuggerId ID of the debugger backend 1829 @type str 1830 @param threadName name of the thread signaling the event 1831 @type str 1832 """ 1833 if self.running: 1834 self.clientSyntaxError.emit(message, filename, lineNo, characterNo, 1835 debuggerId, threadName) 1836 1837 def signalClientSignal(self, message, filename, lineNo, 1838 funcName, funcArgs, debuggerId): 1839 """ 1840 Public method to process a signal generated on the client side. 1841 1842 @param message message of the syntax error 1843 @type str 1844 @param filename translated filename of the syntax error position 1845 @type str 1846 @param lineNo line number of the syntax error position 1847 @type int 1848 @param funcName name of the function causing the signal 1849 @type str 1850 @param funcArgs function arguments 1851 @type str 1852 @param debuggerId ID of the debugger backend 1853 @type str 1854 """ 1855 if self.running: 1856 self.clientSignal.emit(message, filename, lineNo, 1857 funcName, funcArgs, debuggerId) 1858 1859 def signalClientDisconnected(self, debuggerId): 1860 """ 1861 Public method to send a signal when a debug client has closed its 1862 connection. 1863 1864 @param debuggerId ID of the debugger backend 1865 @type str 1866 """ 1867 self.clientDisconnected.emit(debuggerId) 1868 1869 def signalClientExit(self, program, status, message, debuggerId): 1870 """ 1871 Public method to process the client exit status. 1872 1873 @param program name of the exited program 1874 @type str 1875 @param status exit code 1876 @type int 1877 @param message message sent with the exit 1878 @type str 1879 @param debuggerId ID of the debugger backend 1880 @type str 1881 """ 1882 self.clientExit.emit(program, int(status), message, False, debuggerId) 1883 1884 def signalMainClientExit(self): 1885 """ 1886 Public method to process the main client exiting. 1887 """ 1888 self.mainClientExit.emit() 1889 1890 def signalLastClientExited(self): 1891 """ 1892 Public method to process the last client exit event. 1893 """ 1894 if self.passive: 1895 self.__passiveShutDown() 1896 self.lastClientExited.emit() 1897 if Preferences.getDebugger("AutomaticReset") or (self.running and 1898 not self.debugging): 1899 self.debugging = False 1900 self.startClient(False, forProject=self.__forProject) 1901 if self.passive: 1902 self.__createDebuggerInterface("None") 1903 self.signalClientOutput(self.tr('\nNot connected\n')) 1904 self.signalClientStatement(False, "") 1905 self.running = False 1906 1907 def signalClientClearBreak(self, filename, lineno, debuggerId): 1908 """ 1909 Public method to process the client clear breakpoint command. 1910 1911 @param filename filename of the breakpoint 1912 @type str 1913 @param lineno line umber of the breakpoint 1914 @type int 1915 @param debuggerId ID of the debugger backend 1916 @type str 1917 """ 1918 self.clientClearBreak.emit(filename, lineno, debuggerId) 1919 1920 def signalClientBreakConditionError(self, filename, lineno, debuggerId): 1921 """ 1922 Public method to process the client breakpoint condition error info. 1923 1924 @param filename filename of the breakpoint 1925 @type str 1926 @param lineno line umber of the breakpoint 1927 @type int 1928 @param debuggerId ID of the debugger backend 1929 @type str 1930 """ 1931 if (filename, lineno) not in self.__reportedBreakpointIssues: 1932 self.__reportedBreakpointIssues.append((filename, lineno)) 1933 self.clientBreakConditionError.emit(filename, lineno, debuggerId) 1934 1935 def signalClientClearWatch(self, condition, debuggerId): 1936 """ 1937 Public slot to handle the clientClearWatch signal. 1938 1939 @param condition expression of watch expression to clear 1940 @type str 1941 @param debuggerId ID of the debugger backend 1942 @type str 1943 """ 1944 self.clientClearWatch.emit(condition, debuggerId) 1945 1946 def signalClientWatchConditionError(self, condition, debuggerId): 1947 """ 1948 Public method to process the client watch expression error info. 1949 1950 @param condition expression of watch expression to clear 1951 @type str 1952 @param debuggerId ID of the debugger backend 1953 @type str 1954 """ 1955 if condition not in self.__reportedWatchpointIssues: 1956 self.__reportedWatchpointIssues.append(condition) 1957 self.clientWatchConditionError.emit(condition, debuggerId) 1958 1959 def signalClientRawInput(self, prompt, echo, debuggerId): 1960 """ 1961 Public method to process the client raw input command. 1962 1963 @param prompt the input prompt 1964 @type str 1965 @param echo flag indicating an echoing of the input 1966 @type bool 1967 @param debuggerId ID of the debugger backend 1968 @type str 1969 """ 1970 self.clientRawInput.emit(prompt, echo, debuggerId) 1971 1972 def signalClientBanner(self, version, platform, venvName): 1973 """ 1974 Public method to process the client banner info. 1975 1976 @param version interpreter version info 1977 @type str 1978 @param platform hostname of the client 1979 @type str 1980 @param venvName name of the virtual environment 1981 @type str 1982 """ 1983 self.clientBanner.emit(version, platform, venvName) 1984 1985 def signalClientCapabilities(self, capabilities, clientType, venvName): 1986 """ 1987 Public method to process the client capabilities info. 1988 1989 @param capabilities bitmaks with the client capabilities 1990 @type int 1991 @param clientType type of the debug client 1992 @type str 1993 @param venvName name of the virtual environment 1994 @type str 1995 """ 1996 with contextlib.suppress(KeyError): 1997 self.__debuggerInterfaceRegistry[clientType][0] = capabilities 1998 self.clientCapabilities.emit(capabilities, clientType, venvName) 1999 2000 def signalClientCompletionList(self, completionList, text, debuggerId): 2001 """ 2002 Public method to process the client auto completion info. 2003 2004 @param completionList list of possible completions 2005 @type list of str 2006 @param text the text to be completed 2007 @type str 2008 @param debuggerId ID of the debugger backend 2009 @type str 2010 """ 2011 self.clientCompletionList.emit(completionList, text) 2012 2013 def signalClientCallTrace(self, isCall, fromFile, fromLine, fromFunction, 2014 toFile, toLine, toFunction, debuggerId): 2015 """ 2016 Public method to process the client call trace data. 2017 2018 @param isCall flag indicating a 'call' 2019 @type bool 2020 @param fromFile name of the originating file 2021 @type str 2022 @param fromLine line number in the originating file 2023 @type str 2024 @param fromFunction name of the originating function 2025 @type str 2026 @param toFile name of the target file 2027 @type str 2028 @param toLine line number in the target file 2029 @type str 2030 @param toFunction name of the target function 2031 @type str 2032 @param debuggerId ID of the debugger backend 2033 @type str 2034 """ 2035 self.callTraceInfo.emit( 2036 isCall, fromFile, fromLine, fromFunction, 2037 toFile, toLine, toFunction, debuggerId) 2038 2039 def clientUtDiscovered(self, testCases, exceptionType, exceptionValue): 2040 """ 2041 Public method to process the client unittest discover info. 2042 2043 @param testCases list of detected test cases 2044 @type str 2045 @param exceptionType exception type 2046 @type str 2047 @param exceptionValue exception message 2048 @type str 2049 """ 2050 self.utDiscovered.emit(testCases, exceptionType, exceptionValue) 2051 2052 def clientUtPrepared(self, result, exceptionType, exceptionValue): 2053 """ 2054 Public method to process the client unittest prepared info. 2055 2056 @param result number of test cases (0 = error) 2057 @type int 2058 @param exceptionType exception type 2059 @type str 2060 @param exceptionValue exception message 2061 @type str 2062 """ 2063 self.utPrepared.emit(result, exceptionType, exceptionValue) 2064 2065 def clientUtStartTest(self, testname, doc): 2066 """ 2067 Public method to process the client start test info. 2068 2069 @param testname name of the test 2070 @type str 2071 @param doc short description of the test 2072 @type str 2073 """ 2074 self.utStartTest.emit(testname, doc) 2075 2076 def clientUtStopTest(self): 2077 """ 2078 Public method to process the client stop test info. 2079 """ 2080 self.utStopTest.emit() 2081 2082 def clientUtTestFailed(self, testname, traceback, testId): 2083 """ 2084 Public method to process the client test failed info. 2085 2086 @param testname name of the test 2087 @type str 2088 @param traceback lines of traceback info 2089 @type list of str 2090 @param testId id of the test 2091 @type str 2092 """ 2093 self.utTestFailed.emit(testname, traceback, testId) 2094 2095 def clientUtTestErrored(self, testname, traceback, testId): 2096 """ 2097 Public method to process the client test errored info. 2098 2099 @param testname name of the test 2100 @type str 2101 @param traceback lines of traceback info 2102 @type list of str 2103 @param testId id of the test 2104 @type str 2105 """ 2106 self.utTestErrored.emit(testname, traceback, testId) 2107 2108 def clientUtTestSkipped(self, testname, reason, testId): 2109 """ 2110 Public method to process the client test skipped info. 2111 2112 @param testname name of the test 2113 @type str 2114 @param reason reason for skipping the test 2115 @type str 2116 @param testId id of the test 2117 @type str 2118 """ 2119 self.utTestSkipped.emit(testname, reason, testId) 2120 2121 def clientUtTestFailedExpected(self, testname, traceback, testId): 2122 """ 2123 Public method to process the client test failed expected info. 2124 2125 @param testname name of the test 2126 @type str 2127 @param traceback lines of traceback info 2128 @type list of str 2129 @param testId id of the test 2130 @type str 2131 """ 2132 self.utTestFailedExpected.emit(testname, traceback, testId) 2133 2134 def clientUtTestSucceededUnexpected(self, testname, testId): 2135 """ 2136 Public method to process the client test succeeded unexpected info. 2137 2138 @param testname name of the test 2139 @type str 2140 @param testId id of the test 2141 @type str 2142 """ 2143 self.utTestSucceededUnexpected.emit(testname, testId) 2144 2145 def clientUtFinished(self, status): 2146 """ 2147 Public method to process the client unit test finished info. 2148 2149 @param status exit status of the unit test 2150 @type int 2151 """ 2152 self.utFinished.emit() 2153 2154 self.clientExit.emit("", int(status), "", True, "") 2155 self.debugging = False 2156 self.running = False 2157 2158 def passiveStartUp(self, fn, exc, debuggerId): 2159 """ 2160 Public method to handle a passive debug connection. 2161 2162 @param fn filename of the debugged script 2163 @type str 2164 @param exc flag to enable exception reporting of the IDE 2165 @type bool 2166 @param debuggerId ID of the debugger backend 2167 @type str 2168 """ 2169 self.appendStdout.emit(self.tr("Passive debug connection received\n")) 2170 self.passiveClientExited = False 2171 self.debugging = True 2172 self.running = True 2173 self.__restoreBreakpoints(debuggerId) 2174 self.__restoreWatchpoints(debuggerId) 2175 self.passiveDebugStarted.emit(fn, exc) 2176 2177 def __passiveShutDown(self): 2178 """ 2179 Private method to shut down a passive debug connection. 2180 """ 2181 self.passiveClientExited = True 2182 self.shutdownServer() 2183 self.appendStdout.emit(self.tr("Passive debug connection closed\n")) 2184 2185 def __restoreBreakpoints(self, debuggerId=""): 2186 """ 2187 Private method to restore the breakpoints after a restart. 2188 2189 @param debuggerId ID of the debugger backend to send to. If this is 2190 empty, they will be broadcast to all connected backends. 2191 @type str 2192 """ 2193 if self.debugging: 2194 self.__addBreakPoints( 2195 QModelIndex(), 0, self.breakpointModel.rowCount() - 1, 2196 debuggerId) 2197 2198 def __restoreWatchpoints(self, debuggerId=""): 2199 """ 2200 Private method to restore the watch expressions after a restart. 2201 2202 @param debuggerId ID of the debugger backend to send to. If this is 2203 empty, they will be broadcast to all connected backends. 2204 @type str 2205 """ 2206 if self.debugging: 2207 self.__addWatchPoints( 2208 QModelIndex(), 0, self.watchpointModel.rowCount() - 1, 2209 debuggerId) 2210 2211 def getBreakPointModel(self): 2212 """ 2213 Public slot to get a reference to the breakpoint model object. 2214 2215 @return reference to the breakpoint model object 2216 @rtype BreakPointModel 2217 """ 2218 return self.breakpointModel 2219 2220 def getWatchPointModel(self): 2221 """ 2222 Public slot to get a reference to the watch expression model object. 2223 2224 @return reference to the watch expression model object 2225 @rtype WatchPointModel 2226 """ 2227 return self.watchpointModel 2228 2229 def isConnected(self): 2230 """ 2231 Public method to test, if the debug server is connected to a backend. 2232 2233 @return flag indicating a connection 2234 @rtype bool 2235 """ 2236 return self.debuggerInterface and self.debuggerInterface.isConnected() 2237 2238 def isDebugging(self): 2239 """ 2240 Public method to test, if the debug server is debugging. 2241 2242 @return flag indicating the debugging state 2243 @rtype bool 2244 """ 2245 return self.debugging 2246 2247 def setDebugging(self, on): 2248 """ 2249 Public method to set the debugging state. 2250 2251 @param on flag indicating the new debugging state 2252 @type bool 2253 """ 2254 self.debugging = on 2255 2256 def signalClientDebuggerId(self, debuggerId): 2257 """ 2258 Public method to signal the receipt of a new debugger ID. 2259 2260 This signal indicates, that a new debugger backend has connected. 2261 2262 @param debuggerId ID of the newly connected debugger backend 2263 @type str 2264 """ 2265 self.clientDebuggerId.emit(debuggerId) 2266 2267 def getDebuggerIds(self): 2268 """ 2269 Public method to return the IDs of the connected debugger backends. 2270 2271 @return list of connected debugger backend IDs 2272 @rtype list of str 2273 """ 2274 if self.debuggerInterface: 2275 return self.debuggerInterface.getDebuggerIds() 2276 else: 2277 return [] 2278 2279 def initializeClient(self, debuggerId): 2280 """ 2281 Public method to initialize a freshly connected debug client. 2282 2283 @param debuggerId ID of the connected debugger 2284 @type str 2285 """ 2286 self.__restoreBreakpoints(debuggerId) 2287 self.__restoreWatchpoints(debuggerId) 2288 self.__restoreNoDebugList(debuggerId) 2289 2290 def __restoreNoDebugList(self, debuggerId=""): 2291 """ 2292 Private method to restore the list of scripts not to be debugged after 2293 a restart. 2294 2295 @param debuggerId ID of the debugger backend to send to. If this is 2296 empty, they will be broadcast to all connected backends. 2297 @type str 2298 """ 2299 if self.debugging: 2300 self.debuggerInterface.remoteNoDebugList( 2301 debuggerId, self.__multiprocessNoDebugList) 2302