mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Strip ANSI control codes when writing to the warnings file (#11624)
Co-authored-by: Adam Turner <9087854+aa-turner@users.noreply.github.com>
This commit is contained in:
parent
b935915c57
commit
5fe0bd41eb
@ -20,6 +20,9 @@ Bugs fixed
|
||||
Patch by Vinay Sajip.
|
||||
* #11622: Ensure that the order of keys in ``searchindex.js`` is deterministic.
|
||||
Patch by Pietro Albini.
|
||||
* #11617: ANSI control sequences are stripped from the output when writing to
|
||||
a warnings file with :option:`-w <sphinx-build -w>`.
|
||||
Patch by Bénédikt Tran.
|
||||
|
||||
Testing
|
||||
-------
|
||||
|
@ -195,6 +195,10 @@ Options
|
||||
|
||||
Write warnings (and errors) to the given file, in addition to standard error.
|
||||
|
||||
.. versionchanged:: 7.3
|
||||
|
||||
ANSI control sequences are stripped when writing to *file*.
|
||||
|
||||
.. option:: -W
|
||||
|
||||
Turn warnings into errors. This means that the build stops at the first
|
||||
|
@ -21,7 +21,7 @@ from sphinx import __display_version__
|
||||
from sphinx.application import Sphinx
|
||||
from sphinx.errors import SphinxError, SphinxParallelError
|
||||
from sphinx.locale import __
|
||||
from sphinx.util import Tee
|
||||
from sphinx.util._io import TeeStripANSI
|
||||
from sphinx.util.console import ( # type: ignore[attr-defined]
|
||||
color_terminal,
|
||||
nocolor,
|
||||
@ -34,6 +34,11 @@ from sphinx.util.osutil import ensuredir
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from collections.abc import Sequence
|
||||
from typing import Protocol
|
||||
|
||||
class SupportsWrite(Protocol):
|
||||
def write(self, text: str, /) -> int | None:
|
||||
...
|
||||
|
||||
|
||||
def handle_exception(
|
||||
@ -266,11 +271,12 @@ def _parse_logging(
|
||||
try:
|
||||
warnfile = path.abspath(warnfile)
|
||||
ensuredir(path.dirname(warnfile))
|
||||
# the caller is responsible for closing this file descriptor
|
||||
warnfp = open(warnfile, 'w', encoding="utf-8") # NoQA: SIM115
|
||||
except Exception as exc:
|
||||
parser.error(__('cannot open warning file %r: %s') % (
|
||||
warnfile, exc))
|
||||
warning = Tee(warning, warnfp) # type: ignore[assignment]
|
||||
warning = TeeStripANSI(warning, warnfp) # type: ignore[assignment]
|
||||
error = warning
|
||||
|
||||
return status, warning, error, warnfp
|
||||
@ -334,6 +340,10 @@ def build_main(argv: Sequence[str]) -> int:
|
||||
except (Exception, KeyboardInterrupt) as exc:
|
||||
handle_exception(app, args, exc, args.error)
|
||||
return 2
|
||||
finally:
|
||||
if warnfp is not None:
|
||||
# close the file descriptor for the warnings file opened by Sphinx
|
||||
warnfp.close()
|
||||
|
||||
|
||||
def _bug_report_info() -> int:
|
||||
|
@ -1,3 +1,5 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from sphinx.util.console import _strip_escape_sequences
|
||||
@ -6,7 +8,7 @@ if TYPE_CHECKING:
|
||||
from typing import Protocol
|
||||
|
||||
class SupportsWrite(Protocol):
|
||||
def write(self, text: str, /) -> None:
|
||||
def write(self, text: str, /) -> int | None:
|
||||
...
|
||||
|
||||
|
||||
|
@ -2,11 +2,14 @@
|
||||
|
||||
import os
|
||||
import shutil
|
||||
from contextlib import contextmanager
|
||||
from pathlib import Path
|
||||
from unittest import mock
|
||||
|
||||
import pytest
|
||||
from docutils import nodes
|
||||
|
||||
from sphinx.cmd.build import build_main
|
||||
from sphinx.errors import SphinxError
|
||||
|
||||
|
||||
@ -133,3 +136,29 @@ def test_image_glob(app, status, warning):
|
||||
assert doctree[0][3][0]['candidates'] == {'application/pdf': 'subdir/svgimg.pdf',
|
||||
'image/svg+xml': 'subdir/svgimg.svg'}
|
||||
assert doctree[0][3][0]['uri'] == 'subdir/svgimg.*'
|
||||
|
||||
|
||||
@contextmanager
|
||||
def force_colors():
|
||||
forcecolor = os.environ.get('FORCE_COLOR', None)
|
||||
|
||||
try:
|
||||
os.environ['FORCE_COLOR'] = '1'
|
||||
yield
|
||||
finally:
|
||||
if forcecolor is None:
|
||||
os.environ.pop('FORCE_COLOR', None)
|
||||
else:
|
||||
os.environ['FORCE_COLOR'] = forcecolor
|
||||
|
||||
|
||||
def test_log_no_ansi_colors(tmp_path):
|
||||
with force_colors():
|
||||
wfile = tmp_path / 'warnings.txt'
|
||||
srcdir = Path(__file__).parent / 'roots/test-nitpicky-warnings'
|
||||
argv = list(map(str, ['-b', 'html', srcdir, tmp_path, '-n', '-w', wfile]))
|
||||
retcode = build_main(argv)
|
||||
assert retcode == 0
|
||||
|
||||
content = wfile.read_text(encoding='utf8')
|
||||
assert '\x1b[91m' not in content
|
||||
|
Loading…
Reference in New Issue
Block a user