Skip to content

Commit

Permalink
[3.11] gh-80109: Fix io.TextIOWrapper dropping the internal buffer du…
Browse files Browse the repository at this point in the history
…ring write() (GH-22535) (GH-113809)

io.TextIOWrapper was dropping the internal decoding buffer
during read() and write() calls.
(cherry picked from commit 73c9326)

Co-authored-by: Zackery Spytz <zspytz@gmail.com>
  • Loading branch information
miss-islington and ZackerySpytz committed Jan 8, 2024
1 parent 320c160 commit 4db8d3b
Show file tree
Hide file tree
Showing 4 changed files with 24 additions and 8 deletions.
10 changes: 6 additions & 4 deletions Lib/_pyio.py
Original file line number Diff line number Diff line change
Expand Up @@ -2224,8 +2224,9 @@ def write(self, s):
self.buffer.write(b)
if self._line_buffering and (haslf or "\r" in s):
self.flush()
self._set_decoded_chars('')
self._snapshot = None
if self._snapshot is not None:
self._set_decoded_chars('')
self._snapshot = None
if self._decoder:
self._decoder.reset()
return length
Expand Down Expand Up @@ -2539,8 +2540,9 @@ def read(self, size=None):
# Read everything.
result = (self._get_decoded_chars() +
decoder.decode(self.buffer.read(), final=True))
self._set_decoded_chars('')
self._snapshot = None
if self._snapshot is not None:
self._set_decoded_chars('')
self._snapshot = None
return result
else:
# Keep reading chunks until we have size characters to return.
Expand Down
8 changes: 8 additions & 0 deletions Lib/test/test_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -3788,6 +3788,14 @@ def test_issue25862(self):
t.write('x')
t.tell()

def test_issue35928(self):
p = self.BufferedRWPair(self.BytesIO(b'foo\nbar\n'), self.BytesIO())
f = self.TextIOWrapper(p)
res = f.readline()
self.assertEqual(res, 'foo\n')
f.write(res)
self.assertEqual(res + f.readline(), 'foo\nbar\n')


class MemviewBytesIO(io.BytesIO):
'''A BytesIO object whose read method returns memoryviews
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
:class:`io.TextIOWrapper` now correctly handles the decoding buffer after
``read()`` and ``write()``.
12 changes: 8 additions & 4 deletions Modules/_io/textio.c
Original file line number Diff line number Diff line change
Expand Up @@ -1745,8 +1745,10 @@ _io_TextIOWrapper_write_impl(textio *self, PyObject *text)
Py_DECREF(ret);
}

textiowrapper_set_decoded_chars(self, NULL);
Py_CLEAR(self->snapshot);
if (self->snapshot != NULL) {
textiowrapper_set_decoded_chars(self, NULL);
Py_CLEAR(self->snapshot);
}

if (self->decoder) {
ret = PyObject_CallMethodNoArgs(self->decoder, &_Py_ID(reset));
Expand Down Expand Up @@ -1979,8 +1981,10 @@ _io_TextIOWrapper_read_impl(textio *self, Py_ssize_t n)
if (result == NULL)
goto fail;

textiowrapper_set_decoded_chars(self, NULL);
Py_CLEAR(self->snapshot);
if (self->snapshot != NULL) {
textiowrapper_set_decoded_chars(self, NULL);
Py_CLEAR(self->snapshot);
}
return result;
}
else {
Expand Down

0 comments on commit 4db8d3b

Please sign in to comment.