DebugClients/Python2/DebugBase.py

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

eric ide

mercurial