From 6fcbb5e4116dfcdb3f70f9120b59cc9729a04430 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Sat, 26 Oct 2019 03:24:17 +0200 Subject: [PATCH] [4.6] capsys: ensure fd is unbuffered Fixes https://github.com/pytest-dev/pytest/issues/5134. --- changelog/5134.bugfix.rst | 1 + src/_pytest/capture.py | 3 +++ testing/test_capture.py | 49 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+) create mode 100644 changelog/5134.bugfix.rst diff --git a/changelog/5134.bugfix.rst b/changelog/5134.bugfix.rst new file mode 100644 index 0000000000..ffa40abf92 --- /dev/null +++ b/changelog/5134.bugfix.rst @@ -0,0 +1 @@ +Fix buffering with capsys fixture on Python 2. diff --git a/src/_pytest/capture.py b/src/_pytest/capture.py index 68c17772f3..ea885d319f 100644 --- a/src/_pytest/capture.py +++ b/src/_pytest/capture.py @@ -652,6 +652,9 @@ class SysCapture(object): def __init__(self, fd, tmpfile=None): name = patchsysdict[fd] self._old = getattr(sys, name) + if six.PY2: + # Ensure fd is unbuffered (#5134). + self._old = os.fdopen(self._old.fileno(), "wb+", 0) self.name = name if tmpfile is None: if name == "stdin": diff --git a/testing/test_capture.py b/testing/test_capture.py index 01123bf5b4..1374fb39a4 100644 --- a/testing/test_capture.py +++ b/testing/test_capture.py @@ -1577,3 +1577,52 @@ def test_fails(): ) else: assert result_with_capture.ret == 0 + + +def test_syscapture_is_unbuffered_when_suspended(testdir, LineMatcher): + import time + + stampfile = testdir.tmpdir.join("stampfile") + testdir.makepyfile( + **{ + "conftest.py": """ + import ctypes + + libc = ctypes.CDLL(None) + libc.puts(b'this comes from C via conftest') + """, + "test_pass.py": """ + import os + import time + + def test_capfd(capfd): + print("test_capfd 1") + with capfd.disabled(): + for i in range(0, 5): + if os.path.exists({stampfile!r}): + break + print("test_capfd 2: %d" % i) + time.sleep(1) + """.format( + stampfile=str(stampfile) + ), + } + ) + + child = testdir.spawn_pytest("-s --color=no -vv") + start = time.time() + child.expect_exact("test_capfd 2: 0\r\n") + stampfile.ensure() + out = child.before + child.buffer + child.after + duration = time.time() - start + assert duration < 5 + + out += child.read() + lm = LineMatcher(out.decode().splitlines()) + lm.fnmatch_lines( + [ + "this comes from C via conftest", + "test_pass.py::test_capfd test_capfd 2: 0", + "*= 1 passed in *", + ] + )