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