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