Stdout/Stderr Capture

Purpose

This subtopic addresses the need to **capture standard output (stdout) and standard error (stderr) streams** generated during test execution. Within the broader context of output and log capture, it specifically focuses on mechanisms to intercept, store, and optionally display or suppress these streams. This is crucial for isolating test output, enabling detailed failure diagnostics, avoiding pollution of test runner outputs, and supporting test fixtures that allow tests to examine their own output.

Functionality

The core functionality revolves around **intercepting writes to stdout and stderr (and optionally stdin)** through various capturing strategies selectable by the user:

Key Classes and Workflows

Capture Lifecycle Example

  1. Pytest initializes CaptureManager with the configured capture method (fd, sys, no, or tee-sys).

  2. At test collection and each test phase, global capturing is started.

  3. During test execution, output sent to stdout/stderr is redirected to buffers or temporary files.

  4. After each phase, captured output is retrieved and attached to test reports.

  5. Test fixtures such as capsys provide granular control to tests for reading or disabling capture.

  6. Capturing can be suspended and resumed to allow output to pass through temporarily (e.g., for debugging).

Example Fixture Usage

def test_output(capsys):
    print("hello")
    captured = capsys.readouterr()
    assert captured.out == "hello\n"

Here, `capsys` captures output written to Python’s `sys.stdout`, allowing the test to assert on it.

Integration

Stdout/Stderr Capture is a **critical subcomponent of the overall output and log capture system**. It complements:

This subtopic introduces the **low-level implementation details of capturing output streams**, which are not covered in the parent topic’s overview of output capture in general. It provides the foundational mechanisms enabling pytest to capture, control, and expose stdout and stderr output effectively.

Diagram

The following flowchart illustrates the **stdout/stderr capture lifecycle during test execution** managed by the CaptureManager:

flowchart TD
    Start[Test Execution Begins]
    Init[Initialize CaptureManager with method]
    StartGlobal[Start Global Capture (stdout, stderr)]
    TestPhase[Run Test Phase (setup/call/teardown)]
    CaptureOutput[Output is redirected to capture buffers/files]
    PhaseEnd[End of Test Phase]
    Retrieve[Retrieve Captured Output]
    Attach[Attach Output to Test Report]
    SuspendResume[Suspend/Resume Capture if requested]
    FixtureCapture[Activate/Deactivate CaptureFixture (capsys/capfd)]
    End[Test Execution Ends]

    Start --> Init --> StartGlobal --> TestPhase --> CaptureOutput --> PhaseEnd --> Retrieve --> Attach
    Retrieve --> SuspendResume --> TestPhase
    SuspendResume --> FixtureCapture --> TestPhase
    Attach --> TestPhase
    PhaseEnd --> SuspendResume
    TestPhase --> End

This flowchart highlights how output is captured transparently during test phases, optionally overridden by fixture-level capture, and then attached to reporting.


Code Snippet Highlight

def pytest_addoption(parser: Parser) -> None:
    group = parser.getgroup("general")
    group.addoption(
        "--capture",
        action="store",
        default="fd",
        choices=["fd", "sys", "no", "tee-sys"],
        help="Per-test capturing method: one of fd|sys|no|tee-sys",
    )

This snippet shows how the capture method is configured via pytest’s CLI.

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

    def stop_global_capturing(self) -> None:
        self._global_capturing.pop_outerr_to_orig()
        self._global_capturing.stop_capturing()
        self._global_capturing = None

This excerpt demonstrates how capturing is started and stopped globally during test run phases.


Stdout/Stderr Capture is fundamental for pytest’s ability to **control and report test output cleanly**, underpinning many advanced test features and user conveniences.