Fix crash when printing while capsysbinary is active
Previously, writing to sys.stdout/stderr in text-mode (e.g.
`print('foo')`) while a `capsysbinary` fixture is active, would crash
with:
/usr/lib/python3.7/contextlib.py:119: in __exit__
next(self.gen)
E TypeError: write() argument must be str, not bytes
This is due to some confusion in the types. The relevant functions are
`snap()` and `writeorg()`. The function `snap()` returns what was
captured, and the return type should be `bytes` for the binary captures
and `str` for the regular ones. The `snap()` return value is eventually
passed to `writeorg()` to be written to the original file, so it's input
type should correspond to `snap()`. But this was incorrect for
`SysCaptureBinary`, which handled it like `str`.
To fix this, be explicit in the `snap()` and `writeorg()`
implementations, also of the other Capture types.
We can't add type annotations yet, because the current inheritance
scheme breaks Liskov Substitution and mypy would complain. To be
refactored later.
Fixes: https://github.com/pytest-dev/pytest/issues/6871
Co-authored-by: Ran Benita (some modifications & commit message)
This commit is contained in:
committed by
Ran Benita
parent
1d244b3d82
commit
1fda861190
@@ -515,18 +515,40 @@ class TestCaptureFixture:
|
||||
reprec.assertoutcome(passed=1)
|
||||
|
||||
def test_capsysbinary(self, testdir):
|
||||
reprec = testdir.inline_runsource(
|
||||
"""\
|
||||
p1 = testdir.makepyfile(
|
||||
r"""
|
||||
def test_hello(capsysbinary):
|
||||
import sys
|
||||
# some likely un-decodable bytes
|
||||
sys.stdout.buffer.write(b'\\xfe\\x98\\x20')
|
||||
|
||||
sys.stdout.buffer.write(b'hello')
|
||||
|
||||
# Some likely un-decodable bytes.
|
||||
sys.stdout.buffer.write(b'\xfe\x98\x20')
|
||||
|
||||
sys.stdout.buffer.flush()
|
||||
|
||||
# Ensure writing in text mode still works and is captured.
|
||||
# https://github.com/pytest-dev/pytest/issues/6871
|
||||
print("world", flush=True)
|
||||
|
||||
out, err = capsysbinary.readouterr()
|
||||
assert out == b'\\xfe\\x98\\x20'
|
||||
assert out == b'hello\xfe\x98\x20world\n'
|
||||
assert err == b''
|
||||
|
||||
print("stdout after")
|
||||
print("stderr after", file=sys.stderr)
|
||||
"""
|
||||
)
|
||||
reprec.assertoutcome(passed=1)
|
||||
result = testdir.runpytest(str(p1), "-rA")
|
||||
result.stdout.fnmatch_lines(
|
||||
[
|
||||
"*- Captured stdout call -*",
|
||||
"stdout after",
|
||||
"*- Captured stderr call -*",
|
||||
"stderr after",
|
||||
"*= 1 passed in *",
|
||||
]
|
||||
)
|
||||
|
||||
def test_partial_setup_failure(self, testdir):
|
||||
p = testdir.makepyfile(
|
||||
@@ -890,7 +912,7 @@ class TestFDCapture:
|
||||
cap.start()
|
||||
tmpfile.write(data1)
|
||||
tmpfile.flush()
|
||||
cap.writeorg(data2)
|
||||
cap.writeorg(data2.decode("ascii"))
|
||||
scap = cap.snap()
|
||||
cap.done()
|
||||
assert scap == data1.decode("ascii")
|
||||
|
||||
Reference in New Issue
Block a user