-
Notifications
You must be signed in to change notification settings - Fork 17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Better diff for multiline strings #14
Comments
I spent a bit of time this morning on this and looks like this is due to pytest's behaviour:
https://docs.pytest.org/en/6.2.x/assert.html#defining-your-own-explanation-for-failed-assertions So we should be able to find a way to improve suppor for multiline diffs :) I don't have a lot of time now, but I might try in future :) |
Briefly looked into this, seems like this is something pprintpp should support, if anything. icdiff only has to worry about files, we have the additional step of converting arbitrary objects to a string representation – breaking at Just tried to hack it for fun. Looks like we could cheese it by making a deep copy of the objects, replacing every diff --git a/pytest_icdiff.py b/pytest_icdiff.py
index 16fbba5..4a7f654 100644
--- a/pytest_icdiff.py
+++ b/pytest_icdiff.py
@@ -2,6 +2,7 @@
import shutil
from pprintpp import pformat
import icdiff
+from copy import deepcopy, _deepcopy_dispatch
COLS = shutil.get_terminal_size().columns
MARGIN_L = 10
@@ -26,6 +27,13 @@ def pytest_assertrepr_compare(config, op, left, right):
half_cols = COLS / 2 - MARGINS
+ # Temporarily patch copy function for str
+ str_atomic = _deepcopy_dispatch[str]
+ _deepcopy_dispatch[str] = lambda x, memo: PrettyStr(x)
+ left = deepcopy(left)
+ right = deepcopy(right)
+ _deepcopy_dispatch[str] = str_atomic
+
pretty_left = pformat(left, indent=2, width=half_cols).splitlines()
pretty_right = pformat(right, indent=2, width=half_cols).splitlines()
diff_cols = COLS - MARGINS
@@ -57,3 +65,15 @@ def pytest_assertrepr_compare(config, op, left, right):
icdiff_lines = list(differ.make_table(pretty_left, pretty_right, context=True))
return ["equals failed"] + [color_off + l for l in icdiff_lines]
+
+
+class PrettyStr(str):
+ def __repr__(self):
+ # Add a newline indication to all but the last line
+ lines = self.splitlines()
+ lines = list(map(self._pretty_line, lines[:-1])) + [repr(lines[-1])]
+ return '\n'.join(lines)
+ @staticmethod
+ def _pretty_line(x):
+ r = repr(x)
+ return r[:-1] + '\n' + r[-1:]
diff --git a/tests/test_pytest_icdiff.py b/tests/test_pytest_icdiff.py
index be5a5e1..81dff54 100644
--- a/tests/test_pytest_icdiff.py
+++ b/tests/test_pytest_icdiff.py
@@ -289,3 +289,16 @@ def test_really_long_diffs_use_context_mode(testdir):
output = testdir.runpytest('-vv', '--color=yes').stdout.str()
assert len(output.splitlines()) < 50
assert "---" in output # context split marker
+
+def test_pretty_strings(testdir):
+ testdir.makepyfile(
+ f"""
+ def test_one():
+ one = '\\n'.join(str(i) for i in range(30))
+ two = '\\n'.join(str(i) for i in range(1, 31))
+ assert one == two
+ """
+ )
+ output = testdir.runpytest('-vv', '--color=yes').stdout.str()
+ assert len(output.splitlines()) > 10
+ assert "---" in output This seems to work, but no idea how efficiently. I definitely don't think this will work with multiple threads. |
Hi there, would be possible to get a better diff for multiline strings?
Right now it prints the "\n", which is not ideal, example here:
The text was updated successfully, but these errors were encountered: