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

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

657 statements  

1""" 

2Pdb debugger class. 

3 

4 

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

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

7improvements. 

8 

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

10extra configuration options. 

11 

12Among other things, this subclass of PDB: 

13 - supports many IPython magics like pdef/psource 

14 - hide frames in tracebacks based on `__tracebackhide__` 

15 - allows to skip frames based on `__debuggerskip__` 

16 

17 

18Global Configuration 

19-------------------- 

20 

21The IPython debugger will by read the global ``~/.pdbrc`` file. 

22That is to say you can list all commands supported by ipdb in your `~/.pdbrc` 

23configuration file, to globally configure pdb. 

24 

25Example:: 

26 

27 # ~/.pdbrc 

28 skip_predicates debuggerskip false 

29 skip_hidden false 

30 context 25 

31 

32Features 

33-------- 

34 

35The IPython debugger can hide and skip frames when printing or moving through 

36the stack. This can have a performance impact, so can be configures. 

37 

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

39command. 

40 

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

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

43 

44Frames containing ``__debuggerskip__`` will be stepped over, frames whose parent 

45frames value of ``__debuggerskip__`` is ``True`` will also be skipped. 

46 

47 >>> def helpers_helper(): 

48 ... pass 

49 ... 

50 ... def helper_1(): 

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

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

53 ... 

54 ... 

55 ... def helper_2(): 

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

57 ... 

58 

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

60 

61 >>> def pdb_skipped_decorator(function): 

62 ... 

63 ... 

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

65 ... __debuggerskip__ = True 

66 ... helper_1() 

67 ... __debuggerskip__ = False 

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

69 ... __debuggerskip__ = True 

70 ... helper_2() 

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

72 ... return result 

73 ... 

74 ... return wrapped_fn 

75 

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

77default: 

78 

79 >>> @foo_decorator 

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

81 ... return x * y 

82 

83 

84You can toggle the behavior with 

85 

86 ipdb> skip_predicates debuggerskip false 

87 

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

89 

90 

91 

92License 

93------- 

94 

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

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

97damaged. 

98 

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

100pdb. 

101 

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

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

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

105see: 

106 

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

108 

109 

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

111 

112""" 

113 

114# ***************************************************************************** 

115# 

116# This file is licensed under the PSF license. 

117# 

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

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

120# 

121# 

122# ***************************************************************************** 

123 

124from __future__ import annotations 

125 

126import inspect 

127import linecache 

128import os 

129import re 

130import sys 

131import warnings 

132from contextlib import contextmanager 

133 

134from IPython.core.getipython import get_ipython 

135from IPython.core.debugger_backport import PdbClosureBackport 

136from IPython.utils import PyColorize 

137from IPython.utils.PyColorize import TokenStream 

138 

139from typing import TYPE_CHECKING 

140from types import FrameType 

141 

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

143from pdb import Pdb as _OldPdb 

144from pygments.token import Token 

145 

146 

147if sys.version_info < (3, 13): 

148 

149 class OldPdb(PdbClosureBackport, _OldPdb): 

150 pass 

151 

152else: 

153 OldPdb = _OldPdb 

154 

155if TYPE_CHECKING: 

156 # otherwise circular import 

157 from IPython.core.interactiveshell import InteractiveShell 

158 

159# skip module docstests 

160__skip_doctest__ = True 

161 

162prompt = "ipdb> " 

163 

164 

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

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

167# the Tracer constructor. 

168 

169DEBUGGERSKIP = "__debuggerskip__" 

170 

171 

172# this has been implemented in Pdb in Python 3.13 (https://github.com/python/cpython/pull/106676 

173# on lower python versions, we backported the feature. 

174CHAIN_EXCEPTIONS = sys.version_info < (3, 13) 

175 

176 

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

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

179 

180 All other exceptions are processed using the `excepthook` 

181 parameter. 

182 """ 

183 raise ValueError( 

184 "`BdbQuit_excepthook` is deprecated since version 5.1. It is still around only because it is still imported by ipdb.", 

185 ) 

186 

187 

188RGX_EXTRA_INDENT = re.compile(r"(?<=\n)\s+") 

189 

190 

191def strip_indentation(multiline_string): 

192 return RGX_EXTRA_INDENT.sub("", multiline_string) 

193 

194 

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

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

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

198 Adapted from from a comp.lang.python posting 

199 by Duncan Booth.""" 

200 

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

202 return new_fn(*args, **kw) 

203 

204 if old_fn.__doc__: 

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

206 return wrapper 

207 

208 

209class Pdb(OldPdb): 

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

211 

212 for a standalone version that uses prompt_toolkit, see 

213 `IPython.terminal.debugger.TerminalPdb` and 

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

215 

216 

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

218 See the `skip_predicates` commands. 

219 

220 """ 

221 

222 shell: InteractiveShell 

223 _theme_name: str 

224 _context: int 

225 

226 _chained_exceptions: tuple[Exception, ...] 

227 _chained_exception_index: int 

228 

229 if CHAIN_EXCEPTIONS: 

230 MAX_CHAINED_EXCEPTION_DEPTH = 999 

231 

232 default_predicates = { 

233 "tbhide": True, 

234 "readonly": False, 

235 "ipython_internal": True, 

236 "debuggerskip": True, 

237 } 

238 

239 def __init__( 

240 self, 

241 completekey=None, 

242 stdin=None, 

243 stdout=None, 

244 context: int | None | str = 5, 

245 *, 

246 mode: str | None = None, 

247 **kwargs, 

248 ): 

249 """Create a new IPython debugger. 

250 

251 Parameters 

252 ---------- 

253 completekey : default None 

254 Passed to pdb.Pdb. 

255 stdin : default None 

256 Passed to pdb.Pdb. 

257 stdout : default None 

258 Passed to pdb.Pdb. 

259 context : int 

260 Number of lines of source code context to show when 

261 displaying stacktrace information. 

262 mode : str, optional 

263 How the debugger was invoked, one of ``'inline'`` (used by the 

264 ``breakpoint()`` builtin), ``'cli'`` (used by the command line 

265 invocation) or ``None`` (backwards compatible behaviour). This 

266 argument was added to stdlib's ``pdb.Pdb`` in Python 3.14; it is 

267 accepted on every supported Python version here but only forwarded 

268 to the underlying ``pdb.Pdb`` when it is actually supported. 

269 **kwargs 

270 Passed to pdb.Pdb. 

271 

272 Notes 

273 ----- 

274 The possibilities are python version dependent, see the python 

275 docs for more info. 

276 """ 

277 # ipdb issue, see https://github.com/ipython/ipython/issues/14811 

278 if context is None: 

279 context = 5 

280 if isinstance(context, str): 

281 context = int(context) 

282 self.context = context 

283 

284 # The `mode` argument was added to `pdb.Pdb` in Python 3.14. We accept 

285 # it on every supported Python version so that callers written against 

286 # 3.14+ keep working, but only forward it to the underlying `pdb.Pdb` 

287 # when it understands it. 

288 if sys.version_info >= (3, 14): 

289 kwargs["mode"] = mode 

290 else: 

291 self.mode = mode 

292 

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

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

295 # Python 3.15+ should define this, so no need to initialize 

296 # this avoids some getattr(self, 'curframe') 

297 if sys.version_info < (3, 15): 

298 self.curframe = None 

299 

300 # IPython changes... 

301 shell = get_ipython() 

302 

303 if shell is None: 

304 save_main = sys.modules["__main__"] 

305 # No IPython instance running, we must create one 

306 from IPython.terminal.interactiveshell import TerminalInteractiveShell 

307 

308 shell = TerminalInteractiveShell.instance() 

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

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

311 sys.modules["__main__"] = save_main 

312 self.shell = shell 

313 

314 self.aliases = {} 

315 

316 theme_name = self.shell.colors 

317 assert isinstance(theme_name, str) 

318 assert theme_name.lower() == theme_name 

319 

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

321 # debugging. 

322 self.parser = PyColorize.Parser(theme_name=theme_name) 

323 self.set_theme_name(theme_name) 

324 

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

326 self.prompt = prompt 

327 self.skip_hidden = True 

328 self.report_skipped = True 

329 

330 # list of predicates we use to skip frames 

331 self._predicates = self.default_predicates 

332 

333 # Per-instance caches for the DEBUGGERSKIP frame checks (see 

334 # `_cachable_skip`). Keyed by frame objects, so they must not outlive 

335 # the debugger stop they were computed for: they are cleared on every 

336 # `interaction` (and size-bounded) to avoid pinning frames — and 

337 # transitively their locals and whole back-chains — in memory. 

338 self._skip_cache: dict[FrameType, bool] = {} 

339 self._parent_skip_cache: dict[FrameType, bool | None] = {} 

340 

341 if CHAIN_EXCEPTIONS: 

342 self._chained_exceptions = tuple() 

343 self._chained_exception_index = 0 

344 

345 @property 

346 def context(self) -> int: 

347 return self._context 

348 

349 @context.setter 

350 def context(self, value: int | str) -> None: 

351 # ipdb issue see https://github.com/ipython/ipython/issues/14811 

352 if not isinstance(value, int): 

353 value = int(value) 

354 assert isinstance(value, int) 

355 assert value >= 0 

356 self._context = value 

357 

358 def set_theme_name(self, name): 

359 assert name.lower() == name 

360 assert isinstance(name, str) 

361 self._theme_name = name 

362 self.parser.theme_name = name 

363 

364 @property 

365 def theme(self): 

366 return PyColorize.theme_table[self._theme_name] 

367 

368 # 

369 def set_colors(self, scheme): 

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

371 warnings.warn( 

372 "set_colors is deprecated since IPython 9.0, use set_theme_name instead", 

373 DeprecationWarning, 

374 stacklevel=2, 

375 ) 

376 assert scheme == scheme.lower() 

377 self._theme_name = scheme.lower() 

378 self.parser.theme_name = scheme.lower() 

379 

380 def set_trace(self, frame=None, **kwargs): 

381 if frame is None: 

382 frame = sys._getframe().f_back 

383 self.initial_frame = frame 

384 return super().set_trace(frame, **kwargs) 

385 

386 def get_stack(self, *args, **kwargs): 

387 stack, pos = super().get_stack(*args, **kwargs) 

388 if len(stack) >= 0 and self._is_internal_frame(stack[0][0]): 

389 stack.pop(0) 

390 pos -= 1 

391 return stack, pos 

392 

393 def _is_internal_frame(self, frame): 

394 """Determine if this frame should be skipped as internal""" 

395 filename = frame.f_code.co_filename 

396 

397 # Skip bdb.py runcall and internal operations 

398 if filename.endswith("bdb.py"): 

399 func_name = frame.f_code.co_name 

400 # Skip internal bdb operations but allow breakpoint hits 

401 if func_name in ("runcall", "run", "runeval"): 

402 return True 

403 

404 return False 

405 

406 def _hidden_predicate(self, frame): 

407 """ 

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

409 """ 

410 

411 if self._predicates["readonly"]: 

412 fname = frame.f_code.co_filename 

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

414 # function would otherwise appear as RO. 

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

416 return True 

417 

418 if self._predicates["tbhide"]: 

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

420 return False 

421 frame_locals = self._get_frame_locals(frame) 

422 if "__tracebackhide__" not in frame_locals: 

423 return False 

424 return frame_locals["__tracebackhide__"] 

425 return False 

426 

427 def hidden_frames(self, stack): 

428 """ 

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

430 

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

432 """ 

433 # The f_locals dictionary is updated from the actual frame 

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

435 # avoid calling it here to preserve self._curframe_locals. 

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

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

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

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

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

441 return ip_hide 

442 

443 if CHAIN_EXCEPTIONS: 

444 

445 def _get_tb_and_exceptions(self, tb_or_exc): 

446 """ 

447 Given a tracecack or an exception, return a tuple of chained exceptions 

448 and current traceback to inspect. 

449 This will deal with selecting the right ``__cause__`` or ``__context__`` 

450 as well as handling cycles, and return a flattened list of exceptions we 

451 can jump to with do_exceptions. 

452 """ 

453 _exceptions = [] 

454 if isinstance(tb_or_exc, BaseException): 

455 traceback, current = tb_or_exc.__traceback__, tb_or_exc 

456 

457 while current is not None: 

458 if current in _exceptions: 

459 break 

460 _exceptions.append(current) 

461 if current.__cause__ is not None: 

462 current = current.__cause__ 

463 elif ( 

464 current.__context__ is not None 

465 and not current.__suppress_context__ 

466 ): 

467 current = current.__context__ 

468 

469 if len(_exceptions) >= self.MAX_CHAINED_EXCEPTION_DEPTH: 

470 self.message( 

471 f"More than {self.MAX_CHAINED_EXCEPTION_DEPTH}" 

472 " chained exceptions found, not all exceptions" 

473 " will be browsable with `exceptions`." 

474 ) 

475 break 

476 else: 

477 traceback = tb_or_exc 

478 return tuple(reversed(_exceptions)), traceback 

479 

480 @contextmanager 

481 def _hold_exceptions(self, exceptions): 

482 """ 

483 Context manager to ensure proper cleaning of exceptions references 

484 When given a chained exception instead of a traceback, 

485 pdb may hold references to many objects which may leak memory. 

486 We use this context manager to make sure everything is properly cleaned 

487 """ 

488 try: 

489 self._chained_exceptions = exceptions 

490 self._chained_exception_index = len(exceptions) - 1 

491 yield 

492 finally: 

493 # we can't put those in forget as otherwise they would 

494 # be cleared on exception change 

495 self._chained_exceptions = tuple() 

496 self._chained_exception_index = 0 

497 

498 def do_exceptions(self, arg): 

499 """exceptions [number] 

500 List or change current exception in an exception chain. 

501 Without arguments, list all the current exception in the exception 

502 chain. Exceptions will be numbered, with the current exception indicated 

503 with an arrow. 

504 If given an integer as argument, switch to the exception at that index. 

505 ``exception`` can be used as an alias for this command. 

506 """ 

507 if not self._chained_exceptions: 

508 self.message( 

509 "Did not find chained exceptions. To move between" 

510 " exceptions, pdb/post_mortem must be given an exception" 

511 " object rather than a traceback." 

512 ) 

513 return 

514 if not arg: 

515 for ix, exc in enumerate(self._chained_exceptions): 

516 prompt = ">" if ix == self._chained_exception_index else " " 

517 rep = repr(exc) 

518 if len(rep) > 80: 

519 rep = rep[:77] + "..." 

520 indicator = ( 

521 " -" 

522 if self._chained_exceptions[ix].__traceback__ is None 

523 else f"{ix:>3}" 

524 ) 

525 self.message(f"{prompt} {indicator} {rep}") 

526 else: 

527 try: 

528 number = int(arg) 

529 except ValueError: 

530 self.error("Argument must be an integer") 

531 return 

532 if 0 <= number < len(self._chained_exceptions): 

533 if self._chained_exceptions[number].__traceback__ is None: 

534 self.error( 

535 "This exception does not have a traceback, cannot jump to it" 

536 ) 

537 return 

538 

539 self._chained_exception_index = number 

540 self.setup(None, self._chained_exceptions[number].__traceback__) 

541 self.print_stack_entry(self.stack[self.curindex]) 

542 else: 

543 self.error("No exception with that number") 

544 

545 def do_exception(self, arg): 

546 """exception [number] 

547 Alias for the ``exceptions`` command. 

548 """ 

549 return self.do_exceptions(arg) 

550 

551 def _cmdloop(self): 

552 # Override to bypass Python 3.15's _maybe_use_pyrepl_as_stdin(), which 

553 # sets use_rawinput=False and conflicts with IPython's own input handling. 

554 while True: 

555 try: 

556 self.allow_kbdint = True 

557 self.cmdloop() 

558 self.allow_kbdint = False 

559 break 

560 except KeyboardInterrupt: 

561 self.message("--KeyboardInterrupt--") 

562 

563 def interaction(self, frame, tb_or_exc): 

564 # The DEBUGGERSKIP caches are only valid for a single stop: frame 

565 # locals may change while the program runs, and keeping frame keys 

566 # alive across stops would leak memory (see `_cachable_skip`). 

567 self._skip_cache.clear() 

568 self._parent_skip_cache.clear() 

569 try: 

570 if CHAIN_EXCEPTIONS: 

571 # this context manager is part of interaction in 3.13 

572 _chained_exceptions, tb = self._get_tb_and_exceptions(tb_or_exc) 

573 if isinstance(tb_or_exc, BaseException): 

574 assert tb is not None, "main exception must have a traceback" 

575 with self._hold_exceptions(_chained_exceptions): 

576 OldPdb.interaction(self, frame, tb) 

577 else: 

578 OldPdb.interaction(self, frame, tb_or_exc) 

579 

580 except KeyboardInterrupt: 

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

582 

583 def precmd(self, line): 

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

585 

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

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

588 elif line.endswith("?"): 

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

590 

591 line = super().precmd(line) 

592 

593 return line 

594 

595 def new_do_quit(self, arg): 

596 return OldPdb.do_quit(self, arg) 

597 

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

599 

600 def print_stack_trace(self, context: int | None = None): 

601 if context is None: 

602 context = self.context 

603 try: 

604 skipped = 0 

605 to_print = "" 

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

607 if hidden and self.skip_hidden: 

608 skipped += 1 

609 continue 

610 if skipped: 

611 to_print += self.theme.format( 

612 [ 

613 ( 

614 Token.ExcName, 

615 f" [... skipping {skipped} hidden frame(s)]", 

616 ), 

617 (Token, "\n"), 

618 ] 

619 ) 

620 

621 skipped = 0 

622 to_print += self.format_stack_entry(frame_lineno) 

623 if skipped: 

624 to_print += self.theme.format( 

625 [ 

626 ( 

627 Token.ExcName, 

628 f" [... skipping {skipped} hidden frame(s)]", 

629 ), 

630 (Token, "\n"), 

631 ] 

632 ) 

633 print(to_print, file=self.stdout) 

634 except KeyboardInterrupt: 

635 pass 

636 

637 def print_stack_entry( 

638 self, frame_lineno: tuple[FrameType, int], prompt_prefix: str = "\n-> " 

639 ) -> None: 

640 """ 

641 Overwrite print_stack_entry from superclass (PDB) 

642 """ 

643 print(self.format_stack_entry(frame_lineno, ""), file=self.stdout) 

644 

645 frame, lineno = frame_lineno 

646 filename = frame.f_code.co_filename 

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

648 

649 def _pdbcmd_print_frame_status(self, arg): 

650 """Use print_stack_entry to print frames in Python 3.14+.""" 

651 if sys.version_info[:2] >= (3, 14): 

652 # This is the only line changed from the base class. 

653 self.print_stack_entry(self.stack[self.curindex]) 

654 

655 # Same as in 3.14 

656 self._validate_file_mtime() 

657 self._show_display() 

658 else: 

659 # 3.13 and 3.12 don't need any changes. 

660 super()._pdbcmd_print_frame_status(arg) # type: ignore[misc] 

661 

662 @property 

663 def _curframe_locals(self): 

664 """Locals of the frame the debugger currently points at. 

665 

666 On Python 3.13+, ``frame.f_locals`` is a write-through proxy (PEP 667) 

667 which pdb no longer caches, and ``Pdb.curframe_locals`` is deprecated 

668 in 3.14 in favor of ``curframe.f_locals``. On older versions 

669 ``curframe_locals`` is a snapshot which must be reused, see 

670 `_get_frame_locals`. 

671 """ 

672 assert self.curframe is not None 

673 if sys.version_info >= (3, 13): 

674 return self.curframe.f_locals 

675 return self.curframe_locals 

676 

677 def _get_frame_locals(self, frame): 

678 """ " 

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

680 that or the following can happen 

681 

682 ipdb> foo 

683 "old" 

684 ipdb> foo = "new" 

685 ipdb> foo 

686 "new" 

687 ipdb> where 

688 ipdb> foo 

689 "old" 

690 

691 So if frame is self.current_frame we instead return self._curframe_locals 

692 

693 """ 

694 if frame is self.curframe: 

695 return self._curframe_locals 

696 else: 

697 return frame.f_locals 

698 

699 def format_stack_entry( 

700 self, 

701 frame_lineno: tuple[FrameType, int], 

702 lprefix: str = ": ", 

703 ) -> str: 

704 """ 

705 overwrite from super class so must -> str 

706 """ 

707 context = self.context 

708 try: 

709 context = int(context) 

710 if context <= 0: 

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

712 except (TypeError, ValueError): 

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

714 

715 import reprlib 

716 

717 ret_tok = [] 

718 

719 frame, lineno = frame_lineno 

720 

721 return_value = "" 

722 loc_frame = self._get_frame_locals(frame) 

723 if "__return__" in loc_frame: 

724 rv = loc_frame["__return__"] 

725 # return_value += '->' 

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

727 ret_tok.extend([(Token, return_value)]) 

728 

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

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

731 link_tok = (Token.FilenameEm, filename) 

732 

733 if frame.f_code.co_name: 

734 func = frame.f_code.co_name 

735 else: 

736 func = "<lambda>" 

737 

738 call_toks = [] 

739 if func != "?": 

740 if "__args__" in loc_frame: 

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

742 else: 

743 args = "()" 

744 call_toks = [(Token.VName, func), (Token.ValEm, args)] 

745 

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

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

748 if frame is self.curframe: 

749 ret_tok.append((Token.CurrentFrame, self.theme.make_arrow(2))) 

750 else: 

751 ret_tok.append((Token, " ")) 

752 

753 ret_tok.extend( 

754 [ 

755 link_tok, 

756 (Token, "("), 

757 (Token.Lineno, str(lineno)), 

758 (Token, ")"), 

759 *call_toks, 

760 (Token, "\n"), 

761 ] 

762 ) 

763 

764 start = lineno - 1 - context // 2 

765 lines = linecache.getlines(filename) 

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

767 start = max(start, 0) 

768 lines = lines[start : start + context] 

769 

770 for i, line in enumerate(lines): 

771 show_arrow = start + 1 + i == lineno 

772 

773 bp, num, colored_line = self.__line_content( 

774 filename, 

775 start + 1 + i, 

776 line, 

777 arrow=show_arrow, 

778 ) 

779 if frame is self.curframe or show_arrow: 

780 rlt = [ 

781 bp, 

782 (Token.LinenoEm, num), 

783 (Token, " "), 

784 # TODO: investigate Toke.Line here, likely LineEm, 

785 # Token is problematic here as line is already colored, a 

786 # and this changes the full style of the colored line. 

787 # ideally, __line_content returns the token and we modify the style. 

788 (Token, colored_line), 

789 ] 

790 else: 

791 rlt = [ 

792 bp, 

793 (Token.Lineno, num), 

794 (Token, " "), 

795 # TODO: investigate Toke.Line here, likely Line 

796 # Token is problematic here as line is already colored, a 

797 # and this changes the full style of the colored line. 

798 # ideally, __line_content returns the token and we modify the style. 

799 (Token.Line, colored_line), 

800 ] 

801 ret_tok.extend(rlt) 

802 

803 return self.theme.format(ret_tok) 

804 

805 def __line_content( 

806 self, filename: str, lineno: int, line: str, arrow: bool = False 

807 ): 

808 bp_mark = "" 

809 BreakpointToken = Token.Breakpoint 

810 

811 new_line, err = self.parser.format2(line, "str") 

812 if not err: 

813 assert new_line is not None 

814 line = new_line 

815 

816 bp = None 

817 if lineno in self.get_file_breaks(filename): 

818 bps = self.get_breaks(filename, lineno) 

819 bp = bps[-1] 

820 

821 if bp: 

822 bp_mark = str(bp.number) 

823 BreakpointToken = Token.Breakpoint.Enabled 

824 if not bp.enabled: 

825 BreakpointToken = Token.Breakpoint.Disabled 

826 numbers_width = 7 

827 if arrow: 

828 # This is the line with the error 

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

830 num = "{}{}".format(self.theme.make_arrow(pad), str(lineno)) 

831 else: 

832 num = "%*s" % (numbers_width - len(bp_mark), str(lineno)) 

833 bp_str = (BreakpointToken, bp_mark) 

834 return (bp_str, num, line) 

835 

836 def print_list_lines(self, filename: str, first: int, last: int) -> None: 

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

838 command.""" 

839 toks: TokenStream = [] 

840 try: 

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

842 filename = self._exec_filename 

843 

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

845 line = linecache.getline(filename, lineno) 

846 if not line: 

847 break 

848 

849 assert self.curframe is not None 

850 

851 if lineno == self.curframe.f_lineno: 

852 bp, num, colored_line = self.__line_content( 

853 filename, lineno, line, arrow=True 

854 ) 

855 toks.extend( 

856 [ 

857 bp, 

858 (Token.LinenoEm, num), 

859 (Token, " "), 

860 # TODO: investigate Token.Line here 

861 (Token, colored_line), 

862 ] 

863 ) 

864 else: 

865 bp, num, colored_line = self.__line_content( 

866 filename, lineno, line, arrow=False 

867 ) 

868 toks.extend( 

869 [ 

870 bp, 

871 (Token.Lineno, num), 

872 (Token, " "), 

873 (Token, colored_line), 

874 ] 

875 ) 

876 

877 self.lineno = lineno 

878 

879 print(self.theme.format(toks), file=self.stdout) 

880 

881 except KeyboardInterrupt: 

882 pass 

883 

884 def do_skip_predicates(self, args): 

885 """ 

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

887 

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

889 

890 To change the value of a predicate 

891 

892 skip_predicates key [true|false] 

893 

894 Call without arguments to see the current values. 

895 

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

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

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

899 attribute. 

900 """ 

901 if not args.strip(): 

902 print("current predicates:") 

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

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

905 return 

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

907 if len(type_value) != 2: 

908 print( 

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

910 ) 

911 return 

912 

913 type_, value = type_value 

914 if type_ not in self._predicates: 

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

916 return 

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

918 print( 

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

920 ) 

921 return 

922 

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

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

925 print( 

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

927 ) 

928 

929 def do_skip_hidden(self, arg): 

930 """ 

931 Change whether or not we should skip frames with the 

932 __tracebackhide__ attribute. 

933 """ 

934 if not arg.strip(): 

935 print( 

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

937 ) 

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

939 self.skip_hidden = True 

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

941 self.skip_hidden = False 

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

943 print( 

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

945 ) 

946 

947 def do_list(self, arg): 

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

949 self.lastcmd = "list" 

950 last = None 

951 if arg and arg != ".": 

952 try: 

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

954 if type(x) == type(()): 

955 first, last = x # type: ignore[misc] 

956 first = int(first) 

957 last = int(last) # type: ignore[call-overload] 

958 if last < first: 

959 # Assume it's a count 

960 last = first + last 

961 else: 

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

963 except ValueError: 

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

965 return 

966 elif self.lineno is None or arg == ".": 

967 assert self.curframe is not None 

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

969 else: 

970 first = self.lineno + 1 

971 if last is None: 

972 last = first + 10 

973 assert self.curframe is not None 

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

975 

976 lineno = first 

977 filename = self.curframe.f_code.co_filename 

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

979 

980 do_l = do_list 

981 

982 def getsourcelines(self, obj): 

983 lines, lineno = inspect.findsource(obj) 

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

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

986 return lines, 1 

987 elif inspect.ismodule(obj): 

988 return lines, 1 

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

990 

991 def do_longlist(self, arg): 

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

993 

994 Shows more lines than 'list' does. 

995 """ 

996 self.lastcmd = "longlist" 

997 try: 

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

999 except OSError as err: 

1000 self.error(str(err)) 

1001 return 

1002 last = lineno + len(lines) 

1003 assert self.curframe is not None 

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

1005 

1006 do_ll = do_longlist 

1007 

1008 def do_debug(self, arg): 

1009 """debug code 

1010 Enter a recursive debugger that steps through the code 

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

1012 executed in the current environment). 

1013 """ 

1014 trace_function = sys.gettrace() 

1015 sys.settrace(None) 

1016 assert self.curframe is not None 

1017 globals = self.curframe.f_globals 

1018 locals = self._curframe_locals 

1019 p = self.__class__( 

1020 completekey=self.completekey, stdin=self.stdin, stdout=self.stdout 

1021 ) 

1022 p.use_rawinput = self.use_rawinput 

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

1024 self.message("ENTERING RECURSIVE DEBUGGER") 

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

1026 self.message("LEAVING RECURSIVE DEBUGGER") 

1027 sys.settrace(trace_function) 

1028 self.lastcmd = p.lastcmd 

1029 

1030 def do_pdef(self, arg): 

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

1032 

1033 The debugger interface to %pdef""" 

1034 assert self.curframe is not None 

1035 namespaces = [ 

1036 ("Locals", self._curframe_locals), 

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

1038 ] 

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

1040 

1041 def do_pdoc(self, arg): 

1042 """Print the docstring for an object. 

1043 

1044 The debugger interface to %pdoc.""" 

1045 assert self.curframe is not None 

1046 namespaces = [ 

1047 ("Locals", self._curframe_locals), 

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

1049 ] 

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

1051 

1052 def do_pfile(self, arg): 

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

1054 

1055 The debugger interface to %pfile. 

1056 """ 

1057 assert self.curframe is not None 

1058 namespaces = [ 

1059 ("Locals", self._curframe_locals), 

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

1061 ] 

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

1063 

1064 def do_pinfo(self, arg): 

1065 """Provide detailed information about an object. 

1066 

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

1068 assert self.curframe is not None 

1069 namespaces = [ 

1070 ("Locals", self._curframe_locals), 

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

1072 ] 

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

1074 

1075 def do_pinfo2(self, arg): 

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

1077 

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

1079 assert self.curframe is not None 

1080 namespaces = [ 

1081 ("Locals", self._curframe_locals), 

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

1083 ] 

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

1085 

1086 def do_psource(self, arg): 

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

1088 assert self.curframe is not None 

1089 namespaces = [ 

1090 ("Locals", self._curframe_locals), 

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

1092 ] 

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

1094 

1095 def do_where(self, arg: str): 

1096 """w(here) 

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

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

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

1100 

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

1102 print""" 

1103 if arg: 

1104 try: 

1105 context = int(arg) 

1106 except ValueError as err: 

1107 self.error(str(err)) 

1108 return 

1109 self.print_stack_trace(context) 

1110 else: 

1111 self.print_stack_trace() 

1112 

1113 do_w = do_where 

1114 

1115 def break_anywhere(self, frame): 

1116 """ 

1117 _stop_in_decorator_internals is overly restrictive, as we may still want 

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

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

1120 stop at any point inside the function 

1121 

1122 """ 

1123 

1124 sup = super().break_anywhere(frame) 

1125 if sup: 

1126 return sup 

1127 if self._predicates["debuggerskip"]: 

1128 if DEBUGGERSKIP in frame.f_code.co_varnames: 

1129 return True 

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

1131 return True 

1132 return False 

1133 

1134 def _is_in_decorator_internal_and_should_skip(self, frame): 

1135 """ 

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

1137 

1138 """ 

1139 # if we are disabled don't skip 

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

1141 return False 

1142 

1143 return self._cachable_skip(frame) 

1144 

1145 def _cached_one_parent_frame_debuggerskip(self, frame): 

1146 """ 

1147 Cache looking up for DEBUGGERSKIP on parent frame. 

1148 

1149 This should speedup walking through deep frame when one of the highest 

1150 one does have a debugger skip. 

1151 

1152 This is likely to introduce fake positive though. 

1153 """ 

1154 try: 

1155 return self._parent_skip_cache[frame] 

1156 except KeyError: 

1157 pass 

1158 result = None 

1159 current = frame 

1160 while getattr(current, "f_back", None): 

1161 current = current.f_back 

1162 if self._get_frame_locals(current).get(DEBUGGERSKIP): 

1163 result = True 

1164 break 

1165 self._parent_skip_cache[frame] = result 

1166 return result 

1167 

1168 def _cachable_skip(self, frame): 

1169 # These caches used to be class-level ``lru_cache``\ s, which kept 

1170 # every debugger instance and up to 1024 frames (plus their locals and 

1171 # back-chains) alive for the lifetime of the process. They are now 

1172 # per-instance, size-bounded here, and cleared on each `interaction`. 

1173 if len(self._skip_cache) >= 1024: 

1174 self._skip_cache.clear() 

1175 self._parent_skip_cache.clear() 

1176 try: 

1177 return self._skip_cache[frame] 

1178 except KeyError: 

1179 pass 

1180 

1181 # if frame is tagged, skip by default. 

1182 if DEBUGGERSKIP in frame.f_code.co_varnames: 

1183 result = True 

1184 else: 

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

1186 result = bool(self._cached_one_parent_frame_debuggerskip(frame)) 

1187 

1188 self._skip_cache[frame] = result 

1189 return result 

1190 

1191 def stop_here(self, frame): 

1192 if self._is_in_decorator_internal_and_should_skip(frame) is True: 

1193 return False 

1194 

1195 hidden = False 

1196 if self.skip_hidden: 

1197 hidden = self._hidden_predicate(frame) 

1198 if hidden: 

1199 if self.report_skipped: 

1200 print( 

1201 self.theme.format( 

1202 [ 

1203 ( 

1204 Token.ExcName, 

1205 " [... skipped 1 hidden frame(s)]", 

1206 ), 

1207 (Token, "\n"), 

1208 ] 

1209 ) 

1210 ) 

1211 if self.skip and self.is_skipped_module(frame.f_globals.get("__name__", "")): 

1212 print( 

1213 self.theme.format( 

1214 [ 

1215 ( 

1216 Token.ExcName, 

1217 " [... skipped 1 ignored module(s)]", 

1218 ), 

1219 (Token, "\n"), 

1220 ] 

1221 ) 

1222 ) 

1223 

1224 return False 

1225 

1226 return super().stop_here(frame) 

1227 

1228 def do_up(self, arg): 

1229 """u(p) [count] 

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

1231 stack trace (to an older frame). 

1232 

1233 Will skip hidden frames and ignored modules. 

1234 """ 

1235 # modified version of upstream that skips 

1236 # frames with __tracebackhide__ and ignored modules 

1237 if self.curindex == 0: 

1238 self.error("Oldest frame") 

1239 return 

1240 try: 

1241 count = int(arg or 1) 

1242 except ValueError: 

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

1244 return 

1245 

1246 hidden_skipped = 0 

1247 module_skipped = 0 

1248 

1249 if count < 0: 

1250 _newframe = 0 

1251 else: 

1252 counter = 0 

1253 hidden_frames = self.hidden_frames(self.stack) 

1254 

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

1256 should_skip_hidden = hidden_frames[i] and self.skip_hidden 

1257 should_skip_module = self.skip and self.is_skipped_module( 

1258 self.stack[i][0].f_globals.get("__name__", "") 

1259 ) 

1260 

1261 if should_skip_hidden or should_skip_module: 

1262 if should_skip_hidden: 

1263 hidden_skipped += 1 

1264 if should_skip_module: 

1265 module_skipped += 1 

1266 continue 

1267 counter += 1 

1268 if counter >= count: 

1269 break 

1270 else: 

1271 # if no break occurred. 

1272 self.error( 

1273 "all frames above skipped (hidden frames and ignored modules). Use `skip_hidden False` for hidden frames or unignore_module for ignored modules." 

1274 ) 

1275 return 

1276 

1277 _newframe = i 

1278 self._select_frame(_newframe) 

1279 

1280 total_skipped = hidden_skipped + module_skipped 

1281 if total_skipped: 

1282 print( 

1283 self.theme.format( 

1284 [ 

1285 ( 

1286 Token.ExcName, 

1287 f" [... skipped {total_skipped} frame(s): {hidden_skipped} hidden frames + {module_skipped} ignored modules]", 

1288 ), 

1289 (Token, "\n"), 

1290 ] 

1291 ) 

1292 ) 

1293 

1294 def do_down(self, arg): 

1295 """d(own) [count] 

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

1297 stack trace (to a newer frame). 

1298 

1299 Will skip hidden frames and ignored modules. 

1300 """ 

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

1302 self.error("Newest frame") 

1303 return 

1304 try: 

1305 count = int(arg or 1) 

1306 except ValueError: 

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

1308 return 

1309 if count < 0: 

1310 _newframe = len(self.stack) - 1 

1311 else: 

1312 counter = 0 

1313 hidden_skipped = 0 

1314 module_skipped = 0 

1315 hidden_frames = self.hidden_frames(self.stack) 

1316 

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

1318 should_skip_hidden = hidden_frames[i] and self.skip_hidden 

1319 should_skip_module = self.skip and self.is_skipped_module( 

1320 self.stack[i][0].f_globals.get("__name__", "") 

1321 ) 

1322 

1323 if should_skip_hidden or should_skip_module: 

1324 if should_skip_hidden: 

1325 hidden_skipped += 1 

1326 if should_skip_module: 

1327 module_skipped += 1 

1328 continue 

1329 counter += 1 

1330 if counter >= count: 

1331 break 

1332 else: 

1333 self.error( 

1334 "all frames below skipped (hidden frames and ignored modules). Use `skip_hidden False` for hidden frames or unignore_module for ignored modules." 

1335 ) 

1336 return 

1337 

1338 total_skipped = hidden_skipped + module_skipped 

1339 if total_skipped: 

1340 print( 

1341 self.theme.format( 

1342 [ 

1343 ( 

1344 Token.ExcName, 

1345 f" [... skipped {total_skipped} frame(s): {hidden_skipped} hidden frames + {module_skipped} ignored modules]", 

1346 ), 

1347 (Token, "\n"), 

1348 ] 

1349 ) 

1350 ) 

1351 _newframe = i 

1352 

1353 self._select_frame(_newframe) 

1354 

1355 do_d = do_down 

1356 do_u = do_up 

1357 

1358 def _show_ignored_modules(self): 

1359 """Display currently ignored modules.""" 

1360 if self.skip: 

1361 print(f"Currently ignored modules: {sorted(self.skip)}") 

1362 else: 

1363 print("No modules are currently ignored.") 

1364 

1365 def do_ignore_module(self, arg): 

1366 """ignore_module <module_name> 

1367 

1368 Add a module to the list of modules to skip when navigating frames. 

1369 When a module is ignored, the debugger will automatically skip over 

1370 frames from that module. 

1371 

1372 Supports wildcard patterns using fnmatch syntax: 

1373 

1374 Usage: 

1375 ignore_module threading # Skip threading module frames 

1376 ignore_module asyncio.\\* # Skip all asyncio submodules 

1377 ignore_module \\*.tests # Skip all test modules 

1378 ignore_module # List currently ignored modules 

1379 """ 

1380 

1381 if self.skip is None: 

1382 self.skip = set() 

1383 

1384 module_name = arg.strip() 

1385 

1386 if not module_name: 

1387 self._show_ignored_modules() 

1388 return 

1389 

1390 self.skip.add(module_name) 

1391 

1392 def do_unignore_module(self, arg): 

1393 """unignore_module <module_name> 

1394 

1395 Remove a module from the list of modules to skip when navigating frames. 

1396 This will allow the debugger to step into frames from the specified module. 

1397 

1398 Usage: 

1399 unignore_module threading # Stop ignoring threading module frames 

1400 unignore_module asyncio.\\* # Remove asyncio.* pattern 

1401 unignore_module # List currently ignored modules 

1402 """ 

1403 

1404 if self.skip is None: 

1405 self.skip = set() 

1406 

1407 module_name = arg.strip() 

1408 

1409 if not module_name: 

1410 self._show_ignored_modules() 

1411 return 

1412 

1413 try: 

1414 self.skip.remove(module_name) 

1415 except KeyError: 

1416 print(f"Module {module_name} is not currently ignored") 

1417 self._show_ignored_modules() 

1418 

1419 def do_context(self, context: str): 

1420 """context number_of_lines 

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

1422 stacktrace information. 

1423 """ 

1424 try: 

1425 new_context = int(context) 

1426 if new_context <= 0: 

1427 raise ValueError() 

1428 self.context = new_context 

1429 except ValueError: 

1430 self.error( 

1431 f"The 'context' command requires a positive integer argument (current value {self.context})." 

1432 ) 

1433 

1434 

1435class InterruptiblePdb(Pdb): 

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

1437 

1438 def cmdloop(self, intro=None): 

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

1440 try: 

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

1442 except KeyboardInterrupt: 

1443 self.stop_here = lambda frame: False # type: ignore[method-assign] 

1444 self.do_quit("") 

1445 sys.settrace(None) 

1446 self.quitting = False 

1447 raise 

1448 

1449 def _cmdloop(self): 

1450 while True: 

1451 try: 

1452 # keyboard interrupts allow for an easy way to cancel 

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

1454 self.allow_kbdint = True 

1455 self.cmdloop() 

1456 self.allow_kbdint = False 

1457 break 

1458 except KeyboardInterrupt: 

1459 self.message("--KeyboardInterrupt--") 

1460 raise 

1461 

1462 

1463def set_trace(frame=None, header=None): 

1464 """ 

1465 Start debugging from `frame`. 

1466 

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

1468 """ 

1469 pdb = Pdb() 

1470 if header is not None: 

1471 pdb.message(header) 

1472 pdb.set_trace(frame or sys._getframe().f_back)