Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 2b47f46

Browse filesBrowse files
authored
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
1 parent fa70bf8 commit 2b47f46
Copy full SHA for 2b47f46

File tree

Expand file treeCollapse file tree

4 files changed

+22
-1
lines changed
Filter options
Expand file treeCollapse file tree

4 files changed

+22
-1
lines changed

‎Doc/library/hashlib.rst

Copy file name to clipboardExpand all lines: Doc/library/hashlib.rst
+8-1Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,10 @@ a file or file-like object.
270270
*fileobj* must be a file-like object opened for reading in binary mode.
271271
It accepts file objects from builtin :func:`open`, :class:`~io.BytesIO`
272272
instances, SocketIO objects from :meth:`socket.socket.makefile`, and
273-
similar. The function may bypass Python's I/O and use the file descriptor
273+
similar. *fileobj* must be opened in blocking mode, otherwise a
274+
:exc:`BlockingIOError` may be raised.
275+
276+
The function may bypass Python's I/O and use the file descriptor
274277
from :meth:`~io.IOBase.fileno` directly. *fileobj* must be assumed to be
275278
in an unknown state after this function returns or raises. It is up to
276279
the caller to close *fileobj*.
@@ -299,6 +302,10 @@ a file or file-like object.
299302

300303
.. versionadded:: 3.11
301304

305+
.. versionchanged:: next
306+
Now raises a :exc:`BlockingIOError` if the file is opened in blocking
307+
mode. Previously, spurious null bytes were added to the digest.
308+
302309

303310
Key derivation
304311
--------------

‎Lib/hashlib.py

Copy file name to clipboardExpand all lines: Lib/hashlib.py
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,8 @@ def file_digest(fileobj, digest, /, *, _bufsize=2**18):
231231
view = memoryview(buf)
232232
while True:
233233
size = fileobj.readinto(buf)
234+
if size is None:
235+
raise BlockingIOError("I/O operation would block.")
234236
if size == 0:
235237
break # EOF
236238
digestobj.update(view[:size])

‎Lib/test/test_hashlib.py

Copy file name to clipboardExpand all lines: Lib/test/test_hashlib.py
+9Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1199,6 +1199,15 @@ def test_file_digest(self):
11991199
with self.assertRaises(ValueError):
12001200
hashlib.file_digest(None, "sha256")
12011201

1202+
class NonBlocking:
1203+
def readinto(self, buf):
1204+
return None
1205+
def readable(self):
1206+
return True
1207+
1208+
with self.assertRaises(BlockingIOError):
1209+
hashlib.file_digest(NonBlocking(), hashlib.sha256)
1210+
12021211

12031212
if __name__ == "__main__":
12041213
unittest.main()
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
:func:`hashlib.file_digest` now raises :exc:`BlockingIOError` when no data
2+
is available during non-blocking I/O. Before, it added spurious null bytes
3+
to the digest.

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.