Воркед
This commit is contained in:
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()
|
||||
Reference in new issue
Block a user