Skip to content

Inconsistent wrapping of sys.stdout/stderr causes both capfd and capsys to fail #9361

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
Tronic opened this issue Dec 1, 2021 · 1 comment
Labels
plugin: capture related to the capture builtin plugin type: enhancement new feature or API change, should be merged into features branch

Comments

@Tronic
Copy link

Tronic commented Dec 1, 2021

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.

@RonnyPfannschmidt
Copy link
Member

@nicoddemus i beleive it would be a help if we enabled pytest to have Capure Aware IO wrappes that allow to replace the underlying objects more easily

i believe we may also have to investigate at having fd capture create propper dunder attributes for stdout/stderr as pytest breaks those with the duping

@Zac-HD Zac-HD added plugin: capture related to the capture builtin plugin type: enhancement new feature or API change, should be merged into features branch labels Dec 3, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
plugin: capture related to the capture builtin plugin type: enhancement new feature or API change, should be merged into features branch
Projects
None yet
Development

No branches or pull requests

3 participants