Skip to content

Commit 48b0fa1

Browse files
committed
add more hashlib test helpers
- add `requires_builtin_hmac` to check if built-in HMAC is available - refactor `requires_hashdigest` in prevision of a future `requires_builtin_hashdigest` for built-in hashes only
1 parent 1300cce commit 48b0fa1

File tree

1 file changed

+53
-29
lines changed

1 file changed

+53
-29
lines changed

Lib/test/support/hashlib_helper.py

Lines changed: 53 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -7,49 +7,73 @@
77
except ImportError:
88
_hashlib = None
99

10+
try:
11+
import _hmac
12+
except:
13+
_hmac = None
14+
1015

1116
def requires_hashlib():
1217
return unittest.skipIf(_hashlib is None, "requires _hashlib")
1318

1419

20+
def requires_builtin_hmac():
21+
return unittest.skipIf(_hmac is None, "requires _hmac")
22+
23+
24+
def _decorate_func_or_class(func_or_class, decorator_func):
25+
if not isinstance(func_or_class, type):
26+
return decorator_func(func_or_class)
27+
28+
decorated_class = func_or_class
29+
setUpClass = decorated_class.__dict__.get('setUpClass')
30+
if setUpClass is None:
31+
def setUpClass(cls):
32+
super(decorated_class, cls).setUpClass()
33+
setUpClass.__qualname__ = decorated_class.__qualname__ + '.setUpClass'
34+
setUpClass.__module__ = decorated_class.__module__
35+
else:
36+
setUpClass = setUpClass.__func__
37+
setUpClass = classmethod(decorator_func(setUpClass))
38+
decorated_class.setUpClass = setUpClass
39+
return decorated_class
40+
41+
1542
def requires_hashdigest(digestname, openssl=None, usedforsecurity=True):
16-
"""Decorator raising SkipTest if a hashing algorithm is not available
43+
"""Decorator raising SkipTest if a hashing algorithm is not available.
1744
18-
The hashing algorithm could be missing or blocked by a strict crypto
19-
policy.
45+
The hashing algorithm may be missing, blocked by a strict crypto policy,
46+
or Python may be configured with `--with-builtin-hashlib-hashes=no`.
2047
2148
If 'openssl' is True, then the decorator checks that OpenSSL provides
22-
the algorithm. Otherwise the check falls back to built-in
23-
implementations. The usedforsecurity flag is passed to the constructor.
49+
the algorithm. Otherwise the check falls back to (optional) built-in
50+
HACL* implementations.
51+
52+
The usedforsecurity flag is passed to the constructor but has no effect
53+
for HACL* implementations.
2454
55+
Examples of exceptions being suppressed:
2556
ValueError: [digital envelope routines: EVP_DigestInit_ex] disabled for FIPS
2657
ValueError: unsupported hash type md4
2758
"""
28-
def decorator(func_or_class):
29-
if isinstance(func_or_class, type):
30-
setUpClass = func_or_class.__dict__.get('setUpClass')
31-
if setUpClass is None:
32-
def setUpClass(cls):
33-
super(func_or_class, cls).setUpClass()
34-
setUpClass.__qualname__ = func_or_class.__qualname__ + '.setUpClass'
35-
setUpClass.__module__ = func_or_class.__module__
36-
else:
37-
setUpClass = setUpClass.__func__
38-
setUpClass = classmethod(decorator(setUpClass))
39-
func_or_class.setUpClass = setUpClass
40-
return func_or_class
41-
42-
@functools.wraps(func_or_class)
59+
if openssl and _hashlib is not None:
60+
def test_availability():
61+
_hashlib.new(digestname, usedforsecurity=usedforsecurity)
62+
else:
63+
def test_availability():
64+
hashlib.new(digestname, usedforsecurity=usedforsecurity)
65+
66+
def decorator_func(func):
67+
@functools.wraps(func)
4368
def wrapper(*args, **kwargs):
4469
try:
45-
if openssl and _hashlib is not None:
46-
_hashlib.new(digestname, usedforsecurity=usedforsecurity)
47-
else:
48-
hashlib.new(digestname, usedforsecurity=usedforsecurity)
49-
except ValueError:
50-
raise unittest.SkipTest(
51-
f"hash digest {digestname!r} is not available."
52-
)
53-
return func_or_class(*args, **kwargs)
70+
test_availability()
71+
except ValueError as exc:
72+
msg = f"missing hash algorithm: {digestname!r}"
73+
raise unittest.SkipTest(msg) from exc
74+
return func(*args, **kwargs)
5475
return wrapper
76+
77+
def decorator(func_or_class):
78+
return _decorate_func_or_class(func_or_class, decorator_func)
5579
return decorator

0 commit comments

Comments
 (0)