Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[6.0.x] logging: fix capture handler level not reset on teardown after caplog.set_level() #7573

Merged
merged 1 commit into from Jul 29, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/_pytest/logging.py
Expand Up @@ -345,6 +345,7 @@ def __init__(self, item: nodes.Node) -> None:
"""Creates a new funcarg."""
self._item = item
# dict of log name -> log level
self._initial_handler_level = None # type: Optional[int]
self._initial_logger_levels = {} # type: Dict[Optional[str], int]

def _finalize(self) -> None:
Expand All @@ -353,6 +354,8 @@ def _finalize(self) -> None:
This restores the log levels changed by :meth:`set_level`.
"""
# restore log levels
if self._initial_handler_level is not None:
self.handler.setLevel(self._initial_handler_level)
for logger_name, level in self._initial_logger_levels.items():
logger = logging.getLogger(logger_name)
logger.setLevel(level)
Expand Down Expand Up @@ -434,6 +437,7 @@ def set_level(self, level: Union[int, str], logger: Optional[str] = None) -> Non
# save the original log-level to restore it during teardown
self._initial_logger_levels.setdefault(logger, logger_obj.level)
logger_obj.setLevel(level)
self._initial_handler_level = self.handler.level
self.handler.setLevel(level)

@contextmanager
Expand Down
35 changes: 33 additions & 2 deletions testing/logging/test_fixture.py
Expand Up @@ -2,6 +2,7 @@

import pytest
from _pytest.logging import caplog_records_key
from _pytest.pytester import Testdir

logger = logging.getLogger(__name__)
sublogger = logging.getLogger(__name__ + ".baz")
Expand All @@ -27,8 +28,11 @@ def test_change_level(caplog):
assert "CRITICAL" in caplog.text


def test_change_level_undo(testdir):
"""Ensure that 'set_level' is undone after the end of the test"""
def test_change_level_undo(testdir: Testdir) -> None:
"""Ensure that 'set_level' is undone after the end of the test.

Tests the logging output themselves (affacted both by logger and handler levels).
"""
testdir.makepyfile(
"""
import logging
Expand All @@ -50,6 +54,33 @@ def test2(caplog):
result.stdout.no_fnmatch_line("*log from test2*")


def test_change_level_undos_handler_level(testdir: Testdir) -> None:
"""Ensure that 'set_level' is undone after the end of the test (handler).

Issue #7569. Tests the handler level specifically.
"""
testdir.makepyfile(
"""
import logging

def test1(caplog):
assert caplog.handler.level == 0
caplog.set_level(41)
assert caplog.handler.level == 41

def test2(caplog):
assert caplog.handler.level == 0

def test3(caplog):
assert caplog.handler.level == 0
caplog.set_level(43)
assert caplog.handler.level == 43
"""
)
result = testdir.runpytest()
result.assert_outcomes(passed=3)


def test_with_statement(caplog):
with caplog.at_level(logging.INFO):
logger.debug("handler DEBUG level")
Expand Down