Воркед

This commit is contained in:
kromskii2 committed 2025-03-15 09:36:28 +07:00
1 parent ac32c55ab9
commit ee94d8e529
1138 files changed
+55771 -77901

No files matched your search

@@ -1,12 +1,23 @@
from __future__ import absolute_import
import inspect
import linecache
import os
import platform
import sys
from dataclasses import dataclass, field
from itertools import islice
from traceback import walk_tb
from types import ModuleType, TracebackType
from typing import Any, Callable, Dict, Iterable, List, Optional, Sequence, Type, Union
from typing import (
Any,
Callable,
Dict,
Iterable,
List,
Optional,
Sequence,
Tuple,
Type,
Union,
)
from pip._vendor.pygments.lexers import guess_lexer_for_filename
from pip._vendor.pygments.token import Comment, Keyword, Name, Number, Operator, String
@@ -27,7 +38,7 @@ from .syntax import Syntax
from .text import Text
from .theme import Theme
WINDOWS = platform.system() == "Windows"
WINDOWS = sys.platform == "win32"
LOCALS_MAX_LENGTH = 10
LOCALS_MAX_STRING = 80
@@ -37,10 +48,15 @@ def install(
*,
console: Optional[Console] = None,
width: Optional[int] = 100,
code_width: Optional[int] = 88,
extra_lines: int = 3,
theme: Optional[str] = None,
word_wrap: bool = False,
show_locals: bool = False,
locals_max_length: int = LOCALS_MAX_LENGTH,
locals_max_string: int = LOCALS_MAX_STRING,
locals_hide_dunder: bool = True,
locals_hide_sunder: Optional[bool] = None,
indent_guides: bool = True,
suppress: Iterable[Union[str, ModuleType]] = (),
max_frames: int = 100,
@@ -53,11 +69,17 @@ def install(
Args:
console (Optional[Console], optional): Console to write exception to. Default uses internal Console instance.
width (Optional[int], optional): Width (in characters) of traceback. Defaults to 100.
code_width (Optional[int], optional): Code width (in characters) of traceback. Defaults to 88.
extra_lines (int, optional): Extra lines of code. Defaults to 3.
theme (Optional[str], optional): Pygments theme to use in traceback. Defaults to ``None`` which will pick
a theme appropriate for the platform.
word_wrap (bool, optional): Enable word wrapping of long lines. Defaults to False.
show_locals (bool, optional): Enable display of local variables. Defaults to False.
locals_max_length (int, optional): Maximum length of containers before abbreviating, or None for no abbreviation.
Defaults to 10.
locals_max_string (int, optional): Maximum length of string before truncating, or None to disable. Defaults to 80.
locals_hide_dunder (bool, optional): Hide locals prefixed with double underscore. Defaults to True.
locals_hide_sunder (bool, optional): Hide locals prefixed with single underscore. Defaults to False.
indent_guides (bool, optional): Enable indent guides in code and locals. Defaults to True.
suppress (Sequence[Union[str, ModuleType]]): Optional sequence of modules or paths to exclude from traceback.
@@ -65,7 +87,13 @@ def install(
Callable: The previous exception handler that was replaced.
"""
traceback_console = Console(file=sys.stderr) if console is None else console
traceback_console = Console(stderr=True) if console is None else console
locals_hide_sunder = (
True
if (traceback_console.is_jupyter and locals_hide_sunder is None)
else locals_hide_sunder
)
def excepthook(
type_: Type[BaseException],
@@ -78,10 +106,15 @@ def install(
value,
traceback,
width=width,
code_width=code_width,
extra_lines=extra_lines,
theme=theme,
word_wrap=word_wrap,
show_locals=show_locals,
locals_max_length=locals_max_length,
locals_max_string=locals_max_string,
locals_hide_dunder=locals_hide_dunder,
locals_hide_sunder=bool(locals_hide_sunder),
indent_guides=indent_guides,
suppress=suppress,
max_frames=max_frames,
@@ -148,6 +181,7 @@ class Frame:
name: str
line: str = ""
locals: Optional[Dict[str, pretty.Node]] = None
last_instruction: Optional[Tuple[Tuple[int, int], Tuple[int, int]]] = None
@dataclass
@@ -184,6 +218,7 @@ class Traceback:
trace (Trace, optional): A `Trace` object produced from `extract`. Defaults to None, which uses
the last exception.
width (Optional[int], optional): Number of characters used to traceback. Defaults to 100.
code_width (Optional[int], optional): Number of code characters used to traceback. Defaults to 88.
extra_lines (int, optional): Additional lines of code to render. Defaults to 3.
theme (str, optional): Override pygments theme used in traceback.
word_wrap (bool, optional): Enable word wrapping of long lines. Defaults to False.
@@ -192,6 +227,8 @@ class Traceback:
locals_max_length (int, optional): Maximum length of containers before abbreviating, or None for no abbreviation.
Defaults to 10.
locals_max_string (int, optional): Maximum length of string before truncating, or None to disable. Defaults to 80.
locals_hide_dunder (bool, optional): Hide locals prefixed with double underscore. Defaults to True.
locals_hide_sunder (bool, optional): Hide locals prefixed with single underscore. Defaults to False.
suppress (Sequence[Union[str, ModuleType]]): Optional sequence of modules or paths to exclude from traceback.
max_frames (int): Maximum number of frames to show in a traceback, 0 for no maximum. Defaults to 100.
@@ -208,14 +245,18 @@ class Traceback:
def __init__(
self,
trace: Optional[Trace] = None,
*,
width: Optional[int] = 100,
code_width: Optional[int] = 88,
extra_lines: int = 3,
theme: Optional[str] = None,
word_wrap: bool = False,
show_locals: bool = False,
indent_guides: bool = True,
locals_max_length: int = LOCALS_MAX_LENGTH,
locals_max_string: int = LOCALS_MAX_STRING,
locals_hide_dunder: bool = True,
locals_hide_sunder: bool = False,
indent_guides: bool = True,
suppress: Iterable[Union[str, ModuleType]] = (),
max_frames: int = 100,
):
@@ -230,6 +271,7 @@ class Traceback:
)
self.trace = trace
self.width = width
self.code_width = code_width
self.extra_lines = extra_lines
self.theme = Syntax.get_theme(theme or "ansi_dark")
self.word_wrap = word_wrap
@@ -237,6 +279,8 @@ class Traceback:
self.indent_guides = indent_guides
self.locals_max_length = locals_max_length
self.locals_max_string = locals_max_string
self.locals_hide_dunder = locals_hide_dunder
self.locals_hide_sunder = locals_hide_sunder
self.suppress: Sequence[str] = []
for suppress_entity in suppress:
@@ -257,14 +301,18 @@ class Traceback:
exc_type: Type[Any],
exc_value: BaseException,
traceback: Optional[TracebackType],
*,
width: Optional[int] = 100,
code_width: Optional[int] = 88,
extra_lines: int = 3,
theme: Optional[str] = None,
word_wrap: bool = False,
show_locals: bool = False,
indent_guides: bool = True,
locals_max_length: int = LOCALS_MAX_LENGTH,
locals_max_string: int = LOCALS_MAX_STRING,
locals_hide_dunder: bool = True,
locals_hide_sunder: bool = False,
indent_guides: bool = True,
suppress: Iterable[Union[str, ModuleType]] = (),
max_frames: int = 100,
) -> "Traceback":
@@ -275,6 +323,7 @@ class Traceback:
exc_value (BaseException): Exception value.
traceback (TracebackType): Python Traceback object.
width (Optional[int], optional): Number of characters used to traceback. Defaults to 100.
code_width (Optional[int], optional): Number of code characters used to traceback. Defaults to 88.
extra_lines (int, optional): Additional lines of code to render. Defaults to 3.
theme (str, optional): Override pygments theme used in traceback.
word_wrap (bool, optional): Enable word wrapping of long lines. Defaults to False.
@@ -283,6 +332,8 @@ class Traceback:
locals_max_length (int, optional): Maximum length of containers before abbreviating, or None for no abbreviation.
Defaults to 10.
locals_max_string (int, optional): Maximum length of string before truncating, or None to disable. Defaults to 80.
locals_hide_dunder (bool, optional): Hide locals prefixed with double underscore. Defaults to True.
locals_hide_sunder (bool, optional): Hide locals prefixed with single underscore. Defaults to False.
suppress (Iterable[Union[str, ModuleType]]): Optional sequence of modules or paths to exclude from traceback.
max_frames (int): Maximum number of frames to show in a traceback, 0 for no maximum. Defaults to 100.
@@ -290,11 +341,20 @@ class Traceback:
Traceback: A Traceback instance that may be printed.
"""
rich_traceback = cls.extract(
exc_type, exc_value, traceback, show_locals=show_locals
exc_type,
exc_value,
traceback,
show_locals=show_locals,
locals_max_length=locals_max_length,
locals_max_string=locals_max_string,
locals_hide_dunder=locals_hide_dunder,
locals_hide_sunder=locals_hide_sunder,
)
return cls(
rich_traceback,
width=width,
code_width=code_width,
extra_lines=extra_lines,
theme=theme,
word_wrap=word_wrap,
@@ -302,6 +362,8 @@ class Traceback:
indent_guides=indent_guides,
locals_max_length=locals_max_length,
locals_max_string=locals_max_string,
locals_hide_dunder=locals_hide_dunder,
locals_hide_sunder=locals_hide_sunder,
suppress=suppress,
max_frames=max_frames,
)
@@ -312,9 +374,12 @@ class Traceback:
exc_type: Type[BaseException],
exc_value: BaseException,
traceback: Optional[TracebackType],
*,
show_locals: bool = False,
locals_max_length: int = LOCALS_MAX_LENGTH,
locals_max_string: int = LOCALS_MAX_STRING,
locals_hide_dunder: bool = True,
locals_hide_sunder: bool = False,
) -> Trace:
"""Extract traceback information.
@@ -326,6 +391,8 @@ class Traceback:
locals_max_length (int, optional): Maximum length of containers before abbreviating, or None for no abbreviation.
Defaults to 10.
locals_max_string (int, optional): Maximum length of string before truncating, or None to disable. Defaults to 80.
locals_hide_dunder (bool, optional): Hide locals prefixed with double underscore. Defaults to True.
locals_hide_sunder (bool, optional): Hide locals prefixed with single underscore. Defaults to False.
Returns:
Trace: A Trace instance which you can use to construct a `Traceback`.
@@ -337,7 +404,7 @@ class Traceback:
from pip._vendor.rich import _IMPORT_CWD
def safe_str(_object: Any) -> str:
"""Don't allow exceptions from __str__ to propegate."""
"""Don't allow exceptions from __str__ to propagate."""
try:
return str(_object)
except Exception:
@@ -362,46 +429,92 @@ class Traceback:
stacks.append(stack)
append = stack.frames.append
def get_locals(
iter_locals: Iterable[Tuple[str, object]]
) -> Iterable[Tuple[str, object]]:
"""Extract locals from an iterator of key pairs."""
if not (locals_hide_dunder or locals_hide_sunder):
yield from iter_locals
return
for key, value in iter_locals:
if locals_hide_dunder and key.startswith("__"):
continue
if locals_hide_sunder and key.startswith("_"):
continue
yield key, value
for frame_summary, line_no in walk_tb(traceback):
filename = frame_summary.f_code.co_filename
last_instruction: Optional[Tuple[Tuple[int, int], Tuple[int, int]]]
last_instruction = None
if sys.version_info >= (3, 11):
instruction_index = frame_summary.f_lasti // 2
instruction_position = next(
islice(
frame_summary.f_code.co_positions(),
instruction_index,
instruction_index + 1,
)
)
(
start_line,
end_line,
start_column,
end_column,
) = instruction_position
if (
start_line is not None
and end_line is not None
and start_column is not None
and end_column is not None
):
last_instruction = (
(start_line, start_column),
(end_line, end_column),
)
if filename and not filename.startswith("<"):
if not os.path.isabs(filename):
filename = os.path.join(_IMPORT_CWD, filename)
if frame_summary.f_locals.get("_rich_traceback_omit", False):
continue
frame = Frame(
filename=filename or "?",
lineno=line_no,
name=frame_summary.f_code.co_name,
locals={
key: pretty.traverse(
value,
max_length=locals_max_length,
max_string=locals_max_string,
)
for key, value in frame_summary.f_locals.items()
}
if show_locals
else None,
locals=(
{
key: pretty.traverse(
value,
max_length=locals_max_length,
max_string=locals_max_string,
)
for key, value in get_locals(frame_summary.f_locals.items())
if not (inspect.isfunction(value) or inspect.isclass(value))
}
if show_locals
else None
),
last_instruction=last_instruction,
)
append(frame)
if frame_summary.f_locals.get("_rich_traceback_guard", False):
del stack.frames[:]
cause = getattr(exc_value, "__cause__", None)
if cause and cause.__traceback__:
if cause:
exc_type = cause.__class__
exc_value = cause
# __traceback__ can be None, e.g. for exceptions raised by the
# 'multiprocessing' module
traceback = cause.__traceback__
is_cause = True
continue
cause = exc_value.__context__
if (
cause
and cause.__traceback__
and not getattr(exc_value, "__suppress_context__", False)
):
if cause and not getattr(exc_value, "__suppress_context__", False):
exc_type = cause.__class__
exc_value = cause
traceback = cause.__traceback__
@@ -496,13 +609,14 @@ class Traceback:
highlighter = ReprHighlighter()
path_highlighter = PathHighlighter()
if syntax_error.filename != "<stdin>":
text = Text.assemble(
(f" {syntax_error.filename}", "pygments.string"),
(":", "pygments.text"),
(str(syntax_error.lineno), "pygments.number"),
style="pygments.text",
)
yield path_highlighter(text)
if os.path.exists(syntax_error.filename):
text = Text.assemble(
(f" {syntax_error.filename}", "pygments.string"),
(":", "pygments.text"),
(str(syntax_error.lineno), "pygments.number"),
style="pygments.text",
)
yield path_highlighter(text)
syntax_error_text = highlighter(syntax_error.line.rstrip())
syntax_error_text.no_wrap = True
offset = min(syntax_error.offset - 1, len(syntax_error_text))
@@ -533,7 +647,6 @@ class Traceback:
def _render_stack(self, stack: Stack) -> RenderResult:
path_highlighter = PathHighlighter()
theme = self.theme
code_cache: Dict[str, str] = {}
def read_code(filename: str) -> str:
"""Read files, and cache results on filename.
@@ -544,14 +657,7 @@ class Traceback:
Returns:
str: Contents of file
"""
code = code_cache.get(filename)
if code is None:
with open(
filename, "rt", encoding="utf-8", errors="replace"
) as code_file:
code = code_file.read()
code_cache[filename] = code
return code
return "".join(linecache.getlines(filename))
def render_locals(frame: Frame) -> Iterable[ConsoleRenderable]:
if frame.locals:
@@ -572,7 +678,6 @@ class Traceback:
excluded = False
for frame_index, frame in enumerate(stack.frames):
if exclude_frames and frame_index in exclude_frames:
excluded = True
continue
@@ -590,14 +695,23 @@ class Traceback:
frame_filename = frame.filename
suppressed = any(frame_filename.startswith(path) for path in self.suppress)
text = Text.assemble(
path_highlighter(Text(frame.filename, style="pygments.string")),
(":", "pygments.text"),
(str(frame.lineno), "pygments.number"),
" in ",
(frame.name, "pygments.function"),
style="pygments.text",
)
if os.path.exists(frame.filename):
text = Text.assemble(
path_highlighter(Text(frame.filename, style="pygments.string")),
(":", "pygments.text"),
(str(frame.lineno), "pygments.number"),
" in ",
(frame.name, "pygments.function"),
style="pygments.text",
)
else:
text = Text.assemble(
"in ",
(frame.name, "pygments.function"),
(":", "pygments.text"),
(str(frame.lineno), "pygments.number"),
style="pygments.text",
)
if not frame.filename.startswith("<") and not first:
yield ""
yield text
@@ -607,6 +721,10 @@ class Traceback:
if not suppressed:
try:
code = read_code(frame.filename)
if not code:
# code may be an empty string if the file doesn't exist, OR
# if the traceback filename is generated dynamically
continue
lexer_name = self._guess_lexer(frame.filename, code)
syntax = Syntax(
code,
@@ -619,7 +737,7 @@ class Traceback:
),
highlight_lines={frame.lineno},
word_wrap=self.word_wrap,
code_width=88,
code_width=self.code_width,
indent_guides=self.indent_guides,
dedent=False,
)
@@ -629,6 +747,14 @@ class Traceback:
(f"\n{error}", "traceback.error"),
)
else:
if frame.last_instruction is not None:
start, end = frame.last_instruction
syntax.stylize_range(
style="traceback.error_range",
start=start,
end=end,
style_before=True,
)
yield (
Columns(
[
@@ -643,13 +769,12 @@ class Traceback:
if __name__ == "__main__": # pragma: no cover
from .console import Console
console = Console()
install(show_locals=True)
import sys
def bar(a: Any) -> None: # 这是对亚洲语言支持的测试。面对模棱两可的想法,拒绝猜测的诱惑
def bar(
a: Any,
) -> None: # 这是对亚洲语言支持的测试。面对模棱两可的想法,拒绝猜测的诱惑
one = 1
print(one / a)
@@ -667,13 +792,6 @@ if __name__ == "__main__": # pragma: no cover
bar(a)
def error() -> None:
try:
try:
foo(0)
except:
slfkjsldkfj # type: ignore[name-defined]
except:
console.print_exception(show_locals=True)
foo(0)
error()