Skip to content

Commit 73b72d1

Browse files
committed
[4.6] capsys: ensure fd is unbuffered
Fixes pytest-dev#5134.
1 parent 3edf417 commit 73b72d1

File tree

3 files changed

+55
-1
lines changed

3 files changed

+55
-1
lines changed

changelog/5134.bugfix.rst

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix buffering with capsys fixture on Python 2.

src/_pytest/capture.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -685,7 +685,11 @@ def done(self):
685685
self._state = "done"
686686

687687
def suspend(self):
688-
setattr(sys, self.name, self._old)
688+
if six.PY2:
689+
# Ensure fd is unbuffered (#5134).
690+
setattr(sys, self.name, os.fdopen(self._old.fileno(), "wb+", 0))
691+
else:
692+
setattr(sys, self.name, self._old)
689693
self._state = "suspended"
690694

691695
def resume(self):

testing/test_capture.py

+49
Original file line numberDiff line numberDiff line change
@@ -1577,3 +1577,52 @@ def test_fails():
15771577
)
15781578
else:
15791579
assert result_with_capture.ret == 0
1580+
1581+
1582+
def test_syscapture_is_unbuffered_when_suspended(testdir, LineMatcher):
1583+
import time
1584+
1585+
stampfile = testdir.tmpdir.join("stampfile")
1586+
testdir.makepyfile(
1587+
**{
1588+
"conftest.py": """
1589+
import ctypes
1590+
1591+
libc = ctypes.CDLL(None)
1592+
libc.puts(b'this comes from C via conftest')
1593+
""",
1594+
"test_pass.py": """
1595+
import os
1596+
import time
1597+
1598+
def test_capfd(capfd):
1599+
print("test_capfd 1")
1600+
with capfd.disabled():
1601+
for i in range(0, 5):
1602+
if os.path.exists({stampfile!r}):
1603+
break
1604+
print("test_capfd 2: %d" % i)
1605+
time.sleep(1)
1606+
""".format(
1607+
stampfile=str(stampfile)
1608+
),
1609+
}
1610+
)
1611+
1612+
child = testdir.spawn_pytest("-s --color=no -vv")
1613+
start = time.time()
1614+
child.expect_exact("test_capfd 2: 0\r\n")
1615+
stampfile.ensure()
1616+
out = child.before + child.buffer + child.after
1617+
duration = time.time() - start
1618+
assert duration < 5
1619+
1620+
out += child.read()
1621+
lm = LineMatcher(out.decode().splitlines())
1622+
lm.fnmatch_lines(
1623+
[
1624+
"this comes from C via conftest",
1625+
"test_pass.py::test_capfd test_capfd 2: 0",
1626+
"*= 1 passed in *",
1627+
]
1628+
)

0 commit comments

Comments
 (0)