gh-122179: Fix hashlib.file_digest and non-blocking I/O (GH-122183)

* Fix hashlib.file_digest and non-blocking I/O
* Add documentation around this behavior
* Add versionchanged
This commit is contained in:
Sebastian Rittau 2025-04-21 23:15:05 +02:00 committed by GitHub
parent fa70bf8593
commit 2b47f46d7d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 22 additions and 1 deletions

View file

@ -270,7 +270,10 @@ a file or file-like object.
*fileobj* must be a file-like object opened for reading in binary mode.
It accepts file objects from builtin :func:`open`, :class:`~io.BytesIO`
instances, SocketIO objects from :meth:`socket.socket.makefile`, and
similar. The function may bypass Python's I/O and use the file descriptor
similar. *fileobj* must be opened in blocking mode, otherwise a
:exc:`BlockingIOError` may be raised.
The function may bypass Python's I/O and use the file descriptor
from :meth:`~io.IOBase.fileno` directly. *fileobj* must be assumed to be
in an unknown state after this function returns or raises. It is up to
the caller to close *fileobj*.
@ -299,6 +302,10 @@ a file or file-like object.
.. versionadded:: 3.11
.. versionchanged:: next
Now raises a :exc:`BlockingIOError` if the file is opened in blocking
mode. Previously, spurious null bytes were added to the digest.
Key derivation
--------------

View file

@ -231,6 +231,8 @@ def file_digest(fileobj, digest, /, *, _bufsize=2**18):
view = memoryview(buf)
while True:
size = fileobj.readinto(buf)
if size is None:
raise BlockingIOError("I/O operation would block.")
if size == 0:
break # EOF
digestobj.update(view[:size])

View file

@ -1199,6 +1199,15 @@ def test_file_digest(self):
with self.assertRaises(ValueError):
hashlib.file_digest(None, "sha256")
class NonBlocking:
def readinto(self, buf):
return None
def readable(self):
return True
with self.assertRaises(BlockingIOError):
hashlib.file_digest(NonBlocking(), hashlib.sha256)
if __name__ == "__main__":
unittest.main()

View file

@ -0,0 +1,3 @@
:func:`hashlib.file_digest` now raises :exc:`BlockingIOError` when no data
is available during non-blocking I/O. Before, it added spurious null bytes
to the digest.