-
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
Capture: copy output when using readouterr() instead of consuming it #12081
Comments
I believe that issue was closed as a duplicate of #5997; it predates GitHub adding distinguished issue-close reasons and we don't generally track that anyway. |
Weird, because the issues are actually different (at least in terms of what the user sees) and not duplicates: #3448 (similar to my issue here) was an issue about how caplog/capsys seems to "consume" logging/stdout/stderr, and then whatever you're capturing for validation purposes doesn't appear in the "Captured X call" section of the pytest output for failed tests. #5997 is an issue about how some logging/stdout/stderr apparently shows up in "Captured X call" but can't be captured for validation via caplog/capsys. Issues with the same system (log/stdout/stderr capturing for test validation), but different actual issues (capsys/caplog entirely removing captured calls from the pytest failed test output, vs calls that can be seen via the pytests failed test output not being able to be captured by capsys/caplog). |
I believe it wasn't that - IIRC, the author of that issue closed all their issues after some problematic interactions with the rest of the pytest team. |
Back to the original issue, I think the |
using |
I think I solved this issue #12854 if you use fixture |
I've created a polyfill to add to @pytest.fixture(scope="function")
def capteesys(request):
from _pytest import capture
import warnings
if hasattr(capture, "capteesys"):
warnings.warn(( "You are using a polyfill for capteesys, but this"
" version of pytest supports it natively- you may"
f" remove the polyfill from your {__file__}"),
DeprecationWarning)
# Remove next two lines if you don't want to ever switch to native version
yield request.getfixturevalue("capteesys")
return
capman = request.config.pluginmanager.getplugin("capturemanager")
capture_fixture = capture.CaptureFixture(capture.SysCapture, request, _ispytest=True)
def _inject_start():
self = capture_fixture # closure seems easier than importing Type or Partial
if self._capture is None:
self._capture = capture.MultiCapture(
in_ = None,
out = self.captureclass(1, tee=True),
err = self.captureclass(2, tee=True)
)
self._capture.start_capturing()
capture_fixture._start = _inject_start
capman.set_fixture(capture_fixture)
capture_fixture._start()
yield capture_fixture
capture_fixture.close()
capman.unset_fixture() I will post again on this thread and @ anyone who 🎉s if the fixture name changes from |
Issue
Currently pytest's capfd/capsys fixtures (CaptureFixture) that allow stdout capturing via readouterr() consume stdout, meaning that logs are no longer available in the "Captured stdout call" up to the point in the test where readouterr() was called. The documentation indicates that this is expected behaviour ("readouterr() : Read and return the captured output so far, resetting the internal buffer."), however the "How to capture stdout/stderr output" tutorial seems to imply that the output is copied from the stdout/stderr streams instead of consumed and reset ("The readouterr() call snapshots the output so far - and capturing will be continued. After the test function finishes the original streams will be restored.")
Example
Code:
Expected:
Actual (no captured stdout because it was consumed by
capsys.readouterr()
):Current workaround
Any tests requiring validation of stdout currently need to manually write-back the captured stdout and stderr immediately after capture in order to have them available for viewing under "Captured stdout call" in pytest results. It is not obvious that this is required from the documentation in order to both capture this output for test validation and have the output available for viewing to troubleshoot in the event of test failure.
Example
Code:
Result:
Proposed solution
Either
CaptureFixture.readouterr(...)
callsys.stdout.write(out)
andsys.stderr.write(err)
itself after performing the consuming capture. Can use a new method argcapture_writeback
or similar which defaults toFalse
in order to preserve backwards-compatibility. Update "How to capture stdout/stderr output" tutorial documentation to make it more clear that by defaultreadouterr
destructively consumes the output such that it won't be available in the "Captured stdout call" test results.CaptureFixture.copyouterr()
method that does not destructively consume the stdout/stderror streams and instead copies them for use in test validation, such that the streams also remain intact for the "Captured stdout call" test results. Update "How to capture stdout/stderr output" tutorial documentation to make it more clear thatreadouterr
destructively consumes the output such that it won't be available in the "Captured stdout call" test results, whilecopyouterr
does the same thing non-destructively.Additional context
Originally mentioned on Stackoverflow in 2014
https://stackoverflow.com/questions/26561822/pytest-capsys-checking-output-and-getting-it-reported
Logged as an Issue in this repo in 2018, but closed as "completed" for unknown reasons
#3448
The text was updated successfully, but these errors were encountered: