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 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 652def set_trace(): 653 """Start debugging with a Bdb instance from the caller's frame.""" 654 Bdb().set_trace() 655 656 657class Breakpoint: 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 779def 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 811def 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 864class Tdb(Bdb): 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 882def foo(n): 883 print('foo(', n, ')') 884 x = bar(n*10) 885 print('bar returned', x) 886 887def bar(a): 888 print('bar(', a, ')') 889 return a/2 890 891def test(): 892 t = Tdb() 893 t.run('import bdb; bdb.foo(10)') 894