DebugClients/Python2/DebugBase.py

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

eric ide

mercurial