"Fossies" - the Fresh Open Source Software Archive

Member "eric6-20.9/eric/eric6/Debugger/DebugServer.py" (4 Jul 2020, 72829 Bytes) of package /linux/misc/eric6-20.9.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. For more information about "DebugServer.py" see the Fossies "Dox" file reference documentation.

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