Coverage for /pythoncovmergedfiles/medio/medio/usr/lib/python3.9/bdb.py: 16%

445 statements  

« prev     ^ index     » next       coverage.py v7.3.1, created at 2023-09-25 06:05 +0000

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 s += '()' 

552 if '__return__' in frame.f_locals: 

553 rv = frame.f_locals['__return__'] 

554 s += '->' 

555 s += reprlib.repr(rv) 

556 line = linecache.getline(filename, lineno, frame.f_globals) 

557 if line: 

558 s += lprefix + line.strip() 

559 return s 

560 

561 # The following methods can be called by clients to use 

562 # a debugger to debug a statement or an expression. 

563 # Both can be given as a string, or a code object. 

564 

565 def run(self, cmd, globals=None, locals=None): 

566 """Debug a statement executed via the exec() function. 

567 

568 globals defaults to __main__.dict; locals defaults to globals. 

569 """ 

570 if globals is None: 

571 import __main__ 

572 globals = __main__.__dict__ 

573 if locals is None: 

574 locals = globals 

575 self.reset() 

576 if isinstance(cmd, str): 

577 cmd = compile(cmd, "<string>", "exec") 

578 sys.settrace(self.trace_dispatch) 

579 try: 

580 exec(cmd, globals, locals) 

581 except BdbQuit: 

582 pass 

583 finally: 

584 self.quitting = True 

585 sys.settrace(None) 

586 

587 def runeval(self, expr, globals=None, locals=None): 

588 """Debug an expression executed via the eval() function. 

589 

590 globals defaults to __main__.dict; locals defaults to globals. 

591 """ 

592 if globals is None: 

593 import __main__ 

594 globals = __main__.__dict__ 

595 if locals is None: 

596 locals = globals 

597 self.reset() 

598 sys.settrace(self.trace_dispatch) 

599 try: 

600 return eval(expr, globals, locals) 

601 except BdbQuit: 

602 pass 

603 finally: 

604 self.quitting = True 

605 sys.settrace(None) 

606 

607 def runctx(self, cmd, globals, locals): 

608 """For backwards-compatibility. Defers to run().""" 

609 # B/W compatibility 

610 self.run(cmd, globals, locals) 

611 

612 # This method is more useful to debug a single function call. 

613 

614 def runcall(self, func, /, *args, **kwds): 

615 """Debug a single function call. 

616 

617 Return the result of the function call. 

618 """ 

619 self.reset() 

620 sys.settrace(self.trace_dispatch) 

621 res = None 

622 try: 

623 res = func(*args, **kwds) 

624 except BdbQuit: 

625 pass 

626 finally: 

627 self.quitting = True 

628 sys.settrace(None) 

629 return res 

630 

631 

632def set_trace(): 

633 """Start debugging with a Bdb instance from the caller's frame.""" 

634 Bdb().set_trace() 

635 

636 

637class Breakpoint: 

638 """Breakpoint class. 

639 

640 Implements temporary breakpoints, ignore counts, disabling and 

641 (re)-enabling, and conditionals. 

642 

643 Breakpoints are indexed by number through bpbynumber and by 

644 the (file, line) tuple using bplist. The former points to a 

645 single instance of class Breakpoint. The latter points to a 

646 list of such instances since there may be more than one 

647 breakpoint per line. 

648 

649 When creating a breakpoint, its associated filename should be 

650 in canonical form. If funcname is defined, a breakpoint hit will be 

651 counted when the first line of that function is executed. A 

652 conditional breakpoint always counts a hit. 

653 """ 

654 

655 # XXX Keeping state in the class is a mistake -- this means 

656 # you cannot have more than one active Bdb instance. 

657 

658 next = 1 # Next bp to be assigned 

659 bplist = {} # indexed by (file, lineno) tuple 

660 bpbynumber = [None] # Each entry is None or an instance of Bpt 

661 # index 0 is unused, except for marking an 

662 # effective break .... see effective() 

663 

664 def __init__(self, file, line, temporary=False, cond=None, funcname=None): 

665 self.funcname = funcname 

666 # Needed if funcname is not None. 

667 self.func_first_executable_line = None 

668 self.file = file # This better be in canonical form! 

669 self.line = line 

670 self.temporary = temporary 

671 self.cond = cond 

672 self.enabled = True 

673 self.ignore = 0 

674 self.hits = 0 

675 self.number = Breakpoint.next 

676 Breakpoint.next += 1 

677 # Build the two lists 

678 self.bpbynumber.append(self) 

679 if (file, line) in self.bplist: 

680 self.bplist[file, line].append(self) 

681 else: 

682 self.bplist[file, line] = [self] 

683 

684 def deleteMe(self): 

685 """Delete the breakpoint from the list associated to a file:line. 

686 

687 If it is the last breakpoint in that position, it also deletes 

688 the entry for the file:line. 

689 """ 

690 

691 index = (self.file, self.line) 

692 self.bpbynumber[self.number] = None # No longer in list 

693 self.bplist[index].remove(self) 

694 if not self.bplist[index]: 

695 # No more bp for this f:l combo 

696 del self.bplist[index] 

697 

698 def enable(self): 

699 """Mark the breakpoint as enabled.""" 

700 self.enabled = True 

701 

702 def disable(self): 

703 """Mark the breakpoint as disabled.""" 

704 self.enabled = False 

705 

706 def bpprint(self, out=None): 

707 """Print the output of bpformat(). 

708 

709 The optional out argument directs where the output is sent 

710 and defaults to standard output. 

711 """ 

712 if out is None: 

713 out = sys.stdout 

714 print(self.bpformat(), file=out) 

715 

716 def bpformat(self): 

717 """Return a string with information about the breakpoint. 

718 

719 The information includes the breakpoint number, temporary 

720 status, file:line position, break condition, number of times to 

721 ignore, and number of times hit. 

722 

723 """ 

724 if self.temporary: 

725 disp = 'del ' 

726 else: 

727 disp = 'keep ' 

728 if self.enabled: 

729 disp = disp + 'yes ' 

730 else: 

731 disp = disp + 'no ' 

732 ret = '%-4dbreakpoint %s at %s:%d' % (self.number, disp, 

733 self.file, self.line) 

734 if self.cond: 

735 ret += '\n\tstop only if %s' % (self.cond,) 

736 if self.ignore: 

737 ret += '\n\tignore next %d hits' % (self.ignore,) 

738 if self.hits: 

739 if self.hits > 1: 

740 ss = 's' 

741 else: 

742 ss = '' 

743 ret += '\n\tbreakpoint already hit %d time%s' % (self.hits, ss) 

744 return ret 

745 

746 def __str__(self): 

747 "Return a condensed description of the breakpoint." 

748 return 'breakpoint %s at %s:%s' % (self.number, self.file, self.line) 

749 

750# -----------end of Breakpoint class---------- 

751 

752 

753def checkfuncname(b, frame): 

754 """Return True if break should happen here. 

755 

756 Whether a break should happen depends on the way that b (the breakpoint) 

757 was set. If it was set via line number, check if b.line is the same as 

758 the one in the frame. If it was set via function name, check if this is 

759 the right function and if it is on the first executable line. 

760 """ 

761 if not b.funcname: 

762 # Breakpoint was set via line number. 

763 if b.line != frame.f_lineno: 

764 # Breakpoint was set at a line with a def statement and the function 

765 # defined is called: don't break. 

766 return False 

767 return True 

768 

769 # Breakpoint set via function name. 

770 if frame.f_code.co_name != b.funcname: 

771 # It's not a function call, but rather execution of def statement. 

772 return False 

773 

774 # We are in the right frame. 

775 if not b.func_first_executable_line: 

776 # The function is entered for the 1st time. 

777 b.func_first_executable_line = frame.f_lineno 

778 

779 if b.func_first_executable_line != frame.f_lineno: 

780 # But we are not at the first line number: don't break. 

781 return False 

782 return True 

783 

784 

785# Determines if there is an effective (active) breakpoint at this 

786# line of code. Returns breakpoint number or 0 if none 

787def effective(file, line, frame): 

788 """Determine which breakpoint for this file:line is to be acted upon. 

789 

790 Called only if we know there is a breakpoint at this location. Return 

791 the breakpoint that was triggered and a boolean that indicates if it is 

792 ok to delete a temporary breakpoint. Return (None, None) if there is no 

793 matching breakpoint. 

794 """ 

795 possibles = Breakpoint.bplist[file, line] 

796 for b in possibles: 

797 if not b.enabled: 

798 continue 

799 if not checkfuncname(b, frame): 

800 continue 

801 # Count every hit when bp is enabled 

802 b.hits += 1 

803 if not b.cond: 

804 # If unconditional, and ignoring go on to next, else break 

805 if b.ignore > 0: 

806 b.ignore -= 1 

807 continue 

808 else: 

809 # breakpoint and marker that it's ok to delete if temporary 

810 return (b, True) 

811 else: 

812 # Conditional bp. 

813 # Ignore count applies only to those bpt hits where the 

814 # condition evaluates to true. 

815 try: 

816 val = eval(b.cond, frame.f_globals, frame.f_locals) 

817 if val: 

818 if b.ignore > 0: 

819 b.ignore -= 1 

820 # continue 

821 else: 

822 return (b, True) 

823 # else: 

824 # continue 

825 except: 

826 # if eval fails, most conservative thing is to stop on 

827 # breakpoint regardless of ignore count. Don't delete 

828 # temporary, as another hint to user. 

829 return (b, False) 

830 return (None, None) 

831 

832 

833# -------------------- testing -------------------- 

834 

835class Tdb(Bdb): 

836 def user_call(self, frame, args): 

837 name = frame.f_code.co_name 

838 if not name: name = '???' 

839 print('+++ call', name, args) 

840 def user_line(self, frame): 

841 import linecache 

842 name = frame.f_code.co_name 

843 if not name: name = '???' 

844 fn = self.canonic(frame.f_code.co_filename) 

845 line = linecache.getline(fn, frame.f_lineno, frame.f_globals) 

846 print('+++', fn, frame.f_lineno, name, ':', line.strip()) 

847 def user_return(self, frame, retval): 

848 print('+++ return', retval) 

849 def user_exception(self, frame, exc_stuff): 

850 print('+++ exception', exc_stuff) 

851 self.set_continue() 

852 

853def foo(n): 

854 print('foo(', n, ')') 

855 x = bar(n*10) 

856 print('bar returned', x) 

857 

858def bar(a): 

859 print('bar(', a, ')') 

860 return a/2 

861 

862def test(): 

863 t = Tdb() 

864 t.run('import bdb; bdb.foo(10)')