Skip to content

Commit 20b66e6

Browse files
authored
Merge pull request #6566 from blueyed/rm-encodedfile-writelines
Fix `EncodedFile.writelines`
2 parents a9eab07 + bf5c763 commit 20b66e6

File tree

3 files changed

+27
-13
lines changed

3 files changed

+27
-13
lines changed

changelog/6566.bugfix.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix ``EncodedFile.writelines`` to call the underlying buffer's ``writelines`` method.

src/_pytest/capture.py

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
import sys
1010
from io import UnsupportedOperation
1111
from tempfile import TemporaryFile
12+
from typing import BinaryIO
13+
from typing import Iterable
1214

1315
import pytest
1416
from _pytest.compat import CaptureIO
@@ -413,30 +415,27 @@ def safe_text_dupfile(f, mode, default_encoding="UTF8"):
413415
class EncodedFile:
414416
errors = "strict" # possibly needed by py3 code (issue555)
415417

416-
def __init__(self, buffer, encoding):
418+
def __init__(self, buffer: BinaryIO, encoding: str) -> None:
417419
self.buffer = buffer
418420
self.encoding = encoding
419421

420-
def write(self, obj):
421-
if isinstance(obj, str):
422-
obj = obj.encode(self.encoding, "replace")
423-
else:
422+
def write(self, s: str) -> int:
423+
if not isinstance(s, str):
424424
raise TypeError(
425-
"write() argument must be str, not {}".format(type(obj).__name__)
425+
"write() argument must be str, not {}".format(type(s).__name__)
426426
)
427-
return self.buffer.write(obj)
427+
return self.buffer.write(s.encode(self.encoding, "replace"))
428428

429-
def writelines(self, linelist):
430-
data = "".join(linelist)
431-
self.write(data)
429+
def writelines(self, lines: Iterable[str]) -> None:
430+
self.buffer.writelines(x.encode(self.encoding, "replace") for x in lines)
432431

433432
@property
434-
def name(self):
433+
def name(self) -> str:
435434
"""Ensure that file.name is a string."""
436435
return repr(self.buffer)
437436

438437
@property
439-
def mode(self):
438+
def mode(self) -> str:
440439
return self.buffer.mode.replace("b", "")
441440

442441
def __getattr__(self, name):

testing/test_capture.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
import textwrap
88
from io import StringIO
99
from io import UnsupportedOperation
10+
from typing import BinaryIO
11+
from typing import Generator
1012
from typing import List
1113
from typing import TextIO
1214

@@ -831,7 +833,7 @@ def test_dontreadfrominput():
831833

832834

833835
@pytest.fixture
834-
def tmpfile(testdir):
836+
def tmpfile(testdir) -> Generator[BinaryIO, None, None]:
835837
f = testdir.makepyfile("").open("wb+")
836838
yield f
837839
if not f.closed:
@@ -1497,3 +1499,15 @@ def test_fails():
14971499
def test_stderr_write_returns_len(capsys):
14981500
"""Write on Encoded files, namely captured stderr, should return number of characters written."""
14991501
assert sys.stderr.write("Foo") == 3
1502+
1503+
1504+
def test_encodedfile_writelines(tmpfile: BinaryIO) -> None:
1505+
ef = capture.EncodedFile(tmpfile, "utf-8")
1506+
with pytest.raises(AttributeError):
1507+
ef.writelines([b"line1", b"line2"]) # type: ignore[list-item] # noqa: F821
1508+
assert ef.writelines(["line1", "line2"]) is None # type: ignore[func-returns-value] # noqa: F821
1509+
tmpfile.seek(0)
1510+
assert tmpfile.read() == b"line1line2"
1511+
tmpfile.close()
1512+
with pytest.raises(ValueError):
1513+
ef.read()

0 commit comments

Comments
 (0)