Closed
Description
Formatting of explanation message fails if utf-8 character is returned in object's __repr__
.
Following code fails with two different unicode related exceptions:
# -*- coding: utf-8 -*-
import pytest
class Foo(object):
def __repr__(self):
return "λ"
@pytest.fixture
def foo():
return Foo()
def test_repr_utf8():
assert Foo() == 1
def test_repr_context_utf8(foo):
assert foo == 1
def test_repr_utf8():
> assert Foo() == 1
error.py:17:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
venv/src/pytest/_pytest/assertion/util.py:43: in format_explanation
result = _format_lines(lines)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
lines = ['assert \xce\xbb', '{\xce\xbb = Foo()', '} == 1']
def _format_lines(lines):
"""Format the individual lines
This will replace the '{', '}' and '~' characters of our mini
formatting language with the proper 'where ...', 'and ...' and ' +
...' text, taking care of indentation along the way.
Return a list of formatted lines.
"""
result = lines[:1]
stack = [0]
stackcnt = [0]
for line in lines[1:]:
if line.startswith('{'):
if stackcnt[-1]:
s = u('and ')
else:
s = u('where ')
stack.append(len(result))
stackcnt[-1] += 1
stackcnt.append(0)
> result.append(u(' +') + u(' ')*(len(stack)-1) + s + line[1:])
E UnicodeDecodeError: 'ascii' codec can't decode byte 0xce in position 0: ordinal not in range(128)
venv/src/pytest/_pytest/assertion/util.py:117: UnicodeDecodeError
_________________________________________________________________ test_repr_context_utf8 _________________________________________________________________
foo = λ
def test_repr_context_utf8(foo):
> assert foo == 1
error.py:21:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
explanation = 'assert \xce\xbb == 1'
def format_explanation(explanation):
"""This formats an explanation
Normally all embedded newlines are escaped, however there are
three exceptions: \n{, \n} and \n~. The first two are intended
cover nested explanations, see function and attribute explanations
for examples (.visit_Call(), visit_Attribute()). The last one is
for when one explanation needs to span multiple lines, e.g. when
displaying diffs.
"""
# explanation = ecu(explanation)
explanation = _collapse_false(explanation)
lines = _split_explanation(explanation)
result = _format_lines(lines)
> return u('\n').join(result)
E UnicodeDecodeError: 'ascii' codec can't decode byte 0xce in position 7: ordinal not in range(128)
venv/src/pytest/_pytest/assertion/util.py:44: UnicodeDecodeError
Tested against pytest 2.8.7 and master on python 2.7.10