mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Close #4976: `SphinxLoggerAdapter.info() now supports location` parameter
This commit is contained in:
1
CHANGES
1
CHANGES
@@ -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
|
||||
----------
|
||||
|
||||
@@ -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"``.
|
||||
|
||||
@@ -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())
|
||||
|
||||
|
||||
@@ -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__)
|
||||
|
||||
Reference in New Issue
Block a user