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

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

501 statements  

1""" 

2Verbose and colourful traceback formatting. 

3 

4**ColorTB** 

5 

6I've always found it a bit hard to visually parse tracebacks in Python. The 

7ColorTB class is a solution to that problem. It colors the different parts of a 

8traceback in a manner similar to what you would expect from a syntax-highlighting 

9text editor. 

10 

11Installation instructions for ColorTB:: 

12 

13 import sys,ultratb 

14 sys.excepthook = ultratb.ColorTB() 

15 

16**VerboseTB** 

17 

18I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds 

19of useful info when a traceback occurs. Ping originally had it spit out HTML 

20and intended it for CGI programmers, but why should they have all the fun? I 

21altered it to spit out colored text to the terminal. It's a bit overwhelming, 

22but kind of neat, and maybe useful for long-running programs that you believe 

23are bug-free. If a crash *does* occur in that type of program you want details. 

24Give it a shot--you'll love it or you'll hate it. 

25 

26.. note:: 

27 

28 The Verbose mode prints the variables currently visible where the exception 

29 happened (shortening their strings if too long). This can potentially be 

30 very slow, if you happen to have a huge data structure whose string 

31 representation is complex to compute. Your computer may appear to freeze for 

32 a while with cpu usage at 100%. If this occurs, you can cancel the traceback 

33 with Ctrl-C (maybe hitting it more than once). 

34 

35 If you encounter this kind of situation often, you may want to use the 

36 Verbose_novars mode instead of the regular Verbose, which avoids formatting 

37 variables (but otherwise includes the information and context given by 

38 Verbose). 

39 

40.. note:: 

41 

42 The verbose mode print all variables in the stack, which means it can 

43 potentially leak sensitive information like access keys, or unencrypted 

44 password. 

45 

46Installation instructions for VerboseTB:: 

47 

48 import sys,ultratb 

49 sys.excepthook = ultratb.VerboseTB() 

50 

51Note: Much of the code in this module was lifted verbatim from the standard 

52library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'. 

53 

54 

55Inheritance diagram: 

56 

57.. inheritance-diagram:: IPython.core.ultratb 

58 :parts: 3 

59""" 

60 

61# ***************************************************************************** 

62# Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu> 

63# Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu> 

64# 

65# Distributed under the terms of the BSD License. The full license is in 

66# the file COPYING, distributed as part of this software. 

67# ***************************************************************************** 

68 

69import inspect 

70import linecache 

71import sys 

72import time 

73import traceback 

74import types 

75import warnings 

76from collections.abc import Sequence 

77from types import TracebackType 

78from typing import Any 

79from collections.abc import Callable 

80 

81import stack_data 

82from pygments.formatters.terminal256 import Terminal256Formatter 

83from pygments.token import Token 

84 

85from IPython.core.getipython import get_ipython 

86from IPython.utils.PyColorize import Parser, TokenStream, theme_table 

87from IPython.utils.terminal import get_terminal_size 

88 

89from .display_trap import DisplayTrap 

90from .doctb import DocTB 

91from .tbtools import ( 

92 FrameInfo, 

93 TBTools, 

94 _format_traceback_lines, 

95 _safe_string, 

96 _simple_format_traceback_lines, 

97 _tokens_filename, 

98 eqrepr, 

99 get_line_number_of_frame, 

100 nullrepr, 

101) 

102 

103# Globals 

104# amount of space to put line numbers before verbose tracebacks 

105INDENT_SIZE = 8 

106 

107# When files are too long do not use stackdata to get frames. 

108# it is too long. 

109FAST_THRESHOLD = 10_000 

110 

111# --------------------------------------------------------------------------- 

112class ListTB(TBTools): 

113 """Print traceback information from a traceback list, with optional color. 

114 

115 Calling requires 3 arguments: (etype, evalue, elist) 

116 as would be obtained by:: 

117 

118 etype, evalue, tb = sys.exc_info() 

119 if tb: 

120 elist = traceback.extract_tb(tb) 

121 else: 

122 elist = None 

123 

124 It can thus be used by programs which need to process the traceback before 

125 printing (such as console replacements based on the code module from the 

126 standard library). 

127 

128 Because they are meant to be called without a full traceback (only a 

129 list), instances of this class can't call the interactive pdb debugger.""" 

130 

131 def __call__( 

132 self, 

133 etype: type[BaseException], 

134 evalue: BaseException | None, 

135 etb: TracebackType | None, 

136 ) -> None: 

137 self.ostream.flush() 

138 self.ostream.write(self.text(etype, evalue, etb)) 

139 self.ostream.write("\n") 

140 

141 def _extract_tb(self, tb: TracebackType | None) -> traceback.StackSummary | None: 

142 if tb: 

143 return traceback.extract_tb(tb) 

144 else: 

145 return None 

146 

147 def structured_traceback( 

148 self, 

149 etype: type, 

150 evalue: BaseException | None, 

151 etb: TracebackType | None = None, 

152 tb_offset: int | None = None, 

153 context: int = 5, 

154 ) -> list[str]: 

155 """Return a color formatted string with the traceback info. 

156 

157 Parameters 

158 ---------- 

159 etype : exception type 

160 Type of the exception raised. 

161 evalue : object 

162 Data stored in the exception 

163 etb : list | TracebackType | None 

164 If list: List of frames, see class docstring for details. 

165 If Traceback: Traceback of the exception. 

166 tb_offset : int, optional 

167 Number of frames in the traceback to skip. If not given, the 

168 instance evalue is used (set in constructor). 

169 context : int, optional 

170 Number of lines of context information to print. 

171 

172 Returns 

173 ------- 

174 String with formatted exception. 

175 """ 

176 # This is a workaround to get chained_exc_ids in recursive calls 

177 # etb should not be a tuple if structured_traceback is not recursive 

178 # (see the recursive self.structured_traceback() call below), and can 

179 # also be a pre-built list of frames per the docstring above; neither 

180 # is expressible in the public `TracebackType | None` signature. 

181 if isinstance(etb, tuple): 

182 etb, chained_exc_ids = etb # type: ignore[unreachable] 

183 else: 

184 chained_exc_ids = set() 

185 elist: list[Any] 

186 if isinstance(etb, list): 

187 elist = etb # type: ignore[unreachable] 

188 elif etb is not None: 

189 elist = self._extract_tb(etb) # type: ignore[assignment] 

190 else: 

191 elist = [] 

192 tb_offset = self.tb_offset if tb_offset is None else tb_offset 

193 assert isinstance(tb_offset, int) 

194 out_list: list[str] = [] 

195 if elist: 

196 if tb_offset and len(elist) > tb_offset: 

197 elist = elist[tb_offset:] 

198 

199 out_list.append( 

200 theme_table[self._theme_name].format( 

201 [ 

202 (Token, "Traceback"), 

203 (Token, " "), 

204 (Token.NormalEm, "(most recent call last)"), 

205 (Token, ":"), 

206 (Token, "\n"), 

207 ] 

208 ), 

209 ) 

210 out_list.extend(self._format_list(elist)) 

211 # The exception info should be a single entry in the list. 

212 lines = "".join(self._format_exception_only(etype, evalue)) 

213 out_list.append(lines) 

214 

215 # Find chained exceptions if we have a traceback (not for exception-only mode) 

216 if etb is not None: 

217 exception = self.get_parts_of_chained_exception(evalue) 

218 

219 if exception and (id(exception[1]) not in chained_exc_ids): 

220 chained_exception_message: list[str] = ( 

221 self.prepare_chained_exception_message(evalue.__cause__)[0] 

222 if evalue is not None 

223 else [""] 

224 ) 

225 etype, evalue, etb = exception 

226 # Trace exception to avoid infinite 'cause' loop 

227 chained_exc_ids.add(id(exception[1])) 

228 chained_exceptions_tb_offset = 0 

229 ol1 = self.structured_traceback( 

230 etype, 

231 evalue, 

232 (etb, chained_exc_ids), # type: ignore[arg-type] 

233 chained_exceptions_tb_offset, 

234 context, 

235 ) 

236 ol2 = chained_exception_message 

237 

238 out_list = ol1 + ol2 + out_list 

239 

240 return out_list 

241 

242 def _format_list(self, extracted_list: list[Any]) -> list[str]: 

243 """Format a list of traceback entry tuples for printing. 

244 

245 Given a list of tuples as returned by extract_tb() or 

246 extract_stack(), return a list of strings ready for printing. 

247 Each string in the resulting list corresponds to the item with the 

248 same index in the argument list. Each string ends in a newline; 

249 the strings may contain internal newlines as well, for those items 

250 whose source text line is not None. 

251 

252 Lifted almost verbatim from traceback.py 

253 """ 

254 

255 output_list = [] 

256 for ind, (filename, lineno, name, line) in enumerate(extracted_list): 

257 # Will emphasize the last entry 

258 em = True if ind == len(extracted_list) - 1 else False 

259 

260 item = theme_table[self._theme_name].format( 

261 [(Token.NormalEm if em else Token.Normal, " ")] 

262 + _tokens_filename(em, filename, lineno=lineno) 

263 ) 

264 

265 # This seem to be only in xmode plain (%run sinpleer), investigate why not share with verbose. 

266 # look at _tokens_filename in forma_record. 

267 if name != "<module>": 

268 item += theme_table[self._theme_name].format( 

269 [ 

270 (Token.NormalEm if em else Token.Normal, " in "), 

271 (Token.TB.NameEm if em else Token.TB.Name, name), 

272 ] 

273 ) 

274 item += theme_table[self._theme_name].format( 

275 [(Token.NormalEm if em else Token, "\n")] 

276 ) 

277 if line: 

278 item += theme_table[self._theme_name].format( 

279 [ 

280 (Token.Line if em else Token, " "), 

281 (Token.Line if em else Token, line.strip()), 

282 (Token, "\n"), 

283 ] 

284 ) 

285 output_list.append(item) 

286 

287 return output_list 

288 

289 def _format_exception_only( 

290 self, etype: type[BaseException], value: BaseException | None 

291 ) -> list[str]: 

292 """Format the exception part of a traceback. 

293 

294 The arguments are the exception type and value such as given by 

295 sys.exc_info()[:2]. The return value is a list of strings, each ending 

296 in a newline. Normally, the list contains a single string; however, 

297 for SyntaxError exceptions, it contains several lines that (when 

298 printed) display detailed information about where the syntax error 

299 occurred. The message indicating which exception occurred is the 

300 always last string in the list. 

301 

302 Also lifted nearly verbatim from traceback.py 

303 """ 

304 have_filedata = False 

305 output_list = [] 

306 stype_tokens = [(Token.ExcName, etype.__name__)] 

307 stype: str = theme_table[self._theme_name].format(stype_tokens) 

308 if value is None: 

309 # Not sure if this can still happen in Python 2.6 and above 

310 output_list.append(stype + "\n") 

311 else: 

312 if issubclass(etype, SyntaxError): 

313 assert hasattr(value, "filename") 

314 assert hasattr(value, "lineno") 

315 assert hasattr(value, "text") 

316 assert hasattr(value, "offset") 

317 assert hasattr(value, "msg") 

318 have_filedata = True 

319 if not value.filename: 

320 value.filename = "<string>" 

321 if value.lineno: 

322 lineno = value.lineno 

323 textline = linecache.getline(value.filename, value.lineno) 

324 else: 

325 lineno = "unknown" 

326 textline = "" 

327 output_list.append( 

328 theme_table[self._theme_name].format( 

329 [(Token, " ")] 

330 + _tokens_filename( 

331 True, 

332 value.filename, 

333 lineno=(None if lineno == "unknown" else lineno), 

334 ) 

335 + [(Token, "\n")] 

336 ) 

337 ) 

338 if textline == "": 

339 # sep 2025: 

340 # textline = py3compat.cast_unicode(value.text, "utf-8") 

341 if value.text is None: 

342 textline = "" 

343 else: 

344 assert isinstance(value.text, str) 

345 textline = value.text 

346 

347 if textline is not None: 

348 i = 0 

349 while i < len(textline) and textline[i].isspace(): 

350 i += 1 

351 output_list.append( 

352 theme_table[self._theme_name].format( 

353 [ 

354 (Token.Line, " "), 

355 (Token.Line, textline.strip()), 

356 (Token, "\n"), 

357 ] 

358 ) 

359 ) 

360 if value.offset is not None: 

361 s = " " 

362 for c in textline[i : value.offset - 1]: 

363 if c.isspace(): 

364 s += c 

365 else: 

366 s += " " 

367 output_list.append( 

368 theme_table[self._theme_name].format( 

369 [(Token.Caret, s + "^"), (Token, "\n")] 

370 ) 

371 ) 

372 s = value.msg 

373 else: 

374 s = self._some_str(value) 

375 if s: 

376 output_list.append( 

377 theme_table[self._theme_name].format( 

378 stype_tokens 

379 + [ 

380 (Token.ExcName, ":"), 

381 (Token, " "), 

382 (Token, s), 

383 (Token, "\n"), 

384 ] 

385 ) 

386 ) 

387 else: 

388 output_list.append("%s\n" % stype) 

389 

390 # PEP-678 notes 

391 output_list.extend(f"{x}\n" for x in getattr(value, "__notes__", [])) 

392 

393 # sync with user hooks 

394 if have_filedata: 

395 ipinst = get_ipython() 

396 if ipinst is not None: 

397 assert value is not None 

398 assert hasattr(value, "lineno") 

399 assert hasattr(value, "filename") 

400 ipinst.hooks.synchronize_with_editor(value.filename, value.lineno, 0) 

401 

402 return output_list 

403 

404 def get_exception_only(self, etype, value): 

405 """Only print the exception type and message, without a traceback. 

406 

407 Parameters 

408 ---------- 

409 etype : exception type 

410 value : exception value 

411 """ 

412 return ListTB.structured_traceback(self, etype, value) 

413 

414 def structured_traceback_doctest( 

415 self, 

416 etype, 

417 evalue, 

418 etb=None, 

419 tb_offset=None, 

420 context=5, 

421 ): 

422 """Return a doctest-freindly traceback. 

423 

424 Shows only the header, an ellipsis, and the excepttion line. 

425 """ 

426 # Handle chained exception rule 

427 if isinstance(etb, tuple): 

428 etb, chained_exc_ids = etb 

429 else: 

430 chained_exc_ids = set() 

431 

432 have_traceback = etb is not None 

433 

434 out_list = [] 

435 if have_traceback: 

436 out_list.append("Traceback (most recent call last):\n") 

437 out_list.append(" ...\n") 

438 

439 lines = "".join(self._format_exception_only(etype, evalue)) 

440 out_list.append(lines) 

441 

442 # Handle chained exceptions 

443 if etb is not None: 

444 exception = self.get_parts_of_chained_exception(evalue) 

445 if exception and (id(exception[1]) not in chained_exc_ids): 

446 chained_exception_message = (self.prepare_chained_exception_message(evalue.__cause__)[0] if evalue is not None else [""]) 

447 etype, evalue, etb = exception 

448 chained_exc_ids.add(id(exception[1])) 

449 chained_tb = self.structured_traceback_doctest(etype, evalue, (etb, chained_exc_ids), 0, context) 

450 out_list = chained_tb + chained_exception_message + out_list 

451 

452 return out_list 

453 

454 def show_exception_only( 

455 self, etype: BaseException | None, evalue: TracebackType | None 

456 ) -> None: 

457 """Only print the exception type and message, without a traceback. 

458 

459 Parameters 

460 ---------- 

461 etype : exception type 

462 evalue : exception value 

463 """ 

464 # This method needs to use __call__ from *this* class, not the one from 

465 # a subclass whose signature or behavior may be different 

466 ostream = self.ostream 

467 ostream.flush() 

468 ostream.write("\n".join(self.get_exception_only(etype, evalue))) 

469 ostream.flush() 

470 

471 def _some_str(self, value: Any) -> str: 

472 # Lifted from traceback.py 

473 try: 

474 return str(value) 

475 except Exception: 

476 return "<unprintable %s object>" % type(value).__name__ 

477 

478 

479_sentinel = object() 

480_default = "default" 

481 

482 

483# ---------------------------------------------------------------------------- 

484class VerboseTB(TBTools): 

485 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead 

486 of HTML. Requires inspect and pydoc. Crazy, man. 

487 

488 Modified version which optionally strips the topmost entries from the 

489 traceback, to be used with alternate interpreters (because their own code 

490 would appear in the traceback).""" 

491 

492 tb_highlight = "bg:ansiyellow" 

493 tb_highlight_style = "default" 

494 

495 _mode: str 

496 

497 def __init__( 

498 self, 

499 # TODO: no default ? 

500 theme_name: str = _default, 

501 call_pdb: bool = False, 

502 ostream: Any = None, 

503 tb_offset: int = 0, 

504 long_header: bool = False, 

505 include_vars: bool = True, 

506 check_cache: Callable[[], None] | None = None, 

507 debugger_cls: type | None = None, 

508 *, 

509 color_scheme: Any = _sentinel, 

510 ): 

511 """Specify traceback offset, headers and color scheme. 

512 

513 Define how many frames to drop from the tracebacks. Calling it with 

514 tb_offset=1 allows use of this handler in interpreters which will have 

515 their own code at the top of the traceback (VerboseTB will first 

516 remove that frame before printing the traceback info).""" 

517 if color_scheme is not _sentinel: 

518 assert isinstance(color_scheme, str) 

519 theme_name = color_scheme.lower() 

520 

521 warnings.warn( 

522 "color_scheme is deprecated as of IPython 9.0 and replaced by " 

523 "theme_name (which should be lowercase). As you passed a " 

524 "color_scheme value I will try to see if I have corresponding " 

525 "theme.", 

526 stacklevel=2, 

527 category=DeprecationWarning, 

528 ) 

529 

530 if theme_name != _default: 

531 warnings.warn( 

532 "You passed both `theme_name` and `color_scheme` " 

533 "(deprecated since IPython 9.0) to VerboseTB constructor. `theme_name` will " 

534 "be ignored for the time being.", 

535 stacklevel=2, 

536 category=DeprecationWarning, 

537 ) 

538 

539 if theme_name == _default: 

540 theme_name = "linux" 

541 

542 assert isinstance(theme_name, str) 

543 super().__init__( 

544 theme_name=theme_name, 

545 call_pdb=call_pdb, 

546 ostream=ostream, 

547 debugger_cls=debugger_cls, 

548 ) 

549 self.tb_offset = tb_offset 

550 self.long_header = long_header 

551 self.include_vars = include_vars 

552 # By default we use linecache.checkcache, but the user can provide a 

553 # different check_cache implementation. This was formerly used by the 

554 # IPython kernel for interactive code, but is no longer necessary. 

555 if check_cache is None: 

556 check_cache = linecache.checkcache 

557 self.check_cache = check_cache 

558 

559 self.skip_hidden = True 

560 

561 def format_record(self, frame_info: FrameInfo) -> str: 

562 """Format a single stack frame""" 

563 assert isinstance(frame_info, FrameInfo) 

564 

565 if isinstance(frame_info._sd, stack_data.RepeatedFrames): 

566 return theme_table[self._theme_name].format( 

567 [ 

568 (Token, " "), 

569 ( 

570 Token.ExcName, 

571 "[... skipping similar frames: %s]" % frame_info.description, 

572 ), 

573 (Token, "\n"), 

574 ] 

575 ) 

576 

577 indent: str = " " * INDENT_SIZE 

578 

579 assert isinstance(frame_info.lineno, int) 

580 args, varargs, varkw, locals_ = inspect.getargvalues(frame_info.frame) 

581 func: str 

582 if frame_info.executing is not None: 

583 func = frame_info.executing.code_qualname() 

584 elif frame_info.code is not None: 

585 func = ( 

586 getattr(frame_info.code, "co_qualname", None) or frame_info.code.co_name 

587 ) 

588 else: 

589 func = "?" 

590 if func == "<module>": 

591 call = "" 

592 else: 

593 # Decide whether to include variable details or not 

594 var_repr = eqrepr if self.include_vars else nullrepr 

595 try: 

596 scope = inspect.formatargvalues( 

597 args, varargs, varkw, locals_, formatvalue=var_repr 

598 ) 

599 assert isinstance(scope, str) 

600 call = theme_table[self._theme_name].format( 

601 [(Token, "in "), (Token.VName, func), (Token.ValEm, scope)] 

602 ) 

603 except KeyError: 

604 # This happens in situations like errors inside generator 

605 # expressions, where local variables are listed in the 

606 # line, but can't be extracted from the frame. I'm not 

607 # 100% sure this isn't actually a bug in inspect itself, 

608 # but since there's no info for us to compute with, the 

609 # best we can do is report the failure and move on. Here 

610 # we must *not* call any traceback construction again, 

611 # because that would mess up use of %debug later on. So we 

612 # simply report the failure and move on. The only 

613 # limitation will be that this frame won't have locals 

614 # listed in the call signature. Quite subtle problem... 

615 # I can't think of a good way to validate this in a unit 

616 # test, but running a script consisting of: 

617 # dict( (k,v.strip()) for (k,v) in range(10) ) 

618 # will illustrate the error, if this exception catch is 

619 # disabled. 

620 call = theme_table[self._theme_name].format( 

621 [ 

622 (Token, "in "), 

623 (Token.VName, func), 

624 (Token.ValEm, "(***failed resolving arguments***)"), 

625 ] 

626 ) 

627 

628 lvals_toks: list[TokenStream] = [] 

629 if self.include_vars: 

630 try: 

631 # we likely want to fix stackdata at some point, but 

632 # still need a workaround. 

633 fibp = frame_info.variables_in_executing_piece 

634 for var in fibp: 

635 lvals_toks.append( 

636 [ 

637 (Token, var.name), 

638 (Token, " "), 

639 (Token.ValEm, "= "), 

640 (Token.ValEm, repr(var.value)), 

641 ] 

642 ) 

643 except Exception: 

644 lvals_toks.append( 

645 [ 

646 ( 

647 Token, 

648 "Exception trying to inspect frame. No more locals available.", 

649 ), 

650 ] 

651 ) 

652 

653 if frame_info._sd is None: 

654 # fast fallback if file is too long 

655 assert frame_info.filename is not None 

656 level_tokens = ( 

657 _tokens_filename(True, frame_info.filename, lineno=frame_info.lineno) 

658 + [ 

659 (Token, ", " if call else ""), 

660 (Token, call), 

661 (Token, "\n"), 

662 ] 

663 ) 

664 

665 _line_format = Parser(theme_name=self._theme_name).format2 

666 assert isinstance(frame_info.code, types.CodeType) 

667 first_line: int = frame_info.code.co_firstlineno 

668 current_line: int = frame_info.lineno 

669 raw_lines: list[str] = frame_info.raw_lines 

670 index: int = current_line - first_line 

671 assert frame_info.context is not None 

672 if index >= frame_info.context: 

673 start = max(index - frame_info.context, 0) 

674 stop = index + frame_info.context 

675 index = frame_info.context 

676 else: 

677 start = 0 

678 stop = index + frame_info.context 

679 raw_lines = raw_lines[start:stop] 

680 

681 # Jan 2025: may need _line_format(py3ompat.cast_unicode(s)) 

682 raw_color_err = [] 

683 for s in raw_lines: 

684 formatted, is_error = _line_format(s, "str") 

685 assert formatted is not None, "format2 should return str when out='str'" 

686 raw_color_err.append((s, (formatted, is_error))) 

687 

688 tb_tokens = _simple_format_traceback_lines( 

689 current_line, 

690 index, 

691 raw_color_err, 

692 lvals_toks, 

693 theme=theme_table[self._theme_name], 

694 ) 

695 _tb_lines: str = theme_table[self._theme_name].format(tb_tokens) 

696 

697 return theme_table[self._theme_name].format(level_tokens + tb_tokens) 

698 else: 

699 result = theme_table[self._theme_name].format( 

700 _tokens_filename(True, frame_info.filename, lineno=frame_info.lineno) 

701 ) 

702 result += ", " if call else "" 

703 result += f"{call}\n" 

704 result += theme_table[self._theme_name].format( 

705 _format_traceback_lines( 

706 frame_info.lines, 

707 theme_table[self._theme_name], 

708 self.has_colors, 

709 lvals_toks, 

710 ) 

711 ) 

712 return result 

713 

714 def prepare_header(self, etype: str, long_version: bool = False) -> str: 

715 width = min(75, get_terminal_size()[0]) 

716 if long_version: 

717 # Header with the exception type, python version, and date 

718 pyver = "Python " + sys.version.split()[0] + ": " + sys.executable 

719 date = time.ctime(time.time()) 

720 theme = theme_table[self._theme_name] 

721 head = theme.format( 

722 [ 

723 (Token.Topline, theme.symbols["top_line"] * width), 

724 (Token, "\n"), 

725 (Token.ExcName, etype), 

726 (Token, " " * (width - len(etype) - len(pyver))), 

727 (Token, pyver), 

728 (Token, "\n"), 

729 (Token, date.rjust(width)), 

730 ] 

731 ) 

732 head += ( 

733 "\nA problem occurred executing Python code. Here is the sequence of function" 

734 "\ncalls leading up to the error, with the most recent (innermost) call last." 

735 ) 

736 else: 

737 # Simplified header 

738 head = theme_table[self._theme_name].format( 

739 [ 

740 (Token.ExcName, etype), 

741 ( 

742 Token, 

743 "Traceback (most recent call last)".rjust(width - len(etype)), 

744 ), 

745 ] 

746 ) 

747 

748 return head 

749 

750 def format_exception(self, etype, evalue): 

751 # Get (safely) a string form of the exception info 

752 try: 

753 etype_str, evalue_str = map(str, (etype, evalue)) 

754 except Exception: 

755 # User exception is improperly defined. 

756 etype, evalue = str, sys.exc_info()[:2] 

757 etype_str, evalue_str = map(str, (etype, evalue)) 

758 

759 # PEP-678 notes 

760 notes = getattr(evalue, "__notes__", []) 

761 if not isinstance(notes, Sequence) or isinstance(notes, (str, bytes)): 

762 notes = [_safe_string(notes, "__notes__", func=repr)] 

763 

764 for note in notes: 

765 assert isinstance(note, str) 

766 

767 str_notes: Sequence[str] = notes 

768 

769 # ... and format it 

770 return [ 

771 theme_table[self._theme_name].format( 

772 [(Token.ExcName, etype_str), (Token, ": "), (Token, evalue_str)] 

773 ), 

774 *( 

775 theme_table[self._theme_name].format([(Token, note)]) 

776 for note in str_notes 

777 ), 

778 ] 

779 

780 def format_exception_as_a_whole( 

781 self, 

782 etype: type, 

783 evalue: BaseException | None, 

784 etb: TracebackType | None, 

785 context: int, 

786 tb_offset: int | None, 

787 ) -> list[list[str]]: 

788 """Formats the header, traceback and exception message for a single exception. 

789 

790 This may be called multiple times by Python 3 exception chaining 

791 (PEP 3134). 

792 """ 

793 # some locals 

794 orig_etype = etype 

795 try: 

796 etype = etype.__name__ # type: ignore[assignment] 

797 except AttributeError: 

798 pass 

799 

800 tb_offset = self.tb_offset if tb_offset is None else tb_offset 

801 assert isinstance(tb_offset, int) 

802 head = self.prepare_header(str(etype), self.long_header) 

803 records = self.get_records(etb, context, tb_offset) if etb else [] 

804 

805 frames = [] 

806 skipped = 0 

807 lastrecord = len(records) - 1 

808 for i, record in enumerate(records): 

809 if ( 

810 not isinstance(record._sd, stack_data.RepeatedFrames) 

811 and self.skip_hidden 

812 ): 

813 if ( 

814 record.frame.f_locals.get("__tracebackhide__", 0) 

815 and i != lastrecord 

816 ): 

817 skipped += 1 

818 continue 

819 if skipped: 

820 frames.append( 

821 theme_table[self._theme_name].format( 

822 [ 

823 (Token, " "), 

824 (Token.ExcName, "[... skipping hidden %s frame]" % skipped), 

825 (Token, "\n"), 

826 ] 

827 ) 

828 ) 

829 skipped = 0 

830 frames.append(self.format_record(record)) 

831 if skipped: 

832 frames.append( 

833 theme_table[self._theme_name].format( 

834 [ 

835 (Token, " "), 

836 (Token.ExcName, "[... skipping hidden %s frame]" % skipped), 

837 (Token, "\n"), 

838 ] 

839 ) 

840 ) 

841 

842 formatted_exception = self.format_exception(etype, evalue) 

843 if records: 

844 frame_info = records[-1] 

845 ipinst = get_ipython() 

846 if ipinst is not None: 

847 ipinst.hooks.synchronize_with_editor( 

848 frame_info.filename, frame_info.lineno, 0 

849 ) 

850 

851 return [[head] + frames + formatted_exception] 

852 

853 def get_records(self, etb: TracebackType, context: int, tb_offset: int) -> Any: 

854 assert etb is not None 

855 context = context - 1 

856 after = context // 2 

857 before = context - after 

858 if self.has_colors: 

859 theme = theme_table[self._theme_name] 

860 base_style = theme.as_pygments_style() 

861 tb_highlight = theme.extra_style.get(Token.TbHighlight, self.tb_highlight) 

862 style = stack_data.style_with_executing_node(base_style, tb_highlight) 

863 formatter = Terminal256Formatter(style=style) 

864 else: 

865 formatter = None 

866 options = stack_data.Options( 

867 before=before, 

868 after=after, 

869 pygments_formatter=formatter, 

870 ) 

871 

872 # Collect traceback frames and their module sizes. 

873 cf: TracebackType | None = etb 

874 tbs: list[tuple[TracebackType, int]] = [] 

875 while cf is not None: 

876 try: 

877 mod = inspect.getmodule(cf.tb_frame) 

878 if mod is not None: 

879 mod_name = mod.__name__ 

880 root_name, *_ = mod_name.split(".") 

881 if root_name == "IPython": 

882 cf = cf.tb_next 

883 continue 

884 frame_len = get_line_number_of_frame(cf.tb_frame) 

885 if frame_len == 0: 

886 # File not found or not a .py file (e.g. <string> from 

887 # exec()). Check if source is actually available; if not, 

888 # force the fast path so that FrameInfo's "Could not get 

889 # source" fallback is rendered. 

890 try: 

891 inspect.getsourcelines(cf.tb_frame) 

892 except OSError: 

893 frame_len = FAST_THRESHOLD + 1 

894 except OSError: 

895 frame_len = FAST_THRESHOLD + 1 

896 assert cf is not None # narrowing for mypy; guarded by while condition 

897 tbs.append((cf, frame_len)) 

898 cf = cf.tb_next 

899 

900 # Group consecutive frames by fast/slow and process each group. 

901 # Consecutive slow frames must be processed together so that 

902 # stack_data can detect RepeatedFrames (recursion collapsing). 

903 FIs: list[FrameInfo] = [] 

904 i = 0 

905 while i < len(tbs): 

906 tb, frame_len = tbs[i] 

907 if frame_len > FAST_THRESHOLD: 

908 frame = tb.tb_frame 

909 lineno = frame.f_lineno 

910 code = frame.f_code 

911 filename = code.co_filename 

912 FIs.append( 

913 FrameInfo( 

914 "Raw frame", filename, lineno, frame, code, context=context 

915 ) 

916 ) 

917 i += 1 

918 else: 

919 # Collect the consecutive run of slow frames 

920 group_start = i 

921 while i < len(tbs) and tbs[i][1] <= FAST_THRESHOLD: 

922 i += 1 

923 # Build set of frame objects in this group for filtering 

924 group_frames = {tbs[j][0].tb_frame for j in range(group_start, i)} 

925 # Process via stack_data starting from the first tb in the group 

926 for sd_fi in stack_data.FrameInfo.stack_data( 

927 tbs[group_start][0], options=options 

928 ): 

929 # stack_data follows tb_next through the full chain, 

930 # including IPython frames we skipped during collection. 

931 # Filter those out, but always keep RepeatedFrames. 

932 if isinstance(sd_fi, stack_data.RepeatedFrames) or sd_fi.frame in group_frames: 

933 FIs.append(FrameInfo._from_stack_data_FrameInfo(sd_fi)) 

934 

935 return FIs 

936 

937 def structured_traceback( 

938 self, 

939 etype: type, 

940 evalue: BaseException | None, 

941 etb: TracebackType | None = None, 

942 tb_offset: int | None = None, 

943 context: int = 5, 

944 ) -> list[str]: 

945 """Return a nice text document describing the traceback.""" 

946 formatted_exceptions: list[list[str]] = self.format_exception_as_a_whole( 

947 etype, evalue, etb, context, tb_offset 

948 ) 

949 

950 termsize = min(75, get_terminal_size()[0]) 

951 theme = theme_table[self._theme_name] 

952 head: str = theme.format( 

953 [ 

954 ( 

955 Token.Topline, 

956 theme.symbols["top_line"] * termsize, 

957 ), 

958 ] 

959 ) 

960 structured_traceback_parts: list[str] = [head] 

961 chained_exceptions_tb_offset = 0 

962 lines_of_context = 3 

963 exception = self.get_parts_of_chained_exception(evalue) 

964 if exception: 

965 assert evalue is not None 

966 formatted_exceptions += self.prepare_chained_exception_message( 

967 evalue.__cause__ 

968 ) 

969 etype, evalue, etb = exception 

970 else: 

971 evalue = None 

972 chained_exc_ids = set() 

973 while evalue: 

974 formatted_exceptions += self.format_exception_as_a_whole( 

975 etype, evalue, etb, lines_of_context, chained_exceptions_tb_offset 

976 ) 

977 exception = self.get_parts_of_chained_exception(evalue) 

978 

979 if exception and id(exception[1]) not in chained_exc_ids: 

980 chained_exc_ids.add( 

981 id(exception[1]) 

982 ) # trace exception to avoid infinite 'cause' loop 

983 formatted_exceptions += self.prepare_chained_exception_message( 

984 evalue.__cause__ 

985 ) 

986 etype, evalue, etb = exception 

987 else: 

988 evalue = None 

989 

990 # we want to see exceptions in a reversed order: 

991 # the first exception should be on top 

992 for fx in reversed(formatted_exceptions): 

993 structured_traceback_parts += fx 

994 

995 return structured_traceback_parts 

996 

997 def debugger(self, force: bool = False) -> None: 

998 """Call up the pdb debugger if desired, always clean up the tb 

999 reference. 

1000 

1001 Keywords: 

1002 

1003 - force(False): by default, this routine checks the instance call_pdb 

1004 flag and does not actually invoke the debugger if the flag is false. 

1005 The 'force' option forces the debugger to activate even if the flag 

1006 is false. 

1007 

1008 If the call_pdb flag is set, the pdb interactive debugger is 

1009 invoked. In all cases, the self.tb reference to the current traceback 

1010 is deleted to prevent lingering references which hamper memory 

1011 management. 

1012 

1013 Note that each call to pdb() does an 'import readline', so if your app 

1014 requires a special setup for the readline completers, you'll have to 

1015 fix that by hand after invoking the exception handler.""" 

1016 

1017 if force or self.call_pdb: 

1018 if self.pdb is None: 

1019 self.pdb = self.debugger_cls() 

1020 # the system displayhook may have changed, restore the original 

1021 # for pdb 

1022 display_trap = DisplayTrap(hook=sys.__displayhook__) 

1023 with display_trap: 

1024 self.pdb.reset() 

1025 # Find the right frame so we don't pop up inside ipython itself 

1026 if hasattr(self, "tb") and self.tb is not None: # type: ignore[has-type] 

1027 etb = self.tb # type: ignore[has-type] 

1028 else: 

1029 etb = self.tb = sys.last_traceback 

1030 while self.tb is not None and self.tb.tb_next is not None: 

1031 assert self.tb.tb_next is not None 

1032 self.tb = self.tb.tb_next 

1033 if etb and etb.tb_next: 

1034 etb = etb.tb_next 

1035 self.pdb.botframe = etb.tb_frame 

1036 # last_value should be deprecated, but last-exc sometimme not set 

1037 # please check why later and remove the getattr. 

1038 exc = ( 

1039 sys.last_value 

1040 if sys.version_info < (3, 12) 

1041 else getattr(sys, "last_exc", sys.last_value) 

1042 ) 

1043 if exc: 

1044 self.pdb.interaction(None, exc) 

1045 else: 

1046 self.pdb.interaction(None, etb) 

1047 

1048 if hasattr(self, "tb"): 

1049 del self.tb 

1050 

1051 def handler(self, info=None): 

1052 (etype, evalue, etb) = info or sys.exc_info() 

1053 self.tb = etb 

1054 ostream = self.ostream 

1055 ostream.flush() 

1056 ostream.write(self.text(etype, evalue, etb)) # type:ignore[arg-type] 

1057 ostream.write("\n") 

1058 ostream.flush() 

1059 

1060 # Changed so an instance can just be called as VerboseTB_inst() and print 

1061 # out the right info on its own. 

1062 def __call__(self, etype=None, evalue=None, etb=None): 

1063 """This hook can replace sys.excepthook (for Python 2.1 or higher).""" 

1064 if etb is None: 

1065 self.handler() 

1066 else: 

1067 self.handler((etype, evalue, etb)) 

1068 try: 

1069 self.debugger() 

1070 except KeyboardInterrupt: 

1071 print("\nKeyboardInterrupt") 

1072 

1073 

1074# ---------------------------------------------------------------------------- 

1075class FormattedTB(VerboseTB, ListTB): 

1076 """Subclass ListTB but allow calling with a traceback. 

1077 

1078 It can thus be used as a sys.excepthook for Python > 2.1. 

1079 

1080 Also adds 'Context' and 'Verbose' modes, not available in ListTB. 

1081 

1082 Allows a tb_offset to be specified. This is useful for situations where 

1083 one needs to remove a number of topmost frames from the traceback (such as 

1084 occurs with python programs that themselves execute other python code, 

1085 like Python shells).""" 

1086 

1087 mode: str 

1088 

1089 def __init__( 

1090 self, 

1091 mode="Plain", 

1092 # TODO: no default 

1093 theme_name="linux", 

1094 call_pdb=False, 

1095 ostream=None, 

1096 tb_offset=0, 

1097 long_header=False, 

1098 include_vars=False, 

1099 check_cache=None, 

1100 debugger_cls=None, 

1101 ): 

1102 # NEVER change the order of this list. Put new modes at the end: 

1103 self.valid_modes = ["Plain", "Context", "Verbose", "Minimal", "Docs", "Doctest"] 

1104 self.verbose_modes = self.valid_modes[1:3] 

1105 

1106 VerboseTB.__init__( 

1107 self, 

1108 theme_name=theme_name, 

1109 call_pdb=call_pdb, 

1110 ostream=ostream, 

1111 tb_offset=tb_offset, 

1112 long_header=long_header, 

1113 include_vars=include_vars, 

1114 check_cache=check_cache, 

1115 debugger_cls=debugger_cls, 

1116 ) 

1117 

1118 # Different types of tracebacks are joined with different separators to 

1119 # form a single string. They are taken from this dict 

1120 self._join_chars = dict( 

1121 Plain="", Context="\n", Verbose="\n", Minimal="", Docs="", Doctest="" 

1122 ) 

1123 # set_mode also sets the tb_join_char attribute 

1124 self.set_mode(mode) 

1125 

1126 def structured_traceback( 

1127 self, 

1128 etype: type, 

1129 evalue: BaseException | None, 

1130 etb: TracebackType | None = None, 

1131 tb_offset: int | None = None, 

1132 context: int = 5, 

1133 ) -> list[str]: 

1134 tb_offset = self.tb_offset if tb_offset is None else tb_offset 

1135 mode = self.mode 

1136 if mode in self.verbose_modes: 

1137 # Verbose modes need a full traceback 

1138 return VerboseTB.structured_traceback( 

1139 self, etype, evalue, etb, tb_offset, context 

1140 ) 

1141 elif mode == "Docs": 

1142 # return DocTB 

1143 return DocTB( 

1144 theme_name=self._theme_name, 

1145 call_pdb=self.call_pdb, 

1146 ostream=self.ostream, 

1147 tb_offset=tb_offset, 

1148 long_header=self.long_header, 

1149 include_vars=self.include_vars, 

1150 check_cache=self.check_cache, 

1151 debugger_cls=self.debugger_cls, 

1152 ).structured_traceback( 

1153 etype, evalue, etb, tb_offset, 1 

1154 ) 

1155 

1156 elif mode == "Minimal": 

1157 return ListTB.get_exception_only(self, etype, evalue) 

1158 elif mode == "Doctest": 

1159 return ListTB.structured_traceback_doctest(self, etype, evalue, etb, tb_offset, context) 

1160 else: 

1161 # We must check the source cache because otherwise we can print 

1162 # out-of-date source code. 

1163 self.check_cache() 

1164 # Now we can extract and format the exception 

1165 return ListTB.structured_traceback( 

1166 self, etype, evalue, etb, tb_offset, context 

1167 ) 

1168 

1169 def stb2text(self, stb: list[str]) -> str: 

1170 """Convert a structured traceback (a list) to a string.""" 

1171 return self.tb_join_char.join(stb) 

1172 

1173 def set_mode(self, mode: str | None = None) -> None: 

1174 """Switch to the desired mode. 

1175 

1176 If mode is not specified, cycles through the available modes.""" 

1177 

1178 if not mode: 

1179 new_idx = (self.valid_modes.index(self.mode) + 1) % len(self.valid_modes) 

1180 self.mode = self.valid_modes[new_idx] 

1181 elif mode not in self.valid_modes: 

1182 raise ValueError( 

1183 "Unrecognized mode in FormattedTB: <" + mode + ">\n" 

1184 "Valid modes: " + str(self.valid_modes) 

1185 ) 

1186 else: 

1187 assert isinstance(mode, str) 

1188 self.mode = mode 

1189 # include variable details only in 'Verbose' mode 

1190 self.include_vars = self.mode == self.valid_modes[2] 

1191 # Set the join character for generating text tracebacks 

1192 self.tb_join_char = self._join_chars[self.mode] 

1193 

1194 # some convenient shortcuts 

1195 def plain(self) -> None: 

1196 self.set_mode(self.valid_modes[0]) 

1197 

1198 def context(self) -> None: 

1199 self.set_mode(self.valid_modes[1]) 

1200 

1201 def verbose(self) -> None: 

1202 self.set_mode(self.valid_modes[2]) 

1203 

1204 def minimal(self) -> None: 

1205 self.set_mode(self.valid_modes[3]) 

1206 

1207 

1208# ---------------------------------------------------------------------------- 

1209class AutoFormattedTB(FormattedTB): 

1210 """A traceback printer which can be called on the fly. 

1211 

1212 It will find out about exceptions by itself. 

1213 

1214 A brief example:: 

1215 

1216 AutoTB = AutoFormattedTB(mode = 'Verbose', theme_name='linux') 

1217 try: 

1218 ... 

1219 except: 

1220 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object 

1221 """ 

1222 

1223 def __call__( 

1224 self, 

1225 etype: type | None = None, 

1226 evalue: BaseException | None = None, 

1227 etb: TracebackType | None = None, 

1228 out: Any = None, 

1229 tb_offset: int | None = None, 

1230 ) -> None: 

1231 """Print out a formatted exception traceback. 

1232 

1233 Optional arguments: 

1234 - out: an open file-like object to direct output to. 

1235 

1236 - tb_offset: the number of frames to skip over in the stack, on a 

1237 per-call basis (this overrides temporarily the instance's tb_offset 

1238 given at initialization time.""" 

1239 

1240 if out is None: 

1241 out = self.ostream 

1242 out.flush() 

1243 out.write(self.text(etype, evalue, etb, tb_offset)) # type:ignore[arg-type] 

1244 out.write("\n") 

1245 out.flush() 

1246 # FIXME: we should remove the auto pdb behavior from here and leave 

1247 # that to the clients. 

1248 try: 

1249 self.debugger() 

1250 except KeyboardInterrupt: 

1251 print("\nKeyboardInterrupt") 

1252 

1253 def structured_traceback( 

1254 self, 

1255 etype: type, 

1256 evalue: BaseException | None, 

1257 etb: TracebackType | None = None, 

1258 tb_offset: int | None = None, 

1259 context: int = 5, 

1260 ) -> list[str]: 

1261 # tb: TracebackType or tupleof tb types ? 

1262 # etype can be None when called as structured_traceback(*sys.exc_info()) 

1263 # with no active exception; etb can be a tuple for a chained exception. 

1264 # Neither is expressible in the public signature above. 

1265 if etype is None: 

1266 etype, evalue, etb = sys.exc_info() # type: ignore[unreachable] 

1267 if isinstance(etb, tuple): 

1268 # tb is a tuple if this is a chained exception. 

1269 self.tb = etb[0] # type: ignore[unreachable] 

1270 else: 

1271 self.tb = etb 

1272 return FormattedTB.structured_traceback( 

1273 self, etype, evalue, etb, tb_offset, context 

1274 ) 

1275 

1276 

1277# --------------------------------------------------------------------------- 

1278 

1279 

1280# A simple class to preserve Nathan's original functionality. 

1281class ColorTB(FormattedTB): 

1282 """Deprecated since IPython 9.0.""" 

1283 

1284 def __init__(self, *args, **kwargs): 

1285 warnings.warn( 

1286 "Deprecated since IPython 9.0 use FormattedTB directly ColorTB is just an alias", 

1287 DeprecationWarning, 

1288 stacklevel=2, 

1289 ) 

1290 

1291 super().__init__(*args, **kwargs) 

1292 

1293 

1294class SyntaxTB(ListTB): 

1295 """Extension which holds some state: the last exception value""" 

1296 

1297 last_syntax_error: BaseException | None 

1298 

1299 def __init__(self, *, theme_name): 

1300 super().__init__(theme_name=theme_name) 

1301 self.last_syntax_error = None 

1302 

1303 def __call__(self, etype, value, elist): 

1304 self.last_syntax_error = value 

1305 

1306 super().__call__(etype, value, elist) 

1307 

1308 def structured_traceback( 

1309 self, 

1310 etype: type, 

1311 evalue: BaseException | None, 

1312 etb: TracebackType | None = None, 

1313 tb_offset: int | None = None, 

1314 context: int = 5, 

1315 ) -> list[str]: 

1316 value = evalue 

1317 # If the source file has been edited, the line in the syntax error can 

1318 # be wrong (retrieved from an outdated cache). This replaces it with 

1319 # the current value. 

1320 if ( 

1321 isinstance(value, SyntaxError) 

1322 and isinstance(value.filename, str) 

1323 and isinstance(value.lineno, int) 

1324 ): 

1325 linecache.checkcache(value.filename) 

1326 newtext = linecache.getline(value.filename, value.lineno) 

1327 if newtext: 

1328 value.text = newtext 

1329 self.last_syntax_error = value 

1330 return super().structured_traceback( 

1331 etype, value, etb, tb_offset=tb_offset, context=context 

1332 ) 

1333 

1334 def clear_err_state(self) -> Any | None: 

1335 """Return the current error state and clear it""" 

1336 e = self.last_syntax_error 

1337 self.last_syntax_error = None 

1338 return e 

1339 

1340 def stb2text(self, stb: list[str]) -> str: 

1341 """Convert a structured traceback (a list) to a string.""" 

1342 return "".join(stb)