From 0e0275d8d999863921121d08baab8231f8fa27d8 Mon Sep 17 00:00:00 2001 From: Ran Benita Date: Wed, 29 Jul 2020 14:46:11 +0300 Subject: [PATCH] logging: fix capture handler level not reset on teardown after caplog.set_level() This probably regressed in fcbaab8. --- src/_pytest/logging.py | 4 ++++ testing/logging/test_fixture.py | 35 +++++++++++++++++++++++++++++++-- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/src/_pytest/logging.py b/src/_pytest/logging.py index 11031f2f2..0ee9457ea 100644 --- a/src/_pytest/logging.py +++ b/src/_pytest/logging.py @@ -345,6 +345,7 @@ class LogCaptureFixture: """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: @@ -353,6 +354,8 @@ class LogCaptureFixture: 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) @@ -434,6 +437,7 @@ class LogCaptureFixture: # 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 diff --git a/testing/logging/test_fixture.py b/testing/logging/test_fixture.py index da5303302..6e5e9c2b4 100644 --- a/testing/logging/test_fixture.py +++ b/testing/logging/test_fixture.py @@ -2,6 +2,7 @@ import logging import pytest from _pytest.logging import caplog_records_key +from _pytest.pytester import Testdir logger = logging.getLogger(__name__) sublogger = logging.getLogger(__name__ + ".baz") @@ -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 @@ -50,6 +54,33 @@ def test_change_level_undo(testdir): 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")