capture-stdout-stderr.rst
Overview
This document explains how **pytest** captures and manages **standard output (stdout)** and **standard error (stderr)** streams during test execution. It covers the default behavior of output capturing, the different capturing methods available, how to disable or configure capturing, and how to use pytest fixtures to access or manipulate captured output programmatically within tests.
The capturing mechanism is essential for producing clean test reports, enabling debugging via print statements, and supporting plugins that utilize output data. This file serves as a user guide and reference for understanding and controlling pytest's output capturing features.
Detailed Explanations
Default Capturing Behavior
By default, pytest captures all output sent to **stdout** and **stderr** during test execution. This includes output from print statements and subprocesses invoked by tests.
If a test or its setup/teardown fails, the captured output is displayed alongside the failure traceback.
The stdin stream is replaced with a "null" object to prevent tests from hanging due to attempts to read input.
Capturing is implemented by intercepting writes at the low-level file descriptor (FD) level, which allows capturing output beyond Python’s standard streams.
Capturing Methods
Pytest supports three capturing methods, selectable via the `--capture=` command-line option:
fd (File Descriptor) capturing (default)
Captures all writes to OS file descriptors 1 (stdout) and 2 (stderr). Suitable for capturing output from subprocesses or C extensions.sys capturing
Captures only writes to Python-levelsys.stdoutandsys.stderr. Does not capture output written directly to file descriptors.tee-sys capturing (added in pytest 5.4)
Captures Python-level writes tosys.stdoutandsys.stderrand passes these writes through to the real output streams, enabling live printing alongside capturing (useful for plugins like junitxml).
**Disabling capturing** is possible with `pytest -s`, which turns off all capturing.
**Command-line examples:**
pytest -s # disables capturing
pytest --capture=sys # uses sys capturing
pytest --capture=fd # uses fd capturing (default)
pytest --capture=tee-sys # tee sys capturing
Using Print Statements for Debugging
Because pytest captures output by default, developers can freely use print statements for debugging without cluttering test output.
Example:
def setup_function(function):
print("setting up", function)
def test_func1():
assert True
def test_func2():
assert False
When running the above tests, only the output related to the failing test (`test_func2`) is shown, helping diagnose issues efficiently.
Accessing Captured Output Programmatically
Pytest provides several fixtures for capturing and interacting with **stdout** and **stderr** during tests:
capsys— captures Python-level output (sys.stdout,sys.stderr)capfd— captures OS-level file descriptors (FD1, FD2)capsysbinary— likecapsysbut returns bytes for binary outputcapfdbinary— likecapfdbut returns bytes for binary output
**Usage example with `capsys`:**
def test_myoutput(capsys):
print("hello")
sys.stderr.write("world\n")
captured = capsys.readouterr()
assert captured.out == "hello\n"
assert captured.err == "world\n"
print("next")
captured = capsys.readouterr()
assert captured.out == "next\n"
The
readouterr()method returns a named tuple with.outand.errattributes.It snapshots the output so far and continues capturing after the call.
Original streams are restored automatically after the test finishes.
Temporarily Disabling Capture in a Test
You can disable capturing temporarily inside a test using the `disabled()` context manager available on capture fixtures:
def test_disabling_capturing(capsys):
print("this output is captured")
with capsys.disabled():
print("output not captured, goes directly to sys.stdout")
print("this output is also captured")
Within the `with` block, output is not captured and is sent directly to the console or terminal.
Implementation Details & Algorithms
FD Level Capturing: Pytest redirects the OS file descriptors (1 and 2) to temporary files or pipes to capture output from subprocesses or native extensions.
Sys Level Capturing: Replaces
sys.stdoutandsys.stderrwith in-memory file-like objects to capture Python-level print statements.Tee-Sys Capturing: Wraps
sys.stdoutandsys.stderrto capture output while forwarding it to the real streams, allowing live output display and capture simultaneously.Null Stdin: Replaces
sys.stdinwith a dummy object that raises an error upon read attempts, ensuring automated tests do not hang waiting for input.
The capturing system is designed to be transparent and restore original streams after tests, avoiding side effects on other parts of the application or test suite.
Interactions with Other System Parts
Test Execution: Capturing is tightly integrated with pytest's test runner, invoked automatically during test setup and teardown.
Fixtures: The capturing fixtures (
capsys,capfd, etc.) provide interfaces for test code to interact with captured output.Command-Line Interface: Capturing behavior can be controlled via CLI options (
--capture=,-s,--show-capture).Plugins: Plugins like
junitxmlutilize capturing to enrich test reports with output data.Reporting: Captured output is displayed in test failure reports, aiding debugging.
Usage Summary
Feature | Usage Example |
|---|---|
Disable all capturing | `pytest -s` |
Use sys capturing | `pytest --capture=sys` |
Use fd capturing (default) | `pytest --capture=fd` |
Use tee-sys capturing | `pytest --capture=tee-sys` |
Access captured output in test | use `capsys` or `capfd` fixtures |
Temporarily disable capture | `with capsys.disabled():` |
Visual Diagram
The following flowchart illustrates the key capturing mechanisms and their relationships within this file's context:
flowchart TD
A[Test Execution Starts] --> B{Capture Method?}
B -->|fd (default)| C[Redirect OS File Descriptors (1,2)]
B -->|sys| D[Replace sys.stdout and sys.stderr with in-memory streams]
B -->|tee-sys| E[Wrap sys.stdout/stderr: Capture + Forward writes]
B -->|disabled (-s)| F[No capturing; output goes directly to console]
C --> G[Capture output from print + subprocesses]
D --> H[Capture output from Python print statements only]
E --> I[Capture + live display of Python prints]
F --> J[Output directly shown on console]
G --> K[Captured output available for reports and fixtures]
H --> K
I --> K
J --> K
K --> L[Fixtures: capsys, capfd, capsysbinary, capfdbinary]
L --> M[Allow reading and manipulating captured output]
M --> N[Disabled context manager to temporarily disable capture]
style B fill:#f9f,stroke:#333,stroke-width:2px
style L fill:#bbf,stroke:#333,stroke-width:2px
Summary
This file documents pytest's sophisticated and flexible stdout/stderr capturing system, enabling controlled output handling during tests. It balances capturing for clean reports and debugging convenience while supporting advanced use cases like subprocess output capture and live printing. The provided fixtures and command-line options allow users to tailor capturing to their testing needs efficiently.
End of Documentation for `capture-stdout-stderr.rst`