Skip to content

Commit 912870d

Browse files
committed
Merge pull request #7708 from nicoddemus/repr-line-7707
Fix handle of exceptions in ReprEntry with tb=line
1 parent 0115b71 commit 912870d

File tree

3 files changed

+36
-31
lines changed

3 files changed

+36
-31
lines changed

changelog/7707.bugfix.rst

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix internal error when handling some exceptions that contain multiple lines or the style uses multiple lines (``--tb=line`` for example).

src/_pytest/_code/code.py

+10-14
Original file line numberDiff line numberDiff line change
@@ -1038,25 +1038,21 @@ def _write_entry_lines(self, tw: TerminalWriter) -> None:
10381038
# such as "> assert 0"
10391039
fail_marker = "{} ".format(FormattedExcinfo.fail_marker)
10401040
indent_size = len(fail_marker)
1041-
indents = []
1042-
source_lines = []
1043-
failure_lines = []
1044-
seeing_failures = False
1045-
for line in self.lines:
1046-
is_source_line = not line.startswith(fail_marker)
1047-
if is_source_line:
1048-
assert not seeing_failures, (
1049-
"Unexpected failure lines between source lines:\n"
1050-
+ "\n".join(self.lines)
1051-
)
1041+
indents = [] # type: List[str]
1042+
source_lines = [] # type: List[str]
1043+
failure_lines = [] # type: List[str]
1044+
for index, line in enumerate(self.lines):
1045+
is_failure_line = line.startswith(fail_marker)
1046+
if is_failure_line:
1047+
# from this point on all lines are considered part of the failure
1048+
failure_lines.extend(self.lines[index:])
1049+
break
1050+
else:
10521051
if self.style == "value":
10531052
source_lines.append(line)
10541053
else:
10551054
indents.append(line[:indent_size])
10561055
source_lines.append(line[indent_size:])
1057-
else:
1058-
seeing_failures = True
1059-
failure_lines.append(line)
10601056

10611057
tw._write_source(source_lines, indents)
10621058

testing/code/test_excinfo.py

+25-17
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
import queue
55
import sys
66
import textwrap
7+
from typing import Any
8+
from typing import Dict
79
from typing import Tuple
810
from typing import Union
911

@@ -1045,28 +1047,34 @@ def f():
10451047
@pytest.mark.parametrize(
10461048
"reproptions",
10471049
[
1048-
{
1049-
"style": style,
1050-
"showlocals": showlocals,
1051-
"funcargs": funcargs,
1052-
"tbfilter": tbfilter,
1053-
}
1054-
for style in ("long", "short", "no")
1050+
pytest.param(
1051+
{
1052+
"style": style,
1053+
"showlocals": showlocals,
1054+
"funcargs": funcargs,
1055+
"tbfilter": tbfilter,
1056+
},
1057+
id="style={},showlocals={},funcargs={},tbfilter={}".format(
1058+
style, showlocals, funcargs, tbfilter
1059+
),
1060+
)
1061+
for style in ["long", "short", "line", "no", "native", "value", "auto"]
10551062
for showlocals in (True, False)
10561063
for tbfilter in (True, False)
10571064
for funcargs in (True, False)
10581065
],
10591066
)
1060-
def test_format_excinfo(self, importasmod, reproptions):
1061-
mod = importasmod(
1062-
"""
1063-
def g(x):
1064-
raise ValueError(x)
1065-
def f():
1066-
g(3)
1067-
"""
1068-
)
1069-
excinfo = pytest.raises(ValueError, mod.f)
1067+
def test_format_excinfo(self, reproptions: Dict[str, Any]) -> None:
1068+
def bar():
1069+
assert False, "some error"
1070+
1071+
def foo():
1072+
bar()
1073+
1074+
# using inline functions as opposed to importasmod so we get source code lines
1075+
# in the tracebacks (otherwise getinspect doesn't find the source code).
1076+
with pytest.raises(AssertionError) as excinfo:
1077+
foo()
10701078
file = io.StringIO()
10711079
tw = TerminalWriter(file=file)
10721080
repr = excinfo.getrepr(**reproptions)

0 commit comments

Comments
 (0)