-
-
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
capsys doesn't work correctly when you use C++ iostream from conftest #5134
Comments
Forgot to mention the python version:
|
See https://docs.pytest.org/en/latest/capture.html
|
You are correct. However, the bug is still there even if I use |
ah I see, I misread your issue and assumed you were trying to capture the c++ output. I think maybe there's a misunderstanding here about how streams work in python, in particular the standard streams which are buffered (for performance) Let's factor out the c++ module entirely from the situation: import sys
import time
for i in range(10):
sys.stdout.write('%d\n' % i)
time.sleep(.5) Now try the following commands:
Adding a |
I know about buffering, but I don't think that's not the point of the issue. Note that the issue happens only if both these three conditions are met:
If the problem were the buffering of |
Some more notes:
|
Here's a reproduction not involving pytest: import os
import sys
import time
import tempfile
# get fds
target = sys.stdout.fileno()
orig_fd = os.dup(target)
with tempfile.TemporaryFile() as f:
tmp_fd = os.dup(f.fileno())
with os.fdopen(tmp_fd, 'r') as tmp:
# start capture
os.dup2(tmp_fd, target)
import dummy
sys.stdout.write('hi\n')
sys.stdout.flush()
# retrieve what we captured
tmp.seek(0)
captured = tmp.read()
# end capture
os.dup2(orig_fd, target)
# see what we captured
print(captured)
for i in range(4):
sys.stdout.write('%d\n' % i)
time.sleep(.5) |
Ok, thanks for the example; I can see that either However, my point is that if pytest is able to handle correctly the The example I attached is minimal and contrived, however I have see at least one real-world case in which things started to break and/or to function differently because I moved an import from |
Does using |
Also try it with the features branch of pytest - there might be fixes in this regard already. |
Maybe a |
… It helps to mitigates this pytest issue: pytest-dev/pytest#5134 Prior to this fix, pdb++ failed to display the output when you run it under the conditions described in the issue above.
Reverts/changes 3ff3cfa. Unfortunately the example at pytest-dev/pytest#5134 appears to be for py2 - at least it did not compile for me when trying it.
Reverts/changes 3ff3cfa. Unfortunately the example at pytest-dev/pytest#5134 appears to be for py2 - at least it did not compile for me when trying it.
This appears to be a Python 2 bug/issue: import sys
import tempfile
import time
import os
class Capture(object):
def start(self):
self._old_stdout = sys.stdout
self._stdout_fd = self._old_stdout.fileno()
self._saved_stdout_fd = os.dup(self._stdout_fd)
self._file = sys.stdout = tempfile.TemporaryFile(mode='w+t')
os.dup2(self._file.fileno(), self._stdout_fd)
def stop(self):
os.dup2(self._saved_stdout_fd, self._stdout_fd)
os.close(self._saved_stdout_fd)
sys.stdout = self._old_stdout
self._file.seek(0)
out = self._file.readlines()
self._file.close()
return out
if __name__ == "__main__":
# Workaround: write anything (flushed) before capturing.
# sys.stdout.write('a'); sys.stdout.flush()
c = Capture()
c.start()
# XXX: py2: writing to orig stream causes redirected stream to be buffered?!
sys.__stdout__.write("DBG_STDOUT...\n")
# sys.__stdout__.flush()
print("DBG_stdout")
# py3: works as expected
# ['DBG_STDOUT...\n', 'DBG_stdout\n']
# sleep...
# finished
# py2: without flush:
# sleep...
# DBG_STDOUT...
# ['DBG_stdout\n']
# finished
# py2: with flush (but takes 3s to show up):
# sleep...
# ['DBG_STDOUT...\n', 'DBG_stdout\n']
# finished
x = c.stop()
print(x)
sys.stderr.write("sleep...\n")
time.sleep(3)
print("finished") (you can trigger it in pytest via The example can be made to work in py2 by also assigning |
Closing this off as an issue with Python 2 only (tested with 2.7.17, 3.7.4 - IIRC it also worked with Python 3.3). |
The issue here is that pytest captures (i.e. redirects) output during importing conftest modules, which then makes it behave differently from without output capturing (in py2). |
Maybe the behavior is different then, because something was printed already, and therefore the issue in py2 is not triggered then. I recommend using py3 more.. :) |
Interesting fact from https://stackoverflow.com/a/29204619/15690:
|
Re-opening for now - #6062 appears to fix it. |
hello, first off thank you for the issue! python 2.x support has ended for pytest core. we've decided in #7296 to close the python-2-specific issues to free up some space in our backlog. however, in accordance to our python 2.7 and 3.4 support community patches will still be accepted to the |
The title is a bit obscure, but I think it is better explained with an example. Suppose that the following conditions are met:
std::cout
inside itsinitxxx(void)
function--capture=fd
(the default)with capsys.disabled():
(either directly or indirectly by using--pdb
)In that case, calls to
stdio.write()
are not flushed automatically. The following gist includes a working example:https://gist.github.com/antocuni/b444c2c8b37821a95f45bee42e78d3cf
To reproduce, simply run:
You should be able to see the numbers 0..9 to be printed at regular intervals. However, you see them only when stdout is flushed.
Another way to see the problem is to use
--pdb
; using the provided gist, do the following:Normally, you would expect to see
hello
while sleeping; however, because of the bug you seehello
only AFTER the sleep (this happens becausepdb
usesreadline
which flushes stdout before displaying the prompt).If you do either one of the following things, the bug disappear:
import dummy
insideconftest.py
ORstd::cout
insidedummy.cpp
ORsys.stdout.flush()
intest_noflush.py
Additional info:
pip list
of the virtual environment you are usingThe text was updated successfully, but these errors were encountered: