Skip to content

Commit 58f2c10

Browse files
committed
gh-160427: Return None from TextIOWrapper.buffer when detached
gh-154523 turned the buffer member descriptor into a getter that raises ValueError when the buffer is NULL, and the backport shipped in 3.14.9 and 3.15.1. That made hasattr(stream, "buffer") raise after detach(). Restore the old member descriptor result (None) while keeping the critical section.
1 parent 0e35313 commit 58f2c10

3 files changed

Lines changed: 10 additions & 4 deletions

File tree

‎Lib/test/test_io/test_textio.py‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,7 @@ def test_detach(self):
244244
r = self.BytesIO()
245245
b = self.BufferedWriter(r)
246246
t = self.TextIOWrapper(b, encoding="ascii")
247+
self.assertIs(t.buffer, b)
247248
self.assertIs(t.detach(), b)
248249

249250
t = self.TextIOWrapper(b, encoding="ascii")
@@ -259,6 +260,7 @@ def test_detach(self):
259260
self.assertEqual(t.errors, "strict")
260261
self.assertFalse(t.line_buffering)
261262
self.assertFalse(t.write_through)
263+
self.assertIsNone(t.buffer)
262264

263265
def test_repr(self):
264266
raw = self.BytesIO("hello".encode("utf-8"))
@@ -1721,9 +1723,7 @@ def readinto(self, b):
17211723
self.BufferedReader(raw), encoding="utf-8")
17221724
method = getattr(wrapper, method_name)
17231725
self.assertEqual(method(), "ab\n")
1724-
with self.assertRaisesRegex(ValueError,
1725-
"underlying buffer has been detached"):
1726-
getattr(wrapper, 'buffer')
1726+
self.assertIsNone(wrapper.buffer)
17271727

17281728
def test_reentrant_seek_during_tell(self):
17291729
# gh-153539: reading short of _CHUNK_SIZE leaves residual bytes in the
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix :attr:`~io.TextIOBase.buffer` of a detached :class:`io.TextIOWrapper`
2+
raising :exc:`ValueError` instead of returning ``None``.

‎Modules/_io/textio.c‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3474,7 +3474,11 @@ static PyObject *
34743474
_io_TextIOWrapper_buffer_get_impl(textio *self)
34753475
/*[clinic end generated code: output=d265a34555aa5d4b input=5951cfa148f7350a]*/
34763476
{
3477-
return buffer_access_safe(self);
3477+
/* gh-160427: None once detached, matching the former member descriptor. */
3478+
if (self->buffer == NULL) {
3479+
Py_RETURN_NONE;
3480+
}
3481+
return Py_NewRef(self->buffer);
34783482
}
34793483

34803484
static PyMethodDef incrementalnewlinedecoder_methods[] = {

0 commit comments

Comments
 (0)