Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/IPython/core/debugger.py: 15%

490 statements  

« prev     ^ index     » next       coverage.py v7.4.4, created at 2024-04-20 06:09 +0000

1# -*- coding: utf-8 -*- 

2""" 

3Pdb debugger class. 

4 

5 

6This is an extension to PDB which adds a number of new features. 

7Note that there is also the `IPython.terminal.debugger` class which provides UI 

8improvements. 

9 

10We also strongly recommend to use this via the `ipdb` package, which provides 

11extra configuration options. 

12 

13Among other things, this subclass of PDB: 

14 - supports many IPython magics like pdef/psource 

15 - hide frames in tracebacks based on `__tracebackhide__` 

16 - allows to skip frames based on `__debuggerskip__` 

17 

18The skipping and hiding frames are configurable via the `skip_predicates` 

19command. 

20 

21By default, frames from readonly files will be hidden, frames containing 

22``__tracebackhide__=True`` will be hidden. 

23 

24Frames containing ``__debuggerskip__`` will be stepped over, frames who's parent 

25frames value of ``__debuggerskip__`` is ``True`` will be skipped. 

26 

27 >>> def helpers_helper(): 

28 ... pass 

29 ... 

30 ... def helper_1(): 

31 ... print("don't step in me") 

32 ... helpers_helpers() # will be stepped over unless breakpoint set. 

33 ... 

34 ... 

35 ... def helper_2(): 

36 ... print("in me neither") 

37 ... 

38 

39One can define a decorator that wraps a function between the two helpers: 

40 

41 >>> def pdb_skipped_decorator(function): 

42 ... 

43 ... 

44 ... def wrapped_fn(*args, **kwargs): 

45 ... __debuggerskip__ = True 

46 ... helper_1() 

47 ... __debuggerskip__ = False 

48 ... result = function(*args, **kwargs) 

49 ... __debuggerskip__ = True 

50 ... helper_2() 

51 ... # setting __debuggerskip__ to False again is not necessary 

52 ... return result 

53 ... 

54 ... return wrapped_fn 

55 

56When decorating a function, ipdb will directly step into ``bar()`` by 

57default: 

58 

59 >>> @foo_decorator 

60 ... def bar(x, y): 

61 ... return x * y 

62 

63 

64You can toggle the behavior with 

65 

66 ipdb> skip_predicates debuggerskip false 

67 

68or configure it in your ``.pdbrc`` 

69 

70 

71 

72License 

73------- 

74 

75Modified from the standard pdb.Pdb class to avoid including readline, so that 

76the command line completion of other programs which include this isn't 

77damaged. 

78 

79In the future, this class will be expanded with improvements over the standard 

80pdb. 

81 

82The original code in this file is mainly lifted out of cmd.py in Python 2.2, 

83with minor changes. Licensing should therefore be under the standard Python 

84terms. For details on the PSF (Python Software Foundation) standard license, 

85see: 

86 

87https://docs.python.org/2/license.html 

88 

89 

90All the changes since then are under the same license as IPython. 

91 

92""" 

93 

94#***************************************************************************** 

95# 

96# This file is licensed under the PSF license. 

97# 

98# Copyright (C) 2001 Python Software Foundation, www.python.org 

99# Copyright (C) 2005-2006 Fernando Perez. <fperez@colorado.edu> 

100# 

101# 

102#***************************************************************************** 

103 

104import inspect 

105import linecache 

106import sys 

107import re 

108import os 

109 

110from IPython import get_ipython 

111from IPython.utils import PyColorize 

112from IPython.utils import coloransi, py3compat 

113from IPython.core.excolors import exception_colors 

114 

115# skip module docstests 

116__skip_doctest__ = True 

117 

118prompt = 'ipdb> ' 

119 

120# We have to check this directly from sys.argv, config struct not yet available 

121from pdb import Pdb as OldPdb 

122 

123# Allow the set_trace code to operate outside of an ipython instance, even if 

124# it does so with some limitations. The rest of this support is implemented in 

125# the Tracer constructor. 

126 

127DEBUGGERSKIP = "__debuggerskip__" 

128 

129 

130def make_arrow(pad): 

131 """generate the leading arrow in front of traceback or debugger""" 

132 if pad >= 2: 

133 return '-'*(pad-2) + '> ' 

134 elif pad == 1: 

135 return '>' 

136 return '' 

137 

138 

139def BdbQuit_excepthook(et, ev, tb, excepthook=None): 

140 """Exception hook which handles `BdbQuit` exceptions. 

141 

142 All other exceptions are processed using the `excepthook` 

143 parameter. 

144 """ 

145 raise ValueError( 

146 "`BdbQuit_excepthook` is deprecated since version 5.1", 

147 ) 

148 

149 

150def BdbQuit_IPython_excepthook(self, et, ev, tb, tb_offset=None): 

151 raise ValueError( 

152 "`BdbQuit_IPython_excepthook` is deprecated since version 5.1", 

153 DeprecationWarning, stacklevel=2) 

154 

155 

156RGX_EXTRA_INDENT = re.compile(r'(?<=\n)\s+') 

157 

158 

159def strip_indentation(multiline_string): 

160 return RGX_EXTRA_INDENT.sub('', multiline_string) 

161 

162 

163def decorate_fn_with_doc(new_fn, old_fn, additional_text=""): 

164 """Make new_fn have old_fn's doc string. This is particularly useful 

165 for the ``do_...`` commands that hook into the help system. 

166 Adapted from from a comp.lang.python posting 

167 by Duncan Booth.""" 

168 def wrapper(*args, **kw): 

169 return new_fn(*args, **kw) 

170 if old_fn.__doc__: 

171 wrapper.__doc__ = strip_indentation(old_fn.__doc__) + additional_text 

172 return wrapper 

173 

174 

175class Pdb(OldPdb): 

176 """Modified Pdb class, does not load readline. 

177 

178 for a standalone version that uses prompt_toolkit, see 

179 `IPython.terminal.debugger.TerminalPdb` and 

180 `IPython.terminal.debugger.set_trace()` 

181 

182 

183 This debugger can hide and skip frames that are tagged according to some predicates. 

184 See the `skip_predicates` commands. 

185 

186 """ 

187 

188 default_predicates = { 

189 "tbhide": True, 

190 "readonly": False, 

191 "ipython_internal": True, 

192 "debuggerskip": True, 

193 } 

194 

195 def __init__(self, completekey=None, stdin=None, stdout=None, context=5, **kwargs): 

196 """Create a new IPython debugger. 

197 

198 Parameters 

199 ---------- 

200 completekey : default None 

201 Passed to pdb.Pdb. 

202 stdin : default None 

203 Passed to pdb.Pdb. 

204 stdout : default None 

205 Passed to pdb.Pdb. 

206 context : int 

207 Number of lines of source code context to show when 

208 displaying stacktrace information. 

209 **kwargs 

210 Passed to pdb.Pdb. 

211 

212 Notes 

213 ----- 

214 The possibilities are python version dependent, see the python 

215 docs for more info. 

216 """ 

217 

218 # Parent constructor: 

219 try: 

220 self.context = int(context) 

221 if self.context <= 0: 

222 raise ValueError("Context must be a positive integer") 

223 except (TypeError, ValueError) as e: 

224 raise ValueError("Context must be a positive integer") from e 

225 

226 # `kwargs` ensures full compatibility with stdlib's `pdb.Pdb`. 

227 OldPdb.__init__(self, completekey, stdin, stdout, **kwargs) 

228 

229 # IPython changes... 

230 self.shell = get_ipython() 

231 

232 if self.shell is None: 

233 save_main = sys.modules['__main__'] 

234 # No IPython instance running, we must create one 

235 from IPython.terminal.interactiveshell import \ 

236 TerminalInteractiveShell 

237 self.shell = TerminalInteractiveShell.instance() 

238 # needed by any code which calls __import__("__main__") after 

239 # the debugger was entered. See also #9941. 

240 sys.modules["__main__"] = save_main 

241 

242 

243 color_scheme = self.shell.colors 

244 

245 self.aliases = {} 

246 

247 # Create color table: we copy the default one from the traceback 

248 # module and add a few attributes needed for debugging 

249 self.color_scheme_table = exception_colors() 

250 

251 # shorthands 

252 C = coloransi.TermColors 

253 cst = self.color_scheme_table 

254 

255 cst['NoColor'].colors.prompt = C.NoColor 

256 cst['NoColor'].colors.breakpoint_enabled = C.NoColor 

257 cst['NoColor'].colors.breakpoint_disabled = C.NoColor 

258 

259 cst['Linux'].colors.prompt = C.Green 

260 cst['Linux'].colors.breakpoint_enabled = C.LightRed 

261 cst['Linux'].colors.breakpoint_disabled = C.Red 

262 

263 cst['LightBG'].colors.prompt = C.Blue 

264 cst['LightBG'].colors.breakpoint_enabled = C.LightRed 

265 cst['LightBG'].colors.breakpoint_disabled = C.Red 

266 

267 cst['Neutral'].colors.prompt = C.Blue 

268 cst['Neutral'].colors.breakpoint_enabled = C.LightRed 

269 cst['Neutral'].colors.breakpoint_disabled = C.Red 

270 

271 # Add a python parser so we can syntax highlight source while 

272 # debugging. 

273 self.parser = PyColorize.Parser(style=color_scheme) 

274 self.set_colors(color_scheme) 

275 

276 # Set the prompt - the default prompt is '(Pdb)' 

277 self.prompt = prompt 

278 self.skip_hidden = True 

279 self.report_skipped = True 

280 

281 # list of predicates we use to skip frames 

282 self._predicates = self.default_predicates 

283 

284 # 

285 def set_colors(self, scheme): 

286 """Shorthand access to the color table scheme selector method.""" 

287 self.color_scheme_table.set_active_scheme(scheme) 

288 self.parser.style = scheme 

289 

290 def set_trace(self, frame=None): 

291 if frame is None: 

292 frame = sys._getframe().f_back 

293 self.initial_frame = frame 

294 return super().set_trace(frame) 

295 

296 def _hidden_predicate(self, frame): 

297 """ 

298 Given a frame return whether it it should be hidden or not by IPython. 

299 """ 

300 

301 if self._predicates["readonly"]: 

302 fname = frame.f_code.co_filename 

303 # we need to check for file existence and interactively define 

304 # function would otherwise appear as RO. 

305 if os.path.isfile(fname) and not os.access(fname, os.W_OK): 

306 return True 

307 

308 if self._predicates["tbhide"]: 

309 if frame in (self.curframe, getattr(self, "initial_frame", None)): 

310 return False 

311 frame_locals = self._get_frame_locals(frame) 

312 if "__tracebackhide__" not in frame_locals: 

313 return False 

314 return frame_locals["__tracebackhide__"] 

315 return False 

316 

317 def hidden_frames(self, stack): 

318 """ 

319 Given an index in the stack return whether it should be skipped. 

320 

321 This is used in up/down and where to skip frames. 

322 """ 

323 # The f_locals dictionary is updated from the actual frame 

324 # locals whenever the .f_locals accessor is called, so we 

325 # avoid calling it here to preserve self.curframe_locals. 

326 # Furthermore, there is no good reason to hide the current frame. 

327 ip_hide = [self._hidden_predicate(s[0]) for s in stack] 

328 ip_start = [i for i, s in enumerate(ip_hide) if s == "__ipython_bottom__"] 

329 if ip_start and self._predicates["ipython_internal"]: 

330 ip_hide = [h if i > ip_start[0] else True for (i, h) in enumerate(ip_hide)] 

331 return ip_hide 

332 

333 def interaction(self, frame, traceback): 

334 try: 

335 OldPdb.interaction(self, frame, traceback) 

336 except KeyboardInterrupt: 

337 self.stdout.write("\n" + self.shell.get_exception_only()) 

338 

339 def precmd(self, line): 

340 """Perform useful escapes on the command before it is executed.""" 

341 

342 if line.endswith("??"): 

343 line = "pinfo2 " + line[:-2] 

344 elif line.endswith("?"): 

345 line = "pinfo " + line[:-1] 

346 

347 line = super().precmd(line) 

348 

349 return line 

350 

351 def new_do_frame(self, arg): 

352 OldPdb.do_frame(self, arg) 

353 

354 def new_do_quit(self, arg): 

355 

356 if hasattr(self, 'old_all_completions'): 

357 self.shell.Completer.all_completions = self.old_all_completions 

358 

359 return OldPdb.do_quit(self, arg) 

360 

361 do_q = do_quit = decorate_fn_with_doc(new_do_quit, OldPdb.do_quit) 

362 

363 def new_do_restart(self, arg): 

364 """Restart command. In the context of ipython this is exactly the same 

365 thing as 'quit'.""" 

366 self.msg("Restart doesn't make sense here. Using 'quit' instead.") 

367 return self.do_quit(arg) 

368 

369 def print_stack_trace(self, context=None): 

370 Colors = self.color_scheme_table.active_colors 

371 ColorsNormal = Colors.Normal 

372 if context is None: 

373 context = self.context 

374 try: 

375 context = int(context) 

376 if context <= 0: 

377 raise ValueError("Context must be a positive integer") 

378 except (TypeError, ValueError) as e: 

379 raise ValueError("Context must be a positive integer") from e 

380 try: 

381 skipped = 0 

382 for hidden, frame_lineno in zip(self.hidden_frames(self.stack), self.stack): 

383 if hidden and self.skip_hidden: 

384 skipped += 1 

385 continue 

386 if skipped: 

387 print( 

388 f"{Colors.excName} [... skipping {skipped} hidden frame(s)]{ColorsNormal}\n" 

389 ) 

390 skipped = 0 

391 self.print_stack_entry(frame_lineno, context=context) 

392 if skipped: 

393 print( 

394 f"{Colors.excName} [... skipping {skipped} hidden frame(s)]{ColorsNormal}\n" 

395 ) 

396 except KeyboardInterrupt: 

397 pass 

398 

399 def print_stack_entry(self, frame_lineno, prompt_prefix='\n-> ', 

400 context=None): 

401 if context is None: 

402 context = self.context 

403 try: 

404 context = int(context) 

405 if context <= 0: 

406 raise ValueError("Context must be a positive integer") 

407 except (TypeError, ValueError) as e: 

408 raise ValueError("Context must be a positive integer") from e 

409 print(self.format_stack_entry(frame_lineno, '', context), file=self.stdout) 

410 

411 # vds: >> 

412 frame, lineno = frame_lineno 

413 filename = frame.f_code.co_filename 

414 self.shell.hooks.synchronize_with_editor(filename, lineno, 0) 

415 # vds: << 

416 

417 def _get_frame_locals(self, frame): 

418 """ " 

419 Accessing f_local of current frame reset the namespace, so we want to avoid 

420 that or the following can happen 

421 

422 ipdb> foo 

423 "old" 

424 ipdb> foo = "new" 

425 ipdb> foo 

426 "new" 

427 ipdb> where 

428 ipdb> foo 

429 "old" 

430 

431 So if frame is self.current_frame we instead return self.curframe_locals 

432 

433 """ 

434 if frame is self.curframe: 

435 return self.curframe_locals 

436 else: 

437 return frame.f_locals 

438 

439 def format_stack_entry(self, frame_lineno, lprefix=': ', context=None): 

440 if context is None: 

441 context = self.context 

442 try: 

443 context = int(context) 

444 if context <= 0: 

445 print("Context must be a positive integer", file=self.stdout) 

446 except (TypeError, ValueError): 

447 print("Context must be a positive integer", file=self.stdout) 

448 

449 import reprlib 

450 

451 ret = [] 

452 

453 Colors = self.color_scheme_table.active_colors 

454 ColorsNormal = Colors.Normal 

455 tpl_link = "%s%%s%s" % (Colors.filenameEm, ColorsNormal) 

456 tpl_call = "%s%%s%s%%s%s" % (Colors.vName, Colors.valEm, ColorsNormal) 

457 tpl_line = "%%s%s%%s %s%%s" % (Colors.lineno, ColorsNormal) 

458 tpl_line_em = "%%s%s%%s %s%%s%s" % (Colors.linenoEm, Colors.line, ColorsNormal) 

459 

460 frame, lineno = frame_lineno 

461 

462 return_value = '' 

463 loc_frame = self._get_frame_locals(frame) 

464 if "__return__" in loc_frame: 

465 rv = loc_frame["__return__"] 

466 # return_value += '->' 

467 return_value += reprlib.repr(rv) + "\n" 

468 ret.append(return_value) 

469 

470 #s = filename + '(' + `lineno` + ')' 

471 filename = self.canonic(frame.f_code.co_filename) 

472 link = tpl_link % py3compat.cast_unicode(filename) 

473 

474 if frame.f_code.co_name: 

475 func = frame.f_code.co_name 

476 else: 

477 func = "<lambda>" 

478 

479 call = "" 

480 if func != "?": 

481 if "__args__" in loc_frame: 

482 args = reprlib.repr(loc_frame["__args__"]) 

483 else: 

484 args = '()' 

485 call = tpl_call % (func, args) 

486 

487 # The level info should be generated in the same format pdb uses, to 

488 # avoid breaking the pdbtrack functionality of python-mode in *emacs. 

489 if frame is self.curframe: 

490 ret.append('> ') 

491 else: 

492 ret.append(" ") 

493 ret.append("%s(%s)%s\n" % (link, lineno, call)) 

494 

495 start = lineno - 1 - context//2 

496 lines = linecache.getlines(filename) 

497 start = min(start, len(lines) - context) 

498 start = max(start, 0) 

499 lines = lines[start : start + context] 

500 

501 for i, line in enumerate(lines): 

502 show_arrow = start + 1 + i == lineno 

503 linetpl = (frame is self.curframe or show_arrow) and tpl_line_em or tpl_line 

504 ret.append( 

505 self.__format_line( 

506 linetpl, filename, start + 1 + i, line, arrow=show_arrow 

507 ) 

508 ) 

509 return "".join(ret) 

510 

511 def __format_line(self, tpl_line, filename, lineno, line, arrow=False): 

512 bp_mark = "" 

513 bp_mark_color = "" 

514 

515 new_line, err = self.parser.format2(line, 'str') 

516 if not err: 

517 line = new_line 

518 

519 bp = None 

520 if lineno in self.get_file_breaks(filename): 

521 bps = self.get_breaks(filename, lineno) 

522 bp = bps[-1] 

523 

524 if bp: 

525 Colors = self.color_scheme_table.active_colors 

526 bp_mark = str(bp.number) 

527 bp_mark_color = Colors.breakpoint_enabled 

528 if not bp.enabled: 

529 bp_mark_color = Colors.breakpoint_disabled 

530 

531 numbers_width = 7 

532 if arrow: 

533 # This is the line with the error 

534 pad = numbers_width - len(str(lineno)) - len(bp_mark) 

535 num = '%s%s' % (make_arrow(pad), str(lineno)) 

536 else: 

537 num = '%*s' % (numbers_width - len(bp_mark), str(lineno)) 

538 

539 return tpl_line % (bp_mark_color + bp_mark, num, line) 

540 

541 def print_list_lines(self, filename, first, last): 

542 """The printing (as opposed to the parsing part of a 'list' 

543 command.""" 

544 try: 

545 Colors = self.color_scheme_table.active_colors 

546 ColorsNormal = Colors.Normal 

547 tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal) 

548 tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line, ColorsNormal) 

549 src = [] 

550 if filename == "<string>" and hasattr(self, "_exec_filename"): 

551 filename = self._exec_filename 

552 

553 for lineno in range(first, last+1): 

554 line = linecache.getline(filename, lineno) 

555 if not line: 

556 break 

557 

558 if lineno == self.curframe.f_lineno: 

559 line = self.__format_line( 

560 tpl_line_em, filename, lineno, line, arrow=True 

561 ) 

562 else: 

563 line = self.__format_line( 

564 tpl_line, filename, lineno, line, arrow=False 

565 ) 

566 

567 src.append(line) 

568 self.lineno = lineno 

569 

570 print(''.join(src), file=self.stdout) 

571 

572 except KeyboardInterrupt: 

573 pass 

574 

575 def do_skip_predicates(self, args): 

576 """ 

577 Turn on/off individual predicates as to whether a frame should be hidden/skip. 

578 

579 The global option to skip (or not) hidden frames is set with skip_hidden 

580 

581 To change the value of a predicate 

582 

583 skip_predicates key [true|false] 

584 

585 Call without arguments to see the current values. 

586 

587 To permanently change the value of an option add the corresponding 

588 command to your ``~/.pdbrc`` file. If you are programmatically using the 

589 Pdb instance you can also change the ``default_predicates`` class 

590 attribute. 

591 """ 

592 if not args.strip(): 

593 print("current predicates:") 

594 for p, v in self._predicates.items(): 

595 print(" ", p, ":", v) 

596 return 

597 type_value = args.strip().split(" ") 

598 if len(type_value) != 2: 

599 print( 

600 f"Usage: skip_predicates <type> <value>, with <type> one of {set(self._predicates.keys())}" 

601 ) 

602 return 

603 

604 type_, value = type_value 

605 if type_ not in self._predicates: 

606 print(f"{type_!r} not in {set(self._predicates.keys())}") 

607 return 

608 if value.lower() not in ("true", "yes", "1", "no", "false", "0"): 

609 print( 

610 f"{value!r} is invalid - use one of ('true', 'yes', '1', 'no', 'false', '0')" 

611 ) 

612 return 

613 

614 self._predicates[type_] = value.lower() in ("true", "yes", "1") 

615 if not any(self._predicates.values()): 

616 print( 

617 "Warning, all predicates set to False, skip_hidden may not have any effects." 

618 ) 

619 

620 def do_skip_hidden(self, arg): 

621 """ 

622 Change whether or not we should skip frames with the 

623 __tracebackhide__ attribute. 

624 """ 

625 if not arg.strip(): 

626 print( 

627 f"skip_hidden = {self.skip_hidden}, use 'yes','no', 'true', or 'false' to change." 

628 ) 

629 elif arg.strip().lower() in ("true", "yes"): 

630 self.skip_hidden = True 

631 elif arg.strip().lower() in ("false", "no"): 

632 self.skip_hidden = False 

633 if not any(self._predicates.values()): 

634 print( 

635 "Warning, all predicates set to False, skip_hidden may not have any effects." 

636 ) 

637 

638 def do_list(self, arg): 

639 """Print lines of code from the current stack frame 

640 """ 

641 self.lastcmd = 'list' 

642 last = None 

643 if arg: 

644 try: 

645 x = eval(arg, {}, {}) 

646 if type(x) == type(()): 

647 first, last = x 

648 first = int(first) 

649 last = int(last) 

650 if last < first: 

651 # Assume it's a count 

652 last = first + last 

653 else: 

654 first = max(1, int(x) - 5) 

655 except: 

656 print('*** Error in argument:', repr(arg), file=self.stdout) 

657 return 

658 elif self.lineno is None: 

659 first = max(1, self.curframe.f_lineno - 5) 

660 else: 

661 first = self.lineno + 1 

662 if last is None: 

663 last = first + 10 

664 self.print_list_lines(self.curframe.f_code.co_filename, first, last) 

665 

666 # vds: >> 

667 lineno = first 

668 filename = self.curframe.f_code.co_filename 

669 self.shell.hooks.synchronize_with_editor(filename, lineno, 0) 

670 # vds: << 

671 

672 do_l = do_list 

673 

674 def getsourcelines(self, obj): 

675 lines, lineno = inspect.findsource(obj) 

676 if inspect.isframe(obj) and obj.f_globals is self._get_frame_locals(obj): 

677 # must be a module frame: do not try to cut a block out of it 

678 return lines, 1 

679 elif inspect.ismodule(obj): 

680 return lines, 1 

681 return inspect.getblock(lines[lineno:]), lineno+1 

682 

683 def do_longlist(self, arg): 

684 """Print lines of code from the current stack frame. 

685 

686 Shows more lines than 'list' does. 

687 """ 

688 self.lastcmd = 'longlist' 

689 try: 

690 lines, lineno = self.getsourcelines(self.curframe) 

691 except OSError as err: 

692 self.error(err) 

693 return 

694 last = lineno + len(lines) 

695 self.print_list_lines(self.curframe.f_code.co_filename, lineno, last) 

696 do_ll = do_longlist 

697 

698 def do_debug(self, arg): 

699 """debug code 

700 Enter a recursive debugger that steps through the code 

701 argument (which is an arbitrary expression or statement to be 

702 executed in the current environment). 

703 """ 

704 trace_function = sys.gettrace() 

705 sys.settrace(None) 

706 globals = self.curframe.f_globals 

707 locals = self.curframe_locals 

708 p = self.__class__(completekey=self.completekey, 

709 stdin=self.stdin, stdout=self.stdout) 

710 p.use_rawinput = self.use_rawinput 

711 p.prompt = "(%s) " % self.prompt.strip() 

712 self.message("ENTERING RECURSIVE DEBUGGER") 

713 sys.call_tracing(p.run, (arg, globals, locals)) 

714 self.message("LEAVING RECURSIVE DEBUGGER") 

715 sys.settrace(trace_function) 

716 self.lastcmd = p.lastcmd 

717 

718 def do_pdef(self, arg): 

719 """Print the call signature for any callable object. 

720 

721 The debugger interface to %pdef""" 

722 namespaces = [ 

723 ("Locals", self.curframe_locals), 

724 ("Globals", self.curframe.f_globals), 

725 ] 

726 self.shell.find_line_magic("pdef")(arg, namespaces=namespaces) 

727 

728 def do_pdoc(self, arg): 

729 """Print the docstring for an object. 

730 

731 The debugger interface to %pdoc.""" 

732 namespaces = [ 

733 ("Locals", self.curframe_locals), 

734 ("Globals", self.curframe.f_globals), 

735 ] 

736 self.shell.find_line_magic("pdoc")(arg, namespaces=namespaces) 

737 

738 def do_pfile(self, arg): 

739 """Print (or run through pager) the file where an object is defined. 

740 

741 The debugger interface to %pfile. 

742 """ 

743 namespaces = [ 

744 ("Locals", self.curframe_locals), 

745 ("Globals", self.curframe.f_globals), 

746 ] 

747 self.shell.find_line_magic("pfile")(arg, namespaces=namespaces) 

748 

749 def do_pinfo(self, arg): 

750 """Provide detailed information about an object. 

751 

752 The debugger interface to %pinfo, i.e., obj?.""" 

753 namespaces = [ 

754 ("Locals", self.curframe_locals), 

755 ("Globals", self.curframe.f_globals), 

756 ] 

757 self.shell.find_line_magic("pinfo")(arg, namespaces=namespaces) 

758 

759 def do_pinfo2(self, arg): 

760 """Provide extra detailed information about an object. 

761 

762 The debugger interface to %pinfo2, i.e., obj??.""" 

763 namespaces = [ 

764 ("Locals", self.curframe_locals), 

765 ("Globals", self.curframe.f_globals), 

766 ] 

767 self.shell.find_line_magic("pinfo2")(arg, namespaces=namespaces) 

768 

769 def do_psource(self, arg): 

770 """Print (or run through pager) the source code for an object.""" 

771 namespaces = [ 

772 ("Locals", self.curframe_locals), 

773 ("Globals", self.curframe.f_globals), 

774 ] 

775 self.shell.find_line_magic("psource")(arg, namespaces=namespaces) 

776 

777 def do_where(self, arg): 

778 """w(here) 

779 Print a stack trace, with the most recent frame at the bottom. 

780 An arrow indicates the "current frame", which determines the 

781 context of most commands. 'bt' is an alias for this command. 

782 

783 Take a number as argument as an (optional) number of context line to 

784 print""" 

785 if arg: 

786 try: 

787 context = int(arg) 

788 except ValueError as err: 

789 self.error(err) 

790 return 

791 self.print_stack_trace(context) 

792 else: 

793 self.print_stack_trace() 

794 

795 do_w = do_where 

796 

797 def break_anywhere(self, frame): 

798 """ 

799 _stop_in_decorator_internals is overly restrictive, as we may still want 

800 to trace function calls, so we need to also update break_anywhere so 

801 that is we don't `stop_here`, because of debugger skip, we may still 

802 stop at any point inside the function 

803 

804 """ 

805 

806 sup = super().break_anywhere(frame) 

807 if sup: 

808 return sup 

809 if self._predicates["debuggerskip"]: 

810 if DEBUGGERSKIP in frame.f_code.co_varnames: 

811 return True 

812 if frame.f_back and self._get_frame_locals(frame.f_back).get(DEBUGGERSKIP): 

813 return True 

814 return False 

815 

816 def _is_in_decorator_internal_and_should_skip(self, frame): 

817 """ 

818 Utility to tell us whether we are in a decorator internal and should stop. 

819 

820 """ 

821 

822 # if we are disabled don't skip 

823 if not self._predicates["debuggerskip"]: 

824 return False 

825 

826 # if frame is tagged, skip by default. 

827 if DEBUGGERSKIP in frame.f_code.co_varnames: 

828 return True 

829 

830 # if one of the parent frame value set to True skip as well. 

831 

832 cframe = frame 

833 while getattr(cframe, "f_back", None): 

834 cframe = cframe.f_back 

835 if self._get_frame_locals(cframe).get(DEBUGGERSKIP): 

836 return True 

837 

838 return False 

839 

840 def stop_here(self, frame): 

841 if self._is_in_decorator_internal_and_should_skip(frame) is True: 

842 return False 

843 

844 hidden = False 

845 if self.skip_hidden: 

846 hidden = self._hidden_predicate(frame) 

847 if hidden: 

848 if self.report_skipped: 

849 Colors = self.color_scheme_table.active_colors 

850 ColorsNormal = Colors.Normal 

851 print( 

852 f"{Colors.excName} [... skipped 1 hidden frame]{ColorsNormal}\n" 

853 ) 

854 return super().stop_here(frame) 

855 

856 def do_up(self, arg): 

857 """u(p) [count] 

858 Move the current frame count (default one) levels up in the 

859 stack trace (to an older frame). 

860 

861 Will skip hidden frames. 

862 """ 

863 # modified version of upstream that skips 

864 # frames with __tracebackhide__ 

865 if self.curindex == 0: 

866 self.error("Oldest frame") 

867 return 

868 try: 

869 count = int(arg or 1) 

870 except ValueError: 

871 self.error("Invalid frame count (%s)" % arg) 

872 return 

873 skipped = 0 

874 if count < 0: 

875 _newframe = 0 

876 else: 

877 counter = 0 

878 hidden_frames = self.hidden_frames(self.stack) 

879 for i in range(self.curindex - 1, -1, -1): 

880 if hidden_frames[i] and self.skip_hidden: 

881 skipped += 1 

882 continue 

883 counter += 1 

884 if counter >= count: 

885 break 

886 else: 

887 # if no break occurred. 

888 self.error( 

889 "all frames above hidden, use `skip_hidden False` to get get into those." 

890 ) 

891 return 

892 

893 Colors = self.color_scheme_table.active_colors 

894 ColorsNormal = Colors.Normal 

895 _newframe = i 

896 self._select_frame(_newframe) 

897 if skipped: 

898 print( 

899 f"{Colors.excName} [... skipped {skipped} hidden frame(s)]{ColorsNormal}\n" 

900 ) 

901 

902 def do_down(self, arg): 

903 """d(own) [count] 

904 Move the current frame count (default one) levels down in the 

905 stack trace (to a newer frame). 

906 

907 Will skip hidden frames. 

908 """ 

909 if self.curindex + 1 == len(self.stack): 

910 self.error("Newest frame") 

911 return 

912 try: 

913 count = int(arg or 1) 

914 except ValueError: 

915 self.error("Invalid frame count (%s)" % arg) 

916 return 

917 if count < 0: 

918 _newframe = len(self.stack) - 1 

919 else: 

920 counter = 0 

921 skipped = 0 

922 hidden_frames = self.hidden_frames(self.stack) 

923 for i in range(self.curindex + 1, len(self.stack)): 

924 if hidden_frames[i] and self.skip_hidden: 

925 skipped += 1 

926 continue 

927 counter += 1 

928 if counter >= count: 

929 break 

930 else: 

931 self.error( 

932 "all frames below hidden, use `skip_hidden False` to get get into those." 

933 ) 

934 return 

935 

936 Colors = self.color_scheme_table.active_colors 

937 ColorsNormal = Colors.Normal 

938 if skipped: 

939 print( 

940 f"{Colors.excName} [... skipped {skipped} hidden frame(s)]{ColorsNormal}\n" 

941 ) 

942 _newframe = i 

943 

944 self._select_frame(_newframe) 

945 

946 do_d = do_down 

947 do_u = do_up 

948 

949 def do_context(self, context): 

950 """context number_of_lines 

951 Set the number of lines of source code to show when displaying 

952 stacktrace information. 

953 """ 

954 try: 

955 new_context = int(context) 

956 if new_context <= 0: 

957 raise ValueError() 

958 self.context = new_context 

959 except ValueError: 

960 self.error("The 'context' command requires a positive integer argument.") 

961 

962 

963class InterruptiblePdb(Pdb): 

964 """Version of debugger where KeyboardInterrupt exits the debugger altogether.""" 

965 

966 def cmdloop(self, intro=None): 

967 """Wrap cmdloop() such that KeyboardInterrupt stops the debugger.""" 

968 try: 

969 return OldPdb.cmdloop(self, intro=intro) 

970 except KeyboardInterrupt: 

971 self.stop_here = lambda frame: False 

972 self.do_quit("") 

973 sys.settrace(None) 

974 self.quitting = False 

975 raise 

976 

977 def _cmdloop(self): 

978 while True: 

979 try: 

980 # keyboard interrupts allow for an easy way to cancel 

981 # the current command, so allow them during interactive input 

982 self.allow_kbdint = True 

983 self.cmdloop() 

984 self.allow_kbdint = False 

985 break 

986 except KeyboardInterrupt: 

987 self.message('--KeyboardInterrupt--') 

988 raise 

989 

990 

991def set_trace(frame=None): 

992 """ 

993 Start debugging from `frame`. 

994 

995 If frame is not specified, debugging starts from caller's frame. 

996 """ 

997 Pdb().set_trace(frame or sys._getframe().f_back)