Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 35.2k
gh-90533: Implement BytesIO.peek()#30808
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
b833b8350a2cfbeaa767200457ae882579dc1eed72afc200c79ab9a4b4939142a1c85cd39871726d1e819a19ff99300aded214089d6691b83e51adb3661b65cd40d7704372bd6b9ae8cf7406f6d9528e2bc8134bb6ffca85fe56454126a641ea40c277e04d64d2f2ddc16bebf08bd7da6174fcab8b8cf47ac914eabbd8f007d9e4d3d57f45023ad25203749b32fd791File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -996,6 +996,13 @@ def tell(self): | ||
| raise ValueError("tell on closed file") | ||
| return self._pos | ||
| def peek(self, size=0): | ||
| if self.closed: | ||
| raise ValueError("peek on closed file") | ||
| if size < 1: | ||
cmaloney marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| return self._buffer[self._pos:self._pos + DEFAULT_BUFFER_SIZE] | ||
| return self._buffer[self._pos:self._pos + size] | ||
| def truncate(self, pos=None): | ||
| if self.closed: | ||
| raise ValueError("truncate on closed file") | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -566,6 +566,66 @@ def test_issue141311(self): | ||
| buf = bytearray(2) | ||
| self.assertEqual(0, memio.readinto(buf)) | ||
| def test_peek(self): | ||
| buf = self.buftype("1234567890") | ||
| with self.ioclass(buf) as memio: | ||
| self.assertEqual(memio.tell(), 0) | ||
| self.assertEqual(memio.peek(1), buf[:1]) | ||
| self.assertEqual(memio.peek(1), buf[:1]) | ||
vstinner marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| self.assertEqual(memio.peek(), buf) | ||
| self.assertEqual(memio.peek(3), buf[:3]) | ||
| self.assertEqual(memio.peek(5), buf[:5]) | ||
| self.assertEqual(memio.peek(0), buf) | ||
| self.assertEqual(memio.peek(len(buf) + 100), buf) | ||
| self.assertEqual(memio.peek(-1), buf) | ||
| self.assertEqual(memio.tell(), 0) | ||
| memio.read(1) | ||
| self.assertEqual(memio.tell(), 1) | ||
| self.assertEqual(memio.peek(1), buf[1:2]) | ||
| self.assertEqual(memio.peek(), buf[1:]) | ||
| self.assertEqual(memio.peek(3), buf[1:4]) | ||
| self.assertEqual(memio.peek(5), buf[1:6]) | ||
| self.assertEqual(memio.peek(0), buf[1:]) | ||
| self.assertEqual(memio.peek(len(buf) + 100), buf[1:]) | ||
| self.assertEqual(memio.peek(-1), buf[1:]) | ||
| self.assertEqual(memio.tell(), 1) | ||
| memio.read() | ||
| self.assertEqual(memio.tell(), len(buf)) | ||
| self.assertEqual(memio.peek(1), self.EOF) | ||
| self.assertEqual(memio.peek(3), self.EOF) | ||
| self.assertEqual(memio.peek(5), self.EOF) | ||
| self.assertEqual(memio.peek(0), b"") | ||
| self.assertEqual(memio.tell(), len(buf)) | ||
| # Peeking works after writing | ||
| abc = self.buftype("abc") | ||
| memio.write(abc) | ||
| self.assertEqual(memio.peek(), self.EOF) | ||
| memio.seek(len(buf)) | ||
| self.assertEqual(memio.peek(), abc) | ||
| self.assertEqual(memio.peek(-1), abc) | ||
| self.assertEqual(memio.peek(len(abc) + 100), abc) | ||
| self.assertEqual(memio.tell(), len(buf)) | ||
marcelm marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
cmaloney marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| with self.ioclass(buf) as memio: | ||
| memio.seek(len(buf)) | ||
| self.assertEqual(memio.peek(), self.EOF) | ||
| # Current position beyond buffer end | ||
| with self.ioclass(buf) as memio: | ||
| memio.seek(len(buf) + 100) | ||
| self.assertEqual(memio.peek(), self.EOF) | ||
| with self.ioclass(buf) as memio: | ||
| memio.read() | ||
| memio.truncate(0) | ||
| self.assertEqual(memio.tell(), len(buf)) | ||
| self.assertEqual(memio.peek(), self.EOF) | ||
| self.assertRaises(ValueError, memio.peek) | ||
| def test_unicode(self): | ||
| memio = self.ioclass() | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| Add :meth:`io.BytesIO.peek`. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -420,8 +420,9 @@ _io_BytesIO_tell_impl(bytesio *self) | ||
| return PyLong_FromSsize_t(self->pos); | ||
| } | ||
| // Read without advancing position | ||
| static PyObject * | ||
| read_bytes_lock_held(bytesio *self, Py_ssize_t size) | ||
| peek_bytes_lock_held(bytesio *self, Py_ssize_t size) | ||
| { | ||
| _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(self); | ||
| @@ -432,7 +433,6 @@ read_bytes_lock_held(bytesio *self, Py_ssize_t size) | ||
| if (size > 1 && | ||
marcelm marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| self->pos == 0 && size == PyBytes_GET_SIZE(self->buf) && | ||
| FT_ATOMIC_LOAD_SSIZE_RELAXED(self->exports) == 0) { | ||
| self->pos += size; | ||
| return Py_NewRef(self->buf); | ||
| } | ||
| @@ -444,10 +444,20 @@ read_bytes_lock_held(bytesio *self, Py_ssize_t size) | ||
| } | ||
| output = PyBytes_AS_STRING(self->buf) + self->pos; | ||
| self->pos += size; | ||
| return PyBytes_FromStringAndSize(output, size); | ||
| } | ||
| static PyObject * | ||
| read_bytes_lock_held(bytesio *self, Py_ssize_t size) | ||
| { | ||
| PyObject *bytes = peek_bytes_lock_held(self, size); | ||
| if (bytes != NULL) { | ||
| assert(PyBytes_GET_SIZE(bytes) == size); | ||
| self->pos += size; | ||
marcelm marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| } | ||
| return bytes; | ||
| } | ||
| /*[clinic input] | ||
| @critical_section | ||
| _io.BytesIO.read | ||
| @@ -499,6 +509,38 @@ _io_BytesIO_read1_impl(bytesio *self, Py_ssize_t size) | ||
| return _io_BytesIO_read_impl(self, size); | ||
| } | ||
| /*[clinic input] | ||
| @critical_section | ||
| _io.BytesIO.peek | ||
| size: Py_ssize_t = 0 | ||
| / | ||
| Return bytes from the stream without advancing the position. | ||
| Return an empty bytes object at EOF. | ||
| [clinic start generated code]*/ | ||
| static PyObject * | ||
| _io_BytesIO_peek_impl(bytesio *self, Py_ssize_t size) | ||
| /*[clinic end generated code: output=fa4d8ce28b35db9b input=2ce74234b10aec3e]*/ | ||
| { | ||
| CHECK_CLOSED(self); | ||
| /* adjust invalid sizes */ | ||
| Py_ssize_t n = self->string_size - self->pos; | ||
cmaloney marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| if (size < 1 || size > n) { | ||
| size = n; | ||
| /* n can be negative after truncate() or seek() */ | ||
| if (size < 0) { | ||
| size = 0; | ||
| } | ||
| } | ||
| return peek_bytes_lock_held(self, size); | ||
| } | ||
| /*[clinic input] | ||
| @critical_section | ||
| _io.BytesIO.readline | ||
| @@ -1135,6 +1177,7 @@ static struct PyMethodDef bytesio_methods[] = { | ||
| _IO_BYTESIO_READLINE_METHODDEF | ||
| _IO_BYTESIO_READLINES_METHODDEF | ||
| _IO_BYTESIO_READ_METHODDEF | ||
| _IO_BYTESIO_PEEK_METHODDEF | ||
| _IO_BYTESIO_GETBUFFER_METHODDEF | ||
| _IO_BYTESIO_GETVALUE_METHODDEF | ||
| _IO_BYTESIO_SEEK_METHODDEF | ||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.