Tue, 15 Feb 2011 20:04:42 +0100
Forgot a statement in the last change.
# -*- coding: utf-8 -*- # Copyright (c) 2007 - 2011 Detlev Offenbach <detlev@die-offenbachs.de> # """ Module implementing the debug server. """ import os from PyQt4.QtCore import * from PyQt4.QtNetwork import QTcpServer, QHostAddress, QHostInfo from E5Gui.E5Application import e5App from E5Gui import E5MessageBox from .BreakPointModel import BreakPointModel from .WatchPointModel import WatchPointModel from . import DebugClientCapabilities import Preferences import Utilities DebuggerInterfaces = [ "DebuggerInterfacePython", "DebuggerInterfacePython3", "DebuggerInterfaceRuby", "DebuggerInterfaceNone", ] class DebugServer(QTcpServer): """ Class implementing the debug server embedded within the IDE. @signal clientProcessStdout(str) emitted after the client has sent some output via stdout @signal clientProcessStderr(str) emitted after the client has sent some output via stderr @signal clientOutput(str) emitted after the client has sent some output @signal clientRawInputSent() emitted after the data was sent to the debug client @signal clientLine(filename, lineno, forStack) emitted after the debug client has executed a line of code @signal clientStack(stack) emitted after the debug client has executed a line of code @signal clientThreadList(currentId, threadList) emitted after a thread list has been received @signal clientThreadSet() emitted after the client has acknowledged the change of the current thread @signal clientVariables(scope, variables) emitted after a variables dump has been received @signal clientVariable(scope, variables) emitted after a dump for one class variable has been received @signal clientStatement(bool) emitted after an interactive command has been executed. The parameter is 0 to indicate that the command is complete and 1 if it needs more input. @signal clientException(exception) emitted after an exception occured on the client side @signal clientSyntaxError(exception) emitted after a syntax error has been detected on the client side @signal clientExit(int) emitted with the exit status after the client has exited @signal clientClearBreak(filename, lineno) emitted after the debug client has decided to clear a temporary breakpoint @signal clientBreakConditionError(fn, lineno) emitted after the client has signaled a syntax error in a breakpoint condition @signal clientClearWatch(condition) emitted after the debug client has decided to clear a temporary watch expression @signal clientWatchConditionError(condition) emitted after the client has signaled a syntax error in a watch expression @signal clientRawInput(prompt, echo) emitted after a raw input request was received @signal clientBanner(banner) emitted after the client banner was received @signal clientCapabilities(int capabilities, string cltype) emitted after the clients capabilities were received @signal clientCompletionList(completionList, text) emitted after the client the commandline completion list and the reworked searchstring was received from the client @signal passiveDebugStarted(str, bool) emitted after the debug client has connected in passive debug mode @signal clientGone(bool) emitted if the client went away (planned or unplanned) @signal utPrepared(nrTests, exc_type, exc_value) emitted after the client has loaded a unittest suite @signal utFinished() emitted after the client signalled the end of the unittest @signal utStartTest(testname, testdocu) emitted after the client has started a test @signal utStopTest() emitted after the client has finished a test @signal utTestFailed(testname, exc_info) emitted after the client reported a failed test @signal utTestErrored(testname, exc_info) emitted after the client reported an errored test """ clientClearBreak = pyqtSignal(str, int) clientClearWatch = pyqtSignal(str) clientGone = pyqtSignal(bool) clientProcessStdout = pyqtSignal(str) clientProcessStderr = pyqtSignal(str) clientRawInputSent = pyqtSignal() clientOutput = pyqtSignal(str) clientLine = pyqtSignal(str, int, bool) clientStack = pyqtSignal(list) clientThreadList = pyqtSignal(int, list) clientThreadSet = pyqtSignal() clientVariables = pyqtSignal(int, list) clientVariable = pyqtSignal(int, list) clientStatement = pyqtSignal(bool) clientException = pyqtSignal(str, str, list) clientSyntaxError = pyqtSignal(str, str, int, int) clientExit = pyqtSignal(int) clientBreakConditionError = pyqtSignal(str, int) clientWatchConditionError = pyqtSignal(str) clientRawInput = pyqtSignal(str, bool) clientBanner = pyqtSignal(str, str, str) clientCapabilities = pyqtSignal(int, str) clientCompletionList = pyqtSignal(list, str) utPrepared = pyqtSignal(int, str, str) utStartTest = pyqtSignal(str, str) utStopTest = pyqtSignal() utTestFailed = pyqtSignal(str, str) utTestErrored = pyqtSignal(str, str) utFinished = pyqtSignal() passiveDebugStarted = pyqtSignal(str, bool) def __init__(self): """ Constructor """ QTcpServer.__init__(self) # create our models self.breakpointModel = BreakPointModel(self) self.watchpointModel = WatchPointModel(self) self.watchSpecialCreated = \ self.trUtf8("created", "must be same as in EditWatchpointDialog") self.watchSpecialChanged = \ self.trUtf8("changed", "must be same as in EditWatchpointDialog") self.networkInterface = Preferences.getDebugger("NetworkInterface") if self.networkInterface == "all": hostAddress = QHostAddress("0.0.0.0")#QHostAddress.Any) elif self.networkInterface == "allv6": hostAddress = QHostAddress("::")#QHostAddress.AnyIPv6) else: hostAddress = QHostAddress(Preferences.getDebugger("NetworkInterface")) if Preferences.getDebugger("PassiveDbgEnabled"): socket = Preferences.getDebugger("PassiveDbgPort") # default: 42424 self.listen(hostAddress, socket) self.passive = True self.passiveClientExited = False else: self.listen(hostAddress) self.passive = False self.debuggerInterface = None self.debugging = False self.running = False self.clientProcess = None self.clientType = \ Preferences.Prefs.settings.value('DebugClient/Type', 'Python3') self.lastClientType = '' self.__autoClearShell = False self.clientClearBreak.connect(self.__clientClearBreakPoint) self.clientClearWatch.connect(self.__clientClearWatchPoint) self.newConnection[()].connect(self.__newConnection) self.breakpointModel.rowsAboutToBeRemoved.connect(self.__deleteBreakPoints) self.breakpointModel.dataAboutToBeChanged.connect( self.__breakPointDataAboutToBeChanged) self.breakpointModel.dataChanged.connect(self.__changeBreakPoints) self.breakpointModel.rowsInserted.connect(self.__addBreakPoints) self.watchpointModel.rowsAboutToBeRemoved.connect(self.__deleteWatchPoints) self.watchpointModel.dataAboutToBeChanged.connect( self.__watchPointDataAboutToBeChanged) self.watchpointModel.dataChanged.connect(self.__changeWatchPoints) self.watchpointModel.rowsInserted.connect(self.__addWatchPoints) self.__registerDebuggerInterfaces() def getHostAddress(self, localhost): """ Public method to get the IP address or hostname the debug server is listening. @param localhost flag indicating to return the address for localhost (boolean) @return IP address or hostname (string) """ if self.networkInterface == "all": if localhost: return "127.0.0.1" else: return "{0}@@v4".format(QHostInfo.localHostName()) elif self.networkInterface == "allv6": if localhost: return "::1" else: return "{0}@@v6".format(QHostInfo.localHostName()) else: return self.networkInterface def preferencesChanged(self): """ Public slot to handle the preferencesChanged signal. """ self.__registerDebuggerInterfaces() def __registerDebuggerInterfaces(self): """ Private method to register the available debugger interface modules. """ self.__clientCapabilities = {} self.__clientAssociations = {} for interface in DebuggerInterfaces: modName = "Debugger.{0}".format(interface) mod = __import__(modName) components = modName.split('.') for comp in components[1:]: mod = getattr(mod, comp) clientLanguage, clientCapabilities, clientExtensions = \ mod.getRegistryData() if clientLanguage: self.__clientCapabilities[clientLanguage] = clientCapabilities for extension in clientExtensions: if extension not in self.__clientAssociations: self.__clientAssociations[extension] = clientLanguage def getSupportedLanguages(self, shellOnly = False): """ Public slot to return the supported programming languages. @param shellOnly flag indicating only languages supporting an interactive shell should be returned @return list of supported languages (list of strings) """ languages = list(self.__clientCapabilities.keys()) try: del languages[languages.index("None")] except ValueError: pass # it is not in the list if shellOnly: languages = \ [lang for lang in languages \ if self.__clientCapabilities[lang] & DebugClientCapabilities.HasShell] return languages[:] def getExtensions(self, language): """ Public slot to get the extensions associated with the given language. @param language language to get extensions for (string) @return tuple of extensions associated with the language (tuple of strings) """ extensions = [] for ext, lang in list(self.__clientAssociations.items()): if lang == language: extensions.append(ext) return tuple(extensions) def __createDebuggerInterface(self, clientType = None): """ Private slot to create the debugger interface object. @param clientType type of the client interface to be created (string) """ if self.lastClientType != self.clientType or clientType is not None: if clientType is None: clientType = self.clientType if clientType == "Python2": from .DebuggerInterfacePython import DebuggerInterfacePython self.debuggerInterface = DebuggerInterfacePython(self, self.passive) elif clientType == "Python3": from .DebuggerInterfacePython3 import DebuggerInterfacePython3 self.debuggerInterface = DebuggerInterfacePython3(self, self.passive) elif clientType == "Ruby": from .DebuggerInterfaceRuby import DebuggerInterfaceRuby self.debuggerInterface = DebuggerInterfaceRuby(self, self.passive) elif clientType == "None": from .DebuggerInterfaceNone import DebuggerInterfaceNone self.debuggerInterface = DebuggerInterfaceNone(self, self.passive) else: from .DebuggerInterfaceNone import DebuggerInterfaceNone self.debuggerInterface = DebuggerInterfaceNone(self, self.passive) self.clientType = "None" def __setClientType(self, clType): """ Private method to set the client type. @param clType type of client to be started (string) """ if clType is not None and clType in self.getSupportedLanguages(): self.clientType = clType Preferences.Prefs.settings.setValue('DebugClient/Type', self.clientType) def startClient(self, unplanned = True, clType = None, forProject = False, runInConsole = False): """ Public method to start a debug client. @keyparam unplanned flag indicating that the client has died (boolean) @keyparam clType type of client to be started (string) @keyparam forProject flag indicating a project related action (boolean) @keyparam runInConsole flag indicating to start the debugger in a console window (boolean) """ self.running = False if not self.passive or not self.passiveClientExited: if self.debuggerInterface and self.debuggerInterface.isConnected(): self.shutdownServer() self.clientGone.emit(unplanned and self.debugging) if clType: self.__setClientType(clType) # only start the client, if we are not in passive mode if not self.passive: if self.clientProcess: self.clientProcess.readyReadStandardError.disconnect( self.__clientProcessError) self.clientProcess.readyReadStandardOutput.disconnect( self.__clientProcessOutput) self.clientProcess.close() self.clientProcess.kill() self.clientProcess.waitForFinished(10000) self.clientProcess = None self.__createDebuggerInterface() if forProject: project = e5App().getObject("Project") if not project.isDebugPropertiesLoaded(): self.clientProcess, isNetworked = \ self.debuggerInterface.startRemote(self.serverPort(), runInConsole) else: self.clientProcess, isNetworked = \ self.debuggerInterface.startRemoteForProject(self.serverPort(), runInConsole) else: self.clientProcess, isNetworked = \ self.debuggerInterface.startRemote(self.serverPort(), runInConsole) if self.clientProcess: self.clientProcess.readyReadStandardError.connect( self.__clientProcessError) self.clientProcess.readyReadStandardOutput.connect( self.__clientProcessOutput) if not isNetworked: # the client is connected through stdin and stdout # Perform actions necessary, if client type has changed if self.lastClientType != self.clientType: self.lastClientType = self.clientType self.remoteBanner() elif self.__autoClearShell: self.__autoClearShell = False self.remoteBanner() self.debuggerInterface.flush() else: self.__createDebuggerInterface("None") def __clientProcessOutput(self): """ Private slot to process client output received via stdout. """ output = str(self.clientProcess.readAllStandardOutput(), Preferences.getSystem("IOEncoding"), 'replace') self.clientProcessStdout.emit(output) def __clientProcessError(self): """ Private slot to process client output received via stderr. """ error = str(self.clientProcess.readAllStandardError(), Preferences.getSystem("IOEncoding"), 'replace') self.clientProcessStderr.emit(error) def __clientClearBreakPoint(self, fn, lineno): """ Private slot to handle the clientClearBreak signal. @param fn filename of breakpoint to clear (string) @param lineno line number of breakpoint to clear (integer) """ if self.debugging: index = self.breakpointModel.getBreakPointIndex(fn, lineno) self.breakpointModel.deleteBreakPointByIndex(index) def __deleteBreakPoints(self, parentIndex, start, end): """ Private slot to delete breakpoints. @param parentIndex index of parent item (QModelIndex) @param start start row (integer) @param end end row (integer) """ if self.debugging: for row in range(start, end+1): index = self.breakpointModel.index(row, 0, parentIndex) fn, lineno = self.breakpointModel.getBreakPointByIndex(index)[0:2] self.remoteBreakpoint(fn, lineno, False) def __changeBreakPoints(self, startIndex, endIndex): """ Private slot to set changed breakpoints. @param indexes indexes of changed breakpoints. """ if self.debugging: self.__addBreakPoints(QModelIndex(), startIndex.row(), endIndex.row()) def __breakPointDataAboutToBeChanged(self, startIndex, endIndex): """ Private slot to handle the dataAboutToBeChanged signal of the breakpoint model. @param startIndex start index of the rows to be changed (QModelIndex) @param endIndex end index of the rows to be changed (QModelIndex) """ if self.debugging: self.__deleteBreakPoints(QModelIndex(), startIndex.row(), endIndex.row()) def __addBreakPoints(self, parentIndex, start, end): """ Private slot to add breakpoints. @param parentIndex index of parent item (QModelIndex) @param start start row (integer) @param end end row (integer) """ if self.debugging: for row in range(start, end+1): index = self.breakpointModel.index(row, 0, parentIndex) fn, line, cond, temp, enabled, ignorecount = \ self.breakpointModel.getBreakPointByIndex(index)[:6] self.remoteBreakpoint(fn, line, True, cond, temp) if not enabled: self.__remoteBreakpointEnable(fn, line, False) if ignorecount: self.__remoteBreakpointIgnore(fn, line, ignorecount) def __makeWatchCondition(self, cond, special): """ Private method to construct the condition string. @param cond condition (string) @param special special condition (string) @return condition string (string) """ if special == "": _cond = cond else: if special == self.watchSpecialCreated: _cond = "{0} ??created??".format(cond) elif special == self.watchSpecialChanged: _cond = "{0} ??changed??".format(cond) return _cond def __splitWatchCondition(self, cond): """ Private method to split a remote watch expression. @param cond remote expression (string) @return tuple of local expression (string) and special condition (string) """ if cond.endswith(" ??created??"): cond, special = cond.split() special = self.watchSpecialCreated elif cond.endswith(" ??changed??"): cond, special = cond.split() special = self.watchSpecialChanged else: cond = cond special = "" return cond, special def __clientClearWatchPoint(self, condition): """ Private slot to handle the clientClearWatch signal. @param condition expression of watch expression to clear (string) """ if self.debugging: cond, special = self.__splitWatchCondition(condition) index = self.watchpointModel.getWatchPointIndex(cond, special) self.watchpointModel.deleteWatchPointByIndex(index) def __deleteWatchPoints(self, parentIndex, start, end): """ Private slot to delete watch expressions. @param parentIndex index of parent item (QModelIndex) @param start start row (integer) @param end end row (integer) """ if self.debugging: for row in range(start, end+1): index = self.watchpointModel.index(row, 0, parentIndex) cond, special = self.watchpointModel.getWatchPointByIndex(index)[0:2] cond = self.__makeWatchCondition(cond, special) self.__remoteWatchpoint(cond, False) def __watchPointDataAboutToBeChanged(self, startIndex, endIndex): """ Private slot to handle the dataAboutToBeChanged signal of the watch expression model. @param startIndex start index of the rows to be changed (QModelIndex) @param endIndex end index of the rows to be changed (QModelIndex) """ if self.debugging: self.__deleteWatchPoints(QModelIndex(), startIndex.row(), endIndex.row()) def __addWatchPoints(self, parentIndex, start, end): """ Private slot to set a watch expression. @param parentIndex index of parent item (QModelIndex) @param start start row (integer) @param end end row (integer) """ if self.debugging: for row in range(start, end + 1): index = self.watchpointModel.index(row, 0, parentIndex) cond, special, temp, enabled, ignorecount = \ self.watchpointModel.getWatchPointByIndex(index)[:5] cond = self.__makeWatchCondition(cond, special) self.__remoteWatchpoint(cond, True, temp) if not enabled: self.__remoteWatchpointEnable(cond, False) if ignorecount: self.__remoteWatchpointIgnore(cond, ignorecount) def __changeWatchPoints(self, startIndex, endIndex): """ Private slot to set changed watch expressions. @param startIndex start index of the rows to be changed (QModelIndex) @param endIndex end index of the rows to be changed (QModelIndex) """ if self.debugging: self.__addWatchPoints(QModelIndex(), startIndex.row(), endIndex.row()) def getClientCapabilities(self, type): """ Public method to retrieve the debug clients capabilities. @param type debug client type (string) @return debug client capabilities (integer) """ try: return self.__clientCapabilities[type] except KeyError: return 0 # no capabilities def __newConnection(self): """ Private slot to handle a new connection. """ sock = self.nextPendingConnection() peerAddress = sock.peerAddress().toString() if peerAddress not in Preferences.getDebugger("AllowedHosts"): # the peer is not allowed to connect res = E5MessageBox.yesNo(None, self.trUtf8("Connection from illegal host"), self.trUtf8("""<p>A connection was attempted by the""" """ illegal host <b>{0}</b>. Accept this connection?</p>""")\ .format(peerAddress), icon = E5MessageBox.Warning) if not res: sock.abort() return else: allowedHosts = Preferences.getDebugger("AllowedHosts") allowedHosts.append(peerAddress) Preferences.setDebugger("AllowedHosts", allowedHosts) if self.passive: self.__createDebuggerInterface(Preferences.getDebugger("PassiveDbgType")) accepted = self.debuggerInterface.newConnection(sock) if accepted: # Perform actions necessary, if client type has changed if self.lastClientType != self.clientType: self.lastClientType = self.clientType self.remoteBanner() elif self.__autoClearShell: self.__autoClearShell = False self.remoteBanner() elif self.passive: self.remoteBanner() self.debuggerInterface.flush() def shutdownServer(self): """ Public method to cleanly shut down. It closes our socket and shuts down the debug client. (Needed on Win OS) """ if self.debuggerInterface is not None: self.debuggerInterface.shutdown() def remoteEnvironment(self, env): """ Public method to set the environment for a program to debug, run, ... @param env environment settings (string) """ envlist = Utilities.parseEnvironmentString(env) envdict = {} for el in envlist: try: key, value = el.split('=', 1) if value.startswith('"') or value.startswith("'"): value = value[1:-1] envdict[key] = value except UnpackError: pass self.debuggerInterface.remoteEnvironment(envdict) def remoteLoad(self, fn, argv, wd, env, autoClearShell = True, tracePython = False, autoContinue = True, forProject = False, runInConsole = False, autoFork = False, forkChild = False, clientType = ""): """ Public method to load a new program to debug. @param fn the filename to debug (string) @param argv the commandline arguments to pass to the program (string) @param wd the working directory for the program (string) @param env environment settings (string) @keyparam autoClearShell flag indicating, that the interpreter window should be cleared (boolean) @keyparam tracePython flag indicating if the Python library should be traced as well (boolean) @keyparam autoContinue flag indicating, that the debugger should not stop at the first executable line (boolean) @keyparam forProject flag indicating a project related action (boolean) @keyparam runInConsole flag indicating to start the debugger in a console window (boolean) @keyparam autoFork flag indicating the automatic fork mode (boolean) @keyparam forkChild flag indicating to debug the child after forking (boolean) @keyparam clientType client type to be used (string) """ self.__autoClearShell = autoClearShell self.__autoContinue = autoContinue # Restart the client try: if clientType: self.__setClientType(clientType) else: self.__setClientType(self.__clientAssociations[os.path.splitext(fn)[1]]) except KeyError: self.__setClientType('Python3') # assume it is a Python3 file self.startClient(False, forProject = forProject, runInConsole = runInConsole) self.remoteEnvironment(env) self.debuggerInterface.remoteLoad(fn, argv, wd, tracePython, autoContinue, autoFork, forkChild) self.debugging = True self.running = True self.__restoreBreakpoints() self.__restoreWatchpoints() def remoteRun(self, fn, argv, wd, env, autoClearShell = True, forProject = False, runInConsole = False, autoFork = False, forkChild = False, clientType = ""): """ Public method to load a new program to run. @param fn the filename to run (string) @param argv the commandline arguments to pass to the program (string) @param wd the working directory for the program (string) @param env environment settings (string) @keyparam autoClearShell flag indicating, that the interpreter window should be cleared (boolean) @keyparam forProject flag indicating a project related action (boolean) @keyparam runInConsole flag indicating to start the debugger in a console window (boolean) @keyparam autoFork flag indicating the automatic fork mode (boolean) @keyparam forkChild flag indicating to debug the child after forking (boolean) @keyparam clientType client type to be used (string) """ self.__autoClearShell = autoClearShell # Restart the client try: if clientType: self.__setClientType(clientType) else: self.__setClientType(self.__clientAssociations[os.path.splitext(fn)[1]]) except KeyError: self.__setClientType('Python3') # assume it is a Python3 file self.startClient(False, forProject = forProject, runInConsole = runInConsole) self.remoteEnvironment(env) self.debuggerInterface.remoteRun(fn, argv, wd, autoFork, forkChild) self.debugging = False self.running = True def remoteCoverage(self, fn, argv, wd, env, autoClearShell = True, erase = False, forProject = False, runInConsole = False, clientType = ""): """ Public method to load a new program to collect coverage data. @param fn the filename to run (string) @param argv the commandline arguments to pass to the program (string) @param wd the working directory for the program (string) @param env environment settings (string) @keyparam autoClearShell flag indicating, that the interpreter window should be cleared (boolean) @keyparam erase flag indicating that coverage info should be cleared first (boolean) @keyparam forProject flag indicating a project related action (boolean) @keyparam runInConsole flag indicating to start the debugger in a console window (boolean) @keyparam clientType client type to be used (string) """ self.__autoClearShell = autoClearShell # Restart the client try: if clientType: self.__setClientType(clientType) else: self.__setClientType(self.__clientAssociations[os.path.splitext(fn)[1]]) except KeyError: self.__setClientType('Python3') # assume it is a Python3 file self.startClient(False, forProject = forProject, runInConsole = runInConsole) self.remoteEnvironment(env) self.debuggerInterface.remoteCoverage(fn, argv, wd, erase) self.debugging = False self.running = True def remoteProfile(self, fn, argv, wd, env, autoClearShell = True, erase = False, forProject = False, runInConsole = False, clientType = ""): """ Public method to load a new program to collect profiling data. @param fn the filename to run (string) @param argv the commandline arguments to pass to the program (string) @param wd the working directory for the program (string) @param env environment settings (string) @keyparam autoClearShell flag indicating, that the interpreter window should be cleared (boolean) @keyparam erase flag indicating that timing info should be cleared first (boolean) @keyparam forProject flag indicating a project related action (boolean) @keyparam runInConsole flag indicating to start the debugger in a console window (boolean) @keyparam clientType client type to be used (string) """ self.__autoClearShell = autoClearShell # Restart the client try: if clientType: self.__setClientType(clientType) else: self.__setClientType(self.__clientAssociations[os.path.splitext(fn)[1]]) except KeyError: self.__setClientType('Python3') # assume it is a Python3 file self.startClient(False, forProject = forProject, runInConsole = runInConsole) self.remoteEnvironment(env) self.debuggerInterface.remoteProfile(fn, argv, wd, erase) self.debugging = False self.running = True def remoteStatement(self, stmt): """ Public method to execute a Python statement. @param stmt the Python statement to execute (string). It should not have a trailing newline. """ self.debuggerInterface.remoteStatement(stmt) def remoteStep(self): """ Public method to single step the debugged program. """ self.debuggerInterface.remoteStep() def remoteStepOver(self): """ Public method to step over the debugged program. """ self.debuggerInterface.remoteStepOver() def remoteStepOut(self): """ Public method to step out the debugged program. """ self.debuggerInterface.remoteStepOut() def remoteStepQuit(self): """ Public method to stop the debugged program. """ self.debuggerInterface.remoteStepQuit() def remoteContinue(self, special = False): """ Public method to continue the debugged program. @param special flag indicating a special continue operation """ self.debuggerInterface.remoteContinue(special) def remoteBreakpoint(self, fn, line, set, cond=None, temp=False): """ Public method to set or clear a breakpoint. @param fn filename the breakpoint belongs to (string) @param line linenumber of the breakpoint (int) @param set flag indicating setting or resetting a breakpoint (boolean) @param cond condition of the breakpoint (string) @param temp flag indicating a temporary breakpoint (boolean) """ self.debuggerInterface.remoteBreakpoint(fn, line, set, cond, temp) def __remoteBreakpointEnable(self, fn, line, enable): """ Private method to enable or disable a breakpoint. @param fn filename the breakpoint belongs to (string) @param line linenumber of the breakpoint (int) @param enable flag indicating enabling or disabling a breakpoint (boolean) """ self.debuggerInterface.remoteBreakpointEnable(fn, line, enable) def __remoteBreakpointIgnore(self, fn, line, count): """ Private method to ignore a breakpoint the next couple of occurrences. @param fn filename the breakpoint belongs to (string) @param line linenumber of the breakpoint (int) @param count number of occurrences to ignore (int) """ self.debuggerInterface.remoteBreakpointIgnore(fn, line, count) def __remoteWatchpoint(self, cond, set, temp = False): """ Private method to set or clear a watch expression. @param cond expression of the watch expression (string) @param set flag indicating setting or resetting a watch expression (boolean) @param temp flag indicating a temporary watch expression (boolean) """ # cond is combination of cond and special (s. watch expression viewer) self.debuggerInterface.remoteWatchpoint(cond, set, temp) def __remoteWatchpointEnable(self, cond, enable): """ Private method to enable or disable a watch expression. @param cond expression of the watch expression (string) @param enable flag indicating enabling or disabling a watch expression (boolean) """ # cond is combination of cond and special (s. watch expression viewer) self.debuggerInterface.remoteWatchpointEnable(cond, enable) def __remoteWatchpointIgnore(self, cond, count): """ Private method to ignore a watch expression the next couple of occurrences. @param cond expression of the watch expression (string) @param count number of occurrences to ignore (int) """ # cond is combination of cond and special (s. watch expression viewer) self.debuggerInterface.remoteWatchpointIgnore(cond, count) def remoteRawInput(self,s): """ Public method to send the raw input to the debugged program. @param s the raw input (string) """ self.debuggerInterface.remoteRawInput(s) self.clientRawInputSent.emit() def remoteThreadList(self): """ Public method to request the list of threads from the client. """ self.debuggerInterface.remoteThreadList() def remoteSetThread(self, tid): """ Public method to request to set the given thread as current thread. @param tid id of the thread (integer) """ self.debuggerInterface.remoteSetThread(tid) def remoteClientVariables(self, scope, filter, framenr = 0): """ Public method to request the variables of the debugged program. @param scope the scope of the variables (0 = local, 1 = global) @param filter list of variable types to filter out (list of int) @param framenr framenumber of the variables to retrieve (int) """ self.debuggerInterface.remoteClientVariables(scope, filter, framenr) def remoteClientVariable(self, scope, filter, var, framenr = 0): """ Public method to request the variables of the debugged program. @param scope the scope of the variables (0 = local, 1 = global) @param filter list of variable types to filter out (list of int) @param var list encoded name of variable to retrieve (string) @param framenr framenumber of the variables to retrieve (int) """ self.debuggerInterface.remoteClientVariable(scope, filter, var, framenr) def remoteClientSetFilter(self, scope, filter): """ Public method to set a variables filter list. @param scope the scope of the variables (0 = local, 1 = global) @param filter regexp string for variable names to filter out (string) """ self.debuggerInterface.remoteClientSetFilter(scope, filter) def remoteEval(self, arg): """ Public method to evaluate arg in the current context of the debugged program. @param arg the arguments to evaluate (string) """ self.debuggerInterface.remoteEval(arg) def remoteExec(self, stmt): """ Public method to execute stmt in the current context of the debugged program. @param stmt statement to execute (string) """ self.debuggerInterface.remoteExec(stmt) def remoteBanner(self): """ Public slot to get the banner info of the remote client. """ self.debuggerInterface.remoteBanner() def remoteCapabilities(self): """ Public slot to get the debug clients capabilities. """ self.debuggerInterface.remoteCapabilities() def remoteCompletion(self, text): """ Public slot to get the a list of possible commandline completions from the remote client. @param text the text to be completed (string) """ self.debuggerInterface.remoteCompletion(text) def remoteUTPrepare(self, fn, tn, tfn, cov, covname, coverase): """ Public method to prepare a new unittest run. @param fn the filename to load (string) @param tn the testname to load (string) @param tfn the test function name to load tests from (string) @param cov flag indicating collection of coverage data is requested @param covname filename to be used to assemble the coverage caches filename (string) @param coverase flag indicating erasure of coverage data is requested (boolean) """ # Restart the client if there is already a program loaded. try: self.__setClientType(self.__clientAssociations[os.path.splitext(fn)[1]]) except KeyError: self.__setClientType('Python3') # assume it is a Python3 file self.startClient(False) self.debuggerInterface.remoteUTPrepare(fn, tn, tfn, cov, covname, coverase) self.debugging = False self.running = True def remoteUTRun(self): """ Public method to start a unittest run. """ self.debuggerInterface.remoteUTRun() def remoteUTStop(self): """ public method to stop a unittest run. """ self.debuggerInterface.remoteUTStop() def signalClientOutput(self, line): """ Public method to process a line of client output. @param line client output (string) """ self.clientOutput.emit(line) def signalClientLine(self, filename, lineno, forStack = False): """ Public method to process client position feedback. @param filename name of the file currently being executed (string) @param lineno line of code currently being executed (integer) @param forStack flag indicating this is for a stack dump (boolean) """ self.clientLine.emit(filename, lineno, forStack) def signalClientStack(self, stack): """ Public method to process a client's stack information. @param stack list of stack entries. Each entry is a tuple of three values giving the filename, linenumber and method (list of lists of (string, integer, string)) """ self.clientStack.emit(stack) def signalClientThreadList(self, currentId, threadList): """ Public method to process the client thread list info. @param currentID id of the current thread (integer) @param threadList list of dictionaries containing the thread data """ self.clientThreadList.emit(currentId, threadList) def signalClientThreadSet(self): """ Public method to handle the change of the client thread. """ self.clientThreadSet.emit() def signalClientVariables(self, scope, variables): """ Public method to process the client variables info. @param scope scope of the variables (-1 = empty global, 1 = global, 0 = local) @param variables the list of variables from the client """ self.clientVariables.emit(scope, variables) def signalClientVariable(self, scope, variables): """ Public method to process the client variable info. @param scope scope of the variables (-1 = empty global, 1 = global, 0 = local) @param variables the list of members of a classvariable from the client """ self.clientVariable.emit(scope, variables) def signalClientStatement(self, more): """ Public method to process the input response from the client. @param more flag indicating that more user input is required """ self.clientStatement.emit(more) def signalClientException(self, exceptionType, exceptionMessage, stackTrace): """ Public method to process the exception info from the client. @param exceptionType type of exception raised (string) @param exceptionMessage message given by the exception (string) @param stackTrace list of stack entries with the exception position first. Each stack entry is a list giving the filename and the linenumber. """ if self.running: self.clientException.emit(exceptionType, exceptionMessage, stackTrace) def signalClientSyntaxError(self, message, filename, lineNo, characterNo): """ Public method to process the syntax error info from the client. @param message message of the syntax error (string) @param filename translated filename of the syntax error position (string) @param lineNo line number of the syntax error position (integer) @param characterNo character number of the syntax error position (integer) """ if self.running: self.clientSyntaxError.emit(message, filename, lineNo, characterNo) def signalClientExit(self, status): """ Public method to process the client exit status. @param status exit code as a string (string) """ if self.passive: self.__passiveShutDown() self.clientExit.emit(int(status)) if Preferences.getDebugger("AutomaticReset"): self.startClient(False) if self.passive: self.__createDebuggerInterface("None") self.signalClientOutput(self.trUtf8('\nNot connected\n')) self.signalClientStatement(False) self.running = False def signalClientClearBreak(self, filename, lineno): """ Public method to process the client clear breakpoint command. @param filename filename of the breakpoint (string) @param lineno line umber of the breakpoint (integer) """ self.clientClearBreak.emit(filename, lineno) def signalClientBreakConditionError(self, filename, lineno): """ Public method to process the client breakpoint condition error info. @param filename filename of the breakpoint (string) @param lineno line umber of the breakpoint (integer) """ self.clientBreakConditionError.emit(filename, lineno) def signalClientClearWatch(self, condition): """ Public slot to handle the clientClearWatch signal. @param condition expression of watch expression to clear (string) """ self.clientClearWatch.emit(condition) def signalClientWatchConditionError(self, condition): """ Public method to process the client watch expression error info. @param condition expression of watch expression to clear (string) """ self.clientWatchConditionError.emit(condition) def signalClientRawInput(self, prompt, echo): """ Public method to process the client raw input command. @param prompt the input prompt (string) @param echo flag indicating an echoing of the input (boolean) """ self.clientRawInput.emit(prompt, echo) def signalClientBanner(self, version, platform, debugClient): """ Public method to process the client banner info. @param version interpreter version info (string) @param platform hostname of the client (string) @param debugClient additional debugger type info (string) """ self.clientBanner.emit(version, platform, debugClient) def signalClientCapabilities(self, capabilities, clientType): """ Public method to process the client capabilities info. @param capabilities bitmaks with the client capabilities (integer) @param clientType type of the debug client (string) """ self.__clientCapabilities[clientType] = capabilities self.clientCapabilities.emit(capabilities, clientType) def signalClientCompletionList(self, completionList, text): """ Public method to process the client auto completion info. @param completionList list of possible completions (list of strings) @param text the text to be completed (string) """ self.clientCompletionList.emit(completionList, text) def clientUtPrepared(self, result, exceptionType, exceptionValue): """ Public method to process the client unittest prepared info. @param result number of test cases (0 = error) (integer) @param exceptionType exception type (string) @param exceptionValue exception message (string) """ self.utPrepared.emit(result, exceptionType, exceptionValue) def clientUtStartTest(self, testname, doc): """ Public method to process the client start test info. @param testname name of the test (string) @param doc short description of the test (string) """ self.utStartTest.emit(testname, doc) def clientUtStopTest(self): """ Public method to process the client stop test info. """ self.utStopTest.emit() def clientUtTestFailed(self, testname, traceback): """ Public method to process the client test failed info. @param testname name of the test (string) @param traceback lines of traceback info (string) """ self.utTestFailed.emit(testname, traceback) def clientUtTestErrored(self, testname, traceback): """ Public method to process the client test errored info. @param testname name of the test (string) @param traceback lines of traceback info (string) """ self.utTestErrored.emit(testname, traceback) def clientUtFinished(self): """ Public method to process the client unit test finished info. """ self.utFinished.emit() def passiveStartUp(self, fn, exc): """ Public method to handle a passive debug connection. @param fn filename of the debugged script (string) @param exc flag to enable exception reporting of the IDE (boolean) """ print(self.trUtf8("Passive debug connection received")) self.passiveClientExited = False self.debugging = True self.running = True self.__restoreBreakpoints() self.__restoreWatchpoints() self.passiveDebugStarted.emit(fn, exc) def __passiveShutDown(self): """ Private method to shut down a passive debug connection. """ self.passiveClientExited = True self.shutdownServer() print(self.trUtf8("Passive debug connection closed")) def __restoreBreakpoints(self): """ Private method to restore the breakpoints after a restart. """ if self.debugging: self.__addBreakPoints(QModelIndex(), 0, self.breakpointModel.rowCount()-1) def __restoreWatchpoints(self): """ Private method to restore the watch expressions after a restart. """ if self.debugging: self.__addWatchPoints(QModelIndex(), 0, self.watchpointModel.rowCount()-1) def getBreakPointModel(self): """ Public slot to get a reference to the breakpoint model object. @return reference to the breakpoint model object (BreakPointModel) """ return self.breakpointModel def getWatchPointModel(self): """ Public slot to get a reference to the watch expression model object. @return reference to the watch expression model object (WatchPointModel) """ return self.watchpointModel def isConnected(self): """ Public method to test, if the debug server is connected to a backend. @return flag indicating a connection (boolean) """ return self.debuggerInterface and self.debuggerInterface.isConnected()