DebugClients/Python2/DebugBase.py

branch
debugger speed
changeset 5174
8c48f5e0cd92
parent 5088
5b992bcb3c86
parent 5171
f1e9eebd5469
equal deleted inserted replaced
5170:fb9168c2e069 5174:8c48f5e0cd92
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2002 - 2016 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing the debug base class which based originally on bdb.
8 """
9
10 import sys
11 import os
12 import types
13 import atexit
14 import inspect
15 import ctypes
16 import thread
17 import time
18
19 from inspect import CO_GENERATOR
20 from BreakpointWatch import Breakpoint, Watch
21
22 gRecursionLimit = 64
23
24
25 def printerr(s):
26 """
27 Module function used for debugging the debug client.
28
29 @param s data to be printed
30 """
31 sys.__stderr__.write('%s\n' % unicode(s))
32 sys.__stderr__.flush()
33
34
35 def setRecursionLimit(limit):
36 """
37 Module function to set the recursion limit.
38
39 @param limit recursion limit (integer)
40 """
41 global gRecursionLimit
42 gRecursionLimit = limit
43
44
45 class DebugBase(object):
46 """
47 Class implementing base class of the debugger.
48
49 Provides methods for the 'owning' client to call to step etc.
50 """
51 # Don't thrust distutils.sysconfig.get_python_lib: possible case mismatch
52 # on Windows
53 lib = os.path.dirname(inspect.__file__)
54 # tuple required because it's accessed a lot of times by startswith method
55 pathsToSkip = ('<', os.path.dirname(__file__), inspect.__file__[:-1])
56 filesToSkip = {}
57
58 # cache for fixed file names
59 _fnCache = {}
60
61 def __init__(self, dbgClient):
62 """
63 Constructor
64
65 @param dbgClient the owning client
66 """
67 self._dbgClient = dbgClient
68 self._mainThread = True
69 self.quitting = 0
70
71 self.tracePythonLibs(0)
72
73 # Special handling of a recursion error
74 self.skipFrames = 0
75
76 self.__isBroken = False
77 self.cFrame = None
78
79 # current frame we are at
80 self.currentFrame = None
81
82 # frame that we are stepping in, can be different than currentFrame
83 self.stepFrame = None
84
85 self.botframe = None
86 self.stopframe = None
87 self.returnframe = None
88 self.stop_everywhere = False
89
90 # provide a hook to perform a hard breakpoint
91 # Use it like this:
92 # if hasattr(sys, 'breakpoint): sys.breakpoint()
93 sys.breakpoint = self.set_trace
94
95 self.__recursionDepth = -1
96 self.setRecursionDepth(inspect.currentframe())
97
98 # background task to periodicaly check for client interactions
99 self.eventPollFlag = False
100 self.timer = thread.start_new_thread(self.__eventPollTimer, ())
101
102 def __eventPollTimer(self):
103 """
104 Private method to set a flag every 0.5 s to check for new messages.
105 """
106 while True:
107 time.sleep(0.5)
108 self.eventPollFlag = True
109
110 def getCurrentFrame(self):
111 """
112 Public method to return the current frame.
113
114 @return the current frame
115 """
116 return self.currentFrame
117
118 def getFrameLocals(self, frmnr=0):
119 """
120 Public method to return the locals dictionary of the current frame
121 or a frame below.
122
123 @keyparam frmnr distance of frame to get locals dictionary of. 0 is
124 the current frame (int)
125 @return locals dictionary of the frame
126 """
127 f = self.currentFrame
128 while f is not None and frmnr > 0:
129 f = f.f_back
130 frmnr -= 1
131 return f.f_locals
132
133 def storeFrameLocals(self, frmnr=0):
134 """
135 Public method to store the locals into the frame, so an access to
136 frame.f_locals returns the last data.
137
138 @keyparam frmnr distance of frame to store locals dictionary to. 0 is
139 the current frame (int)
140 """
141 cf = self.currentFrame
142 while cf is not None and frmnr > 0:
143 cf = cf.f_back
144 frmnr -= 1
145
146 try:
147 if "__pypy__" in sys.builtin_module_names:
148 import __pypy__
149 __pypy__.locals_to_fast(cf)
150 return
151 except Exception:
152 pass
153
154 ctypes.pythonapi.PyFrame_LocalsToFast(
155 ctypes.py_object(cf),
156 ctypes.c_int(0))
157
158 def step(self, traceMode):
159 """
160 Public method to perform a step operation in this thread.
161
162 @param traceMode If it is True, then the step is a step into,
163 otherwise it is a step over.
164 """
165 self.stepFrame = self.currentFrame
166
167 if traceMode:
168 self.currentFrame = None
169 self.set_step()
170 else:
171 self.set_next(self.currentFrame)
172
173 def stepOut(self):
174 """
175 Public method to perform a step out of the current call.
176 """
177 self.stepFrame = self.currentFrame
178 self.set_return(self.currentFrame)
179
180 def go(self, special):
181 """
182 Public method to resume the thread.
183
184 It resumes the thread stopping only at breakpoints or exceptions.
185
186 @param special flag indicating a special continue operation
187 """
188 self.currentFrame = None
189 self.set_continue(special)
190
191 def setRecursionDepth(self, frame):
192 """
193 Public method to determine the current recursion depth.
194
195 @param frame The current stack frame.
196 """
197 self.__recursionDepth = 0
198 while frame is not None:
199 self.__recursionDepth += 1
200 frame = frame.f_back
201
202 def profileWithRecursion(self, frame, event, arg):
203 """
204 Public method used to trace some stuff independent of the debugger
205 trace function.
206
207 @param frame current stack frame
208 @type frame object
209 @param event trace event
210 @type str
211 @param arg arguments
212 @type depends on the previous event parameter
213 @exception RuntimeError raised to indicate too many recursions
214 """
215 if event == 'return':
216 self.cFrame = frame.f_back
217 self.__recursionDepth -= 1
218 if self._dbgClient.callTraceEnabled:
219 self.__sendCallTrace(event, frame, self.cFrame)
220 elif event == 'call':
221 if self._dbgClient.callTraceEnabled:
222 self.__sendCallTrace(event, self.cFrame, frame)
223 self.cFrame = frame
224 self.__recursionDepth += 1
225 if self.__recursionDepth > gRecursionLimit:
226 raise RuntimeError(
227 'maximum recursion depth exceeded\n'
228 '(offending frame is two down the stack)')
229
230 def profile(self, frame, event, arg):
231 """
232 Public method used to trace some stuff independent of the debugger
233 trace function.
234
235 @param frame current stack frame
236 @type frame object
237 @param event trace event
238 @type str
239 @param arg arguments
240 @type depends on the previous event parameter
241 """
242 if event == 'return':
243 self.__sendCallTrace(event, frame, frame.f_back)
244 elif event == 'call':
245 self.__sendCallTrace(event, frame.f_back, frame)
246
247 def __sendCallTrace(self, event, fromFrame, toFrame):
248 """
249 Private method to send a call/return trace.
250
251 @param event trace event
252 @type str
253 @param fromFrame originating frame
254 @type frame object
255 @param toFrame destination frame
256 @type frame object
257 """
258 if not self.__skipFrame(fromFrame) and not self.__skipFrame(toFrame):
259 fromInfo = {
260 "filename": self._dbgClient.absPath(
261 self.fix_frame_filename(fromFrame)),
262 "linenumber": fromFrame.f_lineno,
263 "codename": fromFrame.f_code.co_name,
264 }
265 toInfo = {
266 "filename": self._dbgClient.absPath(
267 self.fix_frame_filename(toFrame)),
268 "linenumber": toFrame.f_lineno,
269 "codename": toFrame.f_code.co_name,
270 }
271 self._dbgClient.sendCallTrace(event, fromInfo, toInfo)
272
273 def trace_dispatch(self, frame, event, arg):
274 """
275 Public method reimplemented from bdb.py to do some special things.
276
277 This specialty is to check the connection to the debug server
278 for new events (i.e. new breakpoints) while we are going through
279 the code.
280
281 @param frame The current stack frame
282 @type frame object
283 @param event The trace event
284 @type str
285 @param arg The arguments
286 @type depends on the previous event parameter
287 @return local trace function
288 @rtype trace function or None
289 @exception SystemExit
290 """
291 # give the client a chance to push through new break points.
292 if self.eventPollFlag:
293 self._dbgClient.eventPoll()
294 self.eventPollFlag = False
295
296 if self.quitting:
297 raise SystemExit
298
299 if event == 'line':
300 if self.stop_here(frame) or self.break_here(frame):
301 self.user_line(frame)
302 return
303
304 if event == 'call':
305 if self.botframe is None and frame.f_lineno > 1:
306 self.botframe = frame.f_back
307 frame.f_trace = self.trace_dispatch
308 self._dbgClient.mainFrame = frame
309
310 self.user_line(frame)
311 return self.trace_dispatch
312
313 if not (self.stop_here(frame) or
314 self.__checkBreakInFrame(frame) or
315 Watch.watches != []):
316 # No need to trace this function
317 return
318 return self.trace_dispatch
319
320 if event == 'return':
321 if self.stop_here(frame):
322 # Ignore return events in generator except when stepping.
323 if self.stopframe and frame.f_code.co_flags & CO_GENERATOR:
324 return
325 # The program has finished if we have just left the first frame
326 if (frame == self._dbgClient.mainFrame and
327 self._mainThread):
328 atexit._run_exitfuncs()
329 self._dbgClient.progTerminated(arg)
330
331 if self.quitting and not self._dbgClient.passive:
332 raise SystemExit
333 return
334
335 if event == 'exception':
336 if not self.__skipFrame(frame):
337 # When stepping with next/until/return in a generator frame,
338 # skip the internal StopIteration exception (with no traceback)
339 # triggered by a subiterator run with the 'yield from'
340 # statement.
341 if not (frame.f_code.co_flags & CO_GENERATOR and
342 arg[0] is StopIteration and arg[2] is None):
343 self.user_exception(frame, arg)
344 # Stop at the StopIteration or GeneratorExit exception when the
345 # user has set stopframe in a generator by issuing a return
346 # command, or a next/until command at the last statement in the
347 # generator before the exception.
348 elif (self.stopframe and frame is not self.stopframe and
349 self.stopframe.f_code.co_flags & CO_GENERATOR and
350 arg[0] in (StopIteration, GeneratorExit)):
351 self.user_exception(frame, arg)
352 return
353
354 if event == 'c_call':
355 return
356 if event == 'c_exception':
357 return
358 if event == 'c_return':
359 return
360
361 print('DebugBase.trace_dispatch:' # __IGNORE_WARNING__
362 ' unknown debugging event: ',
363 repr(event))
364 return self.trace_dispatch
365
366 def set_trace(self, frame=None):
367 """
368 Public method to start debugging from 'frame'.
369
370 If frame is not specified, debugging starts from caller's frame.
371 Because of jump optimizations it's not possible to use sys.breakpoint()
372 as last instruction in a function or method.
373
374 @keyparam frame frame to start debugging from
375 @type frame object
376 """
377 if frame is None:
378 frame = sys._getframe().f_back # Skip set_trace method
379
380 frame.f_trace = self.trace_dispatch
381 while frame is not None:
382 # stop at erics debugger frame
383 if frame.f_back.f_code == self._dbgClient.handleLine.func_code:
384 frame.f_trace = self.trace_dispatch
385 self.botframe = frame
386 self._dbgClient.mainFrame = frame
387 break
388
389 frame = frame.f_back
390
391 self.stop_everywhere = True
392 sys.settrace(self.trace_dispatch)
393 sys.setprofile(self._dbgClient.callTraceEnabled)
394
395 def run(self, cmd, globals=None, locals=None):
396 """
397 Public method to start a given command under debugger control.
398
399 @param cmd command / code to execute under debugger control
400 @type str or CodeType
401 @keyparam globals dictionary of global variables for cmd
402 @type dict
403 @keyparam locals dictionary of local variables for cmd
404 @type dict
405 """
406 if globals is None:
407 import __main__
408 globals = __main__.__dict__
409
410 if locals is None:
411 locals = globals
412
413 sys.settrace(self.trace_dispatch)
414 if not isinstance(cmd, types.CodeType):
415 cmd += '\n'
416
417 try:
418 exec cmd in globals, locals
419 except SystemExit:
420 pass
421 finally:
422 self.quitting = 1
423 sys.settrace(None)
424
425 def _set_stopinfo(self, stopframe, returnframe):
426 """
427 Protected method to update the frame pointers.
428
429 @param stopframe the frame object where to stop
430 @type frame object
431 @param returnframe the frame object where to stop on a function return
432 @type frame object
433 """
434 self.stopframe = stopframe
435 self.returnframe = returnframe
436 self.stop_everywhere = False
437
438 def set_continue(self, special):
439 """
440 Public method to stop only on next breakpoint.
441
442 @param special flag indicating a special continue operation
443 @type bool
444 """
445 # Here we only set a new stop frame if it is a normal continue.
446 if not special:
447 self._set_stopinfo(self.botframe, None)
448
449 # Disable tracing if not started in debug mode
450 if not self._dbgClient.debugging:
451 sys.settrace(None)
452 sys.setprofile(None)
453
454 def set_step(self):
455 """
456 Public method to stop after one line of code.
457 """
458 self._set_stopinfo(None, None)
459 self.stop_everywhere = True
460
461 def set_next(self, frame):
462 """
463 Public method to stop on the next line in or below the given frame.
464
465 @param frame the frame object
466 @type frame object
467 """
468 self._set_stopinfo(frame, frame.f_back)
469 frame.f_back.f_trace = self.trace_dispatch
470 frame.f_trace = self.trace_dispatch
471
472 def set_return(self, frame):
473 """
474 Public method to stop when returning from the given frame.
475
476 @param frame the frame object
477 @type frame object
478 """
479 self._set_stopinfo(None, frame.f_back)
480
481 def set_quit(self):
482 """
483 Public method to quit.
484
485 Disables the trace functions and resets all frame pointer.
486 """
487 self.currentFrame = None
488 sys.setprofile(None)
489 sys.settrace(None)
490 self.stopframe = None
491 self.returnframe = None
492 self.quitting = 1
493
494 def fix_frame_filename(self, frame):
495 """
496 Public method used to fixup the filename for a given frame.
497
498 The logic employed here is that if a module was loaded
499 from a .pyc file, then the correct .py to operate with
500 should be in the same path as the .pyc. The reason this
501 logic is needed is that when a .pyc file is generated, the
502 filename embedded and thus what is readable in the code object
503 of the frame object is the fully qualified filepath when the
504 pyc is generated. If files are moved from machine to machine
505 this can break debugging as the .pyc will refer to the .py
506 on the original machine. Another case might be sharing
507 code over a network... This logic deals with that.
508
509 @param frame the frame object
510 @type frame object
511 @return fixed up file name
512 @rtype str
513 """
514 # get module name from __file__
515 fn = frame.f_globals.get('__file__')
516 try:
517 return self._fnCache[fn]
518 except KeyError:
519 if fn and fn != frame.f_code.co_filename:
520 absFilename = os.path.abspath(fn)
521 if absFilename.endswith(('.pyc', '.pyo')):
522 fixedName = absFilename[:-1]
523 if not os.path.exists(fixedName):
524 fixedName = absFilename
525 else:
526 fixedName = absFilename
527 else:
528 fixedName = frame.f_code.co_filename
529 # update cache
530 self._fnCache[fn] = fixedName
531 return fixedName
532
533 def __checkBreakInFrame(self, frame):
534 """
535 Private method to check if the function / method has a line number
536 which is a breakpoint.
537
538 @param frame the frame object
539 @type frame object
540 @return Flag indicating a function / method with breakpoint
541 @rtype bool
542 """
543 try:
544 return Breakpoint.breakInFrameCache[
545 frame.f_globals.get('__file__'),
546 frame.f_code.co_firstlineno]
547 except KeyError:
548 filename = self.fix_frame_filename(frame)
549 if filename not in Breakpoint.breakInFile:
550 Breakpoint.breakInFrameCache[
551 frame.f_globals.get('__file__'),
552 frame.f_code.co_firstlineno] = False
553 return False
554 lineNo = frame.f_code.co_firstlineno
555 lineNumbers = [lineNo]
556 # No need to handle special case if a lot of lines between
557 # (e.g. closure), because the additional lines won't cause a bp
558 for co_lno in frame.f_code.co_lnotab[1::2]:
559 lineNo += ord(co_lno)
560 lineNumbers.append(lineNo)
561
562 for bp in Breakpoint.breakInFile[filename]:
563 if bp in lineNumbers:
564 Breakpoint.breakInFrameCache[
565 frame.f_globals.get('__file__'),
566 frame.f_code.co_firstlineno] = True
567 return True
568 Breakpoint.breakInFrameCache[
569 frame.f_globals.get('__file__'),
570 frame.f_code.co_firstlineno] = False
571 return False
572
573 def break_here(self, frame):
574 """
575 Public method reimplemented from bdb.py to fix the filename from the
576 frame.
577
578 See fix_frame_filename for more info.
579
580 @param frame the frame object
581 @type frame object
582 @return flag indicating the break status
583 @rtype bool
584 """
585 filename = self.fix_frame_filename(frame)
586 if (filename, frame.f_lineno) in Breakpoint.breaks:
587 bp, flag = Breakpoint.effectiveBreak(
588 filename, frame.f_lineno, frame)
589 if bp:
590 # flag says ok to delete temp. bp
591 if flag and bp.temporary:
592 self.__do_clearBreak(filename, frame.f_lineno)
593 return True
594
595 if Watch.watches != []:
596 bp, flag = Watch.effectiveWatch(frame)
597 if bp:
598 # flag says ok to delete temp. watch
599 if flag and bp.temporary:
600 self.__do_clearWatch(bp.cond)
601 return True
602
603 return False
604
605 def __do_clearBreak(self, filename, lineno):
606 """
607 Private method called to clear a temporary breakpoint.
608
609 @param filename name of the file the bp belongs to
610 @type str
611 @param lineno linenumber of the bp
612 @type int
613 """
614 Breakpoint.clear_break(filename, lineno)
615 self._dbgClient.sendClearTemporaryBreakpoint(filename, lineno)
616
617 def __do_clearWatch(self, cond):
618 """
619 Private method called to clear a temporary watch expression.
620
621 @param cond expression of the watch expression to be cleared
622 @type str
623 """
624 Watch.clear_watch(cond)
625 self._dbgClient.sendClearTemporaryWatch(cond)
626
627 def getStack(self):
628 """
629 Public method to get the stack.
630
631 @return list of lists with file name (string), line number (integer)
632 and function name (string)
633 """
634 fr = self.cFrame
635 stack = []
636 while fr is not None:
637 fname = self._dbgClient.absPath(self.fix_frame_filename(fr))
638 if not fname.startswith("<"):
639 fline = fr.f_lineno
640 ffunc = fr.f_code.co_name
641
642 if ffunc == '?':
643 ffunc = ''
644
645 if ffunc and not ffunc.startswith("<"):
646 argInfo = inspect.getargvalues(fr)
647 try:
648 fargs = inspect.formatargvalues(argInfo[0], argInfo[1],
649 argInfo[2], argInfo[3])
650 except Exception:
651 fargs = ""
652 else:
653 fargs = ""
654
655 stack.append([fname, fline, ffunc, fargs])
656
657 if fr == self._dbgClient.mainFrame:
658 fr = None
659 else:
660 fr = fr.f_back
661
662 return stack
663
664 def user_line(self, frame):
665 """
666 Public method reimplemented to handle the program about to execute a
667 particular line.
668
669 @param frame the frame object
670 """
671 # We never stop on line 0.
672 if frame.f_lineno == 0:
673 return
674
675 self.currentFrame = frame
676
677 fr = frame
678 stack = []
679 while fr is not None:
680 # Reset the trace function so we can be sure
681 # to trace all functions up the stack... This gets around
682 # problems where an exception/breakpoint has occurred
683 # but we had disabled tracing along the way via a None
684 # return from dispatch_call
685 fr.f_trace = self.trace_dispatch
686 fname = self._dbgClient.absPath(self.fix_frame_filename(fr))
687 if not fname.startswith("<"):
688 fline = fr.f_lineno
689 ffunc = fr.f_code.co_name
690
691 if ffunc == '?':
692 ffunc = ''
693
694 if ffunc and not ffunc.startswith("<"):
695 argInfo = inspect.getargvalues(fr)
696 try:
697 fargs = inspect.formatargvalues(argInfo[0], argInfo[1],
698 argInfo[2], argInfo[3])
699 except Exception:
700 fargs = ""
701 else:
702 fargs = ""
703
704 stack.append([fname, fline, ffunc, fargs])
705
706 if fr == self._dbgClient.mainFrame:
707 fr = None
708 else:
709 fr = fr.f_back
710
711 self.__isBroken = True
712
713 self._dbgClient.sendResponseLine(stack)
714 self._dbgClient.eventLoop()
715
716 self.__isBroken = False
717
718 def user_exception(self, frame, (exctype, excval, exctb), unhandled=False):
719 """
720 Public method reimplemented to report an exception to the debug server.
721
722 @param frame the frame object
723 @type frame object
724 @param exctype the type of the exception
725 @type Exception
726 @param excval data about the exception
727 @type excval object
728 @param exctb traceback for the exception
729 @type traceback frame object
730 @keyparam unhandled flag indicating an uncaught exception
731 @type bool
732 """
733 if exctype in [GeneratorExit, StopIteration]:
734 # ignore these
735 return
736
737 if exctype == SystemExit:
738 atexit._run_exitfuncs()
739 if excval is None:
740 exitcode = 0
741 message = ""
742 elif isinstance(excval, (unicode, str)):
743 exitcode = 1
744 message = excval
745 elif isinstance(excval, int):
746 exitcode = excval
747 message = ""
748 elif isinstance(excval, SystemExit):
749 code = excval.code
750 if isinstance(code, (unicode, str)):
751 exitcode = 1
752 message = code
753 elif isinstance(code, int):
754 exitcode = code
755 message = ""
756 else:
757 exitcode = 1
758 message = str(code)
759 else:
760 exitcode = 1
761 message = str(excval)
762 self._dbgClient.progTerminated(exitcode, message)
763 return
764
765 if exctype in [SyntaxError, IndentationError]:
766 try:
767 message = unicode(excval)
768 try:
769 message = unicode(excval).encode(
770 self._dbgClient.getCoding())
771 except UnicodeError:
772 message = str(excval)
773 filename = excval.filename
774 lineno = excval.lineno
775 charno = excval.offset
776 realSyntaxError = os.path.exists(filename)
777 except (AttributeError, ValueError):
778 message = ""
779 filename = ""
780 lineno = 0
781 charno = 0
782 realSyntaxError = True
783
784 if realSyntaxError:
785 self._dbgClient.sendSyntaxError(
786 message, filename, lineno, charno)
787 self._dbgClient.eventLoop()
788 return
789
790 self.skipFrames = 0
791 if (exctype == RuntimeError and
792 str(excval).startswith('maximum recursion depth exceeded')):
793 excval = 'maximum recursion depth exceeded'
794 depth = 0
795 tb = exctb
796 while tb:
797 tb = tb.tb_next
798
799 if (tb and tb.tb_frame.f_code.co_name == 'trace_dispatch' and
800 __file__.startswith(tb.tb_frame.f_code.co_filename)):
801 depth = 1
802 self.skipFrames += depth
803
804 if type(exctype) in [types.ClassType, # Python up to 2.4
805 types.TypeType]: # Python 2.5+
806 exctype = exctype.__name__
807
808 if excval is None:
809 excval = ''
810
811 if unhandled:
812 exctypetxt = "unhandled %s" % unicode(exctype)
813 else:
814 exctypetxt = unicode(exctype)
815
816 try:
817 excvaltxt = unicode(excval).encode(self._dbgClient.getCoding())
818 except UnicodeError:
819 excvaltxt = str(excval)
820
821 stack = []
822 if exctb:
823 frlist = self.__extract_stack(exctb)
824 frlist.reverse()
825
826 self.currentFrame = frlist[0]
827
828 for fr in frlist[self.skipFrames:]:
829 filename = self._dbgClient.absPath(self.fix_frame_filename(fr))
830
831 if os.path.basename(filename).startswith("DebugClientBase"):
832 break
833
834 linenr = fr.f_lineno
835 ffunc = fr.f_code.co_name
836
837 if ffunc == '?':
838 ffunc = ''
839
840 if ffunc and not ffunc.startswith("<"):
841 argInfo = inspect.getargvalues(fr)
842 try:
843 fargs = inspect.formatargvalues(argInfo[0], argInfo[1],
844 argInfo[2], argInfo[3])
845 except Exception:
846 fargs = ""
847 else:
848 fargs = ""
849
850 stack.append([filename, linenr, ffunc, fargs])
851
852 self._dbgClient.sendException(exctypetxt, excvaltxt, stack)
853
854 if exctb is None:
855 return
856
857 self._dbgClient.eventLoop()
858 self.skipFrames = 0
859
860 def __extract_stack(self, exctb):
861 """
862 Private member to return a list of stack frames.
863
864 @param exctb exception traceback
865 @return list of stack frames
866 """
867 tb = exctb
868 stack = []
869 while tb is not None:
870 stack.append(tb.tb_frame)
871 tb = tb.tb_next
872 tb = None
873 return stack
874
875 def stop_here(self, frame):
876 """
877 Public method reimplemented to filter out debugger files.
878
879 Tracing is turned off for files that are part of the
880 debugger that are called from the application being debugged.
881
882 @param frame the frame object
883 @type frame object
884 @return flag indicating whether the debugger should stop here
885 @rtype bool
886 """
887 if self.__skipFrame(frame):
888 return False
889
890 return (self.stop_everywhere or
891 frame is self.stopframe or
892 frame is self.returnframe or
893 frame is self.botframe)
894
895 def tracePythonLibs(self, enable):
896 """
897 Public method to update the settings to trace into Python libraries.
898
899 @param enable flag to debug into Python libraries
900 @type bool
901 """
902 pathsToSkip = list(self.pathsToSkip)
903 # don't trace into Python library?
904 if enable:
905 pathsToSkip = [x for x in pathsToSkip if not x.endswith(
906 ("site-packages", "dist-packages", self.lib))]
907 else:
908 pathsToSkip.append(self.lib)
909 localLib = [x for x in sys.path if x.endswith(("site-packages",
910 "dist-packages")) and not x.startswith(self.lib)]
911 pathsToSkip.extend(localLib)
912
913 self.pathsToSkip = tuple(pathsToSkip)
914
915 def __skipFrame(self, frame):
916 """
917 Private method to filter out debugger files.
918
919 Tracing is turned off for files that are part of the
920 debugger that are called from the application being debugged.
921
922 @param frame the frame object
923 @type frame object
924 @return flag indicating whether the debugger should skip this frame
925 @rtype bool
926 """
927 try:
928 return self.filesToSkip[frame.f_code.co_filename]
929 except KeyError:
930 ret = frame.f_code.co_filename.startswith(self.pathsToSkip)
931 self.filesToSkip[frame.f_code.co_filename] = ret
932 return ret
933 except AttributeError:
934 # if frame is None
935 return True
936
937 def isBroken(self):
938 """
939 Public method to return the broken state of the debugger.
940
941 @return flag indicating the broken state
942 @rtype bool
943 """
944 return self.__isBroken
945
946
947 #
948 # eflag: FileType = Python2
949 # eflag: noqa = M601, M702

eric ide

mercurial