• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1"""Debugger basics"""
2
3import fnmatch
4import sys
5import os
6from inspect import CO_GENERATOR, CO_COROUTINE, CO_ASYNC_GENERATOR
7
8__all__ = ["BdbQuit", "Bdb", "Breakpoint"]
9
10GENERATOR_AND_COROUTINE_FLAGS = CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR
11
12
13class BdbQuit(Exception):
14    """Exception to give up completely."""
15
16
17class Bdb:
18    """Generic Python debugger base class.
19
20    This class takes care of details of the trace facility;
21    a derived class should implement user interaction.
22    The standard debugger class (pdb.Pdb) is an example.
23
24    The optional skip argument must be an iterable of glob-style
25    module name patterns.  The debugger will not step into frames
26    that originate in a module that matches one of these patterns.
27    Whether a frame is considered to originate in a certain module
28    is determined by the __name__ in the frame globals.
29    """
30
31    def __init__(self, skip=None):
32        self.skip = set(skip) if skip else None
33        self.breaks = {}
34        self.fncache = {}
35        self.frame_trace_lines_opcodes = {}
36        self.frame_returning = None
37        self.trace_opcodes = False
38        self.enterframe = None
39
40        self._load_breaks()
41
42    def canonic(self, filename):
43        """Return canonical form of filename.
44
45        For real filenames, the canonical form is a case-normalized (on
46        case insensitive filesystems) absolute path.  'Filenames' with
47        angle brackets, such as "<stdin>", generated in interactive
48        mode, are returned unchanged.
49        """
50        if filename == "<" + filename[1:-1] + ">":
51            return filename
52        canonic = self.fncache.get(filename)
53        if not canonic:
54            canonic = os.path.abspath(filename)
55            canonic = os.path.normcase(canonic)
56            self.fncache[filename] = canonic
57        return canonic
58
59    def reset(self):
60        """Set values of attributes as ready to start debugging."""
61        import linecache
62        linecache.checkcache()
63        self.botframe = None
64        self._set_stopinfo(None, None)
65
66    def trace_dispatch(self, frame, event, arg):
67        """Dispatch a trace function for debugged frames based on the event.
68
69        This function is installed as the trace function for debugged
70        frames. Its return value is the new trace function, which is
71        usually itself. The default implementation decides how to
72        dispatch a frame, depending on the type of event (passed in as a
73        string) that is about to be executed.
74
75        The event can be one of the following:
76            line: A new line of code is going to be executed.
77            call: A function is about to be called or another code block
78                  is entered.
79            return: A function or other code block is about to return.
80            exception: An exception has occurred.
81            c_call: A C function is about to be called.
82            c_return: A C function has returned.
83            c_exception: A C function has raised an exception.
84
85        For the Python events, specialized functions (see the dispatch_*()
86        methods) are called.  For the C events, no action is taken.
87
88        The arg parameter depends on the previous event.
89        """
90
91        self.enterframe = frame
92
93        if self.quitting:
94            return # None
95        if event == 'line':
96            return self.dispatch_line(frame)
97        if event == 'call':
98            return self.dispatch_call(frame, arg)
99        if event == 'return':
100            return self.dispatch_return(frame, arg)
101        if event == 'exception':
102            return self.dispatch_exception(frame, arg)
103        if event == 'c_call':
104            return self.trace_dispatch
105        if event == 'c_exception':
106            return self.trace_dispatch
107        if event == 'c_return':
108            return self.trace_dispatch
109        if event == 'opcode':
110            return self.dispatch_opcode(frame, arg)
111        print('bdb.Bdb.dispatch: unknown debugging event:', repr(event))
112        return self.trace_dispatch
113
114    def dispatch_line(self, frame):
115        """Invoke user function and return trace function for line event.
116
117        If the debugger stops on the current line, invoke
118        self.user_line(). Raise BdbQuit if self.quitting is set.
119        Return self.trace_dispatch to continue tracing in this scope.
120        """
121        if self.stop_here(frame) or self.break_here(frame):
122            self.user_line(frame)
123            if self.quitting: raise BdbQuit
124        return self.trace_dispatch
125
126    def dispatch_call(self, frame, arg):
127        """Invoke user function and return trace function for call event.
128
129        If the debugger stops on this function call, invoke
130        self.user_call(). Raise BdbQuit if self.quitting is set.
131        Return self.trace_dispatch to continue tracing in this scope.
132        """
133        # XXX 'arg' is no longer used
134        if self.botframe is None:
135            # First call of dispatch since reset()
136            self.botframe = frame.f_back # (CT) Note that this may also be None!
137            return self.trace_dispatch
138        if not (self.stop_here(frame) or self.break_anywhere(frame)):
139            # No need to trace this function
140            return # None
141        # Ignore call events in generator except when stepping.
142        if self.stopframe and frame.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS:
143            return self.trace_dispatch
144        self.user_call(frame, arg)
145        if self.quitting: raise BdbQuit
146        return self.trace_dispatch
147
148    def dispatch_return(self, frame, arg):
149        """Invoke user function and return trace function for return event.
150
151        If the debugger stops on this function return, invoke
152        self.user_return(). Raise BdbQuit if self.quitting is set.
153        Return self.trace_dispatch to continue tracing in this scope.
154        """
155        if self.stop_here(frame) or frame == self.returnframe:
156            # Ignore return events in generator except when stepping.
157            if self.stopframe and frame.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS:
158                return self.trace_dispatch
159            try:
160                self.frame_returning = frame
161                self.user_return(frame, arg)
162            finally:
163                self.frame_returning = None
164            if self.quitting: raise BdbQuit
165            # The user issued a 'next' or 'until' command.
166            if self.stopframe is frame and self.stoplineno != -1:
167                self._set_stopinfo(None, None)
168            # The previous frame might not have f_trace set, unless we are
169            # issuing a command that does not expect to stop, we should set
170            # f_trace
171            if self.stoplineno != -1:
172                self._set_caller_tracefunc(frame)
173        return self.trace_dispatch
174
175    def dispatch_exception(self, frame, arg):
176        """Invoke user function and return trace function for exception event.
177
178        If the debugger stops on this exception, invoke
179        self.user_exception(). Raise BdbQuit if self.quitting is set.
180        Return self.trace_dispatch to continue tracing in this scope.
181        """
182        if self.stop_here(frame):
183            # When stepping with next/until/return in a generator frame, skip
184            # the internal StopIteration exception (with no traceback)
185            # triggered by a subiterator run with the 'yield from' statement.
186            if not (frame.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS
187                    and arg[0] is StopIteration and arg[2] is None):
188                self.user_exception(frame, arg)
189                if self.quitting: raise BdbQuit
190        # Stop at the StopIteration or GeneratorExit exception when the user
191        # has set stopframe in a generator by issuing a return command, or a
192        # next/until command at the last statement in the generator before the
193        # exception.
194        elif (self.stopframe and frame is not self.stopframe
195                and self.stopframe.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS
196                and arg[0] in (StopIteration, GeneratorExit)):
197            self.user_exception(frame, arg)
198            if self.quitting: raise BdbQuit
199
200        return self.trace_dispatch
201
202    def dispatch_opcode(self, frame, arg):
203        """Invoke user function and return trace function for opcode event.
204        If the debugger stops on the current opcode, invoke
205        self.user_opcode(). Raise BdbQuit if self.quitting is set.
206        Return self.trace_dispatch to continue tracing in this scope.
207        """
208        if self.stop_here(frame) or self.break_here(frame):
209            self.user_opcode(frame)
210            if self.quitting: raise BdbQuit
211        return self.trace_dispatch
212
213    # Normally derived classes don't override the following
214    # methods, but they may if they want to redefine the
215    # definition of stopping and breakpoints.
216
217    def is_skipped_module(self, module_name):
218        "Return True if module_name matches any skip pattern."
219        if module_name is None:  # some modules do not have names
220            return False
221        for pattern in self.skip:
222            if fnmatch.fnmatch(module_name, pattern):
223                return True
224        return False
225
226    def stop_here(self, frame):
227        "Return True if frame is below the starting frame in the stack."
228        # (CT) stopframe may now also be None, see dispatch_call.
229        # (CT) the former test for None is therefore removed from here.
230        if self.skip and \
231               self.is_skipped_module(frame.f_globals.get('__name__')):
232            return False
233        if frame is self.stopframe:
234            if self.stoplineno == -1:
235                return False
236            return frame.f_lineno >= self.stoplineno
237        if not self.stopframe:
238            return True
239        return False
240
241    def break_here(self, frame):
242        """Return True if there is an effective breakpoint for this line.
243
244        Check for line or function breakpoint and if in effect.
245        Delete temporary breakpoints if effective() says to.
246        """
247        filename = self.canonic(frame.f_code.co_filename)
248        if filename not in self.breaks:
249            return False
250        lineno = frame.f_lineno
251        if lineno not in self.breaks[filename]:
252            # The line itself has no breakpoint, but maybe the line is the
253            # first line of a function with breakpoint set by function name.
254            lineno = frame.f_code.co_firstlineno
255            if lineno not in self.breaks[filename]:
256                return False
257
258        # flag says ok to delete temp. bp
259        (bp, flag) = effective(filename, lineno, frame)
260        if bp:
261            self.currentbp = bp.number
262            if (flag and bp.temporary):
263                self.do_clear(str(bp.number))
264            return True
265        else:
266            return False
267
268    def do_clear(self, arg):
269        """Remove temporary breakpoint.
270
271        Must implement in derived classes or get NotImplementedError.
272        """
273        raise NotImplementedError("subclass of bdb must implement do_clear()")
274
275    def break_anywhere(self, frame):
276        """Return True if there is any breakpoint for frame's filename.
277        """
278        return self.canonic(frame.f_code.co_filename) in self.breaks
279
280    # Derived classes should override the user_* methods
281    # to gain control.
282
283    def user_call(self, frame, argument_list):
284        """Called if we might stop in a function."""
285        pass
286
287    def user_line(self, frame):
288        """Called when we stop or break at a line."""
289        pass
290
291    def user_return(self, frame, return_value):
292        """Called when a return trap is set here."""
293        pass
294
295    def user_exception(self, frame, exc_info):
296        """Called when we stop on an exception."""
297        pass
298
299    def user_opcode(self, frame):
300        """Called when we are about to execute an opcode."""
301        pass
302
303    def _set_trace_opcodes(self, trace_opcodes):
304        if trace_opcodes != self.trace_opcodes:
305            self.trace_opcodes = trace_opcodes
306            frame = self.enterframe
307            while frame is not None:
308                frame.f_trace_opcodes = trace_opcodes
309                if frame is self.botframe:
310                    break
311                frame = frame.f_back
312
313    def _set_stopinfo(self, stopframe, returnframe, stoplineno=0, opcode=False):
314        """Set the attributes for stopping.
315
316        If stoplineno is greater than or equal to 0, then stop at line
317        greater than or equal to the stopline.  If stoplineno is -1, then
318        don't stop at all.
319        """
320        self.stopframe = stopframe
321        self.returnframe = returnframe
322        self.quitting = False
323        # stoplineno >= 0 means: stop at line >= the stoplineno
324        # stoplineno -1 means: don't stop at all
325        self.stoplineno = stoplineno
326        self._set_trace_opcodes(opcode)
327
328    def _set_caller_tracefunc(self, current_frame):
329        # Issue #13183: pdb skips frames after hitting a breakpoint and running
330        # step commands.
331        # Restore the trace function in the caller (that may not have been set
332        # for performance reasons) when returning from the current frame, unless
333        # the caller is the botframe.
334        caller_frame = current_frame.f_back
335        if caller_frame and not caller_frame.f_trace and caller_frame is not self.botframe:
336            caller_frame.f_trace = self.trace_dispatch
337
338    # Derived classes and clients can call the following methods
339    # to affect the stepping state.
340
341    def set_until(self, frame, lineno=None):
342        """Stop when the line with the lineno greater than the current one is
343        reached or when returning from current frame."""
344        # the name "until" is borrowed from gdb
345        if lineno is None:
346            lineno = frame.f_lineno + 1
347        self._set_stopinfo(frame, frame, lineno)
348
349    def set_step(self):
350        """Stop after one line of code."""
351        self._set_stopinfo(None, None)
352
353    def set_stepinstr(self):
354        """Stop before the next instruction."""
355        self._set_stopinfo(None, None, opcode=True)
356
357    def set_next(self, frame):
358        """Stop on the next line in or below the given frame."""
359        self._set_stopinfo(frame, None)
360
361    def set_return(self, frame):
362        """Stop when returning from the given frame."""
363        if frame.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS:
364            self._set_stopinfo(frame, None, -1)
365        else:
366            self._set_stopinfo(frame.f_back, frame)
367
368    def set_trace(self, frame=None):
369        """Start debugging from frame.
370
371        If frame is not specified, debugging starts from caller's frame.
372        """
373        if frame is None:
374            frame = sys._getframe().f_back
375        self.reset()
376        self.enterframe = frame
377        while frame:
378            frame.f_trace = self.trace_dispatch
379            self.botframe = frame
380            self.frame_trace_lines_opcodes[frame] = (frame.f_trace_lines, frame.f_trace_opcodes)
381            # We need f_trace_lines == True for the debugger to work
382            frame.f_trace_lines = True
383            frame = frame.f_back
384        self.set_stepinstr()
385        sys.settrace(self.trace_dispatch)
386
387    def set_continue(self):
388        """Stop only at breakpoints or when finished.
389
390        If there are no breakpoints, set the system trace function to None.
391        """
392        # Don't stop except at breakpoints or when finished
393        self._set_stopinfo(self.botframe, None, -1)
394        if not self.breaks:
395            # no breakpoints; run without debugger overhead
396            sys.settrace(None)
397            frame = sys._getframe().f_back
398            while frame and frame is not self.botframe:
399                del frame.f_trace
400                frame = frame.f_back
401            for frame, (trace_lines, trace_opcodes) in self.frame_trace_lines_opcodes.items():
402                frame.f_trace_lines, frame.f_trace_opcodes = trace_lines, trace_opcodes
403            self.frame_trace_lines_opcodes = {}
404
405    def set_quit(self):
406        """Set quitting attribute to True.
407
408        Raises BdbQuit exception in the next call to a dispatch_*() method.
409        """
410        self.stopframe = self.botframe
411        self.returnframe = None
412        self.quitting = True
413        sys.settrace(None)
414
415    # Derived classes and clients can call the following methods
416    # to manipulate breakpoints.  These methods return an
417    # error message if something went wrong, None if all is well.
418    # Set_break prints out the breakpoint line and file:lineno.
419    # Call self.get_*break*() to see the breakpoints or better
420    # for bp in Breakpoint.bpbynumber: if bp: bp.bpprint().
421
422    def _add_to_breaks(self, filename, lineno):
423        """Add breakpoint to breaks, if not already there."""
424        bp_linenos = self.breaks.setdefault(filename, [])
425        if lineno not in bp_linenos:
426            bp_linenos.append(lineno)
427
428    def set_break(self, filename, lineno, temporary=False, cond=None,
429                  funcname=None):
430        """Set a new breakpoint for filename:lineno.
431
432        If lineno doesn't exist for the filename, return an error message.
433        The filename should be in canonical form.
434        """
435        filename = self.canonic(filename)
436        import linecache # Import as late as possible
437        line = linecache.getline(filename, lineno)
438        if not line:
439            return 'Line %s:%d does not exist' % (filename, lineno)
440        self._add_to_breaks(filename, lineno)
441        bp = Breakpoint(filename, lineno, temporary, cond, funcname)
442        # After we set a new breakpoint, we need to search through all frames
443        # and set f_trace to trace_dispatch if there could be a breakpoint in
444        # that frame.
445        frame = self.enterframe
446        while frame:
447            if self.break_anywhere(frame):
448                frame.f_trace = self.trace_dispatch
449            frame = frame.f_back
450        return None
451
452    def _load_breaks(self):
453        """Apply all breakpoints (set in other instances) to this one.
454
455        Populates this instance's breaks list from the Breakpoint class's
456        list, which can have breakpoints set by another Bdb instance. This
457        is necessary for interactive sessions to keep the breakpoints
458        active across multiple calls to run().
459        """
460        for (filename, lineno) in Breakpoint.bplist.keys():
461            self._add_to_breaks(filename, lineno)
462
463    def _prune_breaks(self, filename, lineno):
464        """Prune breakpoints for filename:lineno.
465
466        A list of breakpoints is maintained in the Bdb instance and in
467        the Breakpoint class.  If a breakpoint in the Bdb instance no
468        longer exists in the Breakpoint class, then it's removed from the
469        Bdb instance.
470        """
471        if (filename, lineno) not in Breakpoint.bplist:
472            self.breaks[filename].remove(lineno)
473        if not self.breaks[filename]:
474            del self.breaks[filename]
475
476    def clear_break(self, filename, lineno):
477        """Delete breakpoints for filename:lineno.
478
479        If no breakpoints were set, return an error message.
480        """
481        filename = self.canonic(filename)
482        if filename not in self.breaks:
483            return 'There are no breakpoints in %s' % filename
484        if lineno not in self.breaks[filename]:
485            return 'There is no breakpoint at %s:%d' % (filename, lineno)
486        # If there's only one bp in the list for that file,line
487        # pair, then remove the breaks entry
488        for bp in Breakpoint.bplist[filename, lineno][:]:
489            bp.deleteMe()
490        self._prune_breaks(filename, lineno)
491        return None
492
493    def clear_bpbynumber(self, arg):
494        """Delete a breakpoint by its index in Breakpoint.bpbynumber.
495
496        If arg is invalid, return an error message.
497        """
498        try:
499            bp = self.get_bpbynumber(arg)
500        except ValueError as err:
501            return str(err)
502        bp.deleteMe()
503        self._prune_breaks(bp.file, bp.line)
504        return None
505
506    def clear_all_file_breaks(self, filename):
507        """Delete all breakpoints in filename.
508
509        If none were set, return an error message.
510        """
511        filename = self.canonic(filename)
512        if filename not in self.breaks:
513            return 'There are no breakpoints in %s' % filename
514        for line in self.breaks[filename]:
515            blist = Breakpoint.bplist[filename, line]
516            for bp in blist:
517                bp.deleteMe()
518        del self.breaks[filename]
519        return None
520
521    def clear_all_breaks(self):
522        """Delete all existing breakpoints.
523
524        If none were set, return an error message.
525        """
526        if not self.breaks:
527            return 'There are no breakpoints'
528        for bp in Breakpoint.bpbynumber:
529            if bp:
530                bp.deleteMe()
531        self.breaks = {}
532        return None
533
534    def get_bpbynumber(self, arg):
535        """Return a breakpoint by its index in Breakpoint.bybpnumber.
536
537        For invalid arg values or if the breakpoint doesn't exist,
538        raise a ValueError.
539        """
540        if not arg:
541            raise ValueError('Breakpoint number expected')
542        try:
543            number = int(arg)
544        except ValueError:
545            raise ValueError('Non-numeric breakpoint number %s' % arg) from None
546        try:
547            bp = Breakpoint.bpbynumber[number]
548        except IndexError:
549            raise ValueError('Breakpoint number %d out of range' % number) from None
550        if bp is None:
551            raise ValueError('Breakpoint %d already deleted' % number)
552        return bp
553
554    def get_break(self, filename, lineno):
555        """Return True if there is a breakpoint for filename:lineno."""
556        filename = self.canonic(filename)
557        return filename in self.breaks and \
558            lineno in self.breaks[filename]
559
560    def get_breaks(self, filename, lineno):
561        """Return all breakpoints for filename:lineno.
562
563        If no breakpoints are set, return an empty list.
564        """
565        filename = self.canonic(filename)
566        return filename in self.breaks and \
567            lineno in self.breaks[filename] and \
568            Breakpoint.bplist[filename, lineno] or []
569
570    def get_file_breaks(self, filename):
571        """Return all lines with breakpoints for filename.
572
573        If no breakpoints are set, return an empty list.
574        """
575        filename = self.canonic(filename)
576        if filename in self.breaks:
577            return self.breaks[filename]
578        else:
579            return []
580
581    def get_all_breaks(self):
582        """Return all breakpoints that are set."""
583        return self.breaks
584
585    # Derived classes and clients can call the following method
586    # to get a data structure representing a stack trace.
587
588    def get_stack(self, f, t):
589        """Return a list of (frame, lineno) in a stack trace and a size.
590
591        List starts with original calling frame, if there is one.
592        Size may be number of frames above or below f.
593        """
594        stack = []
595        if t and t.tb_frame is f:
596            t = t.tb_next
597        while f is not None:
598            stack.append((f, f.f_lineno))
599            if f is self.botframe:
600                break
601            f = f.f_back
602        stack.reverse()
603        i = max(0, len(stack) - 1)
604        while t is not None:
605            stack.append((t.tb_frame, t.tb_lineno))
606            t = t.tb_next
607        if f is None:
608            i = max(0, len(stack) - 1)
609        return stack, i
610
611    def format_stack_entry(self, frame_lineno, lprefix=': '):
612        """Return a string with information about a stack entry.
613
614        The stack entry frame_lineno is a (frame, lineno) tuple.  The
615        return string contains the canonical filename, the function name
616        or '<lambda>', the input arguments, the return value, and the
617        line of code (if it exists).
618
619        """
620        import linecache, reprlib
621        frame, lineno = frame_lineno
622        filename = self.canonic(frame.f_code.co_filename)
623        s = '%s(%r)' % (filename, lineno)
624        if frame.f_code.co_name:
625            s += frame.f_code.co_name
626        else:
627            s += "<lambda>"
628        s += '()'
629        if '__return__' in frame.f_locals:
630            rv = frame.f_locals['__return__']
631            s += '->'
632            s += reprlib.repr(rv)
633        if lineno is not None:
634            line = linecache.getline(filename, lineno, frame.f_globals)
635            if line:
636                s += lprefix + line.strip()
637        else:
638            s += f'{lprefix}Warning: lineno is None'
639        return s
640
641    # The following methods can be called by clients to use
642    # a debugger to debug a statement or an expression.
643    # Both can be given as a string, or a code object.
644
645    def run(self, cmd, globals=None, locals=None):
646        """Debug a statement executed via the exec() function.
647
648        globals defaults to __main__.dict; locals defaults to globals.
649        """
650        if globals is None:
651            import __main__
652            globals = __main__.__dict__
653        if locals is None:
654            locals = globals
655        self.reset()
656        if isinstance(cmd, str):
657            cmd = compile(cmd, "<string>", "exec")
658        sys.settrace(self.trace_dispatch)
659        try:
660            exec(cmd, globals, locals)
661        except BdbQuit:
662            pass
663        finally:
664            self.quitting = True
665            sys.settrace(None)
666
667    def runeval(self, expr, globals=None, locals=None):
668        """Debug an expression executed via the eval() function.
669
670        globals defaults to __main__.dict; locals defaults to globals.
671        """
672        if globals is None:
673            import __main__
674            globals = __main__.__dict__
675        if locals is None:
676            locals = globals
677        self.reset()
678        sys.settrace(self.trace_dispatch)
679        try:
680            return eval(expr, globals, locals)
681        except BdbQuit:
682            pass
683        finally:
684            self.quitting = True
685            sys.settrace(None)
686
687    def runctx(self, cmd, globals, locals):
688        """For backwards-compatibility.  Defers to run()."""
689        # B/W compatibility
690        self.run(cmd, globals, locals)
691
692    # This method is more useful to debug a single function call.
693
694    def runcall(self, func, /, *args, **kwds):
695        """Debug a single function call.
696
697        Return the result of the function call.
698        """
699        self.reset()
700        sys.settrace(self.trace_dispatch)
701        res = None
702        try:
703            res = func(*args, **kwds)
704        except BdbQuit:
705            pass
706        finally:
707            self.quitting = True
708            sys.settrace(None)
709        return res
710
711
712def set_trace():
713    """Start debugging with a Bdb instance from the caller's frame."""
714    Bdb().set_trace()
715
716
717class Breakpoint:
718    """Breakpoint class.
719
720    Implements temporary breakpoints, ignore counts, disabling and
721    (re)-enabling, and conditionals.
722
723    Breakpoints are indexed by number through bpbynumber and by
724    the (file, line) tuple using bplist.  The former points to a
725    single instance of class Breakpoint.  The latter points to a
726    list of such instances since there may be more than one
727    breakpoint per line.
728
729    When creating a breakpoint, its associated filename should be
730    in canonical form.  If funcname is defined, a breakpoint hit will be
731    counted when the first line of that function is executed.  A
732    conditional breakpoint always counts a hit.
733    """
734
735    # XXX Keeping state in the class is a mistake -- this means
736    # you cannot have more than one active Bdb instance.
737
738    next = 1        # Next bp to be assigned
739    bplist = {}     # indexed by (file, lineno) tuple
740    bpbynumber = [None] # Each entry is None or an instance of Bpt
741                # index 0 is unused, except for marking an
742                # effective break .... see effective()
743
744    def __init__(self, file, line, temporary=False, cond=None, funcname=None):
745        self.funcname = funcname
746        # Needed if funcname is not None.
747        self.func_first_executable_line = None
748        self.file = file    # This better be in canonical form!
749        self.line = line
750        self.temporary = temporary
751        self.cond = cond
752        self.enabled = True
753        self.ignore = 0
754        self.hits = 0
755        self.number = Breakpoint.next
756        Breakpoint.next += 1
757        # Build the two lists
758        self.bpbynumber.append(self)
759        if (file, line) in self.bplist:
760            self.bplist[file, line].append(self)
761        else:
762            self.bplist[file, line] = [self]
763
764    @staticmethod
765    def clearBreakpoints():
766        Breakpoint.next = 1
767        Breakpoint.bplist = {}
768        Breakpoint.bpbynumber = [None]
769
770    def deleteMe(self):
771        """Delete the breakpoint from the list associated to a file:line.
772
773        If it is the last breakpoint in that position, it also deletes
774        the entry for the file:line.
775        """
776
777        index = (self.file, self.line)
778        self.bpbynumber[self.number] = None   # No longer in list
779        self.bplist[index].remove(self)
780        if not self.bplist[index]:
781            # No more bp for this f:l combo
782            del self.bplist[index]
783
784    def enable(self):
785        """Mark the breakpoint as enabled."""
786        self.enabled = True
787
788    def disable(self):
789        """Mark the breakpoint as disabled."""
790        self.enabled = False
791
792    def bpprint(self, out=None):
793        """Print the output of bpformat().
794
795        The optional out argument directs where the output is sent
796        and defaults to standard output.
797        """
798        if out is None:
799            out = sys.stdout
800        print(self.bpformat(), file=out)
801
802    def bpformat(self):
803        """Return a string with information about the breakpoint.
804
805        The information includes the breakpoint number, temporary
806        status, file:line position, break condition, number of times to
807        ignore, and number of times hit.
808
809        """
810        if self.temporary:
811            disp = 'del  '
812        else:
813            disp = 'keep '
814        if self.enabled:
815            disp = disp + 'yes  '
816        else:
817            disp = disp + 'no   '
818        ret = '%-4dbreakpoint   %s at %s:%d' % (self.number, disp,
819                                                self.file, self.line)
820        if self.cond:
821            ret += '\n\tstop only if %s' % (self.cond,)
822        if self.ignore:
823            ret += '\n\tignore next %d hits' % (self.ignore,)
824        if self.hits:
825            if self.hits > 1:
826                ss = 's'
827            else:
828                ss = ''
829            ret += '\n\tbreakpoint already hit %d time%s' % (self.hits, ss)
830        return ret
831
832    def __str__(self):
833        "Return a condensed description of the breakpoint."
834        return 'breakpoint %s at %s:%s' % (self.number, self.file, self.line)
835
836# -----------end of Breakpoint class----------
837
838
839def checkfuncname(b, frame):
840    """Return True if break should happen here.
841
842    Whether a break should happen depends on the way that b (the breakpoint)
843    was set.  If it was set via line number, check if b.line is the same as
844    the one in the frame.  If it was set via function name, check if this is
845    the right function and if it is on the first executable line.
846    """
847    if not b.funcname:
848        # Breakpoint was set via line number.
849        if b.line != frame.f_lineno:
850            # Breakpoint was set at a line with a def statement and the function
851            # defined is called: don't break.
852            return False
853        return True
854
855    # Breakpoint set via function name.
856    if frame.f_code.co_name != b.funcname:
857        # It's not a function call, but rather execution of def statement.
858        return False
859
860    # We are in the right frame.
861    if not b.func_first_executable_line:
862        # The function is entered for the 1st time.
863        b.func_first_executable_line = frame.f_lineno
864
865    if b.func_first_executable_line != frame.f_lineno:
866        # But we are not at the first line number: don't break.
867        return False
868    return True
869
870
871def effective(file, line, frame):
872    """Return (active breakpoint, delete temporary flag) or (None, None) as
873       breakpoint to act upon.
874
875       The "active breakpoint" is the first entry in bplist[line, file] (which
876       must exist) that is enabled, for which checkfuncname is True, and that
877       has neither a False condition nor a positive ignore count.  The flag,
878       meaning that a temporary breakpoint should be deleted, is False only
879       when the condiion cannot be evaluated (in which case, ignore count is
880       ignored).
881
882       If no such entry exists, then (None, None) is returned.
883    """
884    possibles = Breakpoint.bplist[file, line]
885    for b in possibles:
886        if not b.enabled:
887            continue
888        if not checkfuncname(b, frame):
889            continue
890        # Count every hit when bp is enabled
891        b.hits += 1
892        if not b.cond:
893            # If unconditional, and ignoring go on to next, else break
894            if b.ignore > 0:
895                b.ignore -= 1
896                continue
897            else:
898                # breakpoint and marker that it's ok to delete if temporary
899                return (b, True)
900        else:
901            # Conditional bp.
902            # Ignore count applies only to those bpt hits where the
903            # condition evaluates to true.
904            try:
905                val = eval(b.cond, frame.f_globals, frame.f_locals)
906                if val:
907                    if b.ignore > 0:
908                        b.ignore -= 1
909                        # continue
910                    else:
911                        return (b, True)
912                # else:
913                #   continue
914            except:
915                # if eval fails, most conservative thing is to stop on
916                # breakpoint regardless of ignore count.  Don't delete
917                # temporary, as another hint to user.
918                return (b, False)
919    return (None, None)
920
921
922# -------------------- testing --------------------
923
924class Tdb(Bdb):
925    def user_call(self, frame, args):
926        name = frame.f_code.co_name
927        if not name: name = '???'
928        print('+++ call', name, args)
929    def user_line(self, frame):
930        import linecache
931        name = frame.f_code.co_name
932        if not name: name = '???'
933        fn = self.canonic(frame.f_code.co_filename)
934        line = linecache.getline(fn, frame.f_lineno, frame.f_globals)
935        print('+++', fn, frame.f_lineno, name, ':', line.strip())
936    def user_return(self, frame, retval):
937        print('+++ return', retval)
938    def user_exception(self, frame, exc_stuff):
939        print('+++ exception', exc_stuff)
940        self.set_continue()
941
942def foo(n):
943    print('foo(', n, ')')
944    x = bar(n*10)
945    print('bar returned', x)
946
947def bar(a):
948    print('bar(', a, ')')
949    return a/2
950
951def test():
952    t = Tdb()
953    t.run('import bdb; bdb.foo(10)')
954