Skip to content

Formatting of utf-8 explanations fails #1379

Closed
@biern

Description

@biern

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

This seems to be the regression of #678 and #877.

Metadata

Metadata

Assignees

No one assigned

    Labels

    type: bugproblem that needs to be addressed

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions