mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2026-10-26 07:00:14 -05:00
Merge pull request #7351 from tk0miya/7324_multiple_suffixes_for_same_document
Fix #7324: Emit a warning if multiple files for same document found
This commit is contained in:
4 files changed
+46
-11
No files matched your search
@@ -114,6 +114,8 @@ Features added
|
||||
|
||||
* Added ``SphinxDirective.get_source_info()``
|
||||
and ``SphinxRole.get_source_info()``.
|
||||
* #7324: sphinx-build: Emit a warning if multiple files having different file
|
||||
extensions for same document found
|
||||
|
||||
Bugs fixed
|
||||
----------
|
||||
|
||||
+8
-1
@@ -9,6 +9,7 @@
|
||||
"""
|
||||
|
||||
import os
|
||||
from glob import glob
|
||||
|
||||
from sphinx.locale import __
|
||||
from sphinx.util import get_matching_files
|
||||
@@ -55,7 +56,13 @@ class Project:
|
||||
for filename in get_matching_files(self.srcdir, excludes): # type: ignore
|
||||
docname = self.path2doc(filename)
|
||||
if docname:
|
||||
if os.access(os.path.join(self.srcdir, filename), os.R_OK):
|
||||
if docname in self.docnames:
|
||||
pattern = os.path.join(self.srcdir, docname) + '.*'
|
||||
files = [relpath(f, self.srcdir) for f in glob(pattern)]
|
||||
logger.warning(__('multiple files found for the document "%s": %r\n'
|
||||
'Use %r for the build.'),
|
||||
docname, files, self.doc2path(docname), once=True)
|
||||
elif os.access(os.path.join(self.srcdir, filename), os.R_OK):
|
||||
self.docnames.add(docname)
|
||||
else:
|
||||
logger.warning(__("document not readable. Ignored."), location=docname)
|
||||
|
||||
+25
-10
@@ -118,6 +118,7 @@ class SphinxWarningLogRecord(SphinxLogRecord):
|
||||
|
||||
class SphinxLoggerAdapter(logging.LoggerAdapter):
|
||||
"""LoggerAdapter allowing ``type`` and ``subtype`` keywords."""
|
||||
KEYWORDS = ['type', 'subtype', 'location', 'nonl', 'color', 'once']
|
||||
|
||||
def log(self, level: Union[int, str], msg: str, *args: Any, **kwargs: Any) -> None:
|
||||
if isinstance(level, int):
|
||||
@@ -131,16 +132,9 @@ class SphinxLoggerAdapter(logging.LoggerAdapter):
|
||||
|
||||
def process(self, msg: str, kwargs: Dict) -> Tuple[str, Dict]: # type: ignore
|
||||
extra = kwargs.setdefault('extra', {})
|
||||
if 'type' in kwargs:
|
||||
extra['type'] = kwargs.pop('type')
|
||||
if 'subtype' in kwargs:
|
||||
extra['subtype'] = kwargs.pop('subtype')
|
||||
if 'location' in kwargs:
|
||||
extra['location'] = kwargs.pop('location')
|
||||
if 'nonl' in kwargs:
|
||||
extra['nonl'] = kwargs.pop('nonl')
|
||||
if 'color' in kwargs:
|
||||
extra['color'] = kwargs.pop('color')
|
||||
for keyword in self.KEYWORDS:
|
||||
if keyword in kwargs:
|
||||
extra[keyword] = kwargs.pop(keyword)
|
||||
|
||||
return msg, kwargs
|
||||
|
||||
@@ -446,6 +440,26 @@ class MessagePrefixFilter(logging.Filter):
|
||||
return True
|
||||
|
||||
|
||||
class OnceFilter(logging.Filter):
|
||||
"""Show the message only once."""
|
||||
|
||||
def __init__(self, name: str = '') -> None:
|
||||
super().__init__(name)
|
||||
self.messages = {} # type: Dict[str, List]
|
||||
|
||||
def filter(self, record: logging.LogRecord) -> bool:
|
||||
once = getattr(record, 'once', '')
|
||||
if not once:
|
||||
return True
|
||||
else:
|
||||
params = self.messages.setdefault(record.msg, [])
|
||||
if record.args in params:
|
||||
return False
|
||||
|
||||
params.append(record.args)
|
||||
return True
|
||||
|
||||
|
||||
class SphinxLogRecordTranslator(logging.Filter):
|
||||
"""Converts a log record to one Sphinx expects
|
||||
|
||||
@@ -563,6 +577,7 @@ def setup(app: "Sphinx", status: IO, warning: IO) -> None:
|
||||
warning_handler.addFilter(WarningSuppressor(app))
|
||||
warning_handler.addFilter(WarningLogRecordTranslator(app))
|
||||
warning_handler.addFilter(WarningIsErrorFilter(app))
|
||||
warning_handler.addFilter(OnceFilter())
|
||||
warning_handler.setLevel(logging.WARNING)
|
||||
warning_handler.setFormatter(ColorizeFormatter())
|
||||
|
||||
|
||||
@@ -103,6 +103,17 @@ def test_nonl_info_log(app, status, warning):
|
||||
assert 'message1message2\nmessage3' in status.getvalue()
|
||||
|
||||
|
||||
def test_once_warning_log(app, status, warning):
|
||||
logging.setup(app, status, warning)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
logger.warning('message: %d', 1, once=True)
|
||||
logger.warning('message: %d', 1, once=True)
|
||||
logger.warning('message: %d', 2, once=True)
|
||||
|
||||
assert 'WARNING: message: 1\nWARNING: message: 2\n' in strip_escseq(warning.getvalue())
|
||||
|
||||
|
||||
def test_is_suppressed_warning():
|
||||
suppress_warnings = ["ref", "files.*", "rest.duplicated_labels"]
|
||||
|
||||
|
||||
Reference in new issue
Block a user