pytest-dev / pytest-dev/pytest
Inconsistent wrapping of sys.stdout/stderr causes both capfd and capsys to fail
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 14.5k
- Forks
- 3.4k
- Avg merge
- 2d 9h
- Merged PRs (30d)
- 35
Description
If stdout or stderr objects are imported from sys, capsys and capfd cannot wrap them and thus nothing is captured. I would still expect to be able to capture them on capfd but because pytest itself still manages to wrap them (prior to loading the test module I presume), nothing is actually written to these FDs.
import sys
from sys import stdout
def test_nothing_is_captured(capfd):
stdout.write('Hello\n')
stdout.flush()
cap = capfd.readouterr()
assert cap.out == 'Hello\n'
def test_capture_successful(capfd):
sys.stdout.write('Hello\n')
cap = capfd.readouterr()
assert cap.out == 'Hello\n'
Running this, the first one fails because nothing is captured. Adding os.system("echo Hello") would make this test pass, as true-fd stdout output is still captured. The second test passes, presumably because capfd then also wraps the sys.stdout object so that it can receive anything written there.
Pytest still prints on console the correct capture, showing that pytest itself successfully wrapped the stdout object:
tests/test_cap.py:8: AssertionError
------------------ Captured stdout call ------------------
Hello
================== short test summary info ==================
FAILED tests/test_cap.py::test_nothing_is_captured - AssertionError: assert '' == 'Hello\n'
================== 1 failed, 1 passed in 0.04s ==================
Running pytest 6.2.5 on Linux. Adding --capture=tee-sys allows both tests to pass. This bug is somewhat related to #8900.
Since pytest itself has priority access to do its wrapping prior to loading any user code, it would be nice if capsys and capfd could also inject their code to the already provided wrapper, avoiding the error-prone rewrapping. This would allow both of them work as expected irregardless of how the application being tested imports the sys module.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Reproduce the failure from the issue's tests/test_cap.py example using capfd and an imported sys.stdout, then compare it with the passing sys.stdout case and --capture=tee-sys. Read the capfd and capsys capture entry points and the existing wrapping behavior. Done means imported stdout and stderr are captured correctly by both fixtures without breaking true-file-descriptor capture.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- testing-qa
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100