diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index 4d4fb77ad4f030..8068977375177f 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -230,6 +230,17 @@ difflib (Contributed by Jiahao Li in :gh:`134580`.) +hashlib +------- + +* Ensure that hash functions guaranteed to be always *available* exist as + attributes of :mod:`hashlib` even if they will not work at runtime due to + missing backend implementations. For instance, ``hashlib.md5`` will no + longer raise :exc:`AttributeError` if OpenSSL is not available and Python + has been built without MD5 support. + (Contributed by Bénédikt Tran in :gh:`136929`.) + + http.client ----------- diff --git a/Lib/hashlib.py b/Lib/hashlib.py index a7db778b716537..8e7083ba692348 100644 --- a/Lib/hashlib.py +++ b/Lib/hashlib.py @@ -261,16 +261,39 @@ def file_digest(fileobj, digest, /, *, _bufsize=2**18): return digestobj +__logging = None for __func_name in __always_supported: # try them all, some may not work due to the OpenSSL # version not supporting that algorithm. try: globals()[__func_name] = __get_hash(__func_name) - except ValueError: - import logging - logging.exception('code for hash %s was not found.', __func_name) - + except ValueError as __exc: + import logging as __logging + __logging.error('hash algorithm %s will not be supported at runtime ' + '[reason: %s]', __func_name, __exc) + # The following code can be simplified in Python 3.19 + # once "string" is removed from the signature. + __code = f'''\ +def {__func_name}(data=__UNSET, *, usedforsecurity=True, string=__UNSET): + if data is __UNSET and string is not __UNSET: + import warnings + warnings.warn( + "the 'string' keyword parameter is deprecated since " + "Python 3.15 and slated for removal in Python 3.19; " + "use the 'data' keyword parameter or pass the data " + "to hash as a positional argument instead", + DeprecationWarning, stacklevel=2) + if data is not __UNSET and string is not __UNSET: + raise TypeError("'data' and 'string' are mutually exclusive " + "and support for 'string' keyword parameter " + "is slated for removal in a future version.") + raise ValueError("unsupported hash algorithm {__func_name}") +''' + exec(__code, {"__UNSET": object()}, __locals := {}) + globals()[__func_name] = __locals[__func_name] + del __exc, __code, __locals # Cleanup locals() del __always_supported, __func_name, __get_hash del __py_new, __hash_new, __get_openssl_constructor +del __logging diff --git a/Misc/NEWS.d/next/Library/2025-07-21-16-13-20.gh-issue-136929.obKZ2S.rst b/Misc/NEWS.d/next/Library/2025-07-21-16-13-20.gh-issue-136929.obKZ2S.rst new file mode 100644 index 00000000000000..31b8563f9d8523 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-07-21-16-13-20.gh-issue-136929.obKZ2S.rst @@ -0,0 +1,5 @@ +Ensure that hash functions guaranteed to be always *available* exist as +attributes of :mod:`hashlib` even if they will not work at runtime due to +missing backend implementations. For instance, ``hashlib.md5`` will no +longer raise :exc:`AttributeError` if OpenSSL is not available and Python +has been built without MD5 support. Patch by Bénédikt Tran. pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy