Skip to content

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

Open
@Tronic

Description

@Tronic

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    plugin: capturerelated to the capture builtin plugintype: enhancementnew feature or API change, should be merged into features branch

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions