FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

gh-90533: Implement BytesIO.peek() by marcelm · Pull Request #150917 · python/cpython · GitHub

/ cpython Public

gh-90533: Implement BytesIO.peek() - #150917

Merged
vstinner merged 54 commits into
python:mainfrom
marcelm:fix-issue-46375
Jun 26, 2026
Merged

gh-90533: Implement BytesIO.peek()#150917
vstinner merged 54 commits into
python:mainfrom
marcelm:fix-issue-46375

Conversation

marcelm commented Jun 4, 2026
edited by bedevere-app Bot
Loading

Copy link
Copy Markdown
Contributor

marcelm and others added 30 commits April 10, 2026 20:37
This allows peek() to use the same optimization that read_bytes() has of
returning a reference to the buffer when possible (without copying).
Semantic change: The default argument for peek is now size=1.
Co-authored-by: Erlend E. Aasland <erlend.aasland@protonmail.com>
Co-authored-by: Erlend E. Aasland <erlend.aasland@protonmail.com>
Co-authored-by: Erlend E. Aasland <erlend.aasland@protonmail.com>
Co-authored-by: Erlend E. Aasland <erlend.aasland@protonmail.com>
Co-authored-by: Erlend E. Aasland <erlend.aasland@protonmail.com>
Co-authored-by: Victor Stinner <vstinner@python.org>
Co-authored-by: Erlend E. Aasland <erlend.aasland@protonmail.com>

cmaloney commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

CI all green! :)

Comment thread Doc/library/io.rst Outdated
.. method:: peek(size=0, /)

Return bytes from the current position onwards without advancing the position.
At least one byte of data is returned if not at EOF.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

The size=0 case is not well documented. It's unclear to me when I read the doc if peek() or peek(0) return an empty string or something else.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

I’ve updated the documentation. I also changed the wording to make it clearer that a copy is returned, which I think is good to point out because a copy could potentially be costly.

Comment thread Doc/library/io.rst Outdated

Return a copy of the buffer from the current position onwards without advancing the position.

If *size* is zero or omitted, the returned :class:`bytes` object extends to EOF.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

At least, the Python implementation limits the returned string to io.DEFAULT_BUFFER_SIZE bytes.

marcelm Jun 11, 2026
edited
Loading

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

I have removed the limit even in the Python implementation.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

I think it would still be good to default limit. That way if there's a 1GB BytesIO and you .peek() you don't copy all that data... more just document more precisely.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

I misremembered what was said earlier. I will fix it next week.

Should maybe the the signature be changed to peek(size=DEFAULT_BUFFER_SIZE)?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

I still prefer 0 as a default, differentiating between "unspecified" and "exactly this size".

Copy link
Copy Markdown
Member

Hum, I see multiple discussions about BytesIO.peek(0) limit. Should it return the whole buffer? Or limit to io.DEFAULT_BUFFER_SIZE (128 kiB currently)?

io.BufferedReader.peek(0) is limited to io.BufferedReader.buffer_size which is io.DEFAULT_BUFFER_SIZE by default.

If the BytesIO size if 1 GiB, returning 1 GiB in peek(0) may not be the expected behavior. Calling peek(0) after read(1) has to copy 1 GiB (minus 1 byte) which can be slow.

IMO limiting BytesIO.peek(0) to io.DEFAULT_BUFFER_SIZE would avoid bad surprises. If the caller wants more, they can pass a size of peek(size).

marcelm commented Jun 18, 2026

Copy link
Copy Markdown
Contributor Author

I have updated the behavior such that at most DEFAULT_BUFFER_SIZE bytes are returned if size is less than one or omitted.

Maybe for size=-1, the behavior could be that the full remainder of the buffer is returned, but I don’t mind either way.

Comment thread Doc/library/io.rst Outdated
Comment thread Doc/library/io.rst Outdated
Comment thread Lib/test/test_io/test_memoryio.py Outdated
Comment thread Doc/whatsnew/3.16.rst Outdated
Co-authored-by: Victor Stinner <vstinner@python.org>

vstinner left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

LGTM! Thanks for the updates.

@cmaloney: Would you mind to double check the change?

Maybe for size=-1, the behavior could be that the full remainder of the buffer is returned, but I don’t mind either way.

If you know that the file is smaller than available memory, you can pass sys.maxsize :-)

Copy link
Copy Markdown
Contributor

Maybe for size=-1, the behavior could be that the full remainder of the buffer is returned, but I don’t mind either way.

Ideally this would use PEP-661 so we could distinguish the cases "not provided" and "all" easily but the .peek() API predates that. I do think it may make sense to modify behavior across all them with new sentinels but that raises some breaking change possibility. I really want a reliable .peek(10) returning 10 bytes on regular blocking files... would make a lot of code simpler.

Comment thread Modules/_io/bytesio.c Outdated
Co-authored-by: Cody Maloney <cmaloney@users.noreply.github.com>

Copy link
Copy Markdown
Member

@marcelm: Can you please update your PR and solve the merge conflict on Doc/whatsnew/3.16.rst?

Copy link
Copy Markdown
Contributor

Updated (The lzma whatsnew entry moved to be alphabetical / after logging)

vstinner merged commit 72cad14 into python:main Jun 26, 2026
54 checks passed

Copy link
Copy Markdown
Member

Congrats @marcelm! Finally, I merged your PR! Sorry for all the back and forth, but it was really hard to decide on the exact API, especially for peek() and peek(0). I like the final API :-)

marcelm deleted the fix-issue-46375 branch June 26, 2026 12:00

marcelm commented Jun 26, 2026

Copy link
Copy Markdown
Contributor Author

Oh, nice, happy to see this go in just before going on vacation! 😄

I think what was a bit difficult was that it was hard to tell who gets to decide, that is, whose requests I should implement if there was a disagreement (between core devs). This was also the reason for the long delay between Nov. 2023 and then April this year.

I’m glad it worked out now, even if it took ~180 comments and 54 commits for a ~200 line change. Thanks everyone for your help, I learned a lot along the way!

Copy link
Copy Markdown
Member

~180 comments and 54 commits for a ~200 line change

That's a very long history. Thanks for your tenacity :-D

Copy link
Copy Markdown
Contributor

Thanks for all the work @marcelm!

Noted on the decision and debate parts. Really appreciate working through it and think we ended up with a really nice new feature :)

This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

io.BytesIO does not have peek()

5 participants


Back | FazBrowse Home | New Git URL