Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes15kdownloads
traceback.py925 linesDownload Raw Back to rich
1import inspect2import linecache3import os4import sys5from dataclasses import dataclass, field6from itertools import islice7from traceback import walk_tb8from types import ModuleType, TracebackType9from 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_filename24from pygments.token import Comment, Keyword, Name, Number, Operator, String25from pygments.token import Text as TextToken26from pygments.token import Token27from pygments.util import ClassNotFound28 29from . import pretty30from ._loop import loop_first_last, loop_last31from .columns import Columns32from .console import (33    Console,34    ConsoleOptions,35    ConsoleRenderable,36    OverflowMethod,37    Group,38    RenderResult,39    group,40)41from .constrain import Constrain42from .highlighter import RegexHighlighter, ReprHighlighter43from .panel import Panel44from .scope import render_scope45from .style import Style46from .syntax import Syntax, SyntaxPosition47from .text import Text48from .theme import Theme49 50WINDOWS = sys.platform == "win32"51 52LOCALS_MAX_LENGTH = 1053LOCALS_MAX_STRING = 8054 55 56def _iter_syntax_lines(57    start: SyntaxPosition, end: SyntaxPosition58) -> 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 = start70    line2, column2 = end71 72    if line1 == line2:73        yield line1, column1, column274    else:75        for first, last, line_no in loop_first_last(range(line1, line2 + 1)):76            if first:77                yield line_no, column1, -178            elif last:79                yield line_no, 0, column280            else:81                yield line_no, 0, -182 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 pick114            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 console132 133    locals_hide_sunder = (134        True135        if (traceback_console.is_jupyter and locals_hide_sunder is None)136        else locals_hide_sunder137    )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 cover167        tb_data = {}  # store information about showtraceback call168        default_showtraceback = ip.showtraceback  # keep reference of default traceback169 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_data173            tb_data = kwargs174            default_showtraceback(*args, **kwargs)175 176        def ipy_display_traceback(177            *args: Any, is_syntax: bool = False, **kwargs: Any178        ) -> None:179            """Internally called traceback from ip._showtraceback"""180            nonlocal tb_data181            exc_tuple = ip._get_exc_info()182 183            # do not display trace on syntax error184            tb: Optional[TracebackType] = None if is_syntax else exc_tuple[2]185 186            # determine correct tb_offset187            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 0191            # remove ipython internal frames from trace with tb_offset192            for _ in range(tb_offset):193                if tb is None:194                    break195                tb = tb.tb_next196 197            excepthook(exc_tuple[0], exc_tuple[1], tb)198            tb_data = {}  # clear data upon usage199 200        # replace _showtraceback instead of showtraceback to allow ipython features such as debugging to work201        # this is also what the ipython docs recommends to modify when subclassing InteractiveShell202        ip._showtraceback = ipy_display_traceback203        # add wrapper to capture tb_data204        ip.showtraceback = ipy_show_traceback205        ip.showsyntaxerror = lambda *args, **kwargs: ipy_display_traceback(206            *args, is_syntax=True, **kwargs207        )208 209    try:  # pragma: no cover210        # if within ipython, use customized traceback211        ip = get_ipython()  # type: ignore[name-defined]212        ipy_excepthook_closure(ip)213        return sys.excepthook214    except Exception:215        # otherwise use default system hook216        old_excepthook = sys.excepthook217        sys.excepthook = excepthook218        return old_excepthook219 220 221@dataclass222class Frame:223    filename: str224    lineno: int225    name: str226    line: str = ""227    locals: Optional[Dict[str, pretty.Node]] = None228    last_instruction: Optional[Tuple[Tuple[int, int], Tuple[int, int]]] = None229 230 231@dataclass232class _SyntaxError:233    offset: int234    filename: str235    line: str236    lineno: int237    msg: str238    notes: List[str] = field(default_factory=list)239 240 241@dataclass242class Stack:243    exc_type: str244    exc_value: str245    syntax_error: Optional[_SyntaxError] = None246    is_cause: bool = False247    frames: List[Frame] = field(default_factory=list)248    notes: List[str] = field(default_factory=list)249    is_group: bool = False250    exceptions: List["Trace"] = field(default_factory=list)251 252 253@dataclass254class 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 uses267            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_locals323            )324        self.trace = trace325        self.width = width326        self.code_width = code_width327        self.extra_lines = extra_lines328        self.theme = Syntax.get_theme(theme or "ansi_dark")329        self.word_wrap = word_wrap330        self.show_locals = show_locals331        self.indent_guides = indent_guides332        self.locals_max_length = locals_max_length333        self.locals_max_string = locals_max_string334        self.locals_max_depth = locals_max_depth335        self.locals_hide_dunder = locals_hide_dunder336        self.locals_hide_sunder = locals_hide_sunder337        self.locals_overflow = locals_overlow338 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 None344                ), f"{suppress_entity!r} must be a module with '__file__' attribute"345                path = os.path.dirname(suppress_entity.__file__)346            else:347                path = suppress_entity348            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 0351 352    @classmethod353    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 info376 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    @classmethod433    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 = False467 468        from rich import _IMPORT_CWD469 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_exceptions474        )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 = True494                    for exception in exc_value.exceptions:495                        if exception in grouped_exceptions:496                            continue497                        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.append523 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_locals530                    return531                for key, value in iter_locals:532                    if locals_hide_dunder and key.startswith("__"):533                        continue534                    if locals_hide_sunder and key.startswith("_"):535                        continue536                    yield key, value537 538            for frame_summary, line_no in walk_tb(traceback):539                filename = frame_summary.f_code.co_filename540 541                last_instruction: Optional[Tuple[Tuple[int, int], Tuple[int, int]]]542                last_instruction = None543                if sys.version_info >= (3, 11):544                    instruction_index = frame_summary.f_lasti // 2545                    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_position558                    if (559                        start_line is not None560                        and end_line is not None561                        and start_column is not None562                        and end_column is not None563                    ):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                    continue574 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_locals591                        else None592                    ),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 = cause604                    # __traceback__ can be None, e.g. for exceptions raised by the605                    # 'multiprocessing' module606                    traceback = cause.__traceback__607                    is_cause = True608                    continue609 610                cause = exc_value.__context__611                if cause is not None and not getattr(612                    exc_value, "__suppress_context__", False613                ):614                    exc_type = cause.__class__615                    exc_value = cause616                    traceback = cause.__traceback__617                    is_cause = False618                    continue619            # No cover, code is reached but coverage doesn't recognize it.620            break  # pragma: no cover621 622        trace = Trace(stacks=stacks)623 624        return trace625 626    def __rich_console__(627        self, console: Console, options: ConsoleOptions628    ) -> RenderResult:629        theme = self.theme630        background_style = theme.get_background_style()631        token_style = theme.get_style_for_token632 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_renderable671 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 = True743        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_text750 751    @classmethod752    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 hashbang756            # Note, this is an educated guess and not a guarantee757            # If it fails, the only downside is that the code is highlighted strangely758            new_line_index = code.index("\n")759            first_line = code[:new_line_index] if new_line_index != -1 else code760            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).name764        except ClassNotFound:765            return "text"766 767    @group()768    def _render_stack(self, stack: Stack) -> RenderResult:769        path_highlighter = PathHighlighter()770        theme = self.theme771 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] = None785        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 = False792        for frame_index, frame in enumerate(stack.frames):793            if exclude_frames and frame_index in exclude_frames:794                excluded = True795                continue796 797            if excluded:798                assert exclude_frames is not None799                yield Text(800                    f"\n... {len(exclude_frames)} frames hidden ...",801                    justify="center",802                    style="traceback.error",803                )804                excluded = False805 806            first = frame_index == 0807            frame_filename = frame.filename808            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 text830            if frame.filename.startswith("<"):831                yield from render_locals(frame)832                continue833            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, OR839                        # if the traceback filename is generated dynamically840                        continue841                    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_instruction865 866                        # Stylize a line at a time867                        # 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 here877                                # If last_instruction reports a line out-of-bounds, we don't want to crash878                                continue879 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.locals894                        else syntax895                    )896 897 898if __name__ == "__main__":  # pragma: no cover899    install(show_locals=True)900    import sys901 902    def bar(903        a: Any,904    ) -> None:  # 这是对亚洲语言支持的测试。面对模棱两可的想法,拒绝猜测的诱惑905        one = 1906        print(one / a)907 908    def foo(a: Any) -> None:909        _rich_traceback_guard = True910        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()925 
codekingpro/portable-devtools · Team Ai