eric6/Debugger/DebugServer.py

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

eric ide

mercurial