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.
|
Patch by Vinay Sajip.
|
||||||
* #11622: Ensure that the order of keys in ``searchindex.js`` is deterministic.
|
* #11622: Ensure that the order of keys in ``searchindex.js`` is deterministic.
|
||||||
Patch by Pietro Albini.
|
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
|
Testing
|
||||||
-------
|
-------
|
||||||
|
@ -195,6 +195,10 @@ Options
|
|||||||
|
|
||||||
Write warnings (and errors) to the given file, in addition to standard error.
|
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
|
.. option:: -W
|
||||||
|
|
||||||
Turn warnings into errors. This means that the build stops at the first
|
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.application import Sphinx
|
||||||
from sphinx.errors import SphinxError, SphinxParallelError
|
from sphinx.errors import SphinxError, SphinxParallelError
|
||||||
from sphinx.locale import __
|
from sphinx.locale import __
|
||||||
from sphinx.util import Tee
|
from sphinx.util._io import TeeStripANSI
|
||||||
from sphinx.util.console import ( # type: ignore[attr-defined]
|
from sphinx.util.console import ( # type: ignore[attr-defined]
|
||||||
color_terminal,
|
color_terminal,
|
||||||
nocolor,
|
nocolor,
|
||||||
@ -34,6 +34,11 @@ from sphinx.util.osutil import ensuredir
|
|||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from collections.abc import Sequence
|
from collections.abc import Sequence
|
||||||
|
from typing import Protocol
|
||||||
|
|
||||||
|
class SupportsWrite(Protocol):
|
||||||
|
def write(self, text: str, /) -> int | None:
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
def handle_exception(
|
def handle_exception(
|
||||||
@ -266,11 +271,12 @@ def _parse_logging(
|
|||||||
try:
|
try:
|
||||||
warnfile = path.abspath(warnfile)
|
warnfile = path.abspath(warnfile)
|
||||||
ensuredir(path.dirname(warnfile))
|
ensuredir(path.dirname(warnfile))
|
||||||
|
# the caller is responsible for closing this file descriptor
|
||||||
warnfp = open(warnfile, 'w', encoding="utf-8") # NoQA: SIM115
|
warnfp = open(warnfile, 'w', encoding="utf-8") # NoQA: SIM115
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
parser.error(__('cannot open warning file %r: %s') % (
|
parser.error(__('cannot open warning file %r: %s') % (
|
||||||
warnfile, exc))
|
warnfile, exc))
|
||||||
warning = Tee(warning, warnfp) # type: ignore[assignment]
|
warning = TeeStripANSI(warning, warnfp) # type: ignore[assignment]
|
||||||
error = warning
|
error = warning
|
||||||
|
|
||||||
return status, warning, error, warnfp
|
return status, warning, error, warnfp
|
||||||
@ -334,6 +340,10 @@ def build_main(argv: Sequence[str]) -> int:
|
|||||||
except (Exception, KeyboardInterrupt) as exc:
|
except (Exception, KeyboardInterrupt) as exc:
|
||||||
handle_exception(app, args, exc, args.error)
|
handle_exception(app, args, exc, args.error)
|
||||||
return 2
|
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:
|
def _bug_report_info() -> int:
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from sphinx.util.console import _strip_escape_sequences
|
from sphinx.util.console import _strip_escape_sequences
|
||||||
@ -6,7 +8,7 @@ if TYPE_CHECKING:
|
|||||||
from typing import Protocol
|
from typing import Protocol
|
||||||
|
|
||||||
class SupportsWrite(Protocol):
|
class SupportsWrite(Protocol):
|
||||||
def write(self, text: str, /) -> None:
|
def write(self, text: str, /) -> int | None:
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|
||||||
|
@ -2,11 +2,14 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
|
from contextlib import contextmanager
|
||||||
|
from pathlib import Path
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from docutils import nodes
|
from docutils import nodes
|
||||||
|
|
||||||
|
from sphinx.cmd.build import build_main
|
||||||
from sphinx.errors import SphinxError
|
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',
|
assert doctree[0][3][0]['candidates'] == {'application/pdf': 'subdir/svgimg.pdf',
|
||||||
'image/svg+xml': 'subdir/svgimg.svg'}
|
'image/svg+xml': 'subdir/svgimg.svg'}
|
||||||
assert doctree[0][3][0]['uri'] == 'subdir/svgimg.*'
|
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