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