diff options
author | robot-contrib <robot-contrib@yandex-team.ru> | 2022-05-18 00:43:36 +0300 |
---|---|---|
committer | robot-contrib <robot-contrib@yandex-team.ru> | 2022-05-18 00:43:36 +0300 |
commit | 9e5f436a8b2a27bcc7802e443ea3ef3e41a82a75 (patch) | |
tree | 78b522cab9f76336e62064d4d8ff7c897659b20e /contrib/python/stack-data/stack_data/formatting.py | |
parent | 8113a823ffca6451bb5ff8f0334560885a939a24 (diff) | |
download | ydb-9e5f436a8b2a27bcc7802e443ea3ef3e41a82a75.tar.gz |
Update contrib/python/ipython/py3 to 8.3.0
ref:e84342d4d30476f9148137f37fd0c6405fd36f55
Diffstat (limited to 'contrib/python/stack-data/stack_data/formatting.py')
-rw-r--r-- | contrib/python/stack-data/stack_data/formatting.py | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/contrib/python/stack-data/stack_data/formatting.py b/contrib/python/stack-data/stack_data/formatting.py new file mode 100644 index 0000000000..b37da99b62 --- /dev/null +++ b/contrib/python/stack-data/stack_data/formatting.py @@ -0,0 +1,206 @@ +import inspect +import sys +import traceback +from types import FrameType, TracebackType +from typing import Union, Iterable + +from stack_data import style_with_executing_node, Options, Line, FrameInfo, LINE_GAP, Variable, RepeatedFrames +from stack_data.utils import assert_ + + +class Formatter: + def __init__( + self, *, + options=Options(), + pygmented=False, + show_executing_node=True, + pygments_formatter_cls=None, + pygments_formatter_kwargs=None, + pygments_style="monokai", + executing_node_modifier="bg:#005080", + executing_node_underline="^", + current_line_indicator="-->", + line_gap_string="(...)", + show_variables=False, + use_code_qualname=True, + show_linenos=True, + strip_leading_indent=True, + html=False, + chain=True, + collapse_repeated_frames=True + ): + if pygmented and not options.pygments_formatter: + if show_executing_node: + pygments_style = style_with_executing_node( + pygments_style, executing_node_modifier + ) + + if pygments_formatter_cls is None: + from pygments.formatters.terminal256 import Terminal256Formatter \ + as pygments_formatter_cls + + options.pygments_formatter = pygments_formatter_cls( + style=pygments_style, + **pygments_formatter_kwargs or {}, + ) + + self.pygmented = pygmented + self.show_executing_node = show_executing_node + assert_( + len(executing_node_underline) == 1, + ValueError("executing_node_underline must be a single character"), + ) + self.executing_node_underline = executing_node_underline + self.current_line_indicator = current_line_indicator or "" + self.line_gap_string = line_gap_string + self.show_variables = show_variables + self.show_linenos = show_linenos + self.use_code_qualname = use_code_qualname + self.strip_leading_indent = strip_leading_indent + self.html = html + self.chain = chain + self.options = options + self.collapse_repeated_frames = collapse_repeated_frames + + def set_hook(self): + def excepthook(_etype, evalue, _tb): + self.print_exception(evalue) + + sys.excepthook = excepthook + + def print_exception(self, e=None, *, file=None): + self.print_lines(self.format_exception(e), file=file) + + def print_stack(self, frame_or_tb=None, *, file=None): + if frame_or_tb is None: + frame_or_tb = inspect.currentframe().f_back + + self.print_lines(self.format_stack(frame_or_tb), file=file) + + def print_lines(self, lines, *, file=None): + if file is None: + file = sys.stderr + for line in lines: + print(line, file=file, end="") + + def format_exception(self, e=None) -> Iterable[str]: + if e is None: + e = sys.exc_info()[1] + + if self.chain: + if e.__cause__ is not None: + yield from self.format_exception(e.__cause__) + yield traceback._cause_message + elif (e.__context__ is not None + and not e.__suppress_context__): + yield from self.format_exception(e.__context__) + yield traceback._context_message + + yield 'Traceback (most recent call last):\n' + yield from self.format_stack(e.__traceback__) + yield from traceback.format_exception_only(type(e), e) + + def format_stack(self, frame_or_tb=None) -> Iterable[str]: + if frame_or_tb is None: + frame_or_tb = inspect.currentframe().f_back + + yield from self.format_stack_data( + FrameInfo.stack_data( + frame_or_tb, + self.options, + collapse_repeated_frames=self.collapse_repeated_frames, + ) + ) + + def format_stack_data( + self, stack: Iterable[Union[FrameInfo, RepeatedFrames]] + ) -> Iterable[str]: + for item in stack: + if isinstance(item, FrameInfo): + yield from self.format_frame(item) + else: + yield self.format_repeated_frames(item) + + def format_repeated_frames(self, repeated_frames: RepeatedFrames) -> str: + return ' [... skipping similar frames: {}]\n'.format( + repeated_frames.description + ) + + def format_frame(self, frame: Union[FrameInfo, FrameType, TracebackType]) -> Iterable[str]: + if not isinstance(frame, FrameInfo): + frame = FrameInfo(frame, self.options) + + yield self.format_frame_header(frame) + + for line in frame.lines: + if isinstance(line, Line): + yield self.format_line(line) + else: + assert_(line is LINE_GAP) + yield self.line_gap_string + "\n" + + if self.show_variables: + try: + yield from self.format_variables(frame) + except Exception: + pass + + def format_frame_header(self, frame_info: FrameInfo) -> str: + return ' File "{frame_info.filename}", line {frame_info.lineno}, in {name}\n'.format( + frame_info=frame_info, + name=( + frame_info.executing.code_qualname() + if self.use_code_qualname else + frame_info.code.co_name + ), + ) + + def format_line(self, line: Line) -> str: + result = "" + if self.current_line_indicator: + if line.is_current: + result = self.current_line_indicator + else: + result = " " * len(self.current_line_indicator) + result += " " + + if self.show_linenos: + result += "{:4} | ".format(line.lineno) + + result = result or " " + + prefix = result + + result += line.render( + pygmented=self.pygmented, + escape_html=self.html, + strip_leading_indent=self.strip_leading_indent, + ) + "\n" + + if self.show_executing_node and not self.pygmented: + for line_range in line.executing_node_ranges: + start = line_range.start - line.leading_indent + end = line_range.end - line.leading_indent + result += ( + " " * (start + len(prefix)) + + self.executing_node_underline * (end - start) + + "\n" + ) + + return result + + def format_variables(self, frame_info: FrameInfo) -> Iterable[str]: + for var in sorted(frame_info.variables, key=lambda v: v.name): + try: + yield self.format_variable(var) + "\n" + except Exception: + pass + + def format_variable(self, var: Variable) -> str: + return "{} = {}".format( + var.name, + self.format_variable_value(var.value), + ) + + def format_variable_value(self, value) -> str: + return repr(value) |