simplistix / sybil

Automated testing for the examples in your documentation.
https://sybil.readthedocs.io/en/latest/
Other
69 stars 14 forks source link

Colored output in Python 3.13 causes Sybil to fail #121

Closed sscherfke closed 2 weeks ago

sscherfke commented 2 weeks ago

Python 3.13 uses colors out of the box in the shell and when it prints exceptions:

grafik

The escape sequences for colors cause tests to fail (see this example).

The fix would be to strip ANSI escape sequences from all strings prior to the comaprison, like desribed here: https://dnmtechs.com/removing-ansi-escape-sequences-from-a-string-in-python-3/

I can see if I can start with a PR if that would help. :-)

sscherfke commented 2 weeks ago

The issue is actually in my own Sybil extension. :see_no_evil: O

This is the fix (in case anyone else's plugins are affected, too):

diff --git a/conftest.py b/conftest.py
index 16568f6..f05826c 100644
--- a/conftest.py
+++ b/conftest.py
@@ -1,6 +1,7 @@
 """
 Fixtures for the documentation tests and examples.
 """
+
 import os
 import re
 import subprocess
@@ -23,6 +24,16 @@ import sybil.region
 import sybil.typing

+ANSI_ESCAPE_PATTERN = re.compile(r"\x1B\[[0-?]*[ -/]*[@-~]")
+
+
+def strip_ansi_escape_codes(line: str) -> str:
+    """
+    Remove ANSCI escape sequences (e.g., colors) from the input.
+    """
+    return ANSI_ESCAPE_PATTERN.sub("", line)
+
+
 class CodeFileParser(sybil.parsers.myst.CodeBlockParser):
     """
     Parser for included/referenced files.
@@ -100,7 +111,10 @@ class ConsoleCodeBlockParser(sybil.parsers.myst.CodeBlockParser):
         )
         stdout, _stderr = proc.communicate(cmds)
         # Remove trailing spaces in output:
-        stdout = "".join(f"{line.rstrip()}\n" for line in stdout.splitlines())
+        stdout = "".join(
+            f"{strip_ansi_escape_codes(line.rstrip())}\n"
+            for line in stdout.splitlines()
+        )
         if isinstance(expected, str):
             assert stdout == expected
         else:
cjw296 commented 2 weeks ago

Thanks for the follow up! What does ConsoleCodeBlockParser do that's different from sybil.parsers.myst.CodeBlockParser?

sscherfke commented 2 weeks ago

My docs list settings files and python scripts that read these settings files. If these code-blocks have a caption with a filename, my sybil extension writes them into a tmp file with that name. The following ConsoleCodeBlockParser then runs the bash commands of that block which can invoke the files from the previous listings. Finaly, the output of the invoked shell comands is compared similarly to regular python-doctests.

The examples demonstrate this: https://typed-settings.readthedocs.io/en/latest/#example

sscherfke commented 2 weeks ago

I love Sybil for letting me do this kind of awesome stuff. <3