GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — gh-90533: Implement BytesIO.peek() by marcelm · Pull Request #150917 · python/cpython

Conversation

@marcelm

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

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

Closes #90533

Replaces #30808

  • Issue: io.BytesIO does not have peek() #90533

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
marcelm and others added 30 commits April 10, 2026 20:37
@marcelm
Implement BytesIO.peek()
b833b83
@blurb-it @marcelm
📜🤖 Added by blurb_it.
50a2cfb
@marcelm
Document BytesIO.peek()
eaa7672
@marcelm
Implement with the help of read_bytes()
00457ae
This allows peek() to use the same optimization that read_bytes() has of
returning a reference to the buffer when possible (without copying).
@marcelm
Add to What’s New
882579d
@marcelm
versionadded: 3.12 -> 3.13
c1eed72
@marcelm
Remove unused variable
afc200c
@marcelm
Test tell() after peek()
79ab9a4
@marcelm
Update docs, factor out peek_bytes, semantics
b493914
Semantic change: The default argument for peek is now size=1.
@marcelm @erlend-aasland
Update Misc/NEWS.d/next/Library/2022-04-10-20-10-59.bpo-46375.8j1ogZ.rst
2a1c85c
Co-authored-by: Erlend E. Aasland <[email protected]>
@marcelm @erlend-aasland
Update Modules/_io/bytesio.c
d398717
Co-authored-by: Erlend E. Aasland <[email protected]>
@marcelm @erlend-aasland
Update Modules/_io/bytesio.c
26d1e81
Co-authored-by: Erlend E. Aasland <[email protected]>
@marcelm @erlend-aasland
Use SemBr
9a19ff9
Co-authored-by: Erlend E. Aasland <[email protected]>
@marcelm @erlend-aasland
Update Doc/whatsnew/3.13.rst
9300ade
Co-authored-by: Erlend E. Aasland <[email protected]>
@marcelm @vstinner
Apply suggestions from code review
d214089
Co-authored-by: Victor Stinner <[email protected]>
@marcelm
Use a context manager around memio in test_peek
d6691b8
@marcelm
Add more tests for tell() after peek()
3e51adb
@marcelm
Document why size < 0 can happen
3661b65
@marcelm @erlend-aasland
Update Modules/_io/bytesio.c
cd40d77
Co-authored-by: Erlend E. Aasland <[email protected]>
@marcelm
Do not update pos if peek_bytes failed
04372bd
@marcelm
Size can be negative after truncate or seek
6b9ae8c
@marcelm
Test with size<0 and size>len(buf)
f7406f6
@marcelm
Test peek() after write()
d9528e2
@marcelm
Document BufferedReader.peek and BytesIO.peek similarly
bc8134b
@marcelm
Comment
b6ffca8
@marcelm
Make it more explicit that size is ignored
5fe5645
@marcelm
Return an empty bytes object for size=0
4126a64
@marcelm
Simplify
1ea40c2
@marcelm
Test peek(3) and peek(5)
77e04d6
@marcelm
Run clinic.py
4d2f2dd
@cmaloney

cmaloney commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

CI all green! :)

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

vstinner
vstinner reviewed Jun 9, 2026
View reviewed changes
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.

@vstinner vstinner Jun 9, 2026

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

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.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@marcelm marcelm Jun 11, 2026

Copy link
Copy Markdown
Contributor Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

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.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@marcelm
Clarify what peek(0) does
e2d3929
vstinner
vstinner reviewed Jun 11, 2026
View reviewed changes
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.

@vstinner vstinner Jun 11, 2026

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

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

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@marcelm marcelm Jun 11, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

I have removed the limit even in the Python implementation.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@cmaloney cmaloney Jun 11, 2026

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

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.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@marcelm marcelm Jun 12, 2026

Copy link
Copy Markdown
Contributor Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

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)?

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@cmaloney cmaloney Jun 12, 2026

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

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

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread Lib/test/test_io/test_memoryio.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

marcelm added 3 commits June 11, 2026 16:42
@marcelm
Do not cap at DEFAULT_BUFFER_SIZE even in Python implementation
5f07faa
@marcelm
Test buffer size greater than DEFAULT_BUFFER_SIZE
bb5f648
@marcelm
Test buffer content
8a96f88
@vstinner

vstinner commented Jun 12, 2026

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).

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@marcelm
Return at most DEFAULT_BUFFER_SIZE bytes if size is 0/-1/unspecified
5105c55
@marcelm

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.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

vstinner
vstinner reviewed Jun 18, 2026
View reviewed changes
Comment thread Doc/library/io.rst Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread Doc/library/io.rst Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread Lib/test/test_io/test_memoryio.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread Doc/whatsnew/3.16.rst Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread Misc/NEWS.d/next/Library/2022-04-10-20-10-59.bpo-46375.8j1ogZ.rst Resolved

Uh oh!

There was an error while loading. Please reload this page.

@vstinner
Apply suggestions from code review
11e65fe
Co-authored-by: Victor Stinner <[email protected]>
vstinner
vstinner approved these changes Jun 18, 2026
View reviewed changes

@vstinner vstinner left a comment

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

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 :-)

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

marcelm reacted with thumbs up emoji
All reactions
  • 👍 1 reaction
@bedevere-app bedevere-app Bot added awaiting merge and removed awaiting core review labels Jun 18, 2026
@cmaloney

cmaloney commented Jun 18, 2026

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.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

cmaloney
cmaloney approved these changes Jun 18, 2026
View reviewed changes
Comment thread Modules/_io/bytesio.c Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread Lib/test/test_io/test_memoryio.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

@cmaloney
Apply suggestions from code review
514d102
Co-authored-by: Cody Maloney <[email protected]>
@vstinner

vstinner commented Jun 24, 2026

Copy link
Copy Markdown
Member

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

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@cmaloney
Merge branch 'main' into fix-issue-46375
bead21a
@cmaloney

cmaloney commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

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

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

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

Uh oh!

There was an error while loading. Please reload this page.

@bedevere-app bedevere-app Bot removed the awaiting merge label Jun 26, 2026
@vstinner

vstinner commented Jun 26, 2026

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 and cmaloney reacted with hooray emoji
All reactions
  • 🎉 2 reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

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

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!

cmaloney and stevemarin reacted with thumbs up emoji
All reactions
  • 👍 2 reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@vstinner

vstinner commented Jun 26, 2026

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

marcelm and cmaloney reacted with thumbs up emoji
All reactions
  • 👍 2 reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@cmaloney

cmaloney commented Jun 26, 2026

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 :)

marcelm reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

This was referenced Aug 8, 2026
_pyio.BytesIO.peek() returns bytearray instead of bytes #155389
Closed
gh-155389: Return bytes from _pyio.BytesIO.peek() #155390
Merged
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@StanFromIreland StanFromIreland StanFromIreland left review comments
@vstinner vstinner vstinner approved these changes
@cmaloney cmaloney cmaloney approved these changes
@AA-Turner AA-Turner Awaiting requested review from AA-Turner AA-Turner is a code owner

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

io.BytesIO does not have peek()

Uh oh!

There was an error while loading. Please reload this page.

5 participants

@marcelm @cmaloney @vstinner @StanFromIreland @emmatyping
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.