Output and Log Capture

This module provides comprehensive support for capturing output streams (`stdout`, `stderr`) and logging messages during test execution. This functionality is critical for diagnostics, debugging, and reporting in tests, enabling users to inspect what their code outputs or logs at various stages.


Core Concepts and Purpose

Output and log capture addresses the problem of reliably intercepting and managing:

The module ensures that these outputs do not clutter the test terminal by default but are still available for inspection on failures or via fixtures. It also supports sophisticated features such as live logging, configurable log formatting, and selective capture methods.


Module Structure and Key Functionalities

The output and log capture functionality is divided into two complementary submodules:

  1. Stdout/Stderr Capture (src/_pytest/capture.py):
    Provides mechanisms to capture the textual or binary output to standard streams during tests.
    Key features include:

    • Multiple capture methods (fd, sys, no, tee-sys) selectable via command line.

    • Support for capturing file descriptor output or Python-level stream writes.

    • Fixtures (capsys, capfd, and their binary variants) to provide test functions with access to captured output.

    • Context managers to temporarily suspend or disable capturing for use cases like interactive debugging.

    • Automatic capturing during test collection and each test phase (setup, call, teardown).

    • Handling of platform-specific quirks and workarounds (e.g., Windows console I/O).

  2. Logging Capture and Formatting (src/_pytest/logging.py):
    Manages capturing of Python logging records during tests, including:

    • A custom LogCaptureHandler that stores LogRecord objects and formatted log text.

    • A caplog fixture to expose captured logs to tests.

    • Configurable log levels, formats, date formats, and auto-indentation for multiline logs.

    • Support for live logging (log messages displayed immediately during test execution).

    • File logging to user-specified log files.

    • Integration with pytest’s hook system to capture logs during test phases and add logs to reports.

    • Colorized log output for terminal display using ColoredLevelFormatter.

    • Context managers to temporarily adjust logging levels or apply filters during tests.


How the Module Works: Workflows and Interactions

Stdout/Stderr Capture Workflow

Logging Capture Workflow


Interaction Between Capturing Files and Test Execution


Important Concepts and Unique Design Patterns

Separation of Concerns Between Output and Logging Capture

Layered Capture: Global vs Fixture-Based

Use of Context Managers for Temporary State Changes

Custom Logging Formatters and Live Logging


Code Reference Highlights

Logging Capture — LogCaptureFixture and caplog Fixture

The `LogCaptureFixture` class exposes captured logs during a test, providing access to raw `LogRecord` objects, formatted text, and helper methods:

@property
def text(self) -> str:
    """The formatted log text."""
    return _remove_ansi_escape_sequences(self.handler.stream.getvalue())

@property
def records(self) -> list[logging.LogRecord]:
    """The list of log records."""
    return self.handler.records

The `caplog` fixture yields a `LogCaptureFixture` bound to the current test node:

@fixture
def caplog(request: FixtureRequest) -> Generator[LogCaptureFixture]:
    result = LogCaptureFixture(request.node, _ispytest=True)
    yield result
    result._finalize()

Output Capture — CaptureManager and Capture Fixtures

The `CaptureManager` controls global capturing and delegates to fixture capturing:

def start_global_capturing(self) -> None:
    self._global_capturing = _get_multicapture(self._method)
    self._global_capturing.start_capturing()

def suspend_global_capture(self, in_: bool = False) -> None:
    if self._global_capturing is not None:
        self._global_capturing.suspend_capturing(in_=in_)

Fixtures like `capsys` provide test functions with capture objects that can be queried to read captured output:

@fixture
def capsys(request: SubRequest) -> Generator[CaptureFixture[str]]:
    capman: CaptureManager = request.config.pluginmanager.getplugin("capturemanager")
    capture_fixture = CaptureFixture(SysCapture, request, _ispytest=True)
    capman.set_fixture(capture_fixture)
    capture_fixture._start()
    yield capture_fixture
    capture_fixture.close()
    capman.unset_fixture()

Capture Methods Abstraction

Capture can use different underlying implementations:


Mermaid Diagram: High-Level Flow of Output and Log Capture During Test Execution

sequenceDiagram
    participant TestRunner
    participant CaptureManager
    participant CaptureFixture
    participant LoggingPlugin
    participant LogCaptureHandler
    participant OSStdStreams
    participant PythonLogging

    TestRunner->>CaptureManager: start_global_capturing()
    CaptureManager->>OSStdStreams: redirect stdout/stderr
    CaptureManager->>CaptureFixture: activate if requested (capsys/capfd)
    TestRunner->>CaptureFixture: capture output during test phases
    TestRunner->>LoggingPlugin: configure logging handlers
    LoggingPlugin->>LogCaptureHandler: attach handler to root logger
    PythonLogging->>LogCaptureHandler: emit log records during test
    CaptureFixture->>CaptureManager: suspend/resume capturing as needed
    TestRunner->>CaptureManager: stop_global_capturing()
    CaptureManager->>OSStdStreams: restore stdout/stderr
    TestRunner->>TestRunner: add captured output and logs to reports

This documentation page explains the specific topic of output and log capture within the system, detailing its purpose, workings, and integration with the test lifecycle, referencing the key code components supporting this functionality.