loggingTools: move here the LastResortLogger from py23
and add a small test
This commit is contained in:
parent
e6a5db543d
commit
d9d30c819a
@ -527,6 +527,67 @@ def deprecateFunction(msg, category=UserWarning):
|
||||
return decorator
|
||||
|
||||
|
||||
class LastResortLogger(logging.Logger):
|
||||
""" Adds support for 'lastResort' handler introduced in Python 3.2.
|
||||
It allows to print messages to sys.stderr even when no explicit handler
|
||||
was configured.
|
||||
To enable it, you can do:
|
||||
|
||||
import logging
|
||||
logging.lastResort = StderrHandler(logging.WARNING)
|
||||
logging.setLoggerClass(LastResortLogger)
|
||||
"""
|
||||
|
||||
def callHandlers(self, record):
|
||||
# this is the same as Python 3.5's logging.Logger.callHandlers
|
||||
c = self
|
||||
found = 0
|
||||
while c:
|
||||
for hdlr in c.handlers:
|
||||
found = found + 1
|
||||
if record.levelno >= hdlr.level:
|
||||
hdlr.handle(record)
|
||||
if not c.propagate:
|
||||
c = None # break out
|
||||
else:
|
||||
c = c.parent
|
||||
if found == 0:
|
||||
if logging.lastResort:
|
||||
if record.levelno >= logging.lastResort.level:
|
||||
logging.lastResort.handle(record)
|
||||
elif (
|
||||
logging.raiseExceptions
|
||||
and not self.manager.emittedNoHandlerWarning
|
||||
):
|
||||
sys.stderr.write(
|
||||
"No handlers could be found for logger"
|
||||
' "%s"\n' % self.name
|
||||
)
|
||||
self.manager.emittedNoHandlerWarning = True
|
||||
|
||||
|
||||
class StderrHandler(logging.StreamHandler):
|
||||
""" This class is like a StreamHandler using sys.stderr, but always uses
|
||||
whateve sys.stderr is currently set to rather than the value of
|
||||
sys.stderr at handler construction time.
|
||||
"""
|
||||
|
||||
def __init__(self, level=logging.NOTSET):
|
||||
"""
|
||||
Initialize the handler.
|
||||
"""
|
||||
logging.Handler.__init__(self, level)
|
||||
|
||||
@property
|
||||
def stream(self):
|
||||
# the try/execept avoids failures during interpreter shutdown, when
|
||||
# globals are set to None
|
||||
try:
|
||||
return sys.stderr
|
||||
except AttributeError:
|
||||
return __import__("sys").stderr
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import doctest
|
||||
sys.exit(doctest.testmod(optionflags=doctest.ELLIPSIS).failed)
|
||||
|
@ -419,56 +419,6 @@ else:
|
||||
round = round3
|
||||
|
||||
|
||||
import logging
|
||||
|
||||
|
||||
class _Logger(logging.Logger):
|
||||
""" Add support for 'lastResort' handler introduced in Python 3.2. """
|
||||
|
||||
def callHandlers(self, record):
|
||||
# this is the same as Python 3.5's logging.Logger.callHandlers
|
||||
c = self
|
||||
found = 0
|
||||
while c:
|
||||
for hdlr in c.handlers:
|
||||
found = found + 1
|
||||
if record.levelno >= hdlr.level:
|
||||
hdlr.handle(record)
|
||||
if not c.propagate:
|
||||
c = None # break out
|
||||
else:
|
||||
c = c.parent
|
||||
if (found == 0):
|
||||
if logging.lastResort:
|
||||
if record.levelno >= logging.lastResort.level:
|
||||
logging.lastResort.handle(record)
|
||||
elif logging.raiseExceptions and not self.manager.emittedNoHandlerWarning:
|
||||
sys.stderr.write("No handlers could be found for logger"
|
||||
" \"%s\"\n" % self.name)
|
||||
self.manager.emittedNoHandlerWarning = True
|
||||
|
||||
|
||||
class _StderrHandler(logging.StreamHandler):
|
||||
""" This class is like a StreamHandler using sys.stderr, but always uses
|
||||
whatever sys.stderr is currently set to rather than the value of
|
||||
sys.stderr at handler construction time.
|
||||
"""
|
||||
def __init__(self, level=logging.NOTSET):
|
||||
"""
|
||||
Initialize the handler.
|
||||
"""
|
||||
logging.Handler.__init__(self, level)
|
||||
|
||||
@property
|
||||
def stream(self):
|
||||
# the try/execept avoids failures during interpreter shutdown, when
|
||||
# globals are set to None
|
||||
try:
|
||||
return sys.stderr
|
||||
except AttributeError:
|
||||
return __import__('sys').stderr
|
||||
|
||||
|
||||
try:
|
||||
from types import SimpleNamespace
|
||||
except ImportError:
|
||||
|
@ -1,11 +1,20 @@
|
||||
from __future__ import print_function, division, absolute_import
|
||||
from fontTools.misc.py23 import *
|
||||
from fontTools.misc.loggingTools import (
|
||||
LevelFormatter, Timer, configLogger, ChannelsFilter, LogMixin)
|
||||
LevelFormatter,
|
||||
Timer,
|
||||
configLogger,
|
||||
ChannelsFilter,
|
||||
LogMixin,
|
||||
StderrHandler,
|
||||
LastResortLogger,
|
||||
_resetExistingLoggers,
|
||||
)
|
||||
import logging
|
||||
import textwrap
|
||||
import time
|
||||
import re
|
||||
import sys
|
||||
import pytest
|
||||
|
||||
|
||||
@ -170,3 +179,32 @@ def test_LogMixin():
|
||||
assert isinstance(b.log, logging.Logger)
|
||||
assert a.log.name == "loggingTools_test.A"
|
||||
assert b.log.name == "loggingTools_test.B"
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.version_info[:2] > (2, 7), reason="only for python2.7")
|
||||
@pytest.mark.parametrize(
|
||||
"reset", [True, False], ids=["reset", "no-reset"]
|
||||
)
|
||||
def test_LastResortLogger(reset, capsys, caplog):
|
||||
current = logging.getLoggerClass()
|
||||
msg = "The quick brown fox jumps over the lazy dog"
|
||||
try:
|
||||
if reset:
|
||||
_resetExistingLoggers()
|
||||
else:
|
||||
caplog.set_level(logging.ERROR, logger="myCustomLogger")
|
||||
logging.lastResort = StderrHandler(logging.WARNING)
|
||||
logging.setLoggerClass(LastResortLogger)
|
||||
logger = logging.getLogger("myCustomLogger")
|
||||
logger.error(msg)
|
||||
finally:
|
||||
del logging.lastResort
|
||||
logging.setLoggerClass(current)
|
||||
|
||||
captured = capsys.readouterr()
|
||||
if reset:
|
||||
assert msg in captured.err
|
||||
msg not in caplog.text
|
||||
else:
|
||||
msg in caplog.text
|
||||
msg not in captured.err
|
||||
|
Loading…
x
Reference in New Issue
Block a user