diff --git a/Doc/library/hashlib.rst b/Doc/library/hashlib.rst index ed0b0b2735b5c3..5b666c5adac645 100644 --- a/Doc/library/hashlib.rst +++ b/Doc/library/hashlib.rst @@ -50,12 +50,15 @@ hash supplied more than 2047 bytes of data at once in its constructor or .. index:: single: OpenSSL; (use in module hashlib) Constructors for hash algorithms that are always present in this module are -:func:`sha1`, :func:`sha224`, :func:`sha256`, :func:`sha384`, :func:`sha512`, -:func:`sha3_224`, :func:`sha3_256`, :func:`sha3_384`, :func:`sha3_512`, -:func:`shake_128`, :func:`shake_256`, :func:`blake2b`, and :func:`blake2s`. -:func:`md5` is normally available as well, though it may be missing or blocked -if you are using a rare "FIPS compliant" build of Python. -These correspond to :data:`algorithms_guaranteed`. +:func:`md5`, :func:`sha1`, :func:`sha224`, :func:`sha256`, :func:`sha384`, +:func:`sha512`, :func:`sha3_224`, :func:`sha3_256`, :func:`sha3_384`, +:func:`sha3_512`, :func:`shake_128`, :func:`shake_256`, :func:`blake2b`, and +:func:`blake2s`. These correspond to :data:`algorithms_guaranteed`. + +Any of these may nonetheless be missing or blocked in unusual environments, +such as a rare "FIPS compliant" build of Python or when OpenSSL's "FIPS mode" +is configured to exclude some algorithms from its default provider. Calling +the constructor of an algorithm that is unavailable raises :exc:`ValueError`. Additional algorithms may also be available if your Python distribution's :mod:`!hashlib` was linked against a build of OpenSSL that provides others. diff --git a/Lib/hashlib.py b/Lib/hashlib.py index 6c73eb9f31f8e4..c1e2d07c4357ff 100644 --- a/Lib/hashlib.py +++ b/Lib/hashlib.py @@ -261,16 +261,15 @@ 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 as __exc: - import logging as __logging - __logging.error('hash algorithm %s will not be supported at runtime ' - '[reason: %s]', __func_name, __exc) + except ValueError: + # Don't log here: logging at import time has global side effects and + # would tell the wrong audience; code that uses a missing algorithm + # gets a ValueError from the stub installed below. # The following code can be simplified in Python 3.19 # once "string" is removed from the signature. __code = f'''\ @@ -291,9 +290,8 @@ def {__func_name}(data=__UNSET, *, usedforsecurity=True, string=__UNSET): ''' exec(__code, {"__UNSET": object()}, __locals := {}) globals()[__func_name] = __locals[__func_name] - del __exc, __code, __locals + del __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/2026-06-29-01-08-53.gh-issue-110357.QGWdZQ.rst b/Misc/NEWS.d/next/Library/2026-06-29-01-08-53.gh-issue-110357.QGWdZQ.rst new file mode 100644 index 00000000000000..7c2384ea76fe53 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-29-01-08-53.gh-issue-110357.QGWdZQ.rst @@ -0,0 +1,6 @@ +Importing :mod:`hashlib` no longer logs an error to stderr when a normally +guaranteed hash algorithm is unavailable in the current runtime (for example +under an OpenSSL FIPS configuration or a build using +:option:`--without-builtin-hashlib-hashes <--with-builtin-hashlib-hashes>`). +Code that actually uses the missing algorithm still gets a clear +:exc:`ValueError`.