Repository navigation
Conversation
pythongh-157364 replaced the buffer member descriptor with a getter that goes through buffer_access_safe(), which raises ValueError when the buffer is NULL. The attribute therefore raised instead of returning None after detach(), breaking hasattr() in 3.14.9 and 3.15.1 for code that probes a stream for a buffer. Return None from the getter when the wrapper is detached but initialised, which is what the member descriptor did before pythongh-157364 and what _pyio returns. The safety helper keeps raising for every other caller.
7551b73 to
0071853
Compare
|
@ashm-dev, one thing worth a look from you: I changed an assertion in Before gh-157364 the attribute was a member descriptor, so a detached wrapper read as |
|
Need to work out what the right behavior here is before getting to a PR. Ideally get an agreement in the issue first, then once have that can work on a PR. In this case that means propose the change you'd like to make there and wait for a python triager or developer to figure out if that is the right direction. |
|
Fair. I will take the behaviour question to gh-160427 and hold this as a draft until a triager or developer settles it. |
Fixes gh-160427.
TextIOWrapper.bufferraisesValueError: underlying buffer has been detachedonce the wrapper is detached, so
hasattr(stream, "buffer")raises instead ofreturning a boolean. This is a regression in 3.14.9 and 3.15.1, introduced by
gh-157364.
That change replaced the
buffermember descriptor with a getter that callsbuffer_access_safe(), which raises wheneverself->bufferis NULL. Beforegh-157364 the attribute was exposed as
{"buffer", _Py_T_OBJECT, offsetof(textio, buffer), Py_READONLY}, and a NULLobject member reads as
None._pyio.TextIOWrapper.bufferstill returnsself._buffer, which isNoneafter detach, so the two implementations nowdisagree.
The fix returns
Nonefrom the getter when the wrapper is detached butinitialised.
buffer_access_safe()is untouched, so every other caller keepsthe existing protection, and the uninitialised case still raises.
One existing test needed updating:
test_reentrant_detach_during_readassertedthe
ValueErrorfromwrapper.buffer. Its subject is that the buffer survivesthe read and the wrapper does not crash, which still holds, so it now asserts
wrapper.buffer is None.Tests:
./python -m test test_iopasses, 1,066 tests.test_detachnow alsoasserts the attribute is
Noneand thathasattrworks after detach.I used an AI assistant to help trace the regression and prepare the patch, and
I have reviewed every line of it.