Close #4976: `SphinxLoggerAdapter.info() now supports location` parameter

This commit is contained in:
Takeshi KOMIYA
2018-06-23 14:41:01 +09:00
parent e1201f2779
commit 910be1e2a2
4 changed files with 70 additions and 10 deletions

View File

@@ -143,6 +143,7 @@ Features added
for mathjax
* #4362: latex: Don't overwrite .tex file if document not changed
* #1431: latex: Add alphanumeric enumerated list support
* #4976: ``SphinxLoggerAdapter.info()`` now supports ``location`` parameter
Bugs fixed
----------

View File

@@ -50,6 +50,10 @@ Logging API
If true, the logger does not fold lines at the end of the log message.
The default is ``False``.
**location**
Where the message emitted. For more detail, see
:meth:`SphinxLoggerAdapter.warning`.
**color**
The color of logs. By default, debug level logs are
colored as ``"darkgray"``, and debug2 level ones are ``"lightgray"``.

View File

@@ -24,7 +24,7 @@ from sphinx.util.console import colorize
if False:
# For type annotation
from typing import Any, Dict, Generator, IO, List, Tuple, Union # NOQA
from typing import Any, Dict, Generator, IO, List, Tuple, Type, Union # NOQA
from docutils import nodes # NOQA
from sphinx.application import Sphinx # NOQA
@@ -94,22 +94,33 @@ def convert_serializable(records):
r.location = get_node_location(location) # type: ignore
class SphinxWarningLogRecord(logging.LogRecord):
class SphinxLogRecord(logging.LogRecord):
"""Log record class supporting location"""
prefix = ''
location = None # type: Any
def getMessage(self):
# type: () -> str
message = super(SphinxWarningLogRecord, self).getMessage()
message = super(SphinxLogRecord, self).getMessage()
location = getattr(self, 'location', None)
if location:
message = '%s: WARNING: %s' % (location, message)
elif 'WARNING:' not in message:
message = 'WARNING: %s' % message
message = '%s: %s%s' % (location, self.prefix, message)
elif self.prefix not in message:
message = self.prefix + message
return message
class SphinxInfoLogRecord(SphinxLogRecord):
"""Info log record class supporting location"""
prefix = '' # do not show any prefix for INFO messages
class SphinxWarningLogRecord(SphinxLogRecord):
"""Warning log record class supporting location"""
prefix = 'WARNING: '
class SphinxLoggerAdapter(logging.LoggerAdapter):
"""LoggerAdapter allowing ``type`` and ``subtype`` keywords."""
@@ -412,21 +423,23 @@ class DisableWarningIsErrorFilter(logging.Filter):
return True
class WarningLogRecordTranslator(logging.Filter):
class SphinxLogRecordTranslator(logging.Filter):
"""Converts a log record to one Sphinx expects
* Make a instance of SphinxWarningLogRecord
* Make a instance of SphinxLogRecord
* docname to path if location given
"""
LogRecordClass = None # type: Type[logging.LogRecord]
def __init__(self, app):
# type: (Sphinx) -> None
self.app = app
super(WarningLogRecordTranslator, self).__init__()
super(SphinxLogRecordTranslator, self).__init__()
def filter(self, record): # type: ignore
# type: (SphinxWarningLogRecord) -> bool
if isinstance(record, logging.LogRecord):
record.__class__ = SphinxWarningLogRecord # force subclassing to handle location
record.__class__ = self.LogRecordClass # force subclassing to handle location
location = getattr(record, 'location', None)
if isinstance(location, tuple):
@@ -445,6 +458,16 @@ class WarningLogRecordTranslator(logging.Filter):
return True
class InfoLogRecordTranslator(SphinxLogRecordTranslator):
"""LogRecordTranslator for INFO level log records."""
LogRecordClass = SphinxInfoLogRecord
class WarningLogRecordTranslator(SphinxLogRecordTranslator):
"""LogRecordTranslator for WARNING level log records."""
LogRecordClass = SphinxWarningLogRecord
def get_node_location(node):
# type: (nodes.Node) -> str
(source, line) = get_source_line(node)
@@ -518,6 +541,7 @@ def setup(app, status, warning):
info_handler = NewLineStreamHandler(SafeEncodingWriter(status)) # type: ignore
info_handler.addFilter(InfoFilter())
info_handler.addFilter(InfoLogRecordTranslator(app))
info_handler.setLevel(VERBOSITY_MAP[app.verbosity])
info_handler.setFormatter(ColorizeFormatter())

View File

@@ -171,6 +171,37 @@ def test_warningiserror(app, status, warning):
logger.warning('%s')
def test_info_location(app, status, warning):
logging.setup(app, status, warning)
logger = logging.getLogger(__name__)
logger.info('message1', location='index')
assert 'index.txt: message1' in status.getvalue()
logger.info('message2', location=('index', 10))
assert 'index.txt:10: message2' in status.getvalue()
logger.info('message3', location=None)
assert '\nmessage3' in status.getvalue()
node = nodes.Node()
node.source, node.line = ('index.txt', 10)
logger.info('message4', location=node)
assert 'index.txt:10: message4' in status.getvalue()
node.source, node.line = ('index.txt', None)
logger.info('message5', location=node)
assert 'index.txt:: message5' in status.getvalue()
node.source, node.line = (None, 10)
logger.info('message6', location=node)
assert '<unknown>:10: message6' in status.getvalue()
node.source, node.line = (None, None)
logger.info('message7', location=node)
assert '\nmessage7' in status.getvalue()
def test_warning_location(app, status, warning):
logging.setup(app, status, warning)
logger = logging.getLogger(__name__)