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 line = linecache.getline(filename, lineno, frame.f_globals) 574 if line: 575 s += lprefix + line.strip() 576 return s 577 578 # The following methods can be called by clients to use 579 # a debugger to debug a statement or an expression. 580 # Both can be given as a string, or a code object. 581 582 def run(self, cmd, globals=None, locals=None): 583 """Debug a statement executed via the exec() function. 584 585 globals defaults to __main__.dict; locals defaults to globals. 586 """ 587 if globals is None: 588 import __main__ 589 globals = __main__.__dict__ 590 if locals is None: 591 locals = globals 592 self.reset() 593 if isinstance(cmd, str): 594 cmd = compile(cmd, "<string>", "exec") 595 sys.settrace(self.trace_dispatch) 596 try: 597 exec(cmd, globals, locals) 598 except BdbQuit: 599 pass 600 finally: 601 self.quitting = True 602 sys.settrace(None) 603 604 def runeval(self, expr, globals=None, locals=None): 605 """Debug an expression executed via the eval() function. 606 607 globals defaults to __main__.dict; locals defaults to globals. 608 """ 609 if globals is None: 610 import __main__ 611 globals = __main__.__dict__ 612 if locals is None: 613 locals = globals 614 self.reset() 615 sys.settrace(self.trace_dispatch) 616 try: 617 return eval(expr, globals, locals) 618 except BdbQuit: 619 pass 620 finally: 621 self.quitting = True 622 sys.settrace(None) 623 624 def runctx(self, cmd, globals, locals): 625 """For backwards-compatibility. Defers to run().""" 626 # B/W compatibility 627 self.run(cmd, globals, locals) 628 629 # This method is more useful to debug a single function call. 630 631 def runcall(self, func, /, *args, **kwds): 632 """Debug a single function call. 633 634 Return the result of the function call. 635 """ 636 self.reset() 637 sys.settrace(self.trace_dispatch) 638 res = None 639 try: 640 res = func(*args, **kwds) 641 except BdbQuit: 642 pass 643 finally: 644 self.quitting = True 645 sys.settrace(None) 646 return res 647 648 649def set_trace(): 650 """Start debugging with a Bdb instance from the caller's frame.""" 651 Bdb().set_trace() 652 653 654class Breakpoint: 655 """Breakpoint class. 656 657 Implements temporary breakpoints, ignore counts, disabling and 658 (re)-enabling, and conditionals. 659 660 Breakpoints are indexed by number through bpbynumber and by 661 the (file, line) tuple using bplist. The former points to a 662 single instance of class Breakpoint. The latter points to a 663 list of such instances since there may be more than one 664 breakpoint per line. 665 666 When creating a breakpoint, its associated filename should be 667 in canonical form. If funcname is defined, a breakpoint hit will be 668 counted when the first line of that function is executed. A 669 conditional breakpoint always counts a hit. 670 """ 671 672 # XXX Keeping state in the class is a mistake -- this means 673 # you cannot have more than one active Bdb instance. 674 675 next = 1 # Next bp to be assigned 676 bplist = {} # indexed by (file, lineno) tuple 677 bpbynumber = [None] # Each entry is None or an instance of Bpt 678 # index 0 is unused, except for marking an 679 # effective break .... see effective() 680 681 def __init__(self, file, line, temporary=False, cond=None, funcname=None): 682 self.funcname = funcname 683 # Needed if funcname is not None. 684 self.func_first_executable_line = None 685 self.file = file # This better be in canonical form! 686 self.line = line 687 self.temporary = temporary 688 self.cond = cond 689 self.enabled = True 690 self.ignore = 0 691 self.hits = 0 692 self.number = Breakpoint.next 693 Breakpoint.next += 1 694 # Build the two lists 695 self.bpbynumber.append(self) 696 if (file, line) in self.bplist: 697 self.bplist[file, line].append(self) 698 else: 699 self.bplist[file, line] = [self] 700 701 @staticmethod 702 def clearBreakpoints(): 703 Breakpoint.next = 1 704 Breakpoint.bplist = {} 705 Breakpoint.bpbynumber = [None] 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