From 3c1de38925ddd0986612bbcc24f7c6ea2dca9579 Mon Sep 17 00:00:00 2001 From: tucif Date: Thu, 19 Feb 2026 18:25:07 -0600 Subject: [PATCH 1/5] reuse blake2 conditionals in missing places and skip subtest for test_algorithms_available if implementation is not provided --- Lib/test/test_hashlib.py | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py index 489bb049d2fadb..573d81277f31ca 100644 --- a/Lib/test/test_hashlib.py +++ b/Lib/test/test_hashlib.py @@ -134,8 +134,11 @@ def __init__(self, *args, **kwargs): algorithms.add(algorithm.lower()) _blake2 = self._conditional_import_module('_blake2') + blake2_hashes = {'blake2b', 'blake2s'} if _blake2: - algorithms.update({'blake2b', 'blake2s'}) + algorithms.update(blake2_hashes) + else: + algorithms.difference_update(blake2_hashes) self.constructors_to_test = {} for algorithm in algorithms: @@ -232,7 +235,14 @@ def test_algorithms_available(self): # all available algorithms must be loadable, bpo-47101 self.assertNotIn("undefined", hashlib.algorithms_available) for name in hashlib.algorithms_available: - digest = hashlib.new(name, usedforsecurity=False) + with self.subTest(name): + try: + digest = hashlib.new(name, usedforsecurity=False) + assert digest is not None + except ValueError as verr: + # builtins may be absent if python built with + # a subset of --with-builtin-hashlib-hashes or none. + self.skipTest(verr) def test_usedforsecurity_true(self): hashlib.new("sha256", usedforsecurity=True) @@ -504,6 +514,7 @@ def test_sha3_256_update_over_4gb(self): self.assertEqual(h.hexdigest(), "e2d4535e3b613135c14f2fe4e026d7ad8d569db44901740beffa30d430acb038") @requires_resource('cpu') + @requires_blake2 def test_blake2_update_over_4gb(self): # blake2s or blake2b doesn't matter based on how our C code is structured, this tests the # common loop macro logic. @@ -1052,7 +1063,9 @@ def test_gil(self): # for multithreaded operation. Currently, all cryptographic modules # have the same constant value (2048) but in the future it might not # be the case. - mods = ['_md5', '_sha1', '_sha2', '_sha3', '_blake2', '_hashlib'] + mods = ['_md5', '_sha1', '_sha2', '_sha3', '_hashlib'] + if _blake2: + mods.append('_blake2') gil_minsize = hashlib_helper.find_gil_minsize(mods) for cons in self.hash_constructors: # constructors belong to one of the above modules @@ -1080,7 +1093,10 @@ def test_sha256_gil(self): def test_threaded_hashing_fast(self): # Same as test_threaded_hashing_slow() but only tests some functions # since otherwise test_hashlib.py becomes too slow during development. - for name in ['md5', 'sha1', 'sha256', 'sha3_256', 'blake2s']: + algos = ['md5', 'sha1', 'sha256', 'sha3_256'] + if _blake2: + algos.append('blake2s') + for name in algos: if constructor := getattr(hashlib, name, None): with self.subTest(name): self.do_test_threaded_hashing(constructor, is_shake=False) From dc7c6c697d7b4cf0c49a883becfa375510d4798f Mon Sep 17 00:00:00 2001 From: tucif Date: Fri, 20 Feb 2026 10:51:18 -0600 Subject: [PATCH 2/5] only skip on value error specific for blake2 if not in builtins in test_algorithms_available --- Lib/test/test_hashlib.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py index 573d81277f31ca..afb686f12ca081 100644 --- a/Lib/test/test_hashlib.py +++ b/Lib/test/test_hashlib.py @@ -242,7 +242,11 @@ def test_algorithms_available(self): except ValueError as verr: # builtins may be absent if python built with # a subset of --with-builtin-hashlib-hashes or none. - self.skipTest(verr) + if ("blake2" in name and + "blake2" not in sysconfig.get_config_var("PY_BUILTIN_HASHLIB_HASHES").split(",")): + self.skipTest(verr) + else: + raise def test_usedforsecurity_true(self): hashlib.new("sha256", usedforsecurity=True) From 1fdc8c7759fa260f9c5d8de2bcca67ecb0566264 Mon Sep 17 00:00:00 2001 From: tucif Date: Fri, 20 Feb 2026 13:19:24 -0600 Subject: [PATCH 3/5] Address reviewer comments - Moved retrieval of PY_BUILTIN_HASHLIB_HASHES out of the loop - Removed guard from test_gil --- Lib/test/test_hashlib.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py index afb686f12ca081..57eed49b3e791f 100644 --- a/Lib/test/test_hashlib.py +++ b/Lib/test/test_hashlib.py @@ -234,6 +234,7 @@ def test_algorithms_available(self): issubset(hashlib.algorithms_available)) # all available algorithms must be loadable, bpo-47101 self.assertNotIn("undefined", hashlib.algorithms_available) + algorithms_builtin = sysconfig.get_config_var("PY_BUILTIN_HASHLIB_HASHES").split(",") for name in hashlib.algorithms_available: with self.subTest(name): try: @@ -243,7 +244,7 @@ def test_algorithms_available(self): # builtins may be absent if python built with # a subset of --with-builtin-hashlib-hashes or none. if ("blake2" in name and - "blake2" not in sysconfig.get_config_var("PY_BUILTIN_HASHLIB_HASHES").split(",")): + "blake2" not in algorithms_builtin): self.skipTest(verr) else: raise @@ -1067,9 +1068,7 @@ def test_gil(self): # for multithreaded operation. Currently, all cryptographic modules # have the same constant value (2048) but in the future it might not # be the case. - mods = ['_md5', '_sha1', '_sha2', '_sha3', '_hashlib'] - if _blake2: - mods.append('_blake2') + mods = ['_md5', '_sha1', '_sha2', '_sha3', '_blake2', '_hashlib'] gil_minsize = hashlib_helper.find_gil_minsize(mods) for cons in self.hash_constructors: # constructors belong to one of the above modules From 17eb629f8ad33681080161a3bc80a48ed938675b Mon Sep 17 00:00:00 2001 From: tucif Date: Fri, 20 Feb 2026 17:34:47 -0600 Subject: [PATCH 4/5] add skip_if_blake2_not_builtin helper and use it also from test_threaded_hashing_fast --- Lib/test/test_hashlib.py | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py index 57eed49b3e791f..0279a56efac679 100644 --- a/Lib/test/test_hashlib.py +++ b/Lib/test/test_hashlib.py @@ -234,20 +234,14 @@ def test_algorithms_available(self): issubset(hashlib.algorithms_available)) # all available algorithms must be loadable, bpo-47101 self.assertNotIn("undefined", hashlib.algorithms_available) - algorithms_builtin = sysconfig.get_config_var("PY_BUILTIN_HASHLIB_HASHES").split(",") for name in hashlib.algorithms_available: with self.subTest(name): try: digest = hashlib.new(name, usedforsecurity=False) assert digest is not None except ValueError as verr: - # builtins may be absent if python built with - # a subset of --with-builtin-hashlib-hashes or none. - if ("blake2" in name and - "blake2" not in algorithms_builtin): - self.skipTest(verr) - else: - raise + self.skip_if_blake2_not_builtin(name, verr) + raise def test_usedforsecurity_true(self): hashlib.new("sha256", usedforsecurity=True) @@ -814,6 +808,12 @@ def test_case_sha512_3(self): "e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973eb"+ "de0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b") + def skip_if_blake2_not_builtin(self, name, skip_reason): + # blake2 builtins may be absent if python built with + # a subset of --with-builtin-hashlib-hashes or none. + if "blake2" in name and "blake2" not in builtin_hashes: + self.skipTest(skip_reason) + def check_blake2(self, constructor, salt_size, person_size, key_size, digest_size, max_offset): self.assertEqual(constructor.SALT_SIZE, salt_size) @@ -1096,13 +1096,16 @@ def test_sha256_gil(self): def test_threaded_hashing_fast(self): # Same as test_threaded_hashing_slow() but only tests some functions # since otherwise test_hashlib.py becomes too slow during development. - algos = ['md5', 'sha1', 'sha256', 'sha3_256'] - if _blake2: - algos.append('blake2s') + algos = ['md5', 'sha1', 'sha256', 'sha3_256', 'blake2s'] for name in algos: if constructor := getattr(hashlib, name, None): with self.subTest(name): - self.do_test_threaded_hashing(constructor, is_shake=False) + try: + self.do_test_threaded_hashing(constructor, is_shake=False) + except ValueError as verr: + self.skip_if_blake2_not_builtin(name, verr) + raise + if shake_128 := getattr(hashlib, 'shake_128', None): self.do_test_threaded_hashing(shake_128, is_shake=True) From 3ada5d265b3a8adebf2fda85fdeaa8912347f2a5 Mon Sep 17 00:00:00 2001 From: tucif Date: Fri, 20 Feb 2026 18:09:05 -0600 Subject: [PATCH 5/5] Address review comments - Remove assert for None as that is not a possible return value anyway - Renamed verr to exc - Renamed digest to _ as it is ignored --- Lib/test/test_hashlib.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py index 0279a56efac679..f0e2d527af2615 100644 --- a/Lib/test/test_hashlib.py +++ b/Lib/test/test_hashlib.py @@ -237,10 +237,9 @@ def test_algorithms_available(self): for name in hashlib.algorithms_available: with self.subTest(name): try: - digest = hashlib.new(name, usedforsecurity=False) - assert digest is not None - except ValueError as verr: - self.skip_if_blake2_not_builtin(name, verr) + _ = hashlib.new(name, usedforsecurity=False) + except ValueError as exc: + self.skip_if_blake2_not_builtin(name, exc) raise def test_usedforsecurity_true(self): @@ -1102,8 +1101,8 @@ def test_threaded_hashing_fast(self): with self.subTest(name): try: self.do_test_threaded_hashing(constructor, is_shake=False) - except ValueError as verr: - self.skip_if_blake2_not_builtin(name, verr) + except ValueError as exc: + self.skip_if_blake2_not_builtin(name, exc) raise if shake_128 := getattr(hashlib, 'shake_128', None):