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