diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 80e78ab50..fb0ab1c12 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -54,5 +54,5 @@ repos: - id: py-deprecated name: py library is deprecated language: pygrep - entry: '\bpy\.(builtin\.|code\.|std\.)' + entry: '\bpy\.(builtin\.|code\.|std\.|io\.saferepr)' types: [python] diff --git a/changelog/4657.trivial.rst b/changelog/4657.trivial.rst new file mode 100644 index 000000000..abdab08eb --- /dev/null +++ b/changelog/4657.trivial.rst @@ -0,0 +1 @@ +Copy saferepr from pylib diff --git a/setup.cfg b/setup.cfg index 8cd3858fd..9d0aa332e 100644 --- a/setup.cfg +++ b/setup.cfg @@ -36,10 +36,11 @@ platforms = unix, linux, osx, cygwin, win32 zip_safe = no packages = _pytest - _pytest.assertion _pytest._code - _pytest.mark + _pytest._io + _pytest.assertion _pytest.config + _pytest.mark py_modules = pytest python_requires = >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.* diff --git a/src/_pytest/_code/code.py b/src/_pytest/_code/code.py index 1b49fe75b..fd99c6cdd 100644 --- a/src/_pytest/_code/code.py +++ b/src/_pytest/_code/code.py @@ -18,6 +18,7 @@ import six from six import text_type import _pytest +from _pytest._io.saferepr import saferepr from _pytest.compat import _PY2 from _pytest.compat import _PY3 from _pytest.compat import PY35 @@ -144,7 +145,7 @@ class Frame(object): def repr(self, object): """ return a 'safe' (non-recursive, one-line) string repr for 'object' """ - return py.io.saferepr(object) + return saferepr(object) def is_true(self, object): return object @@ -423,7 +424,7 @@ class ExceptionInfo(object): if exprinfo is None and isinstance(tup[1], AssertionError): exprinfo = getattr(tup[1], "msg", None) if exprinfo is None: - exprinfo = py.io.saferepr(tup[1]) + exprinfo = saferepr(tup[1]) if exprinfo and exprinfo.startswith(cls._assert_start_repr): _striptext = "AssertionError: " @@ -620,7 +621,7 @@ class FormattedExcinfo(object): return source def _saferepr(self, obj): - return py.io.saferepr(obj) + return saferepr(obj) def repr_args(self, entry): if self.funcargs: diff --git a/src/_pytest/assertion/rewrite.py b/src/_pytest/assertion/rewrite.py index 80f182723..52f5ebce7 100644 --- a/src/_pytest/assertion/rewrite.py +++ b/src/_pytest/assertion/rewrite.py @@ -19,6 +19,7 @@ import atomicwrites import py import six +from _pytest._io.saferepr import saferepr from _pytest.assertion import util from _pytest.compat import spec_from_file_location from _pytest.pathlib import fnmatch_ex @@ -484,7 +485,7 @@ def _saferepr(obj): JSON reprs. """ - r = py.io.saferepr(obj) + r = saferepr(obj) # only occurs in python2.x, repr must return text in python3+ if isinstance(r, bytes): # Represent unprintable bytes as `\x##` @@ -503,7 +504,7 @@ def _format_assertmsg(obj): For strings this simply replaces newlines with '\n~' so that util.format_explanation() will preserve them instead of escaping - newlines. For other objects py.io.saferepr() is used first. + newlines. For other objects saferepr() is used first. """ # reprlib appears to have a bug which means that if a string @@ -512,7 +513,7 @@ def _format_assertmsg(obj): # However in either case we want to preserve the newline. replaces = [(u"\n", u"\n~"), (u"%", u"%%")] if not isinstance(obj, six.string_types): - obj = py.io.saferepr(obj) + obj = saferepr(obj) replaces.append((u"\\n", u"\n~")) if isinstance(obj, bytes): @@ -753,7 +754,7 @@ class AssertionRewriter(ast.NodeVisitor): return ast.Name(name, ast.Load()) def display(self, expr): - """Call py.io.saferepr on the expression.""" + """Call saferepr on the expression.""" return self.helper("saferepr", expr) def helper(self, name, *args): diff --git a/src/_pytest/assertion/util.py b/src/_pytest/assertion/util.py index b35b6abc5..6326dddbd 100644 --- a/src/_pytest/assertion/util.py +++ b/src/_pytest/assertion/util.py @@ -5,11 +5,11 @@ from __future__ import print_function import pprint -import py import six import _pytest._code from ..compat import Sequence +from _pytest._io.saferepr import saferepr # The _reprcompare attribute on the util module is used by the new assertion # interpretation code and assertion rewriter to detect this plugin was @@ -105,8 +105,8 @@ except NameError: def assertrepr_compare(config, op, left, right): """Return specialised explanations for some operators/operands""" width = 80 - 15 - len(op) - 2 # 15 chars indentation, 1 space around op - left_repr = py.io.saferepr(left, maxsize=int(width // 2)) - right_repr = py.io.saferepr(right, maxsize=width - len(left_repr)) + left_repr = saferepr(left, maxsize=int(width // 2)) + right_repr = saferepr(right, maxsize=width - len(left_repr)) summary = u"%s %s %s" % (ecu(left_repr), op, ecu(right_repr)) @@ -282,12 +282,12 @@ def _compare_eq_sequence(left, right, verbose=False): if len(left) > len(right): explanation += [ u"Left contains more items, first extra item: %s" - % py.io.saferepr(left[len(right)]) + % saferepr(left[len(right)]) ] elif len(left) < len(right): explanation += [ u"Right contains more items, first extra item: %s" - % py.io.saferepr(right[len(left)]) + % saferepr(right[len(left)]) ] return explanation @@ -299,11 +299,11 @@ def _compare_eq_set(left, right, verbose=False): if diff_left: explanation.append(u"Extra items in the left set:") for item in diff_left: - explanation.append(py.io.saferepr(item)) + explanation.append(saferepr(item)) if diff_right: explanation.append(u"Extra items in the right set:") for item in diff_right: - explanation.append(py.io.saferepr(item)) + explanation.append(saferepr(item)) return explanation @@ -320,9 +320,7 @@ def _compare_eq_dict(left, right, verbose=False): if diff: explanation += [u"Differing items:"] for k in diff: - explanation += [ - py.io.saferepr({k: left[k]}) + " != " + py.io.saferepr({k: right[k]}) - ] + explanation += [saferepr({k: left[k]}) + " != " + saferepr({k: right[k]})] extra_left = set(left) - set(right) if extra_left: explanation.append(u"Left contains more items:") @@ -376,7 +374,7 @@ def _notin_text(term, text, verbose=False): tail = text[index + len(term) :] correct_text = head + tail diff = _diff_text(correct_text, text, verbose) - newdiff = [u"%s is contained here:" % py.io.saferepr(term, maxsize=42)] + newdiff = [u"%s is contained here:" % saferepr(term, maxsize=42)] for line in diff: if line.startswith(u"Skipping"): continue diff --git a/src/_pytest/compat.py b/src/_pytest/compat.py index ff027f308..fa878a485 100644 --- a/src/_pytest/compat.py +++ b/src/_pytest/compat.py @@ -17,6 +17,7 @@ import six from six import text_type import _pytest +from _pytest._io.saferepr import saferepr from _pytest.outcomes import fail from _pytest.outcomes import TEST_OUTCOME @@ -294,7 +295,7 @@ def get_real_func(obj): else: raise ValueError( ("could not find real function of {start}\nstopped at {current}").format( - start=py.io.saferepr(start_obj), current=py.io.saferepr(obj) + start=saferepr(start_obj), current=saferepr(obj) ) ) if isinstance(obj, functools.partial): diff --git a/src/_pytest/pytester.py b/src/_pytest/pytester.py index c59628948..7e255dc9c 100644 --- a/src/_pytest/pytester.py +++ b/src/_pytest/pytester.py @@ -20,6 +20,7 @@ import six import pytest from _pytest._code import Source +from _pytest._io.saferepr import saferepr from _pytest.assertion.rewrite import AssertionRewritingHook from _pytest.capture import MultiCapture from _pytest.capture import SysCapture @@ -1225,9 +1226,7 @@ def getdecoded(out): try: return out.decode("utf-8") except UnicodeDecodeError: - return "INTERNAL not-utf8-decodeable, truncated string:\n%s" % ( - py.io.saferepr(out), - ) + return "INTERNAL not-utf8-decodeable, truncated string:\n%s" % (saferepr(out),) class LineComp(object):