Fix linting errors and py references in saferepr.py

This commit is contained in:
Anthony Sottile 2019-01-20 10:50:18 -08:00
parent dbb6c18c44
commit 095ce2ca7f
2 changed files with 80 additions and 88 deletions

View File

@ -1,14 +1,13 @@
import py
import sys import sys
builtin_repr = repr from six.moves import reprlib
reprlib = py.builtin._tryimport('repr', 'reprlib')
class SafeRepr(reprlib.Repr): class SafeRepr(reprlib.Repr):
""" subclass of repr.Repr that limits the resulting size of repr() """subclass of repr.Repr that limits the resulting size of repr()
and includes information on exceptions raised during the call. and includes information on exceptions raised during the call.
""" """
def repr(self, x): def repr(self, x):
return self._callhelper(reprlib.Repr.repr, self, x) return self._callhelper(reprlib.Repr.repr, self, x)
@ -16,48 +15,50 @@ class SafeRepr(reprlib.Repr):
# Strictly speaking wrong on narrow builds # Strictly speaking wrong on narrow builds
def repr(u): def repr(u):
if "'" not in u: if "'" not in u:
return py.builtin._totext("'%s'") % u return u"'%s'" % u
elif '"' not in u: elif '"' not in u:
return py.builtin._totext('"%s"') % u return u'"%s"' % u
else: else:
return py.builtin._totext("'%s'") % u.replace("'", r"\'") return u"'%s'" % u.replace("'", r"\'")
s = repr(x[:self.maxstring])
s = repr(x[: self.maxstring])
if len(s) > self.maxstring: if len(s) > self.maxstring:
i = max(0, (self.maxstring-3)//2) i = max(0, (self.maxstring - 3) // 2)
j = max(0, self.maxstring-3-i) j = max(0, self.maxstring - 3 - i)
s = repr(x[:i] + x[len(x)-j:]) s = repr(x[:i] + x[len(x) - j :])
s = s[:i] + '...' + s[len(s)-j:] s = s[:i] + "..." + s[len(s) - j :]
return s return s
def repr_instance(self, x, level): def repr_instance(self, x, level):
return self._callhelper(builtin_repr, x) return self._callhelper(repr, x)
def _callhelper(self, call, x, *args): def _callhelper(self, call, x, *args):
try: try:
# Try the vanilla repr and make sure that the result is a string # Try the vanilla repr and make sure that the result is a string
s = call(x, *args) s = call(x, *args)
except py.builtin._sysex: except Exception:
raise
except:
cls, e, tb = sys.exc_info() cls, e, tb = sys.exc_info()
exc_name = getattr(cls, '__name__', 'unknown') exc_name = getattr(cls, "__name__", "unknown")
try: try:
exc_info = str(e) exc_info = str(e)
except py.builtin._sysex: except Exception:
raise exc_info = "unknown"
except:
exc_info = 'unknown'
return '<[%s("%s") raised in repr()] %s object at 0x%x>' % ( return '<[%s("%s") raised in repr()] %s object at 0x%x>' % (
exc_name, exc_info, x.__class__.__name__, id(x)) exc_name,
exc_info,
x.__class__.__name__,
id(x),
)
else: else:
if len(s) > self.maxsize: if len(s) > self.maxsize:
i = max(0, (self.maxsize-3)//2) i = max(0, (self.maxsize - 3) // 2)
j = max(0, self.maxsize-3-i) j = max(0, self.maxsize - 3 - i)
s = s[:i] + '...' + s[len(s)-j:] s = s[:i] + "..." + s[len(s) - j :]
return s return s
def saferepr(obj, maxsize=240): def saferepr(obj, maxsize=240):
""" return a size-limited safe repr-string for the given object. """return a size-limited safe repr-string for the given object.
Failing __repr__ functions of user instances will be represented Failing __repr__ functions of user instances will be represented
with a short exception info and 'saferepr' generally takes with a short exception info and 'saferepr' generally takes
care to never raise exceptions itself. This function is a wrapper care to never raise exceptions itself. This function is a wrapper

View File

@ -1,75 +1,66 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from _pytest._io.saferepr import saferepr
from __future__ import generators
import py
import sys
saferepr = py.io.saferepr def test_simple_repr():
assert saferepr(1) == "1"
assert saferepr(None) == "None"
class TestSafeRepr:
def test_simple_repr(self):
assert saferepr(1) == '1'
assert saferepr(None) == 'None'
def test_maxsize(self): def test_maxsize():
s = saferepr('x'*50, maxsize=25) s = saferepr("x" * 50, maxsize=25)
assert len(s) == 25 assert len(s) == 25
expected = repr('x'*10 + '...' + 'x'*10) expected = repr("x" * 10 + "..." + "x" * 10)
assert s == expected assert s == expected
def test_maxsize_error_on_instance(self):
class A:
def __repr__(self):
raise ValueError('...')
s = saferepr(('*'*50, A()), maxsize=25) def test_maxsize_error_on_instance():
assert len(s) == 25 class A:
assert s[0] == '(' and s[-1] == ')' def __repr__():
raise ValueError("...")
def test_exceptions(self): s = saferepr(("*" * 50, A()), maxsize=25)
class BrokenRepr: assert len(s) == 25
def __init__(self, ex): assert s[0] == "(" and s[-1] == ")"
self.ex = ex
foo = 0
def __repr__(self):
raise self.ex
class BrokenReprException(Exception):
__str__ = None
__repr__ = None
assert 'Exception' in saferepr(BrokenRepr(Exception("broken")))
s = saferepr(BrokenReprException("really broken"))
assert 'TypeError' in s
assert 'TypeError' in saferepr(BrokenRepr("string"))
s2 = saferepr(BrokenRepr(BrokenReprException('omg even worse')))
assert 'NameError' not in s2
assert 'unknown' in s2
def test_big_repr(self): def test_exceptions():
from py._io.saferepr import SafeRepr class BrokenRepr:
assert len(saferepr(range(1000))) <= \ def __init__(self, ex):
len('[' + SafeRepr().maxlist * "1000" + ']') self.ex = ex
def test_repr_on_newstyle(self): def __repr__(self):
class Function(object): raise self.ex
def __repr__(self):
return "<%s>" %(self.name)
try:
s = saferepr(Function())
except Exception:
py.test.fail("saferepr failed for newstyle class")
def test_unicode(self): class BrokenReprException(Exception):
val = py.builtin._totext('£€', 'utf-8') __str__ = None
reprval = py.builtin._totext("'£€'", 'utf-8') __repr__ = None
assert saferepr(val) == reprval
def test_unicode_handling(): assert "Exception" in saferepr(BrokenRepr(Exception("broken")))
value = py.builtin._totext('\xc4\x85\xc4\x87\n', 'utf-8').encode('utf8') s = saferepr(BrokenReprException("really broken"))
def f(): assert "TypeError" in s
raise Exception(value) assert "TypeError" in saferepr(BrokenRepr("string"))
excinfo = py.test.raises(Exception, f)
s = str(excinfo)
if sys.version_info[0] < 3:
u = unicode(excinfo)
s2 = saferepr(BrokenRepr(BrokenReprException("omg even worse")))
assert "NameError" not in s2
assert "unknown" in s2
def test_big_repr():
from _pytest._io.saferepr import SafeRepr
assert len(saferepr(range(1000))) <= len("[" + SafeRepr().maxlist * "1000" + "]")
def test_repr_on_newstyle():
class Function(object):
def __repr__(self):
return "<%s>" % (self.name)
assert saferepr(Function())
def test_unicode():
val = u"£€"
reprval = u"'£€'"
assert saferepr(val) == reprval