|  | import functools | 
|  | import hashlib | 
|  | import unittest | 
|  |  | 
|  | try: | 
|  | import _hashlib | 
|  | except ImportError: | 
|  | _hashlib = None | 
|  |  | 
|  |  | 
|  | def requires_hashdigest(digestname, openssl=None, usedforsecurity=True): | 
|  | """Decorator raising SkipTest if a hashing algorithm is not available | 
|  |  | 
|  | The hashing algorithm could be missing or blocked by a strict crypto | 
|  | policy. | 
|  |  | 
|  | If 'openssl' is True, then the decorator checks that OpenSSL provides | 
|  | the algorithm. Otherwise the check falls back to built-in | 
|  | implementations. The usedforsecurity flag is passed to the constructor. | 
|  |  | 
|  | ValueError: [digital envelope routines: EVP_DigestInit_ex] disabled for FIPS | 
|  | ValueError: unsupported hash type md4 | 
|  | """ | 
|  | def decorator(func): | 
|  | @functools.wraps(func) | 
|  | def wrapper(*args, **kwargs): | 
|  | try: | 
|  | if openssl and _hashlib is not None: | 
|  | _hashlib.new(digestname, usedforsecurity=usedforsecurity) | 
|  | else: | 
|  | hashlib.new(digestname, usedforsecurity=usedforsecurity) | 
|  | except ValueError: | 
|  | raise unittest.SkipTest( | 
|  | f"hash digest '{digestname}' is not available." | 
|  | ) | 
|  | return func(*args, **kwargs) | 
|  | return wrapper | 
|  | return decorator |