Merge pull request #4001 from asottile/fix_bytes_repr_text_mix_python_2

Fix UnicodeDecodeError in assertion with mixed non-ascii bytes repr + text
This commit is contained in:
Ronny Pfannschmidt 2018-09-20 22:16:37 +02:00 committed by GitHub
commit f6eb39df33
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 27 additions and 5 deletions

View File

@ -0,0 +1 @@
Fix ``UnicodeDecodeError`` in python2.x when a class returns a non-ascii binary ``__repr__`` in an assertion which also contains non-ascii text.

View File

@ -8,6 +8,7 @@ import marshal
import os
import re
import six
import string
import struct
import sys
import types
@ -466,10 +467,14 @@ def _saferepr(obj):
"""
r = py.io.saferepr(obj)
if isinstance(r, six.text_type):
return r.replace(u"\n", u"\\n")
else:
return r.replace(b"\n", b"\\n")
# only occurs in python2.x, repr must return text in python3+
if isinstance(r, bytes):
# Represent unprintable bytes as `\x##`
r = u"".join(
u"\\x{:x}".format(ord(c)) if c not in string.printable else c.decode()
for c in r
)
return r.replace(u"\n", u"\\n")
from _pytest.assertion.util import format_explanation as _format_explanation # noqa

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import, division, print_function
import glob
@ -57,7 +58,7 @@ def getmsg(f, extra_ns=None, must_pass=False):
except AssertionError:
if must_pass:
pytest.fail("shouldn't have raised")
s = str(sys.exc_info()[1])
s = six.text_type(sys.exc_info()[1])
if not s.startswith("assert"):
return "AssertionError: " + s
return s
@ -608,6 +609,21 @@ class TestAssertionRewrite(object):
assert r"where 1 = \n{ \n~ \n}.a" in util._format_lines([getmsg(f)])[0]
def test_custom_repr_non_ascii(self):
def f():
class A(object):
name = u"ä"
def __repr__(self):
return self.name.encode("UTF-8") # only legal in python2
a = A()
assert not a.name
msg = getmsg(f)
assert "UnicodeDecodeError" not in msg
assert "UnicodeEncodeError" not in msg
class TestRewriteOnImport(object):
def test_pycache_is_a_file(self, testdir):