Skip to content

Commit

Permalink
Merge branch 'master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
alexmojaki committed Jan 22, 2022
2 parents 8b7af13 + 637e10e commit 4265964
Show file tree
Hide file tree
Showing 16 changed files with 207 additions and 66 deletions.
36 changes: 36 additions & 0 deletions .github/workflows/pytest.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: Tests
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.6, 3.7, 3.8, 3.9, 3.10-dev]
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: run tests
env:
STACK_DATA_SLOW_TESTS: 1
run: |
pip install -U pip
pip install --upgrade coveralls setuptools setuptools_scm pep517
pip install .[tests]
coverage run --source stack_data -m pytest
coverage report -m
- name: Coveralls Python
uses: AndreMiras/coveralls-python-action@v20201129
with:
parallel: true
flag-name: test-${{ matrix.python-version }}
coveralls_finish:
needs: build
runs-on: ubuntu-latest
steps:
- name: Coveralls Finished
uses: AndreMiras/coveralls-python-action@v20201129
with:
parallel-finished: true
32 changes: 0 additions & 32 deletions .travis.yml

This file was deleted.

1 change: 1 addition & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
include LICENSE.txt
include README.md
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# stack_data

[![Build Status](https://travis-ci.org/alexmojaki/stack_data.svg?branch=master)](https://travis-ci.org/alexmojaki/stack_data) [![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)
[![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.

Expand Down
4 changes: 2 additions & 2 deletions make_release.sh
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,5 @@ export TAG="v${1}"
git tag "${TAG}"
git push origin master "${TAG}"
rm -rf ./build ./dist
python3 -m pep517.build -b .
twine upload ./dist/*.whl
python -m build --sdist --wheel .
twine upload ./dist/*.whl dist/*.tar.gz
10 changes: 7 additions & 3 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,23 @@ classifiers =
Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
Programming Language :: Python :: 3.10
License :: OSI Approved :: MIT License
Operating System :: OS Independent
Topic :: Software Development :: Debuggers

[options]
packages = stack_data
install_requires = executing; asttokens; pure_eval
setup_requires = setuptools>=44; wheel; setuptools_scm[toml]>=3.4.3
setup_requires = setuptools>=44; setuptools_scm[toml]>=3.4.3
include_package_data = True
tests_require = pytest; typeguard; pygments
tests_require = pytest; typeguard; pygments; littleutils

[options.extras_require]
tests = pytest; typeguard; pygments; pep517; littleutils
tests = pytest; typeguard; pygments; littleutils

[coverage:run]
relative_files = True

[options.package_data]
stack_data = py.typed
46 changes: 34 additions & 12 deletions stack_data/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@ class Source(executing.Source):

def __init__(self, *args, **kwargs):
super(Source, self).__init__(*args, **kwargs)
self.asttokens()
if self.tree:
self.asttokens()

@cached_property
def pieces(self) -> List[range]:
Expand Down Expand Up @@ -139,8 +140,10 @@ def _raw_split_into_pieces(
for rang, group in sorted(group_by_key_func(body, line_range).items()):
sub_stmt = group[0]
for inner_start, inner_end in self._raw_split_into_pieces(sub_stmt, *rang):
yield start, inner_start
yield inner_start, inner_end
if start < inner_start:
yield start, inner_start
if inner_start < inner_end:
yield inner_start, inner_end
start = inner_end

yield start, end
Expand Down Expand Up @@ -306,12 +309,21 @@ def range_from_node(self, node: ast.AST, data: Any) -> Optional[RangeInLine]:
if not (start <= self.lineno <= end):
return None
if start == self.lineno:
range_start = node.first_token.start[1]
try:
range_start = node.first_token.start[1]
except AttributeError:
range_start = node.col_offset
else:
range_start = 0

if end == self.lineno:
range_end = node.last_token.end[1]
try:
range_end = node.last_token.end[1]
except AttributeError:
try:
range_end = node.end_col_offset
except AttributeError:
return None
else:
range_end = len(self.text)

Expand Down Expand Up @@ -631,7 +643,7 @@ def included_pieces(self) -> List[range]:
if (
self.options.include_signature
and not self.code.co_name.startswith('<')
and isinstance(self.scope, ast.FunctionDef)
and isinstance(self.scope, (ast.FunctionDef, ast.AsyncFunctionDef))
and pieces_start > 0
):
pieces.insert(0, scope_pieces[0])
Expand Down Expand Up @@ -709,7 +721,7 @@ def scope(self) -> Optional[ast.AST]:
# a function definition, e.g. if we're calling a decorator
# In that case we still want the surrounding scope, not that function
stmt = stmt.parent
if isinstance(stmt, (ast.FunctionDef, ast.ClassDef, ast.Module)):
if isinstance(stmt, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef, ast.Module)):
return stmt

@cached_property
Expand Down Expand Up @@ -753,15 +765,14 @@ def variables(self) -> List[Variable]:
return []

evaluator = Evaluator.from_frame(self.frame)
get_text = self.source.asttokens().get_text
scope = self.scope
node_values = [
pair
for pair in evaluator.find_expressions(scope)
if is_expression_interesting(*pair)
] # type: List[Tuple[ast.AST, Any]]

if isinstance(scope, ast.FunctionDef):
if isinstance(scope, (ast.FunctionDef, ast.AsyncFunctionDef)):
for node in ast.walk(scope.args):
if not isinstance(node, ast.arg):
continue
Expand All @@ -773,12 +784,23 @@ def variables(self) -> List[Variable]:
else:
node_values.append((node, value))

# TODO use compile(...).co_code instead of ast.dump?
# Group equivalent nodes together
def get_text(n):
if isinstance(n, ast.arg):
return n.arg
else:
return self.source.asttokens().get_text(n)

def normalise_node(n):
try:
# Add parens to avoid syntax errors for multiline expressions
return ast.parse('(' + get_text(n) + ')')
except Exception:
return n

grouped = group_by_key_func(
node_values,
# Add parens to avoid syntax errors for multiline expressions
lambda nv: ast.dump(ast.parse('(' + get_text(nv[0]) + ')')),
lambda nv: ast.dump(normalise_node(nv[0])),
)

result = []
Expand Down
10 changes: 8 additions & 2 deletions stack_data/formatting.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,10 @@ def format_frame(self, frame: Union[FrameInfo, FrameType, TracebackType]) -> Ite
yield self.line_gap_string + "\n"

if self.show_variables:
yield from self.format_variables(frame)
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(
Expand Down Expand Up @@ -188,7 +191,10 @@ def format_line(self, line: Line) -> str:

def format_variables(self, frame_info: FrameInfo) -> Iterable[str]:
for var in sorted(frame_info.variables, key=lambda v: v.name):
yield self.format_variable(var) + "\n"
try:
yield self.format_variable(var) + "\n"
except Exception:
pass

def format_variable(self, var: Variable) -> str:
return "{} = {}".format(
Expand Down
18 changes: 11 additions & 7 deletions stack_data/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,19 @@ def unique_in_order(it: Iterable[T]) -> List[T]:
def line_range(node: ast.AST) -> Tuple[int, int]:
"""
Returns a pair of numbers representing a half open range
(i.e. suitable as arguments to the range builtin)
(i.e. suitable as arguments to the `range()` builtin)
of line numbers of the given AST nodes.
This function relies on the first_token and last_token
attributes set by asttokens.
"""
return (
node.first_token.start[0],
node.last_token.end[0] + 1,
)
try:
return (
node.first_token.start[0],
node.last_token.end[0] + 1,
)
except AttributeError:
return (
node.lineno,
getattr(node, "end_lineno", node.lineno) + 1,
)


def highlight_unique(lst: List[T]) -> Iterator[Tuple[T, bool]]:
Expand Down
13 changes: 13 additions & 0 deletions tests/golden_files/f_string_new.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Traceback (most recent call last):
File "formatter_example.py", line 57, in f_string
54 | def f_string():
55 | f"""{str
56 | (
--> 57 | 1 /
^^^
58 | 0 + 4
^^^^^^^^^^^
59 | + 5
60 | )
61 | }"""
ZeroDivisionError: division by zero
11 changes: 11 additions & 0 deletions tests/golden_files/f_string_old.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
Traceback (most recent call last):
File "formatter_example.py", line 61, in f_string
54 | def f_string():
55 | f"""{str
56 | (
57 | 1 /
58 | 0 + 4
59 | + 5
60 | )
--> 61 | }"""
ZeroDivisionError: division by zero
10 changes: 10 additions & 0 deletions tests/samples/formatter_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,16 @@ def format_frame(formatter):
return list(formatter.format_frame(frame))


def f_string():
f"""{str
(
1 /
0 + 4
+ 5
)
}"""


if __name__ == '__main__':
try:
bar()
Expand Down
20 changes: 20 additions & 0 deletions tests/samples/pieces.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,26 @@ def foo(x=1, y=2):
str("""
foo
""")
str(f"""
{str(str)}
""")
str(f"""
foo
{
str(
str
)
}
bar
{str(str)}
baz
{
str(
str
)
}
spam
""")


def foo2(
Expand Down
Loading

0 comments on commit 4265964

Please sign in to comment.