Undo log level set by caplog.set_level at the end of the test
Otherwise this leaks the log level information to other tests Ref: #3013
This commit is contained in:
parent
8dcd2718aa
commit
aca1b06747
|
@ -129,6 +129,17 @@ class LogCaptureFixture(object):
|
||||||
def __init__(self, item):
|
def __init__(self, item):
|
||||||
"""Creates a new funcarg."""
|
"""Creates a new funcarg."""
|
||||||
self._item = item
|
self._item = item
|
||||||
|
self._initial_log_levels = {} # type: Dict[str, int] # dict of log name -> log level
|
||||||
|
|
||||||
|
def _finalize(self):
|
||||||
|
"""Finalizes the fixture.
|
||||||
|
|
||||||
|
This restores the log levels changed by :meth:`set_level`.
|
||||||
|
"""
|
||||||
|
# restore log levels
|
||||||
|
for logger_name, level in self._initial_log_levels.items():
|
||||||
|
logger = logging.getLogger(logger_name)
|
||||||
|
logger.setLevel(level)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def handler(self):
|
def handler(self):
|
||||||
|
@ -167,27 +178,30 @@ class LogCaptureFixture(object):
|
||||||
self.handler.records = []
|
self.handler.records = []
|
||||||
|
|
||||||
def set_level(self, level, logger=None):
|
def set_level(self, level, logger=None):
|
||||||
"""Sets the level for capturing of logs.
|
"""Sets the level for capturing of logs. The level will be restored to its previous value at the end of
|
||||||
|
the test.
|
||||||
|
|
||||||
|
:param int level: the logger to level.
|
||||||
|
:param str logger: the logger to update the level. If not given, the root logger level is updated.
|
||||||
|
|
||||||
|
.. versionchanged:: 3.4
|
||||||
|
The levels of the loggers changed by this function will be restored to their initial values at the
|
||||||
|
end of the test.
|
||||||
|
"""
|
||||||
|
logger_name = logger
|
||||||
|
logger = logging.getLogger(logger_name)
|
||||||
|
self._initial_log_levels.setdefault(logger_name, logger.level)
|
||||||
|
logger.setLevel(level)
|
||||||
|
|
||||||
|
@contextmanager
|
||||||
|
def at_level(self, level, logger=None):
|
||||||
|
"""Context manager that sets the level for capturing of logs. After the end of the 'with' statement the
|
||||||
|
level is restored to its original value.
|
||||||
|
|
||||||
:param int level: the logger to level.
|
:param int level: the logger to level.
|
||||||
:param str logger: the logger to update the level. If not given, the root logger level is updated.
|
:param str logger: the logger to update the level. If not given, the root logger level is updated.
|
||||||
"""
|
"""
|
||||||
logger = logging.getLogger(logger)
|
logger = logging.getLogger(logger)
|
||||||
logger.setLevel(level)
|
|
||||||
|
|
||||||
@contextmanager
|
|
||||||
def at_level(self, level, logger=None):
|
|
||||||
"""Context manager that sets the level for capturing of logs.
|
|
||||||
|
|
||||||
By default, the level is set on the handler used to capture
|
|
||||||
logs. Specify a logger name to instead set the level of any
|
|
||||||
logger.
|
|
||||||
"""
|
|
||||||
if logger is None:
|
|
||||||
logger = self.handler
|
|
||||||
else:
|
|
||||||
logger = logging.getLogger(logger)
|
|
||||||
|
|
||||||
orig_level = logger.level
|
orig_level = logger.level
|
||||||
logger.setLevel(level)
|
logger.setLevel(level)
|
||||||
try:
|
try:
|
||||||
|
@ -206,7 +220,9 @@ def caplog(request):
|
||||||
* caplog.records() -> list of logging.LogRecord instances
|
* caplog.records() -> list of logging.LogRecord instances
|
||||||
* caplog.record_tuples() -> list of (logger_name, level, message) tuples
|
* caplog.record_tuples() -> list of (logger_name, level, message) tuples
|
||||||
"""
|
"""
|
||||||
return LogCaptureFixture(request.node)
|
result = LogCaptureFixture(request.node)
|
||||||
|
yield result
|
||||||
|
result._finalize()
|
||||||
|
|
||||||
|
|
||||||
def get_actual_log_level(config, *setting_names):
|
def get_actual_log_level(config, *setting_names):
|
||||||
|
|
|
@ -27,6 +27,30 @@ def test_change_level(caplog):
|
||||||
assert 'CRITICAL' in caplog.text
|
assert 'CRITICAL' in caplog.text
|
||||||
|
|
||||||
|
|
||||||
|
def test_change_level_undo(testdir):
|
||||||
|
"""Ensure that 'set_level' is undone after the end of the test"""
|
||||||
|
testdir.makepyfile('''
|
||||||
|
import logging
|
||||||
|
|
||||||
|
def test1(caplog):
|
||||||
|
caplog.set_level(logging.INFO)
|
||||||
|
# using + operator here so fnmatch_lines doesn't match the code in the traceback
|
||||||
|
logging.info('log from ' + 'test1')
|
||||||
|
assert 0
|
||||||
|
|
||||||
|
def test2(caplog):
|
||||||
|
# using + operator here so fnmatch_lines doesn't match the code in the traceback
|
||||||
|
logging.info('log from ' + 'test2')
|
||||||
|
assert 0
|
||||||
|
''')
|
||||||
|
result = testdir.runpytest_subprocess()
|
||||||
|
result.stdout.fnmatch_lines([
|
||||||
|
'*log from test1*',
|
||||||
|
'*2 failed in *',
|
||||||
|
])
|
||||||
|
assert 'log from test2' not in result.stdout.str()
|
||||||
|
|
||||||
|
|
||||||
def test_with_statement(caplog):
|
def test_with_statement(caplog):
|
||||||
with caplog.at_level(logging.INFO):
|
with caplog.at_level(logging.INFO):
|
||||||
logger.debug('handler DEBUG level')
|
logger.debug('handler DEBUG level')
|
||||||
|
@ -43,6 +67,7 @@ def test_with_statement(caplog):
|
||||||
|
|
||||||
|
|
||||||
def test_log_access(caplog):
|
def test_log_access(caplog):
|
||||||
|
caplog.set_level(logging.INFO)
|
||||||
logger.info('boo %s', 'arg')
|
logger.info('boo %s', 'arg')
|
||||||
assert caplog.records[0].levelname == 'INFO'
|
assert caplog.records[0].levelname == 'INFO'
|
||||||
assert caplog.records[0].msg == 'boo %s'
|
assert caplog.records[0].msg == 'boo %s'
|
||||||
|
@ -50,6 +75,7 @@ def test_log_access(caplog):
|
||||||
|
|
||||||
|
|
||||||
def test_record_tuples(caplog):
|
def test_record_tuples(caplog):
|
||||||
|
caplog.set_level(logging.INFO)
|
||||||
logger.info('boo %s', 'arg')
|
logger.info('boo %s', 'arg')
|
||||||
|
|
||||||
assert caplog.record_tuples == [
|
assert caplog.record_tuples == [
|
||||||
|
@ -58,6 +84,7 @@ def test_record_tuples(caplog):
|
||||||
|
|
||||||
|
|
||||||
def test_unicode(caplog):
|
def test_unicode(caplog):
|
||||||
|
caplog.set_level(logging.INFO)
|
||||||
logger.info(u'bū')
|
logger.info(u'bū')
|
||||||
assert caplog.records[0].levelname == 'INFO'
|
assert caplog.records[0].levelname == 'INFO'
|
||||||
assert caplog.records[0].msg == u'bū'
|
assert caplog.records[0].msg == u'bū'
|
||||||
|
@ -65,6 +92,7 @@ def test_unicode(caplog):
|
||||||
|
|
||||||
|
|
||||||
def test_clear(caplog):
|
def test_clear(caplog):
|
||||||
|
caplog.set_level(logging.INFO)
|
||||||
logger.info(u'bū')
|
logger.info(u'bū')
|
||||||
assert len(caplog.records)
|
assert len(caplog.records)
|
||||||
caplog.clear()
|
caplog.clear()
|
||||||
|
|
Loading…
Reference in New Issue