Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/rich/traceback.py: 67%

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

303 statements  

1import inspect 

2import linecache 

3import os 

4import sys 

5from dataclasses import dataclass, field 

6from itertools import islice 

7from traceback import walk_tb 

8from types import ModuleType, TracebackType 

9from typing import ( 

10 Any, 

11 Callable, 

12 Dict, 

13 Iterable, 

14 List, 

15 Optional, 

16 Sequence, 

17 Set, 

18 Tuple, 

19 Type, 

20 Union, 

21) 

22 

23from pygments.lexers import guess_lexer_for_filename 

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

25from pygments.token import Text as TextToken 

26from pygments.token import Token 

27from pygments.util import ClassNotFound 

28 

29from . import pretty 

30from ._loop import loop_first_last, loop_last 

31from .columns import Columns 

32from .console import ( 

33 Console, 

34 ConsoleOptions, 

35 ConsoleRenderable, 

36 OverflowMethod, 

37 Group, 

38 RenderResult, 

39 group, 

40) 

41from .constrain import Constrain 

42from .highlighter import RegexHighlighter, ReprHighlighter 

43from .panel import Panel 

44from .scope import render_scope 

45from .style import Style 

46from .syntax import Syntax, SyntaxPosition 

47from .text import Text 

48from .theme import Theme 

49 

50WINDOWS = sys.platform == "win32" 

51 

52LOCALS_MAX_LENGTH = 10 

53LOCALS_MAX_STRING = 80 

54 

55 

56def _iter_syntax_lines( 

57 start: SyntaxPosition, end: SyntaxPosition 

58) -> Iterable[Tuple[int, int, int]]: 

59 """Yield start and end positions per line. 

60 

61 Args: 

62 start: Start position. 

63 end: End position. 

64 

65 Returns: 

66 Iterable of (LINE, COLUMN1, COLUMN2). 

67 """ 

68 

69 line1, column1 = start 

70 line2, column2 = end 

71 

72 if line1 == line2: 

73 yield line1, column1, column2 

74 else: 

75 for first, last, line_no in loop_first_last(range(line1, line2 + 1)): 

76 if first: 

77 yield line_no, column1, -1 

78 elif last: 

79 yield line_no, 0, column2 

80 else: 

81 yield line_no, 0, -1 

82 

83 

84def install( 

85 *, 

86 console: Optional[Console] = None, 

87 width: Optional[int] = 100, 

88 code_width: Optional[int] = 88, 

89 extra_lines: int = 3, 

90 theme: Optional[str] = None, 

91 word_wrap: bool = False, 

92 show_locals: bool = False, 

93 locals_max_length: int = LOCALS_MAX_LENGTH, 

94 locals_max_string: int = LOCALS_MAX_STRING, 

95 locals_max_depth: Optional[int] = None, 

96 locals_hide_dunder: bool = True, 

97 locals_hide_sunder: Optional[bool] = None, 

98 locals_overflow: Optional[OverflowMethod] = None, 

99 indent_guides: bool = True, 

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

101 max_frames: int = 100, 

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

103 """Install a rich traceback handler. 

104 

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

106 

107 

108 Args: 

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

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

111 code_width (Optional[int], optional): Code width (in characters) of traceback. Defaults to 88. 

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

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

114 a theme appropriate for the platform. 

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

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

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

118 Defaults to 10. 

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

120 locals_max_depth (int, optional): Maximum depths of locals before truncating, or None to disable. Defaults to None. 

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

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

123 locals_overflow (OverflowMethod, optional): How to handle overflowing locals, or None to disable. Defaults to None. 

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

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

126 

127 Returns: 

128 Callable: The previous exception handler that was replaced. 

129 

130 """ 

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

132 

133 locals_hide_sunder = ( 

134 True 

135 if (traceback_console.is_jupyter and locals_hide_sunder is None) 

136 else locals_hide_sunder 

137 ) 

138 

139 def excepthook( 

140 type_: Type[BaseException], 

141 value: BaseException, 

142 traceback: Optional[TracebackType], 

143 ) -> None: 

144 exception_traceback = Traceback.from_exception( 

145 type_, 

146 value, 

147 traceback, 

148 width=width, 

149 code_width=code_width, 

150 extra_lines=extra_lines, 

151 theme=theme, 

152 word_wrap=word_wrap, 

153 show_locals=show_locals, 

154 locals_max_length=locals_max_length, 

155 locals_max_string=locals_max_string, 

156 locals_max_depth=locals_max_depth, 

157 locals_hide_dunder=locals_hide_dunder, 

158 locals_hide_sunder=bool(locals_hide_sunder), 

159 locals_overflow=locals_overflow, 

160 indent_guides=indent_guides, 

161 suppress=suppress, 

162 max_frames=max_frames, 

163 ) 

164 traceback_console.print(exception_traceback) 

165 

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

167 tb_data = {} # store information about showtraceback call 

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

169 

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

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

172 nonlocal tb_data 

173 tb_data = kwargs 

174 default_showtraceback(*args, **kwargs) 

175 

176 def ipy_display_traceback( 

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

178 ) -> None: 

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

180 nonlocal tb_data 

181 exc_tuple = ip._get_exc_info() 

182 

183 # do not display trace on syntax error 

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

185 

186 # determine correct tb_offset 

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

188 tb_offset = tb_data.get("tb_offset") 

189 if tb_offset is None: 

190 tb_offset = 1 if compiled else 0 

191 # remove ipython internal frames from trace with tb_offset 

192 for _ in range(tb_offset): 

193 if tb is None: 

194 break 

195 tb = tb.tb_next 

196 

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

198 tb_data = {} # clear data upon usage 

199 

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

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

202 ip._showtraceback = ipy_display_traceback 

203 # add wrapper to capture tb_data 

204 ip.showtraceback = ipy_show_traceback 

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

206 *args, is_syntax=True, **kwargs 

207 ) 

208 

209 try: # pragma: no cover 

210 # if within ipython, use customized traceback 

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

212 ipy_excepthook_closure(ip) 

213 return sys.excepthook 

214 except Exception: 

215 # otherwise use default system hook 

216 old_excepthook = sys.excepthook 

217 sys.excepthook = excepthook 

218 return old_excepthook 

219 

220 

221@dataclass 

222class Frame: 

223 filename: str 

224 lineno: int 

225 name: str 

226 line: str = "" 

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

228 last_instruction: Optional[Tuple[Tuple[int, int], Tuple[int, int]]] = None 

229 

230 

231@dataclass 

232class _SyntaxError: 

233 offset: int 

234 filename: str 

235 line: str 

236 lineno: int 

237 msg: str 

238 notes: List[str] = field(default_factory=list) 

239 

240 

241@dataclass 

242class Stack: 

243 exc_type: str 

244 exc_value: str 

245 syntax_error: Optional[_SyntaxError] = None 

246 is_cause: bool = False 

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

248 notes: List[str] = field(default_factory=list) 

249 is_group: bool = False 

250 exceptions: List["Trace"] = field(default_factory=list) 

251 

252 

253@dataclass 

254class Trace: 

255 stacks: List[Stack] 

256 

257 

258class PathHighlighter(RegexHighlighter): 

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

260 

261 

262class Traceback: 

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

264 

265 Args: 

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

267 the last exception. 

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

269 code_width (Optional[int], optional): Number of code characters used to traceback. Defaults to 88. 

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

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

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

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

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

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

276 Defaults to 10. 

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

278 locals_max_depth (int, optional): Maximum depths of locals before truncating, or None to disable. Defaults to None. 

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

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

281 locals_overflow (OverflowMethod, optional): How to handle overflowing locals, or None to disable. Defaults to None. 

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

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

284 

285 """ 

286 

287 LEXERS = { 

288 "": "text", 

289 ".py": "python", 

290 ".pxd": "cython", 

291 ".pyx": "cython", 

292 ".pxi": "pyrex", 

293 } 

294 

295 def __init__( 

296 self, 

297 trace: Optional[Trace] = None, 

298 *, 

299 width: Optional[int] = 100, 

300 code_width: Optional[int] = 88, 

301 extra_lines: int = 3, 

302 theme: Optional[str] = None, 

303 word_wrap: bool = False, 

304 show_locals: bool = False, 

305 locals_max_length: int = LOCALS_MAX_LENGTH, 

306 locals_max_string: int = LOCALS_MAX_STRING, 

307 locals_max_depth: Optional[int] = None, 

308 locals_hide_dunder: bool = True, 

309 locals_hide_sunder: bool = False, 

310 locals_overlow: Optional[OverflowMethod] = None, 

311 indent_guides: bool = True, 

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

313 max_frames: int = 100, 

314 ): 

315 if trace is None: 

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

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

318 raise ValueError( 

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

320 ) 

321 trace = self.extract( 

322 exc_type, exc_value, traceback, show_locals=show_locals 

323 ) 

324 self.trace = trace 

325 self.width = width 

326 self.code_width = code_width 

327 self.extra_lines = extra_lines 

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

329 self.word_wrap = word_wrap 

330 self.show_locals = show_locals 

331 self.indent_guides = indent_guides 

332 self.locals_max_length = locals_max_length 

333 self.locals_max_string = locals_max_string 

334 self.locals_max_depth = locals_max_depth 

335 self.locals_hide_dunder = locals_hide_dunder 

336 self.locals_hide_sunder = locals_hide_sunder 

337 self.locals_overflow = locals_overlow 

338 

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

340 for suppress_entity in suppress: 

341 if not isinstance(suppress_entity, str): 

342 assert ( 

343 suppress_entity.__file__ is not None 

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

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

346 else: 

347 path = suppress_entity 

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

349 self.suppress.append(path) 

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

351 

352 @classmethod 

353 def from_exception( 

354 cls, 

355 exc_type: Type[Any], 

356 exc_value: BaseException, 

357 traceback: Optional[TracebackType], 

358 *, 

359 width: Optional[int] = 100, 

360 code_width: Optional[int] = 88, 

361 extra_lines: int = 3, 

362 theme: Optional[str] = None, 

363 word_wrap: bool = False, 

364 show_locals: bool = False, 

365 locals_max_length: int = LOCALS_MAX_LENGTH, 

366 locals_max_string: int = LOCALS_MAX_STRING, 

367 locals_max_depth: Optional[int] = None, 

368 locals_hide_dunder: bool = True, 

369 locals_hide_sunder: bool = False, 

370 locals_overflow: Optional[OverflowMethod] = None, 

371 indent_guides: bool = True, 

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

373 max_frames: int = 100, 

374 ) -> "Traceback": 

375 """Create a traceback from exception info 

376 

377 Args: 

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

379 exc_value (BaseException): Exception value. 

380 traceback (TracebackType): Python Traceback object. 

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

382 code_width (Optional[int], optional): Number of code characters used to traceback. Defaults to 88. 

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

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

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

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

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

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

389 Defaults to 10. 

390 locals_max_depth (int, optional): Maximum depths of locals before truncating, or None to disable. Defaults to None. 

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

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

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

394 locals_overflow (OverflowMethod, optional): How to handle overflowing locals, or None to disable. Defaults to None. 

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

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

397 

398 Returns: 

399 Traceback: A Traceback instance that may be printed. 

400 """ 

401 rich_traceback = cls.extract( 

402 exc_type, 

403 exc_value, 

404 traceback, 

405 show_locals=show_locals, 

406 locals_max_length=locals_max_length, 

407 locals_max_string=locals_max_string, 

408 locals_max_depth=locals_max_depth, 

409 locals_hide_dunder=locals_hide_dunder, 

410 locals_hide_sunder=locals_hide_sunder, 

411 ) 

412 

413 return cls( 

414 rich_traceback, 

415 width=width, 

416 code_width=code_width, 

417 extra_lines=extra_lines, 

418 theme=theme, 

419 word_wrap=word_wrap, 

420 show_locals=show_locals, 

421 indent_guides=indent_guides, 

422 locals_max_length=locals_max_length, 

423 locals_max_string=locals_max_string, 

424 locals_max_depth=locals_max_depth, 

425 locals_hide_dunder=locals_hide_dunder, 

426 locals_hide_sunder=locals_hide_sunder, 

427 locals_overlow=locals_overflow, 

428 suppress=suppress, 

429 max_frames=max_frames, 

430 ) 

431 

432 @classmethod 

433 def extract( 

434 cls, 

435 exc_type: Type[BaseException], 

436 exc_value: BaseException, 

437 traceback: Optional[TracebackType], 

438 *, 

439 show_locals: bool = False, 

440 locals_max_length: int = LOCALS_MAX_LENGTH, 

441 locals_max_string: int = LOCALS_MAX_STRING, 

442 locals_max_depth: Optional[int] = None, 

443 locals_hide_dunder: bool = True, 

444 locals_hide_sunder: bool = False, 

445 _visited_exceptions: Optional[Set[BaseException]] = None, 

446 ) -> Trace: 

447 """Extract traceback information. 

448 

449 Args: 

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

451 exc_value (BaseException): Exception value. 

452 traceback (TracebackType): Python Traceback object. 

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

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

455 Defaults to 10. 

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

457 locals_max_depth (int, optional): Maximum depths of locals before truncating, or None to disable. Defaults to None. 

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

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

460 

461 Returns: 

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

463 """ 

464 

465 stacks: List[Stack] = [] 

466 is_cause = False 

467 

468 from rich import _IMPORT_CWD 

469 

470 notes: List[str] = getattr(exc_value, "__notes__", None) or [] 

471 

472 grouped_exceptions: Set[BaseException] = ( 

473 set() if _visited_exceptions is None else _visited_exceptions 

474 ) 

475 

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

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

478 try: 

479 return str(_object) 

480 except Exception: 

481 return "<exception str() failed>" 

482 

483 while True: 

484 stack = Stack( 

485 exc_type=safe_str(exc_type.__name__), 

486 exc_value=safe_str(exc_value), 

487 is_cause=is_cause, 

488 notes=notes, 

489 ) 

490 

491 if sys.version_info >= (3, 11): 

492 if isinstance(exc_value, (BaseExceptionGroup, ExceptionGroup)): 

493 stack.is_group = True 

494 for exception in exc_value.exceptions: 

495 if exception in grouped_exceptions: 

496 continue 

497 grouped_exceptions.add(exception) 

498 stack.exceptions.append( 

499 Traceback.extract( 

500 type(exception), 

501 exception, 

502 exception.__traceback__, 

503 show_locals=show_locals, 

504 locals_max_length=locals_max_length, 

505 locals_hide_dunder=locals_hide_dunder, 

506 locals_hide_sunder=locals_hide_sunder, 

507 _visited_exceptions=grouped_exceptions, 

508 ) 

509 ) 

510 

511 if isinstance(exc_value, SyntaxError): 

512 stack.syntax_error = _SyntaxError( 

513 offset=exc_value.offset or 0, 

514 filename=exc_value.filename or "?", 

515 lineno=exc_value.lineno or 0, 

516 line=exc_value.text or "", 

517 msg=exc_value.msg, 

518 notes=notes, 

519 ) 

520 

521 stacks.append(stack) 

522 append = stack.frames.append 

523 

524 def get_locals( 

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

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

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

528 if not (locals_hide_dunder or locals_hide_sunder): 

529 yield from iter_locals 

530 return 

531 for key, value in iter_locals: 

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

533 continue 

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

535 continue 

536 yield key, value 

537 

538 for frame_summary, line_no in walk_tb(traceback): 

539 filename = frame_summary.f_code.co_filename 

540 

541 last_instruction: Optional[Tuple[Tuple[int, int], Tuple[int, int]]] 

542 last_instruction = None 

543 if sys.version_info >= (3, 11): 

544 instruction_index = frame_summary.f_lasti // 2 

545 instruction_position = next( 

546 islice( 

547 frame_summary.f_code.co_positions(), 

548 instruction_index, 

549 instruction_index + 1, 

550 ) 

551 ) 

552 ( 

553 start_line, 

554 end_line, 

555 start_column, 

556 end_column, 

557 ) = instruction_position 

558 if ( 

559 start_line is not None 

560 and end_line is not None 

561 and start_column is not None 

562 and end_column is not None 

563 ): 

564 last_instruction = ( 

565 (start_line, start_column), 

566 (end_line, end_column), 

567 ) 

568 

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

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

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

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

573 continue 

574 

575 frame = Frame( 

576 filename=filename or "?", 

577 lineno=line_no, 

578 name=frame_summary.f_code.co_name, 

579 locals=( 

580 { 

581 key: pretty.traverse( 

582 value, 

583 max_length=locals_max_length, 

584 max_string=locals_max_string, 

585 max_depth=locals_max_depth, 

586 ) 

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

588 if not (inspect.isfunction(value) or inspect.isclass(value)) 

589 } 

590 if show_locals 

591 else None 

592 ), 

593 last_instruction=last_instruction, 

594 ) 

595 append(frame) 

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

597 del stack.frames[:] 

598 

599 if not grouped_exceptions: 

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

601 if cause is not None and cause is not exc_value: 

602 exc_type = cause.__class__ 

603 exc_value = cause 

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

605 # 'multiprocessing' module 

606 traceback = cause.__traceback__ 

607 is_cause = True 

608 continue 

609 

610 cause = exc_value.__context__ 

611 if cause is not None and not getattr( 

612 exc_value, "__suppress_context__", False 

613 ): 

614 exc_type = cause.__class__ 

615 exc_value = cause 

616 traceback = cause.__traceback__ 

617 is_cause = False 

618 continue 

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

620 break # pragma: no cover 

621 

622 trace = Trace(stacks=stacks) 

623 

624 return trace 

625 

626 def __rich_console__( 

627 self, console: Console, options: ConsoleOptions 

628 ) -> RenderResult: 

629 theme = self.theme 

630 background_style = theme.get_background_style() 

631 token_style = theme.get_style_for_token 

632 

633 traceback_theme = Theme( 

634 { 

635 "pretty": token_style(TextToken), 

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

651 }, 

652 inherit=False, 

653 ) 

654 

655 highlighter = ReprHighlighter() 

656 

657 @group() 

658 def render_stack(stack: Stack, last: bool) -> RenderResult: 

659 if stack.frames: 

660 stack_renderable: ConsoleRenderable = Panel( 

661 self._render_stack(stack), 

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

663 style=background_style, 

664 border_style="traceback.border", 

665 expand=True, 

666 padding=(0, 1), 

667 ) 

668 stack_renderable = Constrain(stack_renderable, self.width) 

669 with console.use_theme(traceback_theme): 

670 yield stack_renderable 

671 

672 if stack.syntax_error is not None: 

673 with console.use_theme(traceback_theme): 

674 yield Constrain( 

675 Panel( 

676 self._render_syntax_error(stack.syntax_error), 

677 style=background_style, 

678 border_style="traceback.border.syntax_error", 

679 expand=True, 

680 padding=(0, 1), 

681 width=self.width, 

682 ), 

683 self.width, 

684 ) 

685 yield Text.assemble( 

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

687 highlighter(stack.syntax_error.msg), 

688 ) 

689 elif stack.exc_value: 

690 yield Text.assemble( 

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

692 highlighter(stack.exc_value), 

693 ) 

694 else: 

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

696 

697 for note in stack.notes: 

698 yield Text.assemble(("[NOTE] ", "traceback.note"), highlighter(note)) 

699 

700 if stack.is_group: 

701 for group_no, group_exception in enumerate(stack.exceptions, 1): 

702 grouped_exceptions: List[Group] = [] 

703 for group_last, group_stack in loop_last(group_exception.stacks): 

704 grouped_exceptions.append(render_stack(group_stack, group_last)) 

705 yield "" 

706 yield Constrain( 

707 Panel( 

708 Group(*grouped_exceptions), 

709 title=f"Sub-exception #{group_no}", 

710 border_style="traceback.group.border", 

711 ), 

712 self.width, 

713 ) 

714 

715 if not last: 

716 if stack.is_cause: 

717 yield Text.from_markup( 

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

719 ) 

720 else: 

721 yield Text.from_markup( 

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

723 ) 

724 

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

726 yield render_stack(stack, last) 

727 

728 @group() 

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

730 highlighter = ReprHighlighter() 

731 path_highlighter = PathHighlighter() 

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

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

734 text = Text.assemble( 

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

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

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

738 style="pygments.text", 

739 ) 

740 yield path_highlighter(text) 

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

742 syntax_error_text.no_wrap = True 

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

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

745 syntax_error_text += Text.from_markup( 

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

747 style="pygments.text", 

748 ) 

749 yield syntax_error_text 

750 

751 @classmethod 

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

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

754 if not ext: 

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

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

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

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

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

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

761 return "python" 

762 try: 

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

764 except ClassNotFound: 

765 return "text" 

766 

767 @group() 

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

769 path_highlighter = PathHighlighter() 

770 theme = self.theme 

771 

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

773 if frame.locals: 

774 yield render_scope( 

775 frame.locals, 

776 title="locals", 

777 indent_guides=self.indent_guides, 

778 max_length=self.locals_max_length, 

779 max_string=self.locals_max_string, 

780 max_depth=self.locals_max_depth, 

781 overflow=self.locals_overflow, 

782 ) 

783 

784 exclude_frames: Optional[range] = None 

785 if self.max_frames != 0: 

786 exclude_frames = range( 

787 self.max_frames // 2, 

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

789 ) 

790 

791 excluded = False 

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

793 if exclude_frames and frame_index in exclude_frames: 

794 excluded = True 

795 continue 

796 

797 if excluded: 

798 assert exclude_frames is not None 

799 yield Text( 

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

801 justify="center", 

802 style="traceback.error", 

803 ) 

804 excluded = False 

805 

806 first = frame_index == 0 

807 frame_filename = frame.filename 

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

809 

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

811 text = Text.assemble( 

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

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

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

815 " in ", 

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

817 style="pygments.text", 

818 ) 

819 else: 

820 text = Text.assemble( 

821 "in ", 

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

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

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

825 style="pygments.text", 

826 ) 

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

828 yield "" 

829 yield text 

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

831 yield from render_locals(frame) 

832 continue 

833 if not suppressed: 

834 try: 

835 code_lines = linecache.getlines(frame.filename) 

836 code = "".join(code_lines) 

837 if not code: 

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

839 # if the traceback filename is generated dynamically 

840 continue 

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

842 syntax = Syntax( 

843 code, 

844 lexer_name, 

845 theme=theme, 

846 line_numbers=True, 

847 line_range=( 

848 frame.lineno - self.extra_lines, 

849 frame.lineno + self.extra_lines, 

850 ), 

851 highlight_lines={frame.lineno}, 

852 word_wrap=self.word_wrap, 

853 code_width=self.code_width, 

854 indent_guides=self.indent_guides, 

855 dedent=False, 

856 ) 

857 yield "" 

858 except Exception as error: 

859 yield Text.assemble( 

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

861 ) 

862 else: 

863 if frame.last_instruction is not None: 

864 start, end = frame.last_instruction 

865 

866 # Stylize a line at a time 

867 # So that indentation isn't underlined (which looks bad) 

868 for line1, column1, column2 in _iter_syntax_lines(start, end): 

869 try: 

870 if column1 == 0: 

871 line = code_lines[line1 - 1] 

872 column1 = len(line) - len(line.lstrip()) 

873 if column2 == -1: 

874 column2 = len(code_lines[line1 - 1]) 

875 except IndexError: 

876 # Being defensive here 

877 # If last_instruction reports a line out-of-bounds, we don't want to crash 

878 continue 

879 

880 syntax.stylize_range( 

881 style="traceback.error_range", 

882 start=(line1, column1), 

883 end=(line1, column2), 

884 ) 

885 yield ( 

886 Columns( 

887 [ 

888 syntax, 

889 *render_locals(frame), 

890 ], 

891 padding=1, 

892 ) 

893 if frame.locals 

894 else syntax 

895 ) 

896 

897 

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

899 install(show_locals=True) 

900 import sys 

901 

902 def bar( 

903 a: Any, 

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

905 one = 1 

906 print(one / a) 

907 

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

909 _rich_traceback_guard = True 

910 zed = { 

911 "characters": { 

912 "Paul Atreides", 

913 "Vladimir Harkonnen", 

914 "Thufir Hawat", 

915 "Duncan Idaho", 

916 }, 

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

918 } 

919 bar(a) 

920 

921 def error() -> None: 

922 foo(0) 

923 

924 error()