diff --git a/Lib/test/test_io/test_textio.py b/Lib/test/test_io/test_textio.py index a18386d68569ae..6e649240f08d5b 100644 --- a/Lib/test/test_io/test_textio.py +++ b/Lib/test/test_io/test_textio.py @@ -244,6 +244,7 @@ def test_detach(self): r = self.BytesIO() b = self.BufferedWriter(r) t = self.TextIOWrapper(b, encoding="ascii") + self.assertIs(t.buffer, b) self.assertIs(t.detach(), b) t = self.TextIOWrapper(b, encoding="ascii") @@ -259,6 +260,7 @@ def test_detach(self): self.assertEqual(t.errors, "strict") self.assertFalse(t.line_buffering) self.assertFalse(t.write_through) + self.assertIsNone(t.buffer) def test_repr(self): raw = self.BytesIO("hello".encode("utf-8")) @@ -1721,9 +1723,7 @@ def readinto(self, b): self.BufferedReader(raw), encoding="utf-8") method = getattr(wrapper, method_name) self.assertEqual(method(), "ab\n") - with self.assertRaisesRegex(ValueError, - "underlying buffer has been detached"): - getattr(wrapper, 'buffer') + self.assertIsNone(wrapper.buffer) def test_reentrant_seek_during_tell(self): # gh-153539: reading short of _CHUNK_SIZE leaves residual bytes in the diff --git a/Misc/NEWS.d/next/Library/2026-10-26-16-15-29.gh-issue-160427.9G4EBb.rst b/Misc/NEWS.d/next/Library/2026-10-26-16-15-29.gh-issue-160427.9G4EBb.rst new file mode 100644 index 00000000000000..d57dd02a6d576f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-10-26-16-15-29.gh-issue-160427.9G4EBb.rst @@ -0,0 +1,2 @@ +Fix :attr:`~io.TextIOBase.buffer` of a detached :class:`io.TextIOWrapper` +raising :exc:`ValueError` instead of returning ``None``. diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index 4ef5251d451a4c..b6f3f4f1711928 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -3474,7 +3474,11 @@ static PyObject * _io_TextIOWrapper_buffer_get_impl(textio *self) /*[clinic end generated code: output=d265a34555aa5d4b input=5951cfa148f7350a]*/ { - return buffer_access_safe(self); + /* gh-160427: None once detached, matching the former member descriptor. */ + if (self->buffer == NULL) { + Py_RETURN_NONE; + } + return Py_NewRef(self->buffer); } static PyMethodDef incrementalnewlinedecoder_methods[] = {