terminalwriter: factor out pygments lexer & formatter selection to own functions

We intend to add some more logic here.
This commit is contained in:
Ran Benita 2024-06-10 11:38:33 +03:00
parent 3d91e42229
commit 67a570aea9
1 changed files with 72 additions and 48 deletions

View File

@ -8,11 +8,17 @@ from typing import Literal
from typing import Optional
from typing import Sequence
from typing import TextIO
from typing import TYPE_CHECKING
from ..compat import assert_never
from .wcwidth import wcswidth
if TYPE_CHECKING:
from pygments.formatter import Formatter
from pygments.lexer import Lexer
# This code was initially copied from py 1.8.1, file _io/terminalwriter.py.
@ -194,58 +200,76 @@ class TerminalWriter:
for indent, new_line in zip(indents, new_lines):
self.line(indent + new_line)
def _highlight(
self, source: str, lexer: Literal["diff", "python"] = "python"
) -> str:
"""Highlight the given source if we have markup support."""
def _get_pygments_lexer(
self, lexer: Literal["python", "diff"]
) -> Optional["Lexer"]:
try:
if lexer == "python":
from pygments.lexers.python import PythonLexer
return PythonLexer()
elif lexer == "diff":
from pygments.lexers.diff import DiffLexer
return DiffLexer()
else:
assert_never(lexer)
except ModuleNotFoundError:
return None
def _get_pygments_formatter(self) -> Optional["Formatter"]:
try:
import pygments.util
except ModuleNotFoundError:
return None
from _pytest.config.exceptions import UsageError
if not source or not self.hasmarkup or not self.code_highlight:
return source
theme = os.getenv("PYTEST_THEME")
theme_mode = os.getenv("PYTEST_THEME_MODE", "dark")
try:
from pygments.formatters.terminal import TerminalFormatter
if lexer == "python":
from pygments.lexers.python import PythonLexer as Lexer
elif lexer == "diff":
from pygments.lexers.diff import DiffLexer as Lexer
else:
assert_never(lexer)
from pygments import highlight
import pygments.util
except ImportError:
return source
else:
try:
highlighted: str = highlight(
source,
Lexer(),
TerminalFormatter(
bg=os.getenv("PYTEST_THEME_MODE", "dark"),
style=os.getenv("PYTEST_THEME"),
),
)
# pygments terminal formatter may add a newline when there wasn't one.
# We don't want this, remove.
if highlighted[-1] == "\n" and source[-1] != "\n":
highlighted = highlighted[:-1]
return TerminalFormatter(bg=theme_mode, style=theme)
# Some lexers will not set the initial color explicitly
# which may lead to the previous color being propagated to the
# start of the expression, so reset first.
return "\x1b[0m" + highlighted
except pygments.util.ClassNotFound as e:
raise UsageError(
"PYTEST_THEME environment variable had an invalid value: '{}'. "
"Only valid pygment styles are allowed.".format(
os.getenv("PYTEST_THEME")
)
) from e
except pygments.util.OptionError as e:
raise UsageError(
"PYTEST_THEME_MODE environment variable had an invalid value: '{}'. "
"The only allowed values are 'dark' and 'light'.".format(
os.getenv("PYTEST_THEME_MODE")
)
) from e
except pygments.util.ClassNotFound as e:
raise UsageError(
f"PYTEST_THEME environment variable had an invalid value: '{theme}'. "
"Only valid pygment styles are allowed."
) from e
except pygments.util.OptionError as e:
raise UsageError(
f"PYTEST_THEME_MODE environment variable had an invalid value: '{theme_mode}'. "
"The only allowed values are 'dark' and 'light'."
) from e
def _highlight(
self, source: str, lexer: Literal["diff", "python"] = "python"
) -> str:
"""Highlight the given source if we have markup support."""
if not source or not self.hasmarkup or not self.code_highlight:
return source
pygments_lexer = self._get_pygments_lexer(lexer)
if pygments_lexer is None:
return source
pygments_formatter = self._get_pygments_formatter()
if pygments_formatter is None:
return source
from pygments import highlight
highlighted: str = highlight(source, pygments_lexer, pygments_formatter)
# pygments terminal formatter may add a newline when there wasn't one.
# We don't want this, remove.
if highlighted[-1] == "\n" and source[-1] != "\n":
highlighted = highlighted[:-1]
# Some lexers will not set the initial color explicitly
# which may lead to the previous color being propagated to the
# start of the expression, so reset first.
highlighted = "\x1b[0m" + highlighted
return highlighted