You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
_pyio.BufferedRandom.truncate() keeps the read buffer, so later reads return data that is no longer in the file #161271
_io.BufferedRandom.truncate() flushes and rewinds the raw stream before truncating
(buffered_flush_and_rewind_unlocked() in Modules/_io/bufferedio.c), which drops the
read-ahead buffer. _pyio.BufferedRandom.truncate() does not: the comment there says "Use seek to flush the read buffer", but nothing seeks, so reads after truncate()
still hand out bytes that are no longer in the file.
io b'' 0
_pyio b'bcdef' 0 # the file is empty, yet read() returns 5 bytes
The same divergence appears with truncate() (no argument), with any truncation point
below the read-ahead position, in r+b / w+b / a+b modes, and for a BufferedRandom built directly on a BytesIO.
CPython versions tested on
3.11, 3.13 — the affected code in Lib/_pyio.py is unchanged on main.
Thank you for taking the time to open this issue. Python is a community-driven project, and we want it to be a welcoming place to learn and collaborate.
This issue appears to have been written with AI assistance. Please explain your issue in your own words and describe how you checked the information you provided. This helps us understand your issue and leaves more time to address other issues.
Fair enough, I hadn't seen python/steering-council#372 when I filed this. Happy for it to be closed if _pyio is on the way out.
In my words: _io's truncate rewinds the raw stream and drops the read buffer first (buffered_flush_and_rewind_unlocked), _pyio doesn't, even though the comment right there says "Use seek to flush the read buffer". So the next read still hands back buffered bytes:
open("x","wb").write(b"abcdef")
f=_pyio.open("x","r+b"); f.read(1); f.truncate(0)
f.read() # b'bcdef', and the file is 0 bytes
I checked it on r+b, ab+ and w+b with truncation points 0, 1, 3 and None, comparing the return value, tell(), the next read and the file size against io. 12 of 25 cases differed, 0 after adding self.seek(self.tell()). I used an LLM for the English.
Activity
cmaloney commentedon Nov 3, 2026
holding off on
_pyiochanges until python/steering-council#372 is decided.bedevere-app commentedon Nov 3, 2026
Thank you for taking the time to open this issue. Python is a community-driven project, and we want it to be a welcoming place to learn and collaborate.
This issue appears to have been written with AI assistance. Please explain your issue in your own words and describe how you checked the information you provided. This helps us understand your issue and leaves more time to address other issues.
Please read our guidelines for using AI tools.
tsayin4 commentedon Nov 3, 2026
Fair enough, I hadn't seen python/steering-council#372 when I filed this. Happy for it to be closed if _pyio is on the way out.
In my words: _io's truncate rewinds the raw stream and drops the read buffer first (
buffered_flush_and_rewind_unlocked), _pyio doesn't, even though the comment right there says "Use seek to flush the read buffer". So the next read still hands back buffered bytes:I checked it on r+b, ab+ and w+b with truncation points 0, 1, 3 and None, comparing the return value, tell(), the next read and the file size against io. 12 of 25 cases differed, 0 after adding
self.seek(self.tell()). I used an LLM for the English.