aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorarcadia-devtools <arcadia-devtools@yandex-team.ru>2022-06-16 17:24:12 +0300
committerarcadia-devtools <arcadia-devtools@yandex-team.ru>2022-06-16 17:24:12 +0300
commitf6202b38cf98f2ad0032a6efed86f4ce1ccf86a4 (patch)
tree86b4cfeefeb200e9ac8c1f24f60de089374b70dd
parent108a3f2a5b7ace8b0d68d936451961c889a94aa3 (diff)
downloadydb-f6202b38cf98f2ad0032a6efed86f4ce1ccf86a4.tar.gz
intermediate changes
ref:e623d1e80066c7bc52d0c78d3c885faf82ccd263
-rw-r--r--contrib/python/stack-data/.dist-info/METADATA9
-rw-r--r--contrib/python/stack-data/README.md4
-rw-r--r--contrib/python/stack-data/stack_data/__init__.py1
-rw-r--r--contrib/python/stack-data/stack_data/formatting.py5
-rw-r--r--contrib/python/stack-data/stack_data/serializing.py200
-rw-r--r--contrib/python/stack-data/stack_data/version.py2
6 files changed, 213 insertions, 8 deletions
diff --git a/contrib/python/stack-data/.dist-info/METADATA b/contrib/python/stack-data/.dist-info/METADATA
index e77dd5f3c8..ec17c4a350 100644
--- a/contrib/python/stack-data/.dist-info/METADATA
+++ b/contrib/python/stack-data/.dist-info/METADATA
@@ -1,12 +1,11 @@
Metadata-Version: 2.1
Name: stack-data
-Version: 0.2.0
+Version: 0.3.0
Summary: Extract data from python stack frames and tracebacks for informative displays
Home-page: http://github.com/alexmojaki/stack_data
Author: Alex Hall
Author-email: alex.mojaki@gmail.com
License: MIT
-Platform: UNKNOWN
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
@@ -33,7 +32,9 @@ Requires-Dist: cython ; extra == 'tests'
[![Tests](https://github.com/alexmojaki/stack_data/actions/workflows/pytest.yml/badge.svg)](https://github.com/alexmojaki/stack_data/actions/workflows/pytest.yml) [![Coverage Status](https://coveralls.io/repos/github/alexmojaki/stack_data/badge.svg?branch=master)](https://coveralls.io/github/alexmojaki/stack_data?branch=master) [![Supports Python versions 3.5+](https://img.shields.io/pypi/pyversions/stack_data.svg)](https://pypi.python.org/pypi/stack_data)
-This is a library that extracts data from stack frames and tracebacks, particularly to display more useful tracebacks than the default.
+This is a library that extracts data from stack frames and tracebacks, particularly to display more useful tracebacks than the default. It powers the tracebacks in IPython and [futurecoder](https://futurecoder.io/):
+
+![futurecoder example](https://futurecoder.io/static/img/features/traceback.png)
You can install it from PyPI:
@@ -438,5 +439,3 @@ x = -993
In addition to handling repeated frames, we've passed a traceback object to `FrameInfo.stack_data` instead of a frame.
If you want, you can pass `collapse_repeated_frames=False` to `FrameInfo.stack_data` (not to `Options`) and it will just yield `FrameInfo` objects for the full stack.
-
-
diff --git a/contrib/python/stack-data/README.md b/contrib/python/stack-data/README.md
index a8bc532643..17bcba2990 100644
--- a/contrib/python/stack-data/README.md
+++ b/contrib/python/stack-data/README.md
@@ -2,7 +2,9 @@
[![Tests](https://github.com/alexmojaki/stack_data/actions/workflows/pytest.yml/badge.svg)](https://github.com/alexmojaki/stack_data/actions/workflows/pytest.yml) [![Coverage Status](https://coveralls.io/repos/github/alexmojaki/stack_data/badge.svg?branch=master)](https://coveralls.io/github/alexmojaki/stack_data?branch=master) [![Supports Python versions 3.5+](https://img.shields.io/pypi/pyversions/stack_data.svg)](https://pypi.python.org/pypi/stack_data)
-This is a library that extracts data from stack frames and tracebacks, particularly to display more useful tracebacks than the default.
+This is a library that extracts data from stack frames and tracebacks, particularly to display more useful tracebacks than the default. It powers the tracebacks in IPython and [futurecoder](https://futurecoder.io/):
+
+![futurecoder example](https://futurecoder.io/static/img/features/traceback.png)
You can install it from PyPI:
diff --git a/contrib/python/stack-data/stack_data/__init__.py b/contrib/python/stack-data/stack_data/__init__.py
index e9bc429e62..a75f8846ac 100644
--- a/contrib/python/stack-data/stack_data/__init__.py
+++ b/contrib/python/stack-data/stack_data/__init__.py
@@ -1,6 +1,7 @@
from .core import Source, FrameInfo, markers_from_ranges, Options, LINE_GAP, Line, Variable, RangeInLine, \
RepeatedFrames, MarkerInLine, style_with_executing_node
from .formatting import Formatter
+from .serializing import Serializer
try:
from .version import __version__
diff --git a/contrib/python/stack-data/stack_data/formatting.py b/contrib/python/stack-data/stack_data/formatting.py
index b37da99b62..7c5c0e5fc5 100644
--- a/contrib/python/stack-data/stack_data/formatting.py
+++ b/contrib/python/stack-data/stack_data/formatting.py
@@ -11,7 +11,7 @@ from stack_data.utils import assert_
class Formatter:
def __init__(
self, *,
- options=Options(),
+ options=None,
pygmented=False,
show_executing_node=True,
pygments_formatter_cls=None,
@@ -29,6 +29,9 @@ class Formatter:
chain=True,
collapse_repeated_frames=True
):
+ if options is None:
+ options = Options()
+
if pygmented and not options.pygments_formatter:
if show_executing_node:
pygments_style = style_with_executing_node(
diff --git a/contrib/python/stack-data/stack_data/serializing.py b/contrib/python/stack-data/stack_data/serializing.py
new file mode 100644
index 0000000000..fb67d2906a
--- /dev/null
+++ b/contrib/python/stack-data/stack_data/serializing.py
@@ -0,0 +1,200 @@
+import inspect
+import logging
+import sys
+import traceback
+from collections import Counter
+from html import escape as escape_html
+from types import FrameType, TracebackType
+from typing import Union, Iterable, List
+
+from stack_data import (
+ style_with_executing_node,
+ Options,
+ Line,
+ FrameInfo,
+ Variable,
+ RepeatedFrames,
+)
+
+log = logging.getLogger(__name__)
+
+
+class Serializer:
+ def __init__(
+ self,
+ *,
+ options=None,
+ pygmented=False,
+ show_executing_node=True,
+ pygments_formatter_cls=None,
+ pygments_formatter_kwargs=None,
+ pygments_style="monokai",
+ executing_node_modifier="bg:#005080",
+ use_code_qualname=True,
+ strip_leading_indent=True,
+ html=False,
+ chain=True,
+ collapse_repeated_frames=True,
+ show_variables=False,
+ ):
+ if options is None:
+ options = Options()
+
+ 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:
+ if html:
+ from pygments.formatters.html import (
+ HtmlFormatter as pygments_formatter_cls,
+ )
+ else:
+ 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.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
+ self.show_variables = show_variables
+
+ def format_exception(self, e=None) -> List[dict]:
+ if e is None:
+ e = sys.exc_info()[1]
+
+ result = []
+
+ if self.chain:
+ if e.__cause__ is not None:
+ result = self.format_exception(e.__cause__)
+ result[-1]["tail"] = traceback._cause_message.strip()
+ elif e.__context__ is not None and not e.__suppress_context__:
+ result = self.format_exception(e.__context__)
+ result[-1]["tail"] = traceback._context_message.strip()
+
+ result.append(self.format_traceback_part(e))
+ return result
+
+ def format_traceback_part(self, e: BaseException) -> dict:
+ return dict(
+ frames=self.format_stack(e.__traceback__ or sys.exc_info()[2]),
+ exception=dict(
+ type=type(e).__name__,
+ message=traceback._some_str(e),
+ ),
+ tail="",
+ )
+
+ def format_stack(self, frame_or_tb=None) -> List[dict]:
+ if frame_or_tb is None:
+ frame_or_tb = inspect.currentframe().f_back
+
+ return list(
+ 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[dict]:
+ for item in stack:
+ if isinstance(item, FrameInfo):
+ if not self.should_include_frame(item):
+ continue
+ yield dict(type="frame", **self.format_frame(item))
+ else:
+ yield dict(type="repeated_frames", **self.format_repeated_frames(item))
+
+ def format_repeated_frames(self, repeated_frames: RepeatedFrames) -> dict:
+ counts = sorted(
+ Counter(repeated_frames.frame_keys).items(),
+ key=lambda item: (-item[1], item[0][0].co_name),
+ )
+ return dict(
+ frames=[
+ dict(
+ name=code.co_name,
+ lineno=lineno,
+ count=count,
+ )
+ for (code, lineno), count in counts
+ ]
+ )
+
+ def format_frame(self, frame: Union[FrameInfo, FrameType, TracebackType]) -> dict:
+ if not isinstance(frame, FrameInfo):
+ frame = FrameInfo(frame, self.options)
+
+ result = dict(
+ name=(
+ frame.executing.code_qualname()
+ if self.use_code_qualname
+ else frame.code.co_name
+ ),
+ filename=frame.filename,
+ lineno=frame.lineno,
+ lines=list(self.format_lines(frame.lines)),
+ )
+ if self.show_variables:
+ result["variables"] = list(self.format_variables(frame))
+ return result
+
+ def format_lines(self, lines):
+ for line in lines:
+ if isinstance(line, Line):
+ yield dict(type="line", **self.format_line(line))
+ else:
+ yield dict(type="line_gap")
+
+ def format_line(self, line: Line) -> dict:
+ return dict(
+ is_current=line.is_current,
+ lineno=line.lineno,
+ text=line.render(
+ pygmented=self.pygmented,
+ escape_html=self.html,
+ strip_leading_indent=self.strip_leading_indent,
+ ),
+ )
+
+ def format_variables(self, frame_info: FrameInfo) -> Iterable[dict]:
+ try:
+ for var in sorted(frame_info.variables, key=lambda v: v.name):
+ yield self.format_variable(var)
+ except Exception: # pragma: no cover
+ log.exception("Error in getting frame variables")
+
+ def format_variable(self, var: Variable) -> dict:
+ return dict(
+ name=self.format_variable_part(var.name),
+ value=self.format_variable_part(self.format_variable_value(var.value)),
+ )
+
+ def format_variable_part(self, text):
+ if self.html:
+ return escape_html(text)
+ else:
+ return text
+
+ def format_variable_value(self, value) -> str:
+ return repr(value)
+
+ def should_include_frame(self, frame_info: FrameInfo) -> bool:
+ return True # pragma: no cover
diff --git a/contrib/python/stack-data/stack_data/version.py b/contrib/python/stack-data/stack_data/version.py
index 7fd229a32b..0404d81037 100644
--- a/contrib/python/stack-data/stack_data/version.py
+++ b/contrib/python/stack-data/stack_data/version.py
@@ -1 +1 @@
-__version__ = '0.2.0'
+__version__ = '0.3.0'