diff --git a/changelog/4861.bugfix.rst b/changelog/4861.bugfix.rst new file mode 100644 index 000000000..b4bf125d1 --- /dev/null +++ b/changelog/4861.bugfix.rst @@ -0,0 +1 @@ +Improve validation of contents written to captured output so it behaves the same as when capture is disabled. diff --git a/src/_pytest/capture.py b/src/_pytest/capture.py index 533690949..7bd319b1a 100644 --- a/src/_pytest/capture.py +++ b/src/_pytest/capture.py @@ -17,6 +17,7 @@ from tempfile import TemporaryFile import six import pytest +from _pytest.compat import _PY3 from _pytest.compat import CaptureIO patchsysdict = {0: "stdin", 1: "stdout", 2: "stderr"} @@ -412,6 +413,10 @@ class EncodedFile(object): def write(self, obj): if isinstance(obj, six.text_type): obj = obj.encode(self.encoding, "replace") + elif _PY3: + raise TypeError( + "write() argument must be str, not {}".format(type(obj).__name__) + ) self.buffer.write(obj) def writelines(self, linelist): diff --git a/testing/test_capture.py b/testing/test_capture.py index 81ab4e8a8..546738f28 100644 --- a/testing/test_capture.py +++ b/testing/test_capture.py @@ -18,6 +18,7 @@ from six import text_type import pytest from _pytest import capture from _pytest.capture import CaptureManager +from _pytest.compat import _PY3 from _pytest.main import EXIT_NOTESTSCOLLECTED # note: py.io capture tests where copied from @@ -1526,3 +1527,26 @@ def test_capture_with_live_logging(testdir, capture_fixture): result = testdir.runpytest_subprocess("--log-cli-level=INFO") assert result.ret == 0 + + +def test_typeerror_encodedfile_write(testdir): + """It should behave the same with and without output capturing (#4861).""" + p = testdir.makepyfile( + """ + def test_fails(): + import sys + sys.stdout.write(b"foo") + """ + ) + result_without_capture = testdir.runpytest("-s", str(p)) + + result_with_capture = testdir.runpytest(str(p)) + + assert result_with_capture.ret == result_without_capture.ret + + if _PY3: + result_with_capture.stdout.fnmatch_lines( + ["E TypeError: write() argument must be str, not bytes"] + ) + else: + assert result_with_capture.ret == 0