Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/pip/_vendor/rich/traceback.py: 29%

241 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-06-07 06:48 +0000

1from __future__ import absolute_import 

2 

3import linecache 

4import os 

5import platform 

6import sys 

7from dataclasses import dataclass, field 

8from traceback import walk_tb 

9from types import ModuleType, TracebackType 

10from typing import ( 

11 Any, 

12 Callable, 

13 Dict, 

14 Iterable, 

15 List, 

16 Optional, 

17 Sequence, 

18 Tuple, 

19 Type, 

20 Union, 

21) 

22 

23from pip._vendor.pygments.lexers import guess_lexer_for_filename 

24from pip._vendor.pygments.token import Comment, Keyword, Name, Number, Operator, String 

25from pip._vendor.pygments.token import Text as TextToken 

26from pip._vendor.pygments.token import Token 

27from pip._vendor.pygments.util import ClassNotFound 

28 

29from . import pretty 

30from ._loop import loop_last 

31from .columns import Columns 

32from .console import Console, ConsoleOptions, ConsoleRenderable, RenderResult, group 

33from .constrain import Constrain 

34from .highlighter import RegexHighlighter, ReprHighlighter 

35from .panel import Panel 

36from .scope import render_scope 

37from .style import Style 

38from .syntax import Syntax 

39from .text import Text 

40from .theme import Theme 

41 

42WINDOWS = platform.system() == "Windows" 

43 

44LOCALS_MAX_LENGTH = 10 

45LOCALS_MAX_STRING = 80 

46 

47 

48def install( 

49 *, 

50 console: Optional[Console] = None, 

51 width: Optional[int] = 100, 

52 extra_lines: int = 3, 

53 theme: Optional[str] = None, 

54 word_wrap: bool = False, 

55 show_locals: bool = False, 

56 locals_max_length: int = LOCALS_MAX_LENGTH, 

57 locals_max_string: int = LOCALS_MAX_STRING, 

58 locals_hide_dunder: bool = True, 

59 locals_hide_sunder: Optional[bool] = None, 

60 indent_guides: bool = True, 

61 suppress: Iterable[Union[str, ModuleType]] = (), 

62 max_frames: int = 100, 

63) -> Callable[[Type[BaseException], BaseException, Optional[TracebackType]], Any]: 

64 """Install a rich traceback handler. 

65 

66 Once installed, any tracebacks will be printed with syntax highlighting and rich formatting. 

67 

68 

69 Args: 

70 console (Optional[Console], optional): Console to write exception to. Default uses internal Console instance. 

71 width (Optional[int], optional): Width (in characters) of traceback. Defaults to 100. 

72 extra_lines (int, optional): Extra lines of code. Defaults to 3. 

73 theme (Optional[str], optional): Pygments theme to use in traceback. Defaults to ``None`` which will pick 

74 a theme appropriate for the platform. 

75 word_wrap (bool, optional): Enable word wrapping of long lines. Defaults to False. 

76 show_locals (bool, optional): Enable display of local variables. Defaults to False. 

77 locals_max_length (int, optional): Maximum length of containers before abbreviating, or None for no abbreviation. 

78 Defaults to 10. 

79 locals_max_string (int, optional): Maximum length of string before truncating, or None to disable. Defaults to 80. 

80 locals_hide_dunder (bool, optional): Hide locals prefixed with double underscore. Defaults to True. 

81 locals_hide_sunder (bool, optional): Hide locals prefixed with single underscore. Defaults to False. 

82 indent_guides (bool, optional): Enable indent guides in code and locals. Defaults to True. 

83 suppress (Sequence[Union[str, ModuleType]]): Optional sequence of modules or paths to exclude from traceback. 

84 

85 Returns: 

86 Callable: The previous exception handler that was replaced. 

87 

88 """ 

89 traceback_console = Console(stderr=True) if console is None else console 

90 

91 locals_hide_sunder = ( 

92 True 

93 if (traceback_console.is_jupyter and locals_hide_sunder is None) 

94 else locals_hide_sunder 

95 ) 

96 

97 def excepthook( 

98 type_: Type[BaseException], 

99 value: BaseException, 

100 traceback: Optional[TracebackType], 

101 ) -> None: 

102 traceback_console.print( 

103 Traceback.from_exception( 

104 type_, 

105 value, 

106 traceback, 

107 width=width, 

108 extra_lines=extra_lines, 

109 theme=theme, 

110 word_wrap=word_wrap, 

111 show_locals=show_locals, 

112 locals_max_length=locals_max_length, 

113 locals_max_string=locals_max_string, 

114 locals_hide_dunder=locals_hide_dunder, 

115 locals_hide_sunder=bool(locals_hide_sunder), 

116 indent_guides=indent_guides, 

117 suppress=suppress, 

118 max_frames=max_frames, 

119 ) 

120 ) 

121 

122 def ipy_excepthook_closure(ip: Any) -> None: # pragma: no cover 

123 tb_data = {} # store information about showtraceback call 

124 default_showtraceback = ip.showtraceback # keep reference of default traceback 

125 

126 def ipy_show_traceback(*args: Any, **kwargs: Any) -> None: 

127 """wrap the default ip.showtraceback to store info for ip._showtraceback""" 

128 nonlocal tb_data 

129 tb_data = kwargs 

130 default_showtraceback(*args, **kwargs) 

131 

132 def ipy_display_traceback( 

133 *args: Any, is_syntax: bool = False, **kwargs: Any 

134 ) -> None: 

135 """Internally called traceback from ip._showtraceback""" 

136 nonlocal tb_data 

137 exc_tuple = ip._get_exc_info() 

138 

139 # do not display trace on syntax error 

140 tb: Optional[TracebackType] = None if is_syntax else exc_tuple[2] 

141 

142 # determine correct tb_offset 

143 compiled = tb_data.get("running_compiled_code", False) 

144 tb_offset = tb_data.get("tb_offset", 1 if compiled else 0) 

145 # remove ipython internal frames from trace with tb_offset 

146 for _ in range(tb_offset): 

147 if tb is None: 

148 break 

149 tb = tb.tb_next 

150 

151 excepthook(exc_tuple[0], exc_tuple[1], tb) 

152 tb_data = {} # clear data upon usage 

153 

154 # replace _showtraceback instead of showtraceback to allow ipython features such as debugging to work 

155 # this is also what the ipython docs recommends to modify when subclassing InteractiveShell 

156 ip._showtraceback = ipy_display_traceback 

157 # add wrapper to capture tb_data 

158 ip.showtraceback = ipy_show_traceback 

159 ip.showsyntaxerror = lambda *args, **kwargs: ipy_display_traceback( 

160 *args, is_syntax=True, **kwargs 

161 ) 

162 

163 try: # pragma: no cover 

164 # if within ipython, use customized traceback 

165 ip = get_ipython() # type: ignore[name-defined] 

166 ipy_excepthook_closure(ip) 

167 return sys.excepthook 

168 except Exception: 

169 # otherwise use default system hook 

170 old_excepthook = sys.excepthook 

171 sys.excepthook = excepthook 

172 return old_excepthook 

173 

174 

175@dataclass 

176class Frame: 

177 filename: str 

178 lineno: int 

179 name: str 

180 line: str = "" 

181 locals: Optional[Dict[str, pretty.Node]] = None 

182 

183 

184@dataclass 

185class _SyntaxError: 

186 offset: int 

187 filename: str 

188 line: str 

189 lineno: int 

190 msg: str 

191 

192 

193@dataclass 

194class Stack: 

195 exc_type: str 

196 exc_value: str 

197 syntax_error: Optional[_SyntaxError] = None 

198 is_cause: bool = False 

199 frames: List[Frame] = field(default_factory=list) 

200 

201 

202@dataclass 

203class Trace: 

204 stacks: List[Stack] 

205 

206 

207class PathHighlighter(RegexHighlighter): 

208 highlights = [r"(?P<dim>.*/)(?P<bold>.+)"] 

209 

210 

211class Traceback: 

212 """A Console renderable that renders a traceback. 

213 

214 Args: 

215 trace (Trace, optional): A `Trace` object produced from `extract`. Defaults to None, which uses 

216 the last exception. 

217 width (Optional[int], optional): Number of characters used to traceback. Defaults to 100. 

218 extra_lines (int, optional): Additional lines of code to render. Defaults to 3. 

219 theme (str, optional): Override pygments theme used in traceback. 

220 word_wrap (bool, optional): Enable word wrapping of long lines. Defaults to False. 

221 show_locals (bool, optional): Enable display of local variables. Defaults to False. 

222 indent_guides (bool, optional): Enable indent guides in code and locals. Defaults to True. 

223 locals_max_length (int, optional): Maximum length of containers before abbreviating, or None for no abbreviation. 

224 Defaults to 10. 

225 locals_max_string (int, optional): Maximum length of string before truncating, or None to disable. Defaults to 80. 

226 locals_hide_dunder (bool, optional): Hide locals prefixed with double underscore. Defaults to True. 

227 locals_hide_sunder (bool, optional): Hide locals prefixed with single underscore. Defaults to False. 

228 suppress (Sequence[Union[str, ModuleType]]): Optional sequence of modules or paths to exclude from traceback. 

229 max_frames (int): Maximum number of frames to show in a traceback, 0 for no maximum. Defaults to 100. 

230 

231 """ 

232 

233 LEXERS = { 

234 "": "text", 

235 ".py": "python", 

236 ".pxd": "cython", 

237 ".pyx": "cython", 

238 ".pxi": "pyrex", 

239 } 

240 

241 def __init__( 

242 self, 

243 trace: Optional[Trace] = None, 

244 *, 

245 width: Optional[int] = 100, 

246 extra_lines: int = 3, 

247 theme: Optional[str] = None, 

248 word_wrap: bool = False, 

249 show_locals: bool = False, 

250 locals_max_length: int = LOCALS_MAX_LENGTH, 

251 locals_max_string: int = LOCALS_MAX_STRING, 

252 locals_hide_dunder: bool = True, 

253 locals_hide_sunder: bool = False, 

254 indent_guides: bool = True, 

255 suppress: Iterable[Union[str, ModuleType]] = (), 

256 max_frames: int = 100, 

257 ): 

258 if trace is None: 

259 exc_type, exc_value, traceback = sys.exc_info() 

260 if exc_type is None or exc_value is None or traceback is None: 

261 raise ValueError( 

262 "Value for 'trace' required if not called in except: block" 

263 ) 

264 trace = self.extract( 

265 exc_type, exc_value, traceback, show_locals=show_locals 

266 ) 

267 self.trace = trace 

268 self.width = width 

269 self.extra_lines = extra_lines 

270 self.theme = Syntax.get_theme(theme or "ansi_dark") 

271 self.word_wrap = word_wrap 

272 self.show_locals = show_locals 

273 self.indent_guides = indent_guides 

274 self.locals_max_length = locals_max_length 

275 self.locals_max_string = locals_max_string 

276 self.locals_hide_dunder = locals_hide_dunder 

277 self.locals_hide_sunder = locals_hide_sunder 

278 

279 self.suppress: Sequence[str] = [] 

280 for suppress_entity in suppress: 

281 if not isinstance(suppress_entity, str): 

282 assert ( 

283 suppress_entity.__file__ is not None 

284 ), f"{suppress_entity!r} must be a module with '__file__' attribute" 

285 path = os.path.dirname(suppress_entity.__file__) 

286 else: 

287 path = suppress_entity 

288 path = os.path.normpath(os.path.abspath(path)) 

289 self.suppress.append(path) 

290 self.max_frames = max(4, max_frames) if max_frames > 0 else 0 

291 

292 @classmethod 

293 def from_exception( 

294 cls, 

295 exc_type: Type[Any], 

296 exc_value: BaseException, 

297 traceback: Optional[TracebackType], 

298 *, 

299 width: Optional[int] = 100, 

300 extra_lines: int = 3, 

301 theme: Optional[str] = None, 

302 word_wrap: bool = False, 

303 show_locals: bool = False, 

304 locals_max_length: int = LOCALS_MAX_LENGTH, 

305 locals_max_string: int = LOCALS_MAX_STRING, 

306 locals_hide_dunder: bool = True, 

307 locals_hide_sunder: bool = False, 

308 indent_guides: bool = True, 

309 suppress: Iterable[Union[str, ModuleType]] = (), 

310 max_frames: int = 100, 

311 ) -> "Traceback": 

312 """Create a traceback from exception info 

313 

314 Args: 

315 exc_type (Type[BaseException]): Exception type. 

316 exc_value (BaseException): Exception value. 

317 traceback (TracebackType): Python Traceback object. 

318 width (Optional[int], optional): Number of characters used to traceback. Defaults to 100. 

319 extra_lines (int, optional): Additional lines of code to render. Defaults to 3. 

320 theme (str, optional): Override pygments theme used in traceback. 

321 word_wrap (bool, optional): Enable word wrapping of long lines. Defaults to False. 

322 show_locals (bool, optional): Enable display of local variables. Defaults to False. 

323 indent_guides (bool, optional): Enable indent guides in code and locals. Defaults to True. 

324 locals_max_length (int, optional): Maximum length of containers before abbreviating, or None for no abbreviation. 

325 Defaults to 10. 

326 locals_max_string (int, optional): Maximum length of string before truncating, or None to disable. Defaults to 80. 

327 locals_hide_dunder (bool, optional): Hide locals prefixed with double underscore. Defaults to True. 

328 locals_hide_sunder (bool, optional): Hide locals prefixed with single underscore. Defaults to False. 

329 suppress (Iterable[Union[str, ModuleType]]): Optional sequence of modules or paths to exclude from traceback. 

330 max_frames (int): Maximum number of frames to show in a traceback, 0 for no maximum. Defaults to 100. 

331 

332 Returns: 

333 Traceback: A Traceback instance that may be printed. 

334 """ 

335 rich_traceback = cls.extract( 

336 exc_type, 

337 exc_value, 

338 traceback, 

339 show_locals=show_locals, 

340 locals_max_length=locals_max_length, 

341 locals_max_string=locals_max_string, 

342 locals_hide_dunder=locals_hide_dunder, 

343 locals_hide_sunder=locals_hide_sunder, 

344 ) 

345 

346 return cls( 

347 rich_traceback, 

348 width=width, 

349 extra_lines=extra_lines, 

350 theme=theme, 

351 word_wrap=word_wrap, 

352 show_locals=show_locals, 

353 indent_guides=indent_guides, 

354 locals_max_length=locals_max_length, 

355 locals_max_string=locals_max_string, 

356 locals_hide_dunder=locals_hide_dunder, 

357 locals_hide_sunder=locals_hide_sunder, 

358 suppress=suppress, 

359 max_frames=max_frames, 

360 ) 

361 

362 @classmethod 

363 def extract( 

364 cls, 

365 exc_type: Type[BaseException], 

366 exc_value: BaseException, 

367 traceback: Optional[TracebackType], 

368 *, 

369 show_locals: bool = False, 

370 locals_max_length: int = LOCALS_MAX_LENGTH, 

371 locals_max_string: int = LOCALS_MAX_STRING, 

372 locals_hide_dunder: bool = True, 

373 locals_hide_sunder: bool = False, 

374 ) -> Trace: 

375 """Extract traceback information. 

376 

377 Args: 

378 exc_type (Type[BaseException]): Exception type. 

379 exc_value (BaseException): Exception value. 

380 traceback (TracebackType): Python Traceback object. 

381 show_locals (bool, optional): Enable display of local variables. Defaults to False. 

382 locals_max_length (int, optional): Maximum length of containers before abbreviating, or None for no abbreviation. 

383 Defaults to 10. 

384 locals_max_string (int, optional): Maximum length of string before truncating, or None to disable. Defaults to 80. 

385 locals_hide_dunder (bool, optional): Hide locals prefixed with double underscore. Defaults to True. 

386 locals_hide_sunder (bool, optional): Hide locals prefixed with single underscore. Defaults to False. 

387 

388 Returns: 

389 Trace: A Trace instance which you can use to construct a `Traceback`. 

390 """ 

391 

392 stacks: List[Stack] = [] 

393 is_cause = False 

394 

395 from pip._vendor.rich import _IMPORT_CWD 

396 

397 def safe_str(_object: Any) -> str: 

398 """Don't allow exceptions from __str__ to propagate.""" 

399 try: 

400 return str(_object) 

401 except Exception: 

402 return "<exception str() failed>" 

403 

404 while True: 

405 stack = Stack( 

406 exc_type=safe_str(exc_type.__name__), 

407 exc_value=safe_str(exc_value), 

408 is_cause=is_cause, 

409 ) 

410 

411 if isinstance(exc_value, SyntaxError): 

412 stack.syntax_error = _SyntaxError( 

413 offset=exc_value.offset or 0, 

414 filename=exc_value.filename or "?", 

415 lineno=exc_value.lineno or 0, 

416 line=exc_value.text or "", 

417 msg=exc_value.msg, 

418 ) 

419 

420 stacks.append(stack) 

421 append = stack.frames.append 

422 

423 def get_locals( 

424 iter_locals: Iterable[Tuple[str, object]] 

425 ) -> Iterable[Tuple[str, object]]: 

426 """Extract locals from an iterator of key pairs.""" 

427 if not (locals_hide_dunder or locals_hide_sunder): 

428 yield from iter_locals 

429 return 

430 for key, value in iter_locals: 

431 if locals_hide_dunder and key.startswith("__"): 

432 continue 

433 if locals_hide_sunder and key.startswith("_"): 

434 continue 

435 yield key, value 

436 

437 for frame_summary, line_no in walk_tb(traceback): 

438 filename = frame_summary.f_code.co_filename 

439 if filename and not filename.startswith("<"): 

440 if not os.path.isabs(filename): 

441 filename = os.path.join(_IMPORT_CWD, filename) 

442 if frame_summary.f_locals.get("_rich_traceback_omit", False): 

443 continue 

444 

445 frame = Frame( 

446 filename=filename or "?", 

447 lineno=line_no, 

448 name=frame_summary.f_code.co_name, 

449 locals={ 

450 key: pretty.traverse( 

451 value, 

452 max_length=locals_max_length, 

453 max_string=locals_max_string, 

454 ) 

455 for key, value in get_locals(frame_summary.f_locals.items()) 

456 } 

457 if show_locals 

458 else None, 

459 ) 

460 append(frame) 

461 if frame_summary.f_locals.get("_rich_traceback_guard", False): 

462 del stack.frames[:] 

463 

464 cause = getattr(exc_value, "__cause__", None) 

465 if cause: 

466 exc_type = cause.__class__ 

467 exc_value = cause 

468 # __traceback__ can be None, e.g. for exceptions raised by the 

469 # 'multiprocessing' module 

470 traceback = cause.__traceback__ 

471 is_cause = True 

472 continue 

473 

474 cause = exc_value.__context__ 

475 if cause and not getattr(exc_value, "__suppress_context__", False): 

476 exc_type = cause.__class__ 

477 exc_value = cause 

478 traceback = cause.__traceback__ 

479 is_cause = False 

480 continue 

481 # No cover, code is reached but coverage doesn't recognize it. 

482 break # pragma: no cover 

483 

484 trace = Trace(stacks=stacks) 

485 return trace 

486 

487 def __rich_console__( 

488 self, console: Console, options: ConsoleOptions 

489 ) -> RenderResult: 

490 theme = self.theme 

491 background_style = theme.get_background_style() 

492 token_style = theme.get_style_for_token 

493 

494 traceback_theme = Theme( 

495 { 

496 "pretty": token_style(TextToken), 

497 "pygments.text": token_style(Token), 

498 "pygments.string": token_style(String), 

499 "pygments.function": token_style(Name.Function), 

500 "pygments.number": token_style(Number), 

501 "repr.indent": token_style(Comment) + Style(dim=True), 

502 "repr.str": token_style(String), 

503 "repr.brace": token_style(TextToken) + Style(bold=True), 

504 "repr.number": token_style(Number), 

505 "repr.bool_true": token_style(Keyword.Constant), 

506 "repr.bool_false": token_style(Keyword.Constant), 

507 "repr.none": token_style(Keyword.Constant), 

508 "scope.border": token_style(String.Delimiter), 

509 "scope.equals": token_style(Operator), 

510 "scope.key": token_style(Name), 

511 "scope.key.special": token_style(Name.Constant) + Style(dim=True), 

512 }, 

513 inherit=False, 

514 ) 

515 

516 highlighter = ReprHighlighter() 

517 for last, stack in loop_last(reversed(self.trace.stacks)): 

518 if stack.frames: 

519 stack_renderable: ConsoleRenderable = Panel( 

520 self._render_stack(stack), 

521 title="[traceback.title]Traceback [dim](most recent call last)", 

522 style=background_style, 

523 border_style="traceback.border", 

524 expand=True, 

525 padding=(0, 1), 

526 ) 

527 stack_renderable = Constrain(stack_renderable, self.width) 

528 with console.use_theme(traceback_theme): 

529 yield stack_renderable 

530 if stack.syntax_error is not None: 

531 with console.use_theme(traceback_theme): 

532 yield Constrain( 

533 Panel( 

534 self._render_syntax_error(stack.syntax_error), 

535 style=background_style, 

536 border_style="traceback.border.syntax_error", 

537 expand=True, 

538 padding=(0, 1), 

539 width=self.width, 

540 ), 

541 self.width, 

542 ) 

543 yield Text.assemble( 

544 (f"{stack.exc_type}: ", "traceback.exc_type"), 

545 highlighter(stack.syntax_error.msg), 

546 ) 

547 elif stack.exc_value: 

548 yield Text.assemble( 

549 (f"{stack.exc_type}: ", "traceback.exc_type"), 

550 highlighter(stack.exc_value), 

551 ) 

552 else: 

553 yield Text.assemble((f"{stack.exc_type}", "traceback.exc_type")) 

554 

555 if not last: 

556 if stack.is_cause: 

557 yield Text.from_markup( 

558 "\n[i]The above exception was the direct cause of the following exception:\n", 

559 ) 

560 else: 

561 yield Text.from_markup( 

562 "\n[i]During handling of the above exception, another exception occurred:\n", 

563 ) 

564 

565 @group() 

566 def _render_syntax_error(self, syntax_error: _SyntaxError) -> RenderResult: 

567 highlighter = ReprHighlighter() 

568 path_highlighter = PathHighlighter() 

569 if syntax_error.filename != "<stdin>": 

570 if os.path.exists(syntax_error.filename): 

571 text = Text.assemble( 

572 (f" {syntax_error.filename}", "pygments.string"), 

573 (":", "pygments.text"), 

574 (str(syntax_error.lineno), "pygments.number"), 

575 style="pygments.text", 

576 ) 

577 yield path_highlighter(text) 

578 syntax_error_text = highlighter(syntax_error.line.rstrip()) 

579 syntax_error_text.no_wrap = True 

580 offset = min(syntax_error.offset - 1, len(syntax_error_text)) 

581 syntax_error_text.stylize("bold underline", offset, offset) 

582 syntax_error_text += Text.from_markup( 

583 "\n" + " " * offset + "[traceback.offset]▲[/]", 

584 style="pygments.text", 

585 ) 

586 yield syntax_error_text 

587 

588 @classmethod 

589 def _guess_lexer(cls, filename: str, code: str) -> str: 

590 ext = os.path.splitext(filename)[-1] 

591 if not ext: 

592 # No extension, look at first line to see if it is a hashbang 

593 # Note, this is an educated guess and not a guarantee 

594 # If it fails, the only downside is that the code is highlighted strangely 

595 new_line_index = code.index("\n") 

596 first_line = code[:new_line_index] if new_line_index != -1 else code 

597 if first_line.startswith("#!") and "python" in first_line.lower(): 

598 return "python" 

599 try: 

600 return cls.LEXERS.get(ext) or guess_lexer_for_filename(filename, code).name 

601 except ClassNotFound: 

602 return "text" 

603 

604 @group() 

605 def _render_stack(self, stack: Stack) -> RenderResult: 

606 path_highlighter = PathHighlighter() 

607 theme = self.theme 

608 

609 def read_code(filename: str) -> str: 

610 """Read files, and cache results on filename. 

611 

612 Args: 

613 filename (str): Filename to read 

614 

615 Returns: 

616 str: Contents of file 

617 """ 

618 return "".join(linecache.getlines(filename)) 

619 

620 def render_locals(frame: Frame) -> Iterable[ConsoleRenderable]: 

621 if frame.locals: 

622 yield render_scope( 

623 frame.locals, 

624 title="locals", 

625 indent_guides=self.indent_guides, 

626 max_length=self.locals_max_length, 

627 max_string=self.locals_max_string, 

628 ) 

629 

630 exclude_frames: Optional[range] = None 

631 if self.max_frames != 0: 

632 exclude_frames = range( 

633 self.max_frames // 2, 

634 len(stack.frames) - self.max_frames // 2, 

635 ) 

636 

637 excluded = False 

638 for frame_index, frame in enumerate(stack.frames): 

639 

640 if exclude_frames and frame_index in exclude_frames: 

641 excluded = True 

642 continue 

643 

644 if excluded: 

645 assert exclude_frames is not None 

646 yield Text( 

647 f"\n... {len(exclude_frames)} frames hidden ...", 

648 justify="center", 

649 style="traceback.error", 

650 ) 

651 excluded = False 

652 

653 first = frame_index == 0 

654 frame_filename = frame.filename 

655 suppressed = any(frame_filename.startswith(path) for path in self.suppress) 

656 

657 if os.path.exists(frame.filename): 

658 text = Text.assemble( 

659 path_highlighter(Text(frame.filename, style="pygments.string")), 

660 (":", "pygments.text"), 

661 (str(frame.lineno), "pygments.number"), 

662 " in ", 

663 (frame.name, "pygments.function"), 

664 style="pygments.text", 

665 ) 

666 else: 

667 text = Text.assemble( 

668 "in ", 

669 (frame.name, "pygments.function"), 

670 (":", "pygments.text"), 

671 (str(frame.lineno), "pygments.number"), 

672 style="pygments.text", 

673 ) 

674 if not frame.filename.startswith("<") and not first: 

675 yield "" 

676 yield text 

677 if frame.filename.startswith("<"): 

678 yield from render_locals(frame) 

679 continue 

680 if not suppressed: 

681 try: 

682 code = read_code(frame.filename) 

683 if not code: 

684 # code may be an empty string if the file doesn't exist, OR 

685 # if the traceback filename is generated dynamically 

686 continue 

687 lexer_name = self._guess_lexer(frame.filename, code) 

688 syntax = Syntax( 

689 code, 

690 lexer_name, 

691 theme=theme, 

692 line_numbers=True, 

693 line_range=( 

694 frame.lineno - self.extra_lines, 

695 frame.lineno + self.extra_lines, 

696 ), 

697 highlight_lines={frame.lineno}, 

698 word_wrap=self.word_wrap, 

699 code_width=88, 

700 indent_guides=self.indent_guides, 

701 dedent=False, 

702 ) 

703 yield "" 

704 except Exception as error: 

705 yield Text.assemble( 

706 (f"\n{error}", "traceback.error"), 

707 ) 

708 else: 

709 yield ( 

710 Columns( 

711 [ 

712 syntax, 

713 *render_locals(frame), 

714 ], 

715 padding=1, 

716 ) 

717 if frame.locals 

718 else syntax 

719 ) 

720 

721 

722if __name__ == "__main__": # pragma: no cover 

723 

724 from .console import Console 

725 

726 console = Console() 

727 import sys 

728 

729 def bar(a: Any) -> None: # 这是对亚洲语言支持的测试。面对模棱两可的想法,拒绝猜测的诱惑 

730 one = 1 

731 print(one / a) 

732 

733 def foo(a: Any) -> None: 

734 _rich_traceback_guard = True 

735 zed = { 

736 "characters": { 

737 "Paul Atreides", 

738 "Vladimir Harkonnen", 

739 "Thufir Hawat", 

740 "Duncan Idaho", 

741 }, 

742 "atomic_types": (None, False, True), 

743 } 

744 bar(a) 

745 

746 def error() -> None: 

747 

748 try: 

749 try: 

750 foo(0) 

751 except: 

752 slfkjsldkfj # type: ignore[name-defined] 

753 except: 

754 console.print_exception(show_locals=True) 

755 

756 error()