Skip to content
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

(🎁) color the diff of strings #13175

Open
4 tasks done
KotlinIsland opened this issue Jan 30, 2025 · 1 comment
Open
4 tasks done

(🎁) color the diff of strings #13175

KotlinIsland opened this issue Jan 30, 2025 · 1 comment

Comments

@KotlinIsland
Copy link

KotlinIsland commented Jan 30, 2025

def test_list():
    assert [1, 2, 3] == [1, 4, 3]
def test_str():
    assert "asdf" == "asgf"

Warning

it is CRITICAL that pygments is installed, otherwise the diff won't be colored at all
this is a secret undocumented feature, see: #13174

> uv init
> uv add pytest pygments
...
> uv run pytest -vv
FAILED test_test.py::test_list - assert [1, 2, 3] == [1, 4, 3]

  At index 1 diff: 2 != 4

  Full diff:
    [
        1,
  -     4,
  ?     ^
  +     2,
  ?     ^
        3,
    ]
FAILED test_test.py::test_str - AssertionError: assert 'asdf' == 'asgf'

  - asgf
  ?   ^
  + asdf
  ?   ^

Image

here we can observe that no coloring has been applied to the string diff

  • a detailed description of the bug or problem you are having
  • output of pip list from the virtual environment you are using
    > uv tree
    uv tree
    Resolved 7 packages in 4ms
    test v1
    ├── pygments v2.19.1
    └── pytest v8.3.4
        ├── colorama v0.4.6
        ├── iniconfig v2.0.0
        ├── packaging v24.2
        └── pluggy v1.5.0
    
  • pytest and operating system versions
    windows 10
  • minimal example if possible
@The-Compiler
Copy link
Member

The-Compiler commented Jan 30, 2025

Huh, interesting!

Here is a quick hack that extends _diff_text the same way other diffing functions were in fbe3e29:

diff --git i/src/_pytest/assertion/util.py w/src/_pytest/assertion/util.py
index 3fe7eb9d8..9a7c6da72 100644
--- i/src/_pytest/assertion/util.py
+++ w/src/_pytest/assertion/util.py
@@ -242,7 +242,7 @@ def _compare_eq_any(
 ) -> list[str]:
     explanation = []
     if istext(left) and istext(right):
-        explanation = _diff_text(left, right, verbose)
+        explanation = _diff_text(left, right, highlighter, verbose)
     else:
         from _pytest.python_api import ApproxBase
 
@@ -274,7 +274,9 @@ def _compare_eq_any(
     return explanation
 
 
-def _diff_text(left: str, right: str, verbose: int = 0) -> list[str]:
+def _diff_text(
+    left: str, right: str, highlighter: _HighlightFunc, verbose: int = 0
+) -> list[str]:
     """Return the explanation for the diff between text.
 
     Unless --verbose is used this will skip leading and trailing
@@ -315,10 +317,15 @@ def _diff_text(left: str, right: str, verbose: int = 0) -> list[str]:
         explanation += ["Strings contain only whitespace, escaping them using repr()"]
     # "right" is the expected base against which we compare "left",
     # see https://github.com/pytest-dev/pytest/issues/3333
-    explanation += [
-        line.strip("\n")
-        for line in ndiff(right.splitlines(keepends), left.splitlines(keepends))
-    ]
+    explanation.extend(
+        highlighter(
+            "\n".join(
+                line.strip("\n")
+                for line in ndiff(right.splitlines(keepends), left.splitlines(keepends))
+            ),
+            lexer="diff",
+        ).splitlines()
+    )
     return explanation
 

and from a quick test, that seems to help:

Screenshot

@BenjaminSchubert was there a reason you didn't do _diff_text as part of #11530 as well, or was that just an oversight perhaps?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants