Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix handle of exceptions in ReprEntry with tb=line #7708

Merged
merged 1 commit into from Sep 4, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog/7707.bugfix.rst
@@ -0,0 +1 @@
Fix internal error when handling some exceptions that contain multiple lines or the style uses multiple lines (``--tb=line`` for example).
24 changes: 10 additions & 14 deletions src/_pytest/_code/code.py
Expand Up @@ -1049,25 +1049,21 @@ def _write_entry_lines(self, tw: TerminalWriter) -> None:
# such as "> assert 0"
fail_marker = "{} ".format(FormattedExcinfo.fail_marker)
indent_size = len(fail_marker)
indents = []
source_lines = []
failure_lines = []
seeing_failures = False
for line in self.lines:
is_source_line = not line.startswith(fail_marker)
if is_source_line:
assert not seeing_failures, (
"Unexpected failure lines between source lines:\n"
+ "\n".join(self.lines)
)
indents = [] # type: List[str]
source_lines = [] # type: List[str]
failure_lines = [] # type: List[str]
for index, line in enumerate(self.lines):
is_failure_line = line.startswith(fail_marker)
if is_failure_line:
# from this point on all lines are considered part of the failure
failure_lines.extend(self.lines[index:])
break
else:
if self.style == "value":
source_lines.append(line)
else:
indents.append(line[:indent_size])
source_lines.append(line[indent_size:])
else:
seeing_failures = True
failure_lines.append(line)

tw._write_source(source_lines, indents)

Expand Down
42 changes: 25 additions & 17 deletions testing/code/test_excinfo.py
Expand Up @@ -4,6 +4,8 @@
import queue
import sys
import textwrap
from typing import Any
from typing import Dict
from typing import Tuple
from typing import Union

Expand Down Expand Up @@ -1045,28 +1047,34 @@ def f():
@pytest.mark.parametrize(
"reproptions",
[
{
"style": style,
"showlocals": showlocals,
"funcargs": funcargs,
"tbfilter": tbfilter,
}
for style in ("long", "short", "no")
pytest.param(
{
"style": style,
"showlocals": showlocals,
"funcargs": funcargs,
"tbfilter": tbfilter,
},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could maybe benefit as a typing.NamedTuple once we're free of python<3.6.1

id="style={},showlocals={},funcargs={},tbfilter={}".format(
style, showlocals, funcargs, tbfilter
),
)
for style in ["long", "short", "line", "no", "native", "value", "auto"]
for showlocals in (True, False)
for tbfilter in (True, False)
for funcargs in (True, False)
],
)
def test_format_excinfo(self, importasmod, reproptions):
mod = importasmod(
"""
def g(x):
raise ValueError(x)
def f():
g(3)
"""
)
excinfo = pytest.raises(ValueError, mod.f)
def test_format_excinfo(self, reproptions: Dict[str, Any]) -> None:
def bar():
assert False, "some error"

def foo():
bar()

# using inline functions as opposed to importasmod so we get source code lines
# in the tracebacks (otherwise getinspect doesn't find the source code).
with pytest.raises(AssertionError) as excinfo:
foo()
file = io.StringIO()
tw = TerminalWriter(file=file)
repr = excinfo.getrepr(**reproptions)
Expand Down