Merge pull request #6566 from blueyed/rm-encodedfile-writelines

Fix `EncodedFile.writelines`
This commit is contained in:
Daniel Hahler 2020-01-27 22:58:31 +01:00 committed by GitHub
commit 20b66e60c0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 27 additions and 13 deletions

View File

@ -0,0 +1 @@
Fix ``EncodedFile.writelines`` to call the underlying buffer's ``writelines`` method.

View File

@ -9,6 +9,8 @@ import os
import sys import sys
from io import UnsupportedOperation from io import UnsupportedOperation
from tempfile import TemporaryFile from tempfile import TemporaryFile
from typing import BinaryIO
from typing import Iterable
import pytest import pytest
from _pytest.compat import CaptureIO from _pytest.compat import CaptureIO
@ -413,30 +415,27 @@ def safe_text_dupfile(f, mode, default_encoding="UTF8"):
class EncodedFile: class EncodedFile:
errors = "strict" # possibly needed by py3 code (issue555) errors = "strict" # possibly needed by py3 code (issue555)
def __init__(self, buffer, encoding): def __init__(self, buffer: BinaryIO, encoding: str) -> None:
self.buffer = buffer self.buffer = buffer
self.encoding = encoding self.encoding = encoding
def write(self, obj): def write(self, s: str) -> int:
if isinstance(obj, str): if not isinstance(s, str):
obj = obj.encode(self.encoding, "replace")
else:
raise TypeError( raise TypeError(
"write() argument must be str, not {}".format(type(obj).__name__) "write() argument must be str, not {}".format(type(s).__name__)
) )
return self.buffer.write(obj) return self.buffer.write(s.encode(self.encoding, "replace"))
def writelines(self, linelist): def writelines(self, lines: Iterable[str]) -> None:
data = "".join(linelist) self.buffer.writelines(x.encode(self.encoding, "replace") for x in lines)
self.write(data)
@property @property
def name(self): def name(self) -> str:
"""Ensure that file.name is a string.""" """Ensure that file.name is a string."""
return repr(self.buffer) return repr(self.buffer)
@property @property
def mode(self): def mode(self) -> str:
return self.buffer.mode.replace("b", "") return self.buffer.mode.replace("b", "")
def __getattr__(self, name): def __getattr__(self, name):

View File

@ -7,6 +7,8 @@ import sys
import textwrap import textwrap
from io import StringIO from io import StringIO
from io import UnsupportedOperation from io import UnsupportedOperation
from typing import BinaryIO
from typing import Generator
from typing import List from typing import List
from typing import TextIO from typing import TextIO
@ -831,7 +833,7 @@ def test_dontreadfrominput():
@pytest.fixture @pytest.fixture
def tmpfile(testdir): def tmpfile(testdir) -> Generator[BinaryIO, None, None]:
f = testdir.makepyfile("").open("wb+") f = testdir.makepyfile("").open("wb+")
yield f yield f
if not f.closed: if not f.closed:
@ -1497,3 +1499,15 @@ def test_typeerror_encodedfile_write(testdir):
def test_stderr_write_returns_len(capsys): def test_stderr_write_returns_len(capsys):
"""Write on Encoded files, namely captured stderr, should return number of characters written.""" """Write on Encoded files, namely captured stderr, should return number of characters written."""
assert sys.stderr.write("Foo") == 3 assert sys.stderr.write("Foo") == 3
def test_encodedfile_writelines(tmpfile: BinaryIO) -> None:
ef = capture.EncodedFile(tmpfile, "utf-8")
with pytest.raises(AttributeError):
ef.writelines([b"line1", b"line2"]) # type: ignore[list-item] # noqa: F821
assert ef.writelines(["line1", "line2"]) is None # type: ignore[func-returns-value] # noqa: F821
tmpfile.seek(0)
assert tmpfile.read() == b"line1line2"
tmpfile.close()
with pytest.raises(ValueError):
ef.read()