Migrate to py3 style type annotation: sphinx.util.logging

This commit is contained in:
Takeshi KOMIYA 2019-04-19 13:22:17 +09:00
parent d59e362f5f
commit 47d9035bca

View File

@ -12,8 +12,10 @@ import logging
import logging.handlers import logging.handlers
from collections import defaultdict from collections import defaultdict
from contextlib import contextmanager from contextlib import contextmanager
from typing import Any, Dict, Generator, IO, List, Tuple, Type, Union
from docutils import nodes from docutils import nodes
from docutils.nodes import Node
from docutils.utils import get_source_line from docutils.utils import get_source_line
from sphinx.errors import SphinxWarning from sphinx.errors import SphinxWarning
@ -21,8 +23,7 @@ from sphinx.util.console import colorize
if False: if False:
# For type annotation # For type annotation
from typing import Any, Dict, Generator, IO, List, Tuple, Type, Union # NOQA from sphinx.application import Sphinx
from sphinx.application import Sphinx # NOQA
NAMESPACE = 'sphinx' NAMESPACE = 'sphinx'
@ -54,8 +55,7 @@ COLOR_MAP = defaultdict(lambda: 'blue',
}) })
def getLogger(name): def getLogger(name: str) -> "SphinxLoggerAdapter":
# type: (str) -> SphinxLoggerAdapter
"""Get logger wrapped by :class:`sphinx.util.logging.SphinxLoggerAdapter`. """Get logger wrapped by :class:`sphinx.util.logging.SphinxLoggerAdapter`.
Sphinx logger always uses ``sphinx.*`` namespace to be independent from Sphinx logger always uses ``sphinx.*`` namespace to be independent from
@ -77,8 +77,7 @@ def getLogger(name):
return SphinxLoggerAdapter(logger, {}) return SphinxLoggerAdapter(logger, {})
def convert_serializable(records): def convert_serializable(records: List[logging.LogRecord]) -> None:
# type: (List[logging.LogRecord]) -> None
"""Convert LogRecord serializable.""" """Convert LogRecord serializable."""
for r in records: for r in records:
# extract arguments to a message and clear them # extract arguments to a message and clear them
@ -95,8 +94,7 @@ class SphinxLogRecord(logging.LogRecord):
prefix = '' prefix = ''
location = None # type: Any location = None # type: Any
def getMessage(self): def getMessage(self) -> str:
# type: () -> str
message = super().getMessage() message = super().getMessage()
location = getattr(self, 'location', None) location = getattr(self, 'location', None)
if location: if location:
@ -120,20 +118,17 @@ class SphinxWarningLogRecord(SphinxLogRecord):
class SphinxLoggerAdapter(logging.LoggerAdapter): class SphinxLoggerAdapter(logging.LoggerAdapter):
"""LoggerAdapter allowing ``type`` and ``subtype`` keywords.""" """LoggerAdapter allowing ``type`` and ``subtype`` keywords."""
def log(self, level, msg, *args, **kwargs): def log(self, level: Union[int, str], msg: str, *args, **kwargs) -> None:
# type: (Union[int, str], str, Any, Any) -> None
if isinstance(level, int): if isinstance(level, int):
super().log(level, msg, *args, **kwargs) super().log(level, msg, *args, **kwargs)
else: else:
levelno = LEVEL_NAMES[level] levelno = LEVEL_NAMES[level]
super().log(levelno, msg, *args, **kwargs) super().log(levelno, msg, *args, **kwargs)
def verbose(self, msg, *args, **kwargs): def verbose(self, msg: str, *args, **kwargs) -> None:
# type: (str, Any, Any) -> None
self.log(VERBOSE, msg, *args, **kwargs) self.log(VERBOSE, msg, *args, **kwargs)
def process(self, msg, kwargs): # type: ignore def process(self, msg: str, kwargs: Dict) -> Tuple[str, Dict]: # type: ignore
# type: (str, Dict) -> Tuple[str, Dict]
extra = kwargs.setdefault('extra', {}) extra = kwargs.setdefault('extra', {})
if 'type' in kwargs: if 'type' in kwargs:
extra['type'] = kwargs.pop('type') extra['type'] = kwargs.pop('type')
@ -148,8 +143,7 @@ class SphinxLoggerAdapter(logging.LoggerAdapter):
return msg, kwargs return msg, kwargs
def handle(self, record): def handle(self, record: logging.LogRecord) -> None:
# type: (logging.LogRecord) -> None
self.logger.handle(record) self.logger.handle(record)
@ -161,8 +155,7 @@ class WarningStreamHandler(logging.StreamHandler):
class NewLineStreamHandler(logging.StreamHandler): class NewLineStreamHandler(logging.StreamHandler):
"""StreamHandler which switches line terminator by record.nonl flag.""" """StreamHandler which switches line terminator by record.nonl flag."""
def emit(self, record): def emit(self, record: logging.LogRecord) -> None:
# type: (logging.LogRecord) -> None
try: try:
self.acquire() self.acquire()
if getattr(record, 'nonl', False): if getattr(record, 'nonl', False):
@ -177,16 +170,13 @@ class NewLineStreamHandler(logging.StreamHandler):
class MemoryHandler(logging.handlers.BufferingHandler): class MemoryHandler(logging.handlers.BufferingHandler):
"""Handler buffering all logs.""" """Handler buffering all logs."""
def __init__(self): def __init__(self) -> None:
# type: () -> None
super().__init__(-1) super().__init__(-1)
def shouldFlush(self, record): def shouldFlush(self, record: logging.LogRecord) -> bool:
# type: (logging.LogRecord) -> bool
return False # never flush return False # never flush
def flushTo(self, logger): def flushTo(self, logger: logging.Logger) -> None:
# type: (logging.Logger) -> None
self.acquire() self.acquire()
try: try:
for record in self.buffer: for record in self.buffer:
@ -195,15 +185,13 @@ class MemoryHandler(logging.handlers.BufferingHandler):
finally: finally:
self.release() self.release()
def clear(self): def clear(self) -> List[logging.LogRecord]:
# type: () -> List[logging.LogRecord]
buffer, self.buffer = self.buffer, [] buffer, self.buffer = self.buffer, []
return buffer return buffer
@contextmanager @contextmanager
def pending_warnings(): def pending_warnings() -> Generator[logging.Handler, None, None]:
# type: () -> Generator
"""Contextmanager to pend logging warnings temporary. """Contextmanager to pend logging warnings temporary.
Similar to :func:`pending_logging`. Similar to :func:`pending_logging`.
@ -231,8 +219,7 @@ def pending_warnings():
@contextmanager @contextmanager
def pending_logging(): def pending_logging() -> Generator[MemoryHandler, None, None]:
# type: () -> Generator
"""Contextmanager to pend logging all logs temporary. """Contextmanager to pend logging all logs temporary.
For example:: For example::
@ -264,8 +251,7 @@ def pending_logging():
@contextmanager @contextmanager
def skip_warningiserror(skip=True): def skip_warningiserror(skip: bool = True) -> Generator[None, None, None]:
# type: (bool) -> Generator
"""contextmanager to skip WarningIsErrorFilter for a while.""" """contextmanager to skip WarningIsErrorFilter for a while."""
logger = logging.getLogger(NAMESPACE) logger = logging.getLogger(NAMESPACE)
@ -285,8 +271,7 @@ def skip_warningiserror(skip=True):
@contextmanager @contextmanager
def prefixed_warnings(prefix): def prefixed_warnings(prefix: str) -> Generator[None, None, None]:
# type: (str) -> Generator
"""Prepend prefix to all records for a while. """Prepend prefix to all records for a while.
For example:: For example::
@ -332,13 +317,11 @@ def prefixed_warnings(prefix):
class LogCollector: class LogCollector:
def __init__(self): def __init__(self) -> None:
# type: () -> None
self.logs = [] # type: List[logging.LogRecord] self.logs = [] # type: List[logging.LogRecord]
@contextmanager @contextmanager
def collect(self): def collect(self) -> Generator[None, None, None]:
# type: () -> Generator
with pending_logging() as memhandler: with pending_logging() as memhandler:
yield yield
@ -348,16 +331,14 @@ class LogCollector:
class InfoFilter(logging.Filter): class InfoFilter(logging.Filter):
"""Filter error and warning messages.""" """Filter error and warning messages."""
def filter(self, record): def filter(self, record: logging.LogRecord) -> bool:
# type: (logging.LogRecord) -> bool
if record.levelno < logging.WARNING: if record.levelno < logging.WARNING:
return True return True
else: else:
return False return False
def is_suppressed_warning(type, subtype, suppress_warnings): def is_suppressed_warning(type: str, subtype: str, suppress_warnings: List[str]) -> bool:
# type: (str, str, List[str]) -> bool
"""Check the warning is suppressed or not.""" """Check the warning is suppressed or not."""
if type is None: if type is None:
return False return False
@ -379,13 +360,11 @@ def is_suppressed_warning(type, subtype, suppress_warnings):
class WarningSuppressor(logging.Filter): class WarningSuppressor(logging.Filter):
"""Filter logs by `suppress_warnings`.""" """Filter logs by `suppress_warnings`."""
def __init__(self, app): def __init__(self, app: "Sphinx") -> None:
# type: (Sphinx) -> None
self.app = app self.app = app
super().__init__() super().__init__()
def filter(self, record): def filter(self, record: logging.LogRecord) -> bool:
# type: (logging.LogRecord) -> bool
type = getattr(record, 'type', None) type = getattr(record, 'type', None)
subtype = getattr(record, 'subtype', None) subtype = getattr(record, 'subtype', None)
@ -405,13 +384,11 @@ class WarningSuppressor(logging.Filter):
class WarningIsErrorFilter(logging.Filter): class WarningIsErrorFilter(logging.Filter):
"""Raise exception if warning emitted.""" """Raise exception if warning emitted."""
def __init__(self, app): def __init__(self, app: "Sphinx") -> None:
# type: (Sphinx) -> None
self.app = app self.app = app
super().__init__() super().__init__()
def filter(self, record): def filter(self, record: logging.LogRecord) -> bool:
# type: (logging.LogRecord) -> bool
if getattr(record, 'skip_warningsiserror', False): if getattr(record, 'skip_warningsiserror', False):
# disabled by DisableWarningIsErrorFilter # disabled by DisableWarningIsErrorFilter
return True return True
@ -433,8 +410,7 @@ class WarningIsErrorFilter(logging.Filter):
class DisableWarningIsErrorFilter(logging.Filter): class DisableWarningIsErrorFilter(logging.Filter):
"""Disable WarningIsErrorFilter if this filter installed.""" """Disable WarningIsErrorFilter if this filter installed."""
def filter(self, record): def filter(self, record: logging.LogRecord) -> bool:
# type: (logging.LogRecord) -> bool
record.skip_warningsiserror = True # type: ignore record.skip_warningsiserror = True # type: ignore
return True return True
@ -442,13 +418,11 @@ class DisableWarningIsErrorFilter(logging.Filter):
class MessagePrefixFilter(logging.Filter): class MessagePrefixFilter(logging.Filter):
"""Prepend prefix to all records.""" """Prepend prefix to all records."""
def __init__(self, prefix): def __init__(self, prefix: str) -> None:
# type: (str) -> None
self.prefix = prefix self.prefix = prefix
super().__init__() super().__init__()
def filter(self, record): def filter(self, record: logging.LogRecord) -> bool:
# type: (logging.LogRecord) -> bool
if self.prefix: if self.prefix:
record.msg = self.prefix + ' ' + record.msg record.msg = self.prefix + ' ' + record.msg
return True return True
@ -462,13 +436,11 @@ class SphinxLogRecordTranslator(logging.Filter):
""" """
LogRecordClass = None # type: Type[logging.LogRecord] LogRecordClass = None # type: Type[logging.LogRecord]
def __init__(self, app): def __init__(self, app: "Sphinx") -> None:
# type: (Sphinx) -> None
self.app = app self.app = app
super().__init__() super().__init__()
def filter(self, record): # type: ignore def filter(self, record: SphinxWarningLogRecord) -> bool: # type: ignore
# type: (SphinxWarningLogRecord) -> bool
if isinstance(record, logging.LogRecord): if isinstance(record, logging.LogRecord):
# force subclassing to handle location # force subclassing to handle location
record.__class__ = self.LogRecordClass # type: ignore record.__class__ = self.LogRecordClass # type: ignore
@ -500,8 +472,7 @@ class WarningLogRecordTranslator(SphinxLogRecordTranslator):
LogRecordClass = SphinxWarningLogRecord LogRecordClass = SphinxWarningLogRecord
def get_node_location(node): def get_node_location(node: Node) -> str:
# type: (nodes.Node) -> str
(source, line) = get_source_line(node) (source, line) = get_source_line(node)
if source and line: if source and line:
return "%s:%s" % (source, line) return "%s:%s" % (source, line)
@ -514,8 +485,7 @@ def get_node_location(node):
class ColorizeFormatter(logging.Formatter): class ColorizeFormatter(logging.Formatter):
def format(self, record): def format(self, record: logging.LogRecord) -> str:
# type: (logging.LogRecord) -> str
message = super().format(record) message = super().format(record)
color = getattr(record, 'color', None) color = getattr(record, 'color', None)
if color is None: if color is None:
@ -529,13 +499,11 @@ class ColorizeFormatter(logging.Formatter):
class SafeEncodingWriter: class SafeEncodingWriter:
"""Stream writer which ignores UnicodeEncodeError silently""" """Stream writer which ignores UnicodeEncodeError silently"""
def __init__(self, stream): def __init__(self, stream: IO) -> None:
# type: (IO) -> None
self.stream = stream self.stream = stream
self.encoding = getattr(stream, 'encoding', 'ascii') or 'ascii' self.encoding = getattr(stream, 'encoding', 'ascii') or 'ascii'
def write(self, data): def write(self, data: str) -> None:
# type: (str) -> None
try: try:
self.stream.write(data) self.stream.write(data)
except UnicodeEncodeError: except UnicodeEncodeError:
@ -543,25 +511,21 @@ class SafeEncodingWriter:
# non-encodable characters, then decode them. # non-encodable characters, then decode them.
self.stream.write(data.encode(self.encoding, 'replace').decode(self.encoding)) self.stream.write(data.encode(self.encoding, 'replace').decode(self.encoding))
def flush(self): def flush(self) -> None:
# type: () -> None
if hasattr(self.stream, 'flush'): if hasattr(self.stream, 'flush'):
self.stream.flush() self.stream.flush()
class LastMessagesWriter: class LastMessagesWriter:
"""Stream writer which memories last 10 messages to save trackback""" """Stream writer which memories last 10 messages to save trackback"""
def __init__(self, app, stream): def __init__(self, app: "Sphinx", stream: IO) -> None:
# type: (Sphinx, IO) -> None
self.app = app self.app = app
def write(self, data): def write(self, data: str) -> None:
# type: (str) -> None
self.app.messagelog.append(data) self.app.messagelog.append(data)
def setup(app, status, warning): def setup(app: "Sphinx", status: IO, warning: IO) -> None:
# type: (Sphinx, IO, IO) -> None
"""Setup root logger for Sphinx""" """Setup root logger for Sphinx"""
logger = logging.getLogger(NAMESPACE) logger = logging.getLogger(NAMESPACE)
logger.setLevel(logging.DEBUG) logger.setLevel(logging.DEBUG)