[Python-checkins] bpo-40275: Move requires_hashdigest() to test.support.hashlib_helper (GH-19716)

Hai Shi webhook-mailer at python.org
Tue Apr 28 21:11:37 EDT 2020


https://github.com/python/cpython/commit/66abe98a816de84f89e2de4aa78cf09056227c25
commit: 66abe98a816de84f89e2de4aa78cf09056227c25
branch: master
author: Hai Shi <shihai1992 at gmail.com>
committer: GitHub <noreply at github.com>
date: 2020-04-29T03:11:29+02:00
summary:

bpo-40275: Move requires_hashdigest() to test.support.hashlib_helper (GH-19716)

Add a new test.support.hashlib_helper submodule.

files:
A Lib/test/support/hashlib_helper.py
M Lib/test/support/__init__.py
M Lib/test/test_hashlib.py
M Lib/test/test_hmac.py
M Lib/test/test_imaplib.py
M Lib/test/test_poplib.py
M Lib/test/test_smtplib.py
M Lib/test/test_tarfile.py
M Lib/test/test_urllib2_localnet.py

diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py
index f48decc704cb8..ee5882f237cfc 100644
--- a/Lib/test/support/__init__.py
+++ b/Lib/test/support/__init__.py
@@ -11,7 +11,6 @@
 import functools
 import gc
 import glob
-import hashlib
 import importlib
 import importlib.util
 import locale
@@ -59,11 +58,6 @@
 except ImportError:
     resource = None
 
-try:
-    import _hashlib
-except ImportError:
-    _hashlib = None
-
 __all__ = [
     # globals
     "PIPE_MAX_SIZE", "verbose", "max_memuse", "use_resources", "failfast",
@@ -81,7 +75,7 @@
     "create_empty_file", "can_symlink", "fs_is_case_insensitive",
     # unittest
     "is_resource_enabled", "requires", "requires_freebsd_version",
-    "requires_linux_version", "requires_mac_ver", "requires_hashdigest",
+    "requires_linux_version", "requires_mac_ver",
     "check_syntax_error", "check_syntax_warning",
     "TransientResource", "time_out", "socket_peer_reset", "ioerror_peer_reset",
     "transient_internet", "BasicTestRunner", "run_unittest", "run_doctest",
@@ -685,36 +679,6 @@ def wrapper(*args, **kw):
     return decorator
 
 
-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
-
-
 def system_must_validate_cert(f):
     """Skip the test on TLS certificate validation failures."""
     @functools.wraps(f)
diff --git a/Lib/test/support/hashlib_helper.py b/Lib/test/support/hashlib_helper.py
new file mode 100644
index 0000000000000..a28132a565a0b
--- /dev/null
+++ b/Lib/test/support/hashlib_helper.py
@@ -0,0 +1,38 @@
+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
diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py
index 0e30b2fb11f29..33b687e0b4086 100644
--- a/Lib/test/test_hashlib.py
+++ b/Lib/test/test_hashlib.py
@@ -19,7 +19,6 @@
 import warnings
 from test import support
 from test.support import _4G, bigmemtest, import_fresh_module
-from test.support import requires_hashdigest
 from http.client import HTTPException
 
 # Were we compiled --with-pydebug or with #define Py_DEBUG?
diff --git a/Lib/test/test_hmac.py b/Lib/test/test_hmac.py
index 23c108f6e3c27..08086f0e78c83 100644
--- a/Lib/test/test_hmac.py
+++ b/Lib/test/test_hmac.py
@@ -6,7 +6,7 @@
 import unittest.mock
 import warnings
 
-from test.support import requires_hashdigest
+from test.support import hashlib_helper
 
 
 def ignore_warning(func):
@@ -21,7 +21,7 @@ def wrapper(*args, **kwargs):
 
 class TestVectorsTestCase(unittest.TestCase):
 
-    @requires_hashdigest('md5', openssl=True)
+    @hashlib_helper.requires_hashdigest('md5', openssl=True)
     def test_md5_vectors(self):
         # Test the HMAC module against test vectors from the RFC.
 
@@ -79,7 +79,7 @@ def md5test(key, data, digest):
                  b"and Larger Than One Block-Size Data"),
                 "6f630fad67cda0ee1fb1f562db3aa53e")
 
-    @requires_hashdigest('sha1', openssl=True)
+    @hashlib_helper.requires_hashdigest('sha1', openssl=True)
     def test_sha_vectors(self):
         def shatest(key, data, digest):
             h = hmac.HMAC(key, data, digestmod=hashlib.sha1)
@@ -272,23 +272,23 @@ def hmactest(key, data, hexdigests):
                                    '134676fb6de0446065c97440fa8c6a58',
                  })
 
-    @requires_hashdigest('sha224', openssl=True)
+    @hashlib_helper.requires_hashdigest('sha224', openssl=True)
     def test_sha224_rfc4231(self):
         self._rfc4231_test_cases(hashlib.sha224, 'sha224', 28, 64)
 
-    @requires_hashdigest('sha256', openssl=True)
+    @hashlib_helper.requires_hashdigest('sha256', openssl=True)
     def test_sha256_rfc4231(self):
         self._rfc4231_test_cases(hashlib.sha256, 'sha256', 32, 64)
 
-    @requires_hashdigest('sha384', openssl=True)
+    @hashlib_helper.requires_hashdigest('sha384', openssl=True)
     def test_sha384_rfc4231(self):
         self._rfc4231_test_cases(hashlib.sha384, 'sha384', 48, 128)
 
-    @requires_hashdigest('sha512', openssl=True)
+    @hashlib_helper.requires_hashdigest('sha512', openssl=True)
     def test_sha512_rfc4231(self):
         self._rfc4231_test_cases(hashlib.sha512, 'sha512', 64, 128)
 
-    @requires_hashdigest('sha256')
+    @hashlib_helper.requires_hashdigest('sha256')
     def test_legacy_block_size_warnings(self):
         class MockCrazyHash(object):
             """Ain't no block_size attribute here."""
@@ -329,7 +329,7 @@ class ConstructorTestCase(unittest.TestCase):
         "6c845b47f52b3b47f6590c502db7825aad757bf4fadc8fa972f7cd2e76a5bdeb"
     )
 
-    @requires_hashdigest('sha256')
+    @hashlib_helper.requires_hashdigest('sha256')
     def test_normal(self):
         # Standard constructor call.
         try:
@@ -337,21 +337,21 @@ def test_normal(self):
         except Exception:
             self.fail("Standard constructor call raised exception.")
 
-    @requires_hashdigest('sha256')
+    @hashlib_helper.requires_hashdigest('sha256')
     def test_with_str_key(self):
         # Pass a key of type str, which is an error, because it expects a key
         # of type bytes
         with self.assertRaises(TypeError):
             h = hmac.HMAC("key", digestmod='sha256')
 
-    @requires_hashdigest('sha256')
+    @hashlib_helper.requires_hashdigest('sha256')
     def test_dot_new_with_str_key(self):
         # Pass a key of type str, which is an error, because it expects a key
         # of type bytes
         with self.assertRaises(TypeError):
             h = hmac.new("key", digestmod='sha256')
 
-    @requires_hashdigest('sha256')
+    @hashlib_helper.requires_hashdigest('sha256')
     def test_withtext(self):
         # Constructor call with text.
         try:
@@ -360,7 +360,7 @@ def test_withtext(self):
             self.fail("Constructor call with text argument raised exception.")
         self.assertEqual(h.hexdigest(), self.expected)
 
-    @requires_hashdigest('sha256')
+    @hashlib_helper.requires_hashdigest('sha256')
     def test_with_bytearray(self):
         try:
             h = hmac.HMAC(bytearray(b"key"), bytearray(b"hash this!"),
@@ -369,7 +369,7 @@ def test_with_bytearray(self):
             self.fail("Constructor call with bytearray arguments raised exception.")
         self.assertEqual(h.hexdigest(), self.expected)
 
-    @requires_hashdigest('sha256')
+    @hashlib_helper.requires_hashdigest('sha256')
     def test_with_memoryview_msg(self):
         try:
             h = hmac.HMAC(b"key", memoryview(b"hash this!"), digestmod="sha256")
@@ -377,7 +377,7 @@ def test_with_memoryview_msg(self):
             self.fail("Constructor call with memoryview msg raised exception.")
         self.assertEqual(h.hexdigest(), self.expected)
 
-    @requires_hashdigest('sha256')
+    @hashlib_helper.requires_hashdigest('sha256')
     def test_withmodule(self):
         # Constructor call with text and digest module.
         try:
@@ -388,7 +388,7 @@ def test_withmodule(self):
 
 class SanityTestCase(unittest.TestCase):
 
-    @requires_hashdigest('sha256')
+    @hashlib_helper.requires_hashdigest('sha256')
     def test_exercise_all_methods(self):
         # Exercising all methods once.
         # This must not raise any exceptions
@@ -404,7 +404,7 @@ def test_exercise_all_methods(self):
 
 class CopyTestCase(unittest.TestCase):
 
-    @requires_hashdigest('sha256')
+    @hashlib_helper.requires_hashdigest('sha256')
     def test_attributes(self):
         # Testing if attributes are of same type.
         h1 = hmac.HMAC(b"key", digestmod="sha256")
@@ -416,7 +416,7 @@ def test_attributes(self):
         self.assertEqual(type(h1.outer), type(h2.outer),
             "Types of outer don't match.")
 
-    @requires_hashdigest('sha256')
+    @hashlib_helper.requires_hashdigest('sha256')
     def test_realcopy(self):
         # Testing if the copy method created a real copy.
         h1 = hmac.HMAC(b"key", digestmod="sha256")
@@ -428,7 +428,7 @@ def test_realcopy(self):
         self.assertTrue(id(h1.outer) != id(h2.outer),
             "No real copy of the attribute 'outer'.")
 
-    @requires_hashdigest('sha256')
+    @hashlib_helper.requires_hashdigest('sha256')
     def test_equality(self):
         # Testing if the copy has the same digests.
         h1 = hmac.HMAC(b"key", digestmod="sha256")
diff --git a/Lib/test/test_imaplib.py b/Lib/test/test_imaplib.py
index 69ee63b18c373..ce601565cf1a6 100644
--- a/Lib/test/test_imaplib.py
+++ b/Lib/test/test_imaplib.py
@@ -11,8 +11,8 @@
 import socket
 
 from test.support import (reap_threads, verbose, transient_internet,
-                          run_with_tz, run_with_locale, cpython_only,
-                          requires_hashdigest)
+                          run_with_tz, run_with_locale, cpython_only)
+from test.support import hashlib_helper
 import unittest
 from unittest import mock
 from datetime import datetime, timezone, timedelta
@@ -385,7 +385,7 @@ def cmd_AUTHENTICATE(self, tag, args):
         self.assertEqual(code, 'OK')
         self.assertEqual(server.response, b'ZmFrZQ==\r\n')  # b64 encoded 'fake'
 
-    @requires_hashdigest('md5')
+    @hashlib_helper.requires_hashdigest('md5')
     def test_login_cram_md5_bytes(self):
         class AuthHandler(SimpleIMAPHandler):
             capabilities = 'LOGINDISABLED AUTH=CRAM-MD5'
@@ -403,7 +403,7 @@ def cmd_AUTHENTICATE(self, tag, args):
         ret, _ = client.login_cram_md5("tim", b"tanstaaftanstaaf")
         self.assertEqual(ret, "OK")
 
-    @requires_hashdigest('md5')
+    @hashlib_helper.requires_hashdigest('md5')
     def test_login_cram_md5_plain_text(self):
         class AuthHandler(SimpleIMAPHandler):
             capabilities = 'LOGINDISABLED AUTH=CRAM-MD5'
@@ -849,7 +849,7 @@ def cmd_AUTHENTICATE(self, tag, args):
                              b'ZmFrZQ==\r\n')  # b64 encoded 'fake'
 
     @reap_threads
-    @requires_hashdigest('md5')
+    @hashlib_helper.requires_hashdigest('md5')
     def test_login_cram_md5(self):
 
         class AuthHandler(SimpleIMAPHandler):
diff --git a/Lib/test/test_poplib.py b/Lib/test/test_poplib.py
index d4877b1fbbc6b..b670afcf4e62e 100644
--- a/Lib/test/test_poplib.py
+++ b/Lib/test/test_poplib.py
@@ -13,6 +13,7 @@
 
 from unittest import TestCase, skipUnless
 from test import support as test_support
+from test.support import hashlib_helper
 from test.support import socket_helper
 
 HOST = socket_helper.HOST
@@ -311,11 +312,11 @@ def test_noop(self):
     def test_rpop(self):
         self.assertOK(self.client.rpop('foo'))
 
-    @test_support.requires_hashdigest('md5')
+    @hashlib_helper.requires_hashdigest('md5')
     def test_apop_normal(self):
         self.assertOK(self.client.apop('foo', 'dummypassword'))
 
-    @test_support.requires_hashdigest('md5')
+    @hashlib_helper.requires_hashdigest('md5')
     def test_apop_REDOS(self):
         # Replace welcome with very long evil welcome.
         # NB The upper bound on welcome length is currently 2048.
diff --git a/Lib/test/test_smtplib.py b/Lib/test/test_smtplib.py
index d1ffb368a4f6f..c1bd2e291255b 100644
--- a/Lib/test/test_smtplib.py
+++ b/Lib/test/test_smtplib.py
@@ -20,9 +20,9 @@
 
 import unittest
 from test import support, mock_socket
+from test.support import hashlib_helper
 from test.support import socket_helper
 from test.support import threading_setup, threading_cleanup, join_thread
-from test.support import requires_hashdigest
 from unittest.mock import Mock
 
 HOST = socket_helper.HOST
@@ -1058,7 +1058,7 @@ def testAUTH_LOGIN(self):
         self.assertEqual(resp, (235, b'Authentication Succeeded'))
         smtp.close()
 
-    @requires_hashdigest('md5')
+    @hashlib_helper.requires_hashdigest('md5')
     def testAUTH_CRAM_MD5(self):
         self.serv.add_feature("AUTH CRAM-MD5")
         smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost',
diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py
index 99196f6043191..25e9e93604476 100644
--- a/Lib/test/test_tarfile.py
+++ b/Lib/test/test_tarfile.py
@@ -11,7 +11,7 @@
 import tarfile
 
 from test import support
-from test.support import script_helper, requires_hashdigest
+from test.support import script_helper
 
 # Check for our compression modules.
 try:
diff --git a/Lib/test/test_urllib2_localnet.py b/Lib/test/test_urllib2_localnet.py
index 8cfb214c9af9a..421b9f7de2e21 100644
--- a/Lib/test/test_urllib2_localnet.py
+++ b/Lib/test/test_urllib2_localnet.py
@@ -9,6 +9,7 @@
 import hashlib
 
 from test import support
+from test.support import hashlib_helper
 
 try:
     import ssl
@@ -322,7 +323,7 @@ class ProxyAuthTests(unittest.TestCase):
     PASSWD = "test123"
     REALM = "TestRealm"
 
-    @support.requires_hashdigest("md5")
+    @hashlib_helper.requires_hashdigest("md5")
     def setUp(self):
         super(ProxyAuthTests, self).setUp()
         # Ignore proxy bypass settings in the environment.



More information about the Python-checkins mailing list