diff --git a/src/_pytest/capture.py b/src/_pytest/capture.py index 34d42821f..e6392cb0e 100644 --- a/src/_pytest/capture.py +++ b/src/_pytest/capture.py @@ -122,23 +122,34 @@ class CaptureManager(object): cap.suspend_capturing(in_=in_) return outerr - def activate_fixture(self, item=None): + @contextlib.contextmanager + def disabled(self): + """Temporarily disables capture while inside the 'with' block.""" + if self._current_item is None: + yield + else: + item = self._current_item + fixture = getattr(item, "_capture_fixture", None) + if fixture is None: + yield + else: + fixture._capture.suspend_capturing() + self.suspend_global_capture(item=None, in_=False) + try: + yield + finally: + self.resume_global_capture() + fixture._capture.resume_capturing() + + def activate_fixture(self, item): """If the current item is using ``capsys`` or ``capfd``, activate them so they take precedence over the global capture. """ - if item is None: - if self._current_item is None: - return - item = self._current_item fixture = getattr(item, "_capture_fixture", None) if fixture is not None: fixture._start() - def deactivate_fixture(self, item=None): - if item is None: - if self._current_item is None: - return - item = self._current_item + def deactivate_fixture(self, item): """Deactivates the ``capsys`` or ``capfd`` fixture of this item, if any.""" fixture = getattr(item, "_capture_fixture", None) if fixture is not None: diff --git a/src/_pytest/logging.py b/src/_pytest/logging.py index 65ac2d24b..ad049f1c5 100644 --- a/src/_pytest/logging.py +++ b/src/_pytest/logging.py @@ -573,9 +573,11 @@ class _LiveLoggingStreamHandler(logging.StreamHandler): def emit(self, record): if self.capture_manager is not None: - self.capture_manager.deactivate_fixture() - self.capture_manager.suspend_global_capture() - try: + ctx_manager = self.capture_manager.disabled() + else: + ctx_manager = _dummy_context_manager() + + with ctx_manager: if not self._first_record_emitted: self.stream.write("\n") self._first_record_emitted = True @@ -587,7 +589,3 @@ class _LiveLoggingStreamHandler(logging.StreamHandler): self.stream.section("live log " + self._when, sep="-", bold=True) self._section_name_shown = True logging.StreamHandler.emit(self, record) - finally: - if self.capture_manager is not None: - self.capture_manager.resume_global_capture() - self.capture_manager.activate_fixture() diff --git a/testing/logging/test_reporting.py b/testing/logging/test_reporting.py index a85a0aba0..ed89f5b7a 100644 --- a/testing/logging/test_reporting.py +++ b/testing/logging/test_reporting.py @@ -876,6 +876,7 @@ def test_live_logging_suspends_capture(has_capture_manager, request): is installed. """ import logging + import contextlib from functools import partial from _pytest.capture import CaptureManager from _pytest.logging import _LiveLoggingStreamHandler @@ -883,17 +884,11 @@ def test_live_logging_suspends_capture(has_capture_manager, request): class MockCaptureManager: calls = [] - def suspend_global_capture(self): - self.calls.append("suspend_global_capture") - - def resume_global_capture(self): - self.calls.append("resume_global_capture") - - def activate_fixture(self, item=None): - self.calls.append("activate_fixture") - - def deactivate_fixture(self, item=None): - self.calls.append("deactivate_fixture") + @contextlib.contextmanager + def disabled(self): + self.calls.append("enter disabled") + yield + self.calls.append("exit disabled") # sanity check assert CaptureManager.suspend_capture_item @@ -914,12 +909,7 @@ def test_live_logging_suspends_capture(has_capture_manager, request): logger.critical("some message") if has_capture_manager: - assert MockCaptureManager.calls == [ - "deactivate_fixture", - "suspend_global_capture", - "resume_global_capture", - "activate_fixture", - ] + assert MockCaptureManager.calls == ["enter disabled", "exit disabled"] else: assert MockCaptureManager.calls == [] assert out_file.getvalue() == "\nsome message\n"