Use code highlighting if pygments is installed (#6658)
* Use code highlighting if pygments is installed * Use colorama constants instead of bare ascii codes Could not find the exact equivalent of 'hl-reset' code using colorama constants though. * Refactor ASCII color handling into a fixture * Revert back to using explicit color codes * In Python 3.5 skip rest of tests that require ordered markup in colored output
This commit is contained in:
@@ -1039,21 +1039,58 @@ class ReprEntry(TerminalRepr):
|
||||
self.reprfileloc = filelocrepr
|
||||
self.style = style
|
||||
|
||||
def _write_entry_lines(self, tw: TerminalWriter) -> None:
|
||||
"""Writes the source code portions of a list of traceback entries with syntax highlighting.
|
||||
|
||||
Usually entries are lines like these:
|
||||
|
||||
" x = 1"
|
||||
"> assert x == 2"
|
||||
"E assert 1 == 2"
|
||||
|
||||
This function takes care of rendering the "source" portions of it (the lines without
|
||||
the "E" prefix) using syntax highlighting, taking care to not highlighting the ">"
|
||||
character, as doing so might break line continuations.
|
||||
"""
|
||||
|
||||
indent_size = 4
|
||||
|
||||
def is_fail(line):
|
||||
return line.startswith("{} ".format(FormattedExcinfo.fail_marker))
|
||||
|
||||
if not self.lines:
|
||||
return
|
||||
|
||||
# separate indents and source lines that are not failures: we want to
|
||||
# highlight the code but not the indentation, which may contain markers
|
||||
# such as "> assert 0"
|
||||
indents = []
|
||||
source_lines = []
|
||||
for line in self.lines:
|
||||
if not is_fail(line):
|
||||
indents.append(line[:indent_size])
|
||||
source_lines.append(line[indent_size:])
|
||||
|
||||
tw._write_source(source_lines, indents)
|
||||
|
||||
# failure lines are always completely red and bold
|
||||
for line in (x for x in self.lines if is_fail(x)):
|
||||
tw.line(line, bold=True, red=True)
|
||||
|
||||
def toterminal(self, tw: TerminalWriter) -> None:
|
||||
if self.style == "short":
|
||||
assert self.reprfileloc is not None
|
||||
self.reprfileloc.toterminal(tw)
|
||||
for line in self.lines:
|
||||
red = line.startswith("E ")
|
||||
tw.line(line, bold=True, red=red)
|
||||
self._write_entry_lines(tw)
|
||||
if self.reprlocals:
|
||||
self.reprlocals.toterminal(tw, indent=" " * 8)
|
||||
return
|
||||
|
||||
if self.reprfuncargs:
|
||||
self.reprfuncargs.toterminal(tw)
|
||||
for line in self.lines:
|
||||
red = line.startswith("E ")
|
||||
tw.line(line, bold=True, red=red)
|
||||
|
||||
self._write_entry_lines(tw)
|
||||
|
||||
if self.reprlocals:
|
||||
tw.line("")
|
||||
self.reprlocals.toterminal(tw)
|
||||
|
||||
@@ -1,3 +1,39 @@
|
||||
# Reexport TerminalWriter from here instead of py, to make it easier to
|
||||
# extend or swap our own implementation in the future.
|
||||
from py.io import TerminalWriter as TerminalWriter # noqa: F401
|
||||
from typing import List
|
||||
from typing import Sequence
|
||||
|
||||
from py.io import TerminalWriter as BaseTerminalWriter # noqa: F401
|
||||
|
||||
|
||||
class TerminalWriter(BaseTerminalWriter):
|
||||
def _write_source(self, lines: List[str], indents: Sequence[str] = ()) -> None:
|
||||
"""Write lines of source code possibly highlighted.
|
||||
|
||||
Keeping this private for now because the API is clunky. We should discuss how
|
||||
to evolve the terminal writer so we can have more precise color support, for example
|
||||
being able to write part of a line in one color and the rest in another, and so on.
|
||||
"""
|
||||
if indents and len(indents) != len(lines):
|
||||
raise ValueError(
|
||||
"indents size ({}) should have same size as lines ({})".format(
|
||||
len(indents), len(lines)
|
||||
)
|
||||
)
|
||||
if not indents:
|
||||
indents = [""] * len(lines)
|
||||
source = "\n".join(lines)
|
||||
new_lines = self._highlight(source).splitlines()
|
||||
for indent, new_line in zip(indents, new_lines):
|
||||
self.line(indent + new_line)
|
||||
|
||||
def _highlight(self, source):
|
||||
"""Highlight the given source code according to the "code_highlight" option"""
|
||||
if not self.hasmarkup:
|
||||
return source
|
||||
try:
|
||||
from pygments.formatters.terminal import TerminalFormatter
|
||||
from pygments.lexers.python import PythonLexer
|
||||
from pygments import highlight
|
||||
except ImportError:
|
||||
return source
|
||||
else:
|
||||
return highlight(source, PythonLexer(), TerminalFormatter(bg="dark"))
|
||||
|
||||
Reference in New Issue
Block a user