From 424479cf0f8bb84b97596347a120307bead40916 Mon Sep 17 00:00:00 2001 From: Floris Bruynooghe Date: Mon, 18 Aug 2014 20:07:38 +0200 Subject: [PATCH 1/3] Escape newlines in repr for assertion rewriting The assertion formatting mini-language depends on newlines being escaped. Unfortunately if the repr of an object contained newlines the rewriting module did not escape those, which is now fixed. Fixes issue453. --- CHANGELOG | 3 +++ _pytest/assertion/rewrite.py | 10 +++++++++- testing/test_assertrewrite.py | 11 +++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 9ff564f85..93b34747e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -3,6 +3,9 @@ NEXT - fixed issue561: adapt autouse fixture example for python3. +- fixed issue453: assertion rewriting issue with __repr__ containing + "\n{", "\n}" and "\n~". + 2.6.1 ----------------------------------- diff --git a/_pytest/assertion/rewrite.py b/_pytest/assertion/rewrite.py index 523d2b2dc..772f3ac03 100644 --- a/_pytest/assertion/rewrite.py +++ b/_pytest/assertion/rewrite.py @@ -326,7 +326,15 @@ def rewrite_asserts(mod): AssertionRewriter().run(mod) -_saferepr = py.io.saferepr +def _saferepr(obj): + repr = py.io.saferepr(obj) + if py.builtin._istext(repr): + t = py.builtin.text + else: + t = py.builtin.bytes + return repr.replace(t("\n"), t("\\n")) + + from _pytest.assertion.util import format_explanation as _format_explanation # noqa def _should_repr_global_name(obj): diff --git a/testing/test_assertrewrite.py b/testing/test_assertrewrite.py index 72e2d4e10..7e0cfbf83 100644 --- a/testing/test_assertrewrite.py +++ b/testing/test_assertrewrite.py @@ -313,6 +313,17 @@ class TestAssertionRewrite: assert "%test" == "test" assert getmsg(f).startswith("assert '%test' == 'test'") + def test_custom_repr(self): + def f(): + class Foo(object): + a = 1 + + def __repr__(self): + return "\n{ \n~ \n}" + f = Foo() + assert 0 == f.a + assert r"where 1 = \n{ \n~ \n}.a" in util._format_lines([getmsg(f)])[0] + class TestRewriteOnImport: From e7ed45a5d4d268e253e5836cdb69fac2fd8802b9 Mon Sep 17 00:00:00 2001 From: Floris Bruynooghe Date: Tue, 19 Aug 2014 20:50:25 +0200 Subject: [PATCH 2/3] Explain why this is important --- _pytest/assertion/rewrite.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/_pytest/assertion/rewrite.py b/_pytest/assertion/rewrite.py index 772f3ac03..6cb5ee96c 100644 --- a/_pytest/assertion/rewrite.py +++ b/_pytest/assertion/rewrite.py @@ -327,6 +327,13 @@ def rewrite_asserts(mod): def _saferepr(obj): + """Get a safe repr of an object for assertion error messages + + The assertion formatting (util.format_explanation()) requires + newlines to be escaped since they are a special character for it. + But py.io.saferepr allows newlines, so we need to escape them + here. + """ repr = py.io.saferepr(obj) if py.builtin._istext(repr): t = py.builtin.text From 79c2a479851c7e368f3263ef60a64a1ffea917e7 Mon Sep 17 00:00:00 2001 From: Floris Bruynooghe Date: Sat, 23 Aug 2014 12:10:16 +0200 Subject: [PATCH 3/3] Improve the docstring further --- _pytest/assertion/rewrite.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/_pytest/assertion/rewrite.py b/_pytest/assertion/rewrite.py index 6cb5ee96c..cb8acc187 100644 --- a/_pytest/assertion/rewrite.py +++ b/_pytest/assertion/rewrite.py @@ -327,12 +327,15 @@ def rewrite_asserts(mod): def _saferepr(obj): - """Get a safe repr of an object for assertion error messages + """Get a safe repr of an object for assertion error messages. The assertion formatting (util.format_explanation()) requires newlines to be escaped since they are a special character for it. - But py.io.saferepr allows newlines, so we need to escape them - here. + Normally assertion.util.format_explanation() does this but for a + custom repr it is possible to contain one of the special escape + sequences, especially '\n{' and '\n}' are likely to be present in + JSON reprs. + """ repr = py.io.saferepr(obj) if py.builtin._istext(repr):