Debugger/DebugServer.py

changeset 0
de9c2efb9d02
child 7
c679fb30c8f3
equal deleted inserted replaced
-1:000000000000 0:de9c2efb9d02
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2007 - 2009 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing the debug server.
8 """
9
10 import sys
11 import os
12 import time
13 import signal
14
15 from PyQt4.QtCore import *
16 from PyQt4.QtGui import QMessageBox
17 from PyQt4.QtNetwork import QTcpServer, QHostAddress, QHostInfo
18
19 from E4Gui.E4Application import e4App
20
21 from BreakPointModel import BreakPointModel
22 from WatchPointModel import WatchPointModel
23 import DebugClientCapabilities
24
25 import Preferences
26 import Utilities
27
28
29 DebuggerInterfaces = [
30 "DebuggerInterfacePython",
31 "DebuggerInterfacePython3",
32 "DebuggerInterfaceRuby",
33 "DebuggerInterfaceNone",
34 ]
35
36 class DebugServer(QTcpServer):
37 """
38 Class implementing the debug server embedded within the IDE.
39
40 @signal clientProcessStdout emitted after the client has sent some output
41 via stdout
42 @signal clientProcessStderr emitted after the client has sent some output
43 via stderr
44 @signal clientOutput emitted after the client has sent some output
45 @signal clientRawInputSent emitted after the data was sent to the debug client
46 @signal clientLine(filename, lineno, forStack) emitted after the debug client
47 has executed a line of code
48 @signal clientStack(stack) emitted after the debug client has executed a
49 line of code
50 @signal clientThreadList(currentId, threadList) emitted after a thread list
51 has been received
52 @signal clientThreadSet emitted after the client has acknowledged the change
53 of the current thread
54 @signal clientVariables(scope, variables) emitted after a variables dump has
55 been received
56 @signal clientVariable(scope, variables) emitted after a dump for one class
57 variable has been received
58 @signal clientStatement(boolean) emitted after an interactive command has
59 been executed. The parameter is 0 to indicate that the command is
60 complete and 1 if it needs more input.
61 @signal clientException(exception) emitted after an exception occured on the
62 client side
63 @signal clientSyntaxError(exception) emitted after a syntax error has been detected
64 on the client side
65 @signal clientExit(int) emitted with the exit status after the client has exited
66 @signal clientClearBreak(filename, lineno) emitted after the debug client
67 has decided to clear a temporary breakpoint
68 @signal clientBreakConditionError(fn, lineno) emitted after the client has signaled
69 a syntax error in a breakpoint condition
70 @signal clientClearWatch(condition) emitted after the debug client
71 has decided to clear a temporary watch expression
72 @signal clientWatchConditionError(condition) emitted after the client has signaled
73 a syntax error in a watch expression
74 @signal clientRawInput(prompt, echo) emitted after a raw input request was received
75 @signal clientBanner(banner) emitted after the client banner was received
76 @signal clientCapabilities(int capabilities, QString cltype) emitted after the clients
77 capabilities were received
78 @signal clientCompletionList(completionList, text) emitted after the client
79 the commandline completion list and the reworked searchstring was
80 received from the client
81 @signal passiveDebugStarted emitted after the debug client has connected in
82 passive debug mode
83 @signal clientGone emitted if the client went away (planned or unplanned)
84 @signal utPrepared(nrTests, exc_type, exc_value) emitted after the client has
85 loaded a unittest suite
86 @signal utFinished emitted after the client signalled the end of the unittest
87 @signal utStartTest(testname, testdocu) emitted after the client has started
88 a test
89 @signal utStopTest emitted after the client has finished a test
90 @signal utTestFailed(testname, exc_info) emitted after the client reported
91 a failed test
92 @signal utTestErrored(testname, exc_info) emitted after the client reported
93 an errored test
94 """
95 def __init__(self):
96 """
97 Constructor
98 """
99 QTcpServer.__init__(self)
100
101 # create our models
102 self.breakpointModel = BreakPointModel(self)
103 self.watchpointModel = WatchPointModel(self)
104 self.watchSpecialCreated = \
105 self.trUtf8("created", "must be same as in EditWatchpointDialog")
106 self.watchSpecialChanged = \
107 self.trUtf8("changed", "must be same as in EditWatchpointDialog")
108
109 self.networkInterface = Preferences.getDebugger("NetworkInterface")
110 if self.networkInterface == "all":
111 hostAddress = QHostAddress("0.0.0.0")#QHostAddress.Any)
112 elif self.networkInterface == "allv6":
113 hostAddress = QHostAddress("::")#QHostAddress.AnyIPv6)
114 else:
115 hostAddress = QHostAddress(Preferences.getDebugger("NetworkInterface"))
116 if Preferences.getDebugger("PassiveDbgEnabled"):
117 socket = Preferences.getDebugger("PassiveDbgPort") # default: 42424
118 self.listen(hostAddress, socket)
119 self.passive = True
120 self.passiveClientExited = False
121 else:
122 self.listen(hostAddress)
123 self.passive = False
124
125 self.debuggerInterface = None
126 self.debugging = False
127 self.clientProcess = None
128 self.clientType = \
129 Preferences.Prefs.settings.value('DebugClient/Type',
130 QVariant('Python')).toString()
131 self.lastClientType = ''
132 self.__autoClearShell = False
133
134 self.connect(self, SIGNAL("clientClearBreak"), self.__clientClearBreakPoint)
135 self.connect(self, SIGNAL("clientClearWatch"), self.__clientClearWatchPoint)
136 self.connect(self, SIGNAL("newConnection()"), self.__newConnection)
137
138 self.connect(self.breakpointModel,
139 SIGNAL("rowsAboutToBeRemoved(const QModelIndex &, int, int)"),
140 self.__deleteBreakPoints)
141 self.connect(self.breakpointModel,
142 SIGNAL("dataAboutToBeChanged(const QModelIndex &, const QModelIndex &)"),
143 self.__breakPointDataAboutToBeChanged)
144 self.connect(self.breakpointModel,
145 SIGNAL("dataChanged(const QModelIndex &, const QModelIndex &)"),
146 self.__changeBreakPoints)
147 self.connect(self.breakpointModel,
148 SIGNAL("rowsInserted(const QModelIndex &, int, int)"),
149 self.__addBreakPoints)
150
151 self.connect(self.watchpointModel,
152 SIGNAL("rowsAboutToBeRemoved(const QModelIndex &, int, int)"),
153 self.__deleteWatchPoints)
154 self.connect(self.watchpointModel,
155 SIGNAL("dataAboutToBeChanged(const QModelIndex &, const QModelIndex &)"),
156 self.__watchPointDataAboutToBeChanged)
157 self.connect(self.watchpointModel,
158 SIGNAL("dataChanged(const QModelIndex &, const QModelIndex &)"),
159 self.__changeWatchPoints)
160 self.connect(self.watchpointModel,
161 SIGNAL("rowsInserted(const QModelIndex &, int, int)"),
162 self.__addWatchPoints)
163
164 self.__registerDebuggerInterfaces()
165
166 def getHostAddress(self, localhost):
167 """
168 Public method to get the IP address or hostname the debug server is listening.
169
170 @param localhost flag indicating to return the address for localhost (boolean)
171 @return IP address or hostname (string)
172 """
173 if self.networkInterface == "all":
174 if localhost:
175 return "127.0.0.1"
176 else:
177 return "%s@@v4" % QHostInfo.localHostName()
178 elif self.networkInterface == "allv6":
179 if localhost:
180 return "::1"
181 else:
182 return "%s@@v6" % QHostInfo.localHostName()
183 else:
184 return self.networkInterface
185
186 def preferencesChanged(self):
187 """
188 Public slot to handle the preferencesChanged signal.
189 """
190 self.__registerDebuggerInterfaces()
191
192 def __registerDebuggerInterfaces(self):
193 """
194 Private method to register the available debugger interface modules.
195 """
196 self.__clientCapabilities = {}
197 self.__clientAssociations = {}
198
199 for interface in DebuggerInterfaces:
200 modName = "Debugger.%s" % interface
201 mod = __import__(modName)
202 components = modName.split('.')
203 for comp in components[1:]:
204 mod = getattr(mod, comp)
205
206 clientLanguage, clientCapabilities, clientExtensions = \
207 mod.getRegistryData()
208 if clientLanguage:
209 self.__clientCapabilities[clientLanguage] = clientCapabilities
210 for extension in clientExtensions:
211 if extension not in self.__clientAssociations:
212 self.__clientAssociations[extension] = clientLanguage
213
214 def getSupportedLanguages(self, shellOnly = False):
215 """
216 Public slot to return the supported programming languages.
217
218 @param shellOnly flag indicating only languages supporting an
219 interactive shell should be returned
220 @return list of supported languages (list of strings)
221 """
222 languages = self.__clientCapabilities.keys()
223 try:
224 del languages[languages.index("None")]
225 except ValueError:
226 pass # it is not in the list
227
228 if shellOnly:
229 languages = \
230 [lang for lang in languages \
231 if self.__clientCapabilities[lang] & DebugClientCapabilities.HasShell]
232
233 return languages[:]
234
235 def getExtensions(self, language):
236 """
237 Public slot to get the extensions associated with the given language.
238
239 @param language language to get extensions for (string)
240 @return tuple of extensions associated with the language (tuple of strings)
241 """
242 extensions = []
243 for ext, lang in self.__clientAssociations.items():
244 if lang == language:
245 extensions.append(ext)
246
247 return tuple(extensions)
248
249 def __createDebuggerInterface(self, clientType = None):
250 """
251 Private slot to create the debugger interface object.
252
253 @param clientType type of the client interface to be created (string)
254 """
255 if self.lastClientType != self.clientType or clientType is not None:
256 if clientType is None:
257 clientType = self.clientType
258 if clientType == "Python":
259 from DebuggerInterfacePython import DebuggerInterfacePython
260 self.debuggerInterface = DebuggerInterfacePython(self, self.passive)
261 elif clientType == "Python3":
262 from DebuggerInterfacePython3 import DebuggerInterfacePython3
263 self.debuggerInterface = DebuggerInterfacePython3(self, self.passive)
264 elif clientType == "Ruby":
265 from DebuggerInterfaceRuby import DebuggerInterfaceRuby
266 self.debuggerInterface = DebuggerInterfaceRuby(self, self.passive)
267 elif clientType == "None":
268 from DebuggerInterfaceNone import DebuggerInterfaceNone
269 self.debuggerInterface = DebuggerInterfaceNone(self, self.passive)
270 else:
271 from DebuggerInterfaceNone import DebuggerInterfaceNone
272 self.debuggerInterface = DebuggerInterfaceNone(self, self.passive)
273 self.clientType = "None"
274
275 def __setClientType(self, clType):
276 """
277 Private method to set the client type.
278
279 @param clType type of client to be started (string)
280 """
281 if clType is not None and clType in self.getSupportedLanguages():
282 self.clientType = clType
283 ok = Preferences.Prefs.settings.setValue('DebugClient/Type',
284 QVariant(self.clientType))
285
286 def startClient(self, unplanned = True, clType = None, forProject = False,
287 runInConsole = False):
288 """
289 Public method to start a debug client.
290
291 @keyparam unplanned flag indicating that the client has died (boolean)
292 @keyparam clType type of client to be started (string)
293 @keyparam forProject flag indicating a project related action (boolean)
294 @keyparam runInConsole flag indicating to start the debugger in a
295 console window (boolean)
296 """
297 if not self.passive or not self.passiveClientExited:
298 if self.debuggerInterface and self.debuggerInterface.isConnected():
299 self.shutdownServer()
300 self.emit(SIGNAL('clientGone'), unplanned & self.debugging)
301
302 if clType:
303 self.__setClientType(clType)
304
305 # only start the client, if we are not in passive mode
306 if not self.passive:
307 if self.clientProcess:
308 self.disconnect(self.clientProcess, SIGNAL("readyReadStandardError()"),
309 self.__clientProcessError)
310 self.disconnect(self.clientProcess, SIGNAL("readyReadStandardOutput()"),
311 self.__clientProcessOutput)
312 self.clientProcess.close()
313 self.clientProcess.kill()
314 self.clientProcess.waitForFinished(10000)
315 self.clientProcess = None
316
317 self.__createDebuggerInterface()
318 if forProject:
319 project = e4App().getObject("Project")
320 if not project.isDebugPropertiesLoaded():
321 self.clientProcess, isNetworked = \
322 self.debuggerInterface.startRemote(self.serverPort(),
323 runInConsole)
324 else:
325 self.clientProcess, isNetworked = \
326 self.debuggerInterface.startRemoteForProject(self.serverPort(),
327 runInConsole)
328 else:
329 self.clientProcess, isNetworked = \
330 self.debuggerInterface.startRemote(self.serverPort(), runInConsole)
331
332 if self.clientProcess:
333 self.connect(self.clientProcess, SIGNAL("readyReadStandardError()"),
334 self.__clientProcessError)
335 self.connect(self.clientProcess, SIGNAL("readyReadStandardOutput()"),
336 self.__clientProcessOutput)
337
338 if not isNetworked:
339 # the client is connected through stdin and stdout
340 # Perform actions necessary, if client type has changed
341 if self.lastClientType != self.clientType:
342 self.lastClientType = self.clientType
343 self.remoteBanner()
344 elif self.__autoClearShell:
345 self.__autoClearShell = False
346 self.remoteBanner()
347
348 self.debuggerInterface.flush()
349 else:
350 self.__createDebuggerInterface("None")
351
352 def __clientProcessOutput(self):
353 """
354 Private slot to process client output received via stdout.
355 """
356 output = unicode(self.clientProcess.readAllStandardOutput())
357 self.emit(SIGNAL("clientProcessStdout"), output)
358
359 def __clientProcessError(self):
360 """
361 Private slot to process client output received via stderr.
362 """
363 error = unicode(self.clientProcess.readAllStandardError())
364 self.emit(SIGNAL("clientProcessStderr"), error)
365
366 def __clientClearBreakPoint(self, fn, lineno):
367 """
368 Private slot to handle the clientClearBreak signal.
369
370 @param fn filename of breakpoint to clear (string)
371 @param lineno line number of breakpoint to clear (integer)
372 """
373 if self.debugging:
374 index = self.breakpointModel.getBreakPointIndex(fn, lineno)
375 self.breakpointModel.deleteBreakPointByIndex(index)
376
377 def __deleteBreakPoints(self, parentIndex, start, end):
378 """
379 Private slot to delete breakpoints.
380
381 @param parentIndex index of parent item (QModelIndex)
382 @param start start row (integer)
383 @param end end row (integer)
384 """
385 if self.debugging:
386 for row in range(start, end+1):
387 index = self.breakpointModel.index(row, 0, parentIndex)
388 fn, lineno = self.breakpointModel.getBreakPointByIndex(index)[0:2]
389 self.remoteBreakpoint(fn, lineno, False)
390
391 def __changeBreakPoints(self, startIndex, endIndex):
392 """
393 Private slot to set changed breakpoints.
394
395 @param indexes indexes of changed breakpoints.
396 """
397 if self.debugging:
398 self.__addBreakPoints(QModelIndex(), startIndex.row(), endIndex.row())
399
400 def __breakPointDataAboutToBeChanged(self, startIndex, endIndex):
401 """
402 Private slot to handle the dataAboutToBeChanged signal of the breakpoint model.
403
404 @param startIndex start index of the rows to be changed (QModelIndex)
405 @param endIndex end index of the rows to be changed (QModelIndex)
406 """
407 if self.debugging:
408 self.__deleteBreakPoints(QModelIndex(), startIndex.row(), endIndex.row())
409
410 def __addBreakPoints(self, parentIndex, start, end):
411 """
412 Private slot to add breakpoints.
413
414 @param parentIndex index of parent item (QModelIndex)
415 @param start start row (integer)
416 @param end end row (integer)
417 """
418 if self.debugging:
419 for row in range(start, end+1):
420 index = self.breakpointModel.index(row, 0, parentIndex)
421 fn, line, cond, temp, enabled, ignorecount = \
422 self.breakpointModel.getBreakPointByIndex(index)[:6]
423 self.remoteBreakpoint(fn, line, True, cond, temp)
424 if not enabled:
425 self.__remoteBreakpointEnable(fn, line, False)
426 if ignorecount:
427 self.__remoteBreakpointIgnore(fn, line, ignorecount)
428
429 def __makeWatchCondition(self, cond, special):
430 """
431 Private method to construct the condition string.
432
433 @param cond condition (string)
434 @param special special condition (string)
435 @return condition string (string)
436 """
437 if special == "":
438 _cond = cond
439 else:
440 if special == self.watchSpecialCreated:
441 _cond = "%s ??created??" % cond
442 elif special == self.watchSpecialChanged:
443 _cond = "%s ??changed??" % cond
444 return _cond
445
446 def __splitWatchCondition(self, cond):
447 """
448 Private method to split a remote watch expression.
449
450 @param cond remote expression (string)
451 @return tuple of local expression (string) and special condition (string)
452 """
453 if cond.endswith(" ??created??"):
454 cond, special = cond.split()
455 special = self.watchSpecialCreated
456 elif cond.endswith(" ??changed??"):
457 cond, special = cond.split()
458 special = self.watchSpecialChanged
459 else:
460 return cond, ""
461
462 def __clientClearWatchPoint(self, condition):
463 """
464 Private slot to handle the clientClearWatch signal.
465
466 @param condition expression of watch expression to clear (string)
467 """
468 if self.debugging:
469 cond, special = self.__splitWatchCondition(condition)
470 index = self.watchpointModel.getWatchPointIndex(cond, special)
471 self.watchpointModel.deleteWatchPointByIndex(index)
472
473 def __deleteWatchPoints(self, parentIndex, start, end):
474 """
475 Private slot to delete watch expressions.
476
477 @param parentIndex index of parent item (QModelIndex)
478 @param start start row (integer)
479 @param end end row (integer)
480 """
481 if self.debugging:
482 for row in range(start, end+1):
483 index = self.watchpointModel.index(row, 0, parentIndex)
484 cond, special = self.watchpointModel.getWatchPointByIndex(index)[0:2]
485 cond = self.__makeWatchCondition(cond, special)
486 self.__remoteWatchpoint(cond, False)
487
488 def __watchPointDataAboutToBeChanged(self, startIndex, endIndex):
489 """
490 Private slot to handle the dataAboutToBeChanged signal of the
491 watch expression model.
492
493 @param startIndex start index of the rows to be changed (QModelIndex)
494 @param endIndex end index of the rows to be changed (QModelIndex)
495 """
496 if self.debugging:
497 self.__deleteWatchPoints(QModelIndex(), startIndex.row(), endIndex.row())
498
499 def __addWatchPoints(self, parentIndex, start, end):
500 """
501 Private slot to set a watch expression.
502
503 @param parentIndex index of parent item (QModelIndex)
504 @param start start row (integer)
505 @param end end row (integer)
506 """
507 if self.debugging:
508 for row in range(start, end + 1):
509 index = self.watchpointModel.index(row, 0, parentIndex)
510 cond, special, temp, enabled, ignorecount = \
511 self.watchpointModel.getWatchPointByIndex(index)[:5]
512 cond = self.__makeWatchCondition(cond, special)
513 self.__remoteWatchpoint(cond, True, temp)
514 if not enabled:
515 self.__remoteWatchpointEnable(cond, False)
516 if ignorecount:
517 self.__remoteWatchpointIgnore(cond, ignorecount)
518
519 def __changeWatchPoints(self, startIndex, endIndex):
520 """
521 Private slot to set changed watch expressions.
522
523 @param startIndex start index of the rows to be changed (QModelIndex)
524 @param endIndex end index of the rows to be changed (QModelIndex)
525 """
526 if self.debugging:
527 self.__addWatchPoints(QModelIndex(), startIndex.row(), endIndex.row())
528
529 def getClientCapabilities(self, type):
530 """
531 Public method to retrieve the debug clients capabilities.
532
533 @param type debug client type (string)
534 @return debug client capabilities (integer)
535 """
536 try:
537 return self.__clientCapabilities[type]
538 except KeyError:
539 return 0 # no capabilities
540
541 def __newConnection(self):
542 """
543 Private slot to handle a new connection.
544 """
545 sock = self.nextPendingConnection()
546 peerAddress = sock.peerAddress().toString()
547 if peerAddress not in Preferences.getDebugger("AllowedHosts"):
548 # the peer is not allowed to connect
549 res = QMessageBox.warning(None,
550 self.trUtf8("Connection from illegal host"),
551 self.trUtf8("""<p>A connection was attempted by the"""
552 """ illegal host <b>{0}</b>. Accept this connection?</p>""")\
553 .format(peerAddress),
554 QMessageBox.StandardButtons(\
555 QMessageBox.No | \
556 QMessageBox.Yes),
557 QMessageBox.No)
558 if res == QMessageBox.No:
559 sock.abort()
560 return
561 else:
562 allowedHosts = Preferences.getDebugger("AllowedHosts")
563 allowedHosts.append(peerAddress)
564 Preferences.setDebugger("AllowedHosts", allowedHosts)
565
566 if self.passive:
567 self.__createDebuggerInterface(Preferences.getDebugger("PassiveDbgType"))
568
569 accepted = self.debuggerInterface.newConnection(sock)
570 if accepted:
571 # Perform actions necessary, if client type has changed
572 if self.lastClientType != self.clientType:
573 self.lastClientType = self.clientType
574 self.remoteBanner()
575 elif self.__autoClearShell:
576 self.__autoClearShell = False
577 self.remoteBanner()
578 elif self.passive:
579 self.remoteBanner()
580
581 self.debuggerInterface.flush()
582
583 def shutdownServer(self):
584 """
585 Public method to cleanly shut down.
586
587 It closes our socket and shuts down
588 the debug client. (Needed on Win OS)
589 """
590 if self.debuggerInterface is not None:
591 self.debuggerInterface.shutdown()
592
593 def remoteEnvironment(self, env):
594 """
595 Public method to set the environment for a program to debug, run, ...
596
597 @param env environment settings (string)
598 """
599 envlist = Utilities.parseEnvironmentString(env)
600 envdict = {}
601 for el in envlist:
602 try:
603 key, value = el.split('=', 1)
604 if value.startswith('"') or value.startswith("'"):
605 value = value[1:-1]
606 envdict[key] = value
607 except UnpackError:
608 pass
609 self.debuggerInterface.remoteEnvironment(envdict)
610
611 def remoteLoad(self, fn, argv, wd, env, autoClearShell = True,
612 tracePython = False, autoContinue = True, forProject = False,
613 runInConsole = False, autoFork = False, forkChild = False):
614 """
615 Public method to load a new program to debug.
616
617 @param fn the filename to debug (string)
618 @param argv the commandline arguments to pass to the program (string)
619 @param wd the working directory for the program (string)
620 @param env environment settings (string)
621 @keyparam autoClearShell flag indicating, that the interpreter window should
622 be cleared (boolean)
623 @keyparam tracePython flag indicating if the Python library should be traced
624 as well (boolean)
625 @keyparam autoContinue flag indicating, that the debugger should not stop
626 at the first executable line (boolean)
627 @keyparam forProject flag indicating a project related action (boolean)
628 @keyparam runInConsole flag indicating to start the debugger in a
629 console window (boolean)
630 @keyparam autoFork flag indicating the automatic fork mode (boolean)
631 @keyparam forkChild flag indicating to debug the child after forking (boolean)
632 """
633 self.__autoClearShell = autoClearShell
634 self.__autoContinue = autoContinue
635
636 # Restart the client
637 try:
638 self.__setClientType(self.__clientAssociations[os.path.splitext(fn)[1]])
639 except KeyError:
640 self.__setClientType('Python') # assume it is a Python file
641 self.startClient(False, forProject = forProject, runInConsole = runInConsole)
642
643 self.remoteEnvironment(env)
644
645 self.debuggerInterface.remoteLoad(fn, argv, wd, tracePython, autoContinue,
646 autoFork, forkChild)
647 self.debugging = True
648 self.__restoreBreakpoints()
649 self.__restoreWatchpoints()
650
651 def remoteRun(self, fn, argv, wd, env, autoClearShell = True,
652 forProject = False, runInConsole = False):
653 """
654 Public method to load a new program to run.
655
656 @param fn the filename to run (string)
657 @param argv the commandline arguments to pass to the program (string)
658 @param wd the working directory for the program (string)
659 @param env environment settings (string)
660 @keyparam autoClearShell flag indicating, that the interpreter window should
661 be cleared (boolean)
662 @keyparam forProject flag indicating a project related action (boolean)
663 @keyparam runInConsole flag indicating to start the debugger in a
664 console window (boolean)
665 """
666 self.__autoClearShell = autoClearShell
667
668 # Restart the client
669 try:
670 self.__setClientType(self.__clientAssociations[os.path.splitext(fn)[1]])
671 except KeyError:
672 self.__setClientType('Python') # assume it is a Python file
673 self.startClient(False, forProject = forProject, runInConsole = runInConsole)
674
675 self.remoteEnvironment(env)
676
677 self.debuggerInterface.remoteRun(fn, argv, wd)
678 self.debugging = False
679
680 def remoteCoverage(self, fn, argv, wd, env, autoClearShell = True,
681 erase = False, forProject = False, runInConsole = False):
682 """
683 Public method to load a new program to collect coverage data.
684
685 @param fn the filename to run (string)
686 @param argv the commandline arguments to pass to the program (string)
687 @param wd the working directory for the program (string)
688 @param env environment settings (string)
689 @keyparam autoClearShell flag indicating, that the interpreter window should
690 be cleared (boolean)
691 @keyparam erase flag indicating that coverage info should be
692 cleared first (boolean)
693 @keyparam forProject flag indicating a project related action (boolean)
694 @keyparam runInConsole flag indicating to start the debugger in a
695 console window (boolean)
696 """
697 self.__autoClearShell = autoClearShell
698
699 # Restart the client
700 try:
701 self.__setClientType(self.__clientAssociations[os.path.splitext(fn)[1]])
702 except KeyError:
703 self.__setClientType('Python') # assume it is a Python file
704 self.startClient(False, forProject = forProject, runInConsole = runInConsole)
705
706 self.remoteEnvironment(env)
707
708 self.debuggerInterface.remoteCoverage(fn, argv, wd, erase)
709 self.debugging = False
710
711 def remoteProfile(self, fn, argv, wd, env, autoClearShell = True,
712 erase = False, forProject = False,
713 runInConsole = False):
714 """
715 Public method to load a new program to collect profiling data.
716
717 @param fn the filename to run (string)
718 @param argv the commandline arguments to pass to the program (string)
719 @param wd the working directory for the program (string)
720 @param env environment settings (string)
721 @keyparam autoClearShell flag indicating, that the interpreter window should
722 be cleared (boolean)
723 @keyparam erase flag indicating that timing info should be cleared first (boolean)
724 @keyparam forProject flag indicating a project related action (boolean)
725 @keyparam runInConsole flag indicating to start the debugger in a
726 console window (boolean)
727 """
728 self.__autoClearShell = autoClearShell
729
730 # Restart the client
731 try:
732 self.__setClientType(self.__clientAssociations[os.path.splitext(fn)[1]])
733 except KeyError:
734 self.__setClientType('Python') # assume it is a Python file
735 self.startClient(False, forProject = forProject, runInConsole = runInConsole)
736
737 self.remoteEnvironment(env)
738
739 self.debuggerInterface.remoteProfile(fn, argv, wd, erase)
740 self.debugging = False
741
742 def remoteStatement(self, stmt):
743 """
744 Public method to execute a Python statement.
745
746 @param stmt the Python statement to execute (string). It
747 should not have a trailing newline.
748 """
749 self.debuggerInterface.remoteStatement(stmt)
750
751 def remoteStep(self):
752 """
753 Public method to single step the debugged program.
754 """
755 self.debuggerInterface.remoteStep()
756
757 def remoteStepOver(self):
758 """
759 Public method to step over the debugged program.
760 """
761 self.debuggerInterface.remoteStepOver()
762
763 def remoteStepOut(self):
764 """
765 Public method to step out the debugged program.
766 """
767 self.debuggerInterface.remoteStepOut()
768
769 def remoteStepQuit(self):
770 """
771 Public method to stop the debugged program.
772 """
773 self.debuggerInterface.remoteStepQuit()
774
775 def remoteContinue(self, special = False):
776 """
777 Public method to continue the debugged program.
778
779 @param special flag indicating a special continue operation
780 """
781 self.debuggerInterface.remoteContinue(special)
782
783 def remoteBreakpoint(self, fn, line, set, cond=None, temp=False):
784 """
785 Public method to set or clear a breakpoint.
786
787 @param fn filename the breakpoint belongs to (string)
788 @param line linenumber of the breakpoint (int)
789 @param set flag indicating setting or resetting a breakpoint (boolean)
790 @param cond condition of the breakpoint (string)
791 @param temp flag indicating a temporary breakpoint (boolean)
792 """
793 self.debuggerInterface.remoteBreakpoint(fn, line, set, cond, temp)
794
795 def __remoteBreakpointEnable(self, fn, line, enable):
796 """
797 Private method to enable or disable a breakpoint.
798
799 @param fn filename the breakpoint belongs to (string)
800 @param line linenumber of the breakpoint (int)
801 @param enable flag indicating enabling or disabling a breakpoint (boolean)
802 """
803 self.debuggerInterface.remoteBreakpointEnable(fn, line, enable)
804
805 def __remoteBreakpointIgnore(self, fn, line, count):
806 """
807 Private method to ignore a breakpoint the next couple of occurrences.
808
809 @param fn filename the breakpoint belongs to (string)
810 @param line linenumber of the breakpoint (int)
811 @param count number of occurrences to ignore (int)
812 """
813 self.debuggerInterface.remoteBreakpointIgnore(fn, line, count)
814
815 def __remoteWatchpoint(self, cond, set, temp = False):
816 """
817 Private method to set or clear a watch expression.
818
819 @param cond expression of the watch expression (string)
820 @param set flag indicating setting or resetting a watch expression (boolean)
821 @param temp flag indicating a temporary watch expression (boolean)
822 """
823 # cond is combination of cond and special (s. watch expression viewer)
824 self.debuggerInterface.remoteWatchpoint(cond, set, temp)
825
826 def __remoteWatchpointEnable(self, cond, enable):
827 """
828 Private method to enable or disable a watch expression.
829
830 @param cond expression of the watch expression (string)
831 @param enable flag indicating enabling or disabling a watch expression (boolean)
832 """
833 # cond is combination of cond and special (s. watch expression viewer)
834 self.debuggerInterface.remoteWatchpointEnable(cond, enable)
835
836 def __remoteWatchpointIgnore(self, cond, count):
837 """
838 Private method to ignore a watch expression the next couple of occurrences.
839
840 @param cond expression of the watch expression (string)
841 @param count number of occurrences to ignore (int)
842 """
843 # cond is combination of cond and special (s. watch expression viewer)
844 self.debuggerInterface.remoteWatchpointIgnore(cond, count)
845
846 def remoteRawInput(self,s):
847 """
848 Public method to send the raw input to the debugged program.
849
850 @param s the raw input (string)
851 """
852 self.debuggerInterface.remoteRawInput(s)
853 self.emit(SIGNAL('clientRawInputSent'))
854
855 def remoteThreadList(self):
856 """
857 Public method to request the list of threads from the client.
858 """
859 self.debuggerInterface.remoteThreadList()
860
861 def remoteSetThread(self, tid):
862 """
863 Public method to request to set the given thread as current thread.
864
865 @param tid id of the thread (integer)
866 """
867 self.debuggerInterface.remoteSetThread(tid)
868
869 def remoteClientVariables(self, scope, filter, framenr = 0):
870 """
871 Public method to request the variables of the debugged program.
872
873 @param scope the scope of the variables (0 = local, 1 = global)
874 @param filter list of variable types to filter out (list of int)
875 @param framenr framenumber of the variables to retrieve (int)
876 """
877 self.debuggerInterface.remoteClientVariables(scope, filter, framenr)
878
879 def remoteClientVariable(self, scope, filter, var, framenr = 0):
880 """
881 Public method to request the variables of the debugged program.
882
883 @param scope the scope of the variables (0 = local, 1 = global)
884 @param filter list of variable types to filter out (list of int)
885 @param var list encoded name of variable to retrieve (string)
886 @param framenr framenumber of the variables to retrieve (int)
887 """
888 self.debuggerInterface.remoteClientVariable(scope, filter, var, framenr)
889
890 def remoteClientSetFilter(self, scope, filter):
891 """
892 Public method to set a variables filter list.
893
894 @param scope the scope of the variables (0 = local, 1 = global)
895 @param filter regexp string for variable names to filter out (string)
896 """
897 self.debuggerInterface.remoteClientSetFilter(scope, filter)
898
899 def remoteEval(self, arg):
900 """
901 Public method to evaluate arg in the current context of the debugged program.
902
903 @param arg the arguments to evaluate (string)
904 """
905 self.debuggerInterface.remoteEval(arg)
906
907 def remoteExec(self, stmt):
908 """
909 Public method to execute stmt in the current context of the debugged program.
910
911 @param stmt statement to execute (string)
912 """
913 self.debuggerInterface.remoteExec(stmt)
914
915 def remoteBanner(self):
916 """
917 Public slot to get the banner info of the remote client.
918 """
919 self.debuggerInterface.remoteBanner()
920
921 def remoteCapabilities(self):
922 """
923 Public slot to get the debug clients capabilities.
924 """
925 self.debuggerInterface.remoteCapabilities()
926
927 def remoteCompletion(self, text):
928 """
929 Public slot to get the a list of possible commandline completions
930 from the remote client.
931
932 @param text the text to be completed (string)
933 """
934 self.debuggerInterface.remoteCompletion(text)
935
936 def remoteUTPrepare(self, fn, tn, tfn, cov, covname, coverase):
937 """
938 Public method to prepare a new unittest run.
939
940 @param fn the filename to load (string)
941 @param tn the testname to load (string)
942 @param tfn the test function name to load tests from (string)
943 @param cov flag indicating collection of coverage data is requested
944 @param covname filename to be used to assemble the coverage caches
945 filename (string)
946 @param coverase flag indicating erasure of coverage data is requested (boolean)
947 """
948 # Restart the client if there is already a program loaded.
949 try:
950 self.__setClientType(self.__clientAssociations[os.path.splitext(fn)[1]])
951 except KeyError:
952 self.__setClientType('Python') # assume it is a Python file
953 self.startClient(False)
954
955 self.debuggerInterface.remoteUTPrepare(fn, tn, tfn, cov, covname, coverase)
956 self.debugging = False
957
958 def remoteUTRun(self):
959 """
960 Public method to start a unittest run.
961 """
962 self.debuggerInterface.remoteUTRun()
963
964 def remoteUTStop(self):
965 """
966 public method to stop a unittest run.
967 """
968 self.debuggerInterface.remoteUTStop()
969
970 def clientOutput(self, line):
971 """
972 Public method to process a line of client output.
973
974 @param line client output (string)
975 """
976 self.emit(SIGNAL('clientOutput'), line)
977
978 def clientLine(self, filename, lineno, forStack = False):
979 """
980 Public method to process client position feedback.
981
982 @param filename name of the file currently being executed (string)
983 @param lineno line of code currently being executed (integer)
984 @param forStack flag indicating this is for a stack dump (boolean)
985 """
986 self.emit(SIGNAL('clientLine'), filename, lineno, forStack)
987
988 def clientStack(self, stack):
989 """
990 Public method to process a client's stack information.
991
992 @param stack list of stack entries. Each entry is a tuple of three
993 values giving the filename, linenumber and method
994 (list of lists of (string, integer, string))
995 """
996 self.emit(SIGNAL('clientStack'), stack)
997
998 def clientThreadList(self, currentId, threadList):
999 """
1000 Public method to process the client thread list info.
1001
1002 @param currentID id of the current thread (integer)
1003 @param threadList list of dictionaries containing the thread data
1004 """
1005 self.emit(SIGNAL('clientThreadList'), currentId, threadList)
1006
1007 def clientThreadSet(self):
1008 """
1009 Public method to handle the change of the client thread.
1010 """
1011 self.emit(SIGNAL('clientThreadSet'))
1012
1013 def clientVariables(self, scope, variables):
1014 """
1015 Public method to process the client variables info.
1016
1017 @param scope scope of the variables (-1 = empty global, 1 = global, 0 = local)
1018 @param variables the list of variables from the client
1019 """
1020 self.emit(SIGNAL('clientVariables'), scope, variables)
1021
1022 def clientVariable(self, scope, variables):
1023 """
1024 Public method to process the client variable info.
1025
1026 @param scope scope of the variables (-1 = empty global, 1 = global, 0 = local)
1027 @param variables the list of members of a classvariable from the client
1028 """
1029 self.emit(SIGNAL('clientVariable'), scope, variables)
1030
1031 def clientStatement(self, more):
1032 """
1033 Public method to process the input response from the client.
1034
1035 @param more flag indicating that more user input is required
1036 """
1037 self.emit(SIGNAL('clientStatement'), more)
1038
1039 def clientException(self, exceptionType, exceptionMessage, stackTrace):
1040 """
1041 Public method to process the exception info from the client.
1042
1043 @param exceptionType type of exception raised (string)
1044 @param exceptionMessage message given by the exception (string)
1045 @param stackTrace list of stack entries with the exception position
1046 first. Each stack entry is a list giving the filename and the linenumber.
1047 """
1048 self.emit(SIGNAL('clientException'), exceptionType, exceptionMessage, stackTrace)
1049
1050 def clientSyntaxError(self, message, filename, lineNo, characterNo):
1051 """
1052 Public method to process the syntax error info from the client.
1053
1054 @param message message of the syntax error (string)
1055 @param filename translated filename of the syntax error position (string)
1056 @param lineNo line number of the syntax error position (integer)
1057 @param characterNo character number of the syntax error position (integer)
1058 """
1059 self.emit(SIGNAL('clientSyntaxError'), message, filename, lineNo, characterNo)
1060
1061 def clientExit(self, status):
1062 """
1063 Public method to process the client exit status.
1064
1065 @param status exit code as a string (string)
1066 """
1067 if self.passive:
1068 self.__passiveShutDown()
1069 self.emit(SIGNAL('clientExit(int)'), int(status))
1070 if Preferences.getDebugger("AutomaticReset"):
1071 self.startClient(False)
1072 if self.passive:
1073 self.__createDebuggerInterface("None")
1074 self.clientOutput(self.trUtf8('\nNot connected\n'))
1075 self.clientStatement(False)
1076
1077 def clientClearBreak(self, filename, lineno):
1078 """
1079 Public method to process the client clear breakpoint command.
1080
1081 @param filename filename of the breakpoint (string)
1082 @param lineno line umber of the breakpoint (integer)
1083 """
1084 self.emit(SIGNAL('clientClearBreak'), filename, lineno)
1085
1086 def clientBreakConditionError(self, filename, lineno):
1087 """
1088 Public method to process the client breakpoint condition error info.
1089
1090 @param filename filename of the breakpoint (string)
1091 @param lineno line umber of the breakpoint (integer)
1092 """
1093 self.emit(SIGNAL('clientBreakConditionError'), filename, lineno)
1094
1095 def clientClearWatch(self, condition):
1096 """
1097 Public slot to handle the clientClearWatch signal.
1098
1099 @param condition expression of watch expression to clear (string)
1100 """
1101 self.emit(SIGNAL('clientClearWatch'), condition)
1102
1103 def clientWatchConditionError(self, condition):
1104 """
1105 Public method to process the client watch expression error info.
1106
1107 @param condition expression of watch expression to clear (string)
1108 """
1109 self.emit(SIGNAL('clientWatchConditionError'), condition)
1110
1111 def clientRawInput(self, prompt, echo):
1112 """
1113 Public method to process the client raw input command.
1114
1115 @param prompt the input prompt (string)
1116 @param echo flag indicating an echoing of the input (boolean)
1117 """
1118 self.emit(SIGNAL('clientRawInput'), prompt, echo)
1119
1120 def clientBanner(self, version, platform, debugClient):
1121 """
1122 Public method to process the client banner info.
1123
1124 @param version interpreter version info (string)
1125 @param platform hostname of the client (string)
1126 @param debugClient additional debugger type info (string)
1127 """
1128 self.emit(SIGNAL('clientBanner'), version, platform, debugClient)
1129
1130 def clientCapabilities(self, capabilities, clientType):
1131 """
1132 Public method to process the client capabilities info.
1133
1134 @param capabilities bitmaks with the client capabilities (integer)
1135 @param clientType type of the debug client (string)
1136 """
1137 self.__clientCapabilities[clientType] = capabilities
1138 self.emit(SIGNAL('clientCapabilities'), capabilities, clientType)
1139
1140 def clientCompletionList(self, completionList, text):
1141 """
1142 Public method to process the client auto completion info.
1143
1144 @param completionList list of possible completions (list of strings)
1145 @param text the text to be completed (string)
1146 """
1147 self.emit(SIGNAL('clientCompletionList'), completionList, text)
1148
1149 def clientUtPrepared(self, result, exceptionType, exceptionValue):
1150 """
1151 Public method to process the client unittest prepared info.
1152
1153 @param result number of test cases (0 = error) (integer)
1154 @param exceptionType exception type (string)
1155 @param exceptionValue exception message (string)
1156 """
1157 self.emit(SIGNAL('utPrepared'), result, exceptionType, exceptionValue)
1158
1159 def clientUtStartTest(self, testname, doc):
1160 """
1161 Public method to process the client start test info.
1162
1163 @param testname name of the test (string)
1164 @param doc short description of the test (string)
1165 """
1166 self.emit(SIGNAL('utStartTest'), testname, doc)
1167
1168 def clientUtStopTest(self):
1169 """
1170 Public method to process the client stop test info.
1171 """
1172 self.emit(SIGNAL('utStopTest'))
1173
1174 def clientUtTestFailed(self, testname, traceback):
1175 """
1176 Public method to process the client test failed info.
1177
1178 @param testname name of the test (string)
1179 @param traceback lines of traceback info (string)
1180 """
1181 self.emit(SIGNAL('utTestFailed'), testname, traceback)
1182
1183 def clientUtTestErrored(self, testname, traceback):
1184 """
1185 Public method to process the client test errored info.
1186
1187 @param testname name of the test (string)
1188 @param traceback lines of traceback info (string)
1189 """
1190 self.emit(SIGNAL('utTestErrored'), testname, traceback)
1191
1192 def clientUtFinished(self):
1193 """
1194 Public method to process the client unit test finished info.
1195 """
1196 self.emit(SIGNAL('utFinished'))
1197
1198 def passiveStartUp(self, fn, exc):
1199 """
1200 Public method to handle a passive debug connection.
1201
1202 @param fn filename of the debugged script (string)
1203 @param exc flag to enable exception reporting of the IDE (boolean)
1204 """
1205 print self.trUtf8("Passive debug connection received")
1206 self.passiveClientExited = False
1207 self.debugging = True
1208 self.__restoreBreakpoints()
1209 self.__restoreWatchpoints()
1210 self.emit(SIGNAL('passiveDebugStarted'), fn, exc)
1211
1212 def __passiveShutDown(self):
1213 """
1214 Private method to shut down a passive debug connection.
1215 """
1216 self.passiveClientExited = True
1217 self.shutdownServer()
1218 print self.trUtf8("Passive debug connection closed")
1219
1220 def __restoreBreakpoints(self):
1221 """
1222 Private method to restore the breakpoints after a restart.
1223 """
1224 if self.debugging:
1225 self.__addBreakPoints(QModelIndex(), 0, self.breakpointModel.rowCount()-1)
1226
1227 def __restoreWatchpoints(self):
1228 """
1229 Private method to restore the watch expressions after a restart.
1230 """
1231 if self.debugging:
1232 self.__addWatchPoints(QModelIndex(), 0, self.watchpointModel.rowCount()-1)
1233
1234 def getBreakPointModel(self):
1235 """
1236 Public slot to get a reference to the breakpoint model object.
1237
1238 @return reference to the breakpoint model object (BreakPointModel)
1239 """
1240 return self.breakpointModel
1241
1242 def getWatchPointModel(self):
1243 """
1244 Public slot to get a reference to the watch expression model object.
1245
1246 @return reference to the watch expression model object (WatchPointModel)
1247 """
1248 return self.watchpointModel
1249
1250 def isConnected(self):
1251 """
1252 Public method to test, if the debug server is connected to a backend.
1253
1254 @return flag indicating a connection (boolean)
1255 """
1256 return self.debuggerInterface and self.debuggerInterface.isConnected()

eric ide

mercurial