https://github.com/python/cpython/commit/af665032a599d84edf87457435059393ec38779a commit: af665032a599d84edf87457435059393ec38779a branch: 3.15 author: Miss Islington (bot) <[email protected]> committer: gpshead <[email protected]> date: 2026-06-29T08:39:32Z summary:
[3.15] gh-110357: hashlib no longer logs at import when a guaranteed hash is unavailable (GH-152538) (#152554) gh-110357: hashlib no longer logs at import when a guaranteed hash is unavailable (GH-152538) When a normally-guaranteed hash algorithm cannot be constructed at import time (e.g. an OpenSSL FIPS configuration excludes it from the default provider, or the build used --without-builtin-hashlib-hashes), importing hashlib emitted an "ERROR:root:hash algorithm ... will not be supported at runtime" message to stderr. For the many programs that never use the missing algorithm this is pure noise. Worse, logging.error() lazily calls logging.basicConfig(), which mutates the root logger's handlers -- a global side effect that the test suite flags as an altered execution environment. Stop logging in that path. Code that actually uses a missing algorithm still gets a clear ValueError from the stub constructor installed in its place. The stray output has shown up incidentally in FIPS / "No Builtin Hashes" buildbot reports for years (e.g. gh-110357, gh-76902) without being the reported subject. (cherry picked from commit 8ae1a236fd334a590e90028f615cd4a822ae6f97) Co-authored-by: Gregory P. Smith <[email protected]> files: A Misc/NEWS.d/next/Library/2026-06-29-01-08-53.gh-issue-110357.QGWdZQ.rst M Doc/library/hashlib.rst M Lib/hashlib.py 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`. _______________________________________________ Python-checkins mailing list -- [email protected] To unsubscribe send an email to [email protected] https://mail.python.org/mailman3//lists/python-checkins.python.org Member address: [email protected]
