Skip to content

Commit 2419aee

Browse files
committed
consistent constructor
1 parent 28a603d commit 2419aee

File tree

1 file changed

+45
-27
lines changed

1 file changed

+45
-27
lines changed

Lib/test/support/hashlib_helper.py

Lines changed: 45 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import inspect
66
import unittest
77
import unittest.mock
8-
from functools import partial
98
from test.support import import_helper
109
from types import MappingProxyType
1110

@@ -207,7 +206,7 @@ def _chain_decorators(decorators):
207206
"""
208207
def decorator_func(func):
209208
return functools.reduce(lambda w, deco: deco(w), decorators, func)
210-
return partial(_decorate_func_or_class, decorator_func)
209+
return functools.partial(_decorate_func_or_class, decorator_func)
211210

212211

213212
def _ensure_wrapper_signature(wrapper, wrapped):
@@ -257,22 +256,22 @@ def _hashlib_new(digestname, openssl, /, **kwargs):
257256
If *openssl* is True, module is "_hashlib" (C extension module),
258257
otherwise it is "hashlib" (pure Python interface).
259258
260-
The constructor function is returned, or SkipTest is raised if none exists.
259+
The constructor function is returned (without binding **kwargs),
260+
or SkipTest is raised if none exists.
261261
"""
262262
assert isinstance(digestname, str), digestname
263263
# Re-import 'hashlib' in case it was mocked, but propagate
264264
# exceptions as it should be unconditionally available.
265265
hashlib = importlib.import_module("hashlib")
266266
# re-import '_hashlib' in case it was mocked
267267
_hashlib = try_import_module("_hashlib")
268-
mod = _hashlib if openssl and _hashlib is not None else hashlib
269-
constructor = partial(mod.new, digestname, **kwargs)
268+
module = _hashlib if openssl and _hashlib is not None else hashlib
270269
try:
271-
constructor()
270+
module.new(digestname, **kwargs)
272271
except ValueError:
273-
interface = f"{mod.__name__}.{new.__name__}"
272+
interface = f"{module.__name__}.new"
274273
raise SkipNoHash(digestname, interface=interface) from exc
275-
return constructor
274+
return functools.partial(module.new, digestname)
276275

277276

278277
def _builtin_hash(module_name, digestname, /, **kwargs):
@@ -304,26 +303,27 @@ def _builtin_hash(module_name, digestname, /, **kwargs):
304303
def _openssl_new(digestname, /, **kwargs):
305304
"""Check availability of _hashlib.new(digestname, **kwargs).
306305
307-
The constructor function is returned, or SkipTest is raised if none exists.
306+
The constructor function is returned (without binding **kwargs),
307+
or SkipTest is raised if none exists.
308308
"""
309309
assert isinstance(digestname, str), digestname
310310
try:
311311
# re-import '_hashlib' in case it was mocked
312312
_hashlib = importlib.import_module("_hashlib")
313313
except ImportError as exc:
314314
raise SkipNoHash(digestname, "openssl") from exc
315-
constructor = partial(_hashlib.new, digestname, **kwargs)
316315
try:
317-
constructor()
316+
_hashlib.new(digestname, **kwargs)
318317
except ValueError as exc:
319318
raise SkipNoHash(digestname, interface="_hashlib.new") from exc
320-
return constructor
319+
return functools.partial(_hashlib.new, digestname)
321320

322321

323322
def _openssl_hash(digestname, /, **kwargs):
324323
"""Check availability of _hashlib.openssl_<digestname>(**kwargs).
325324
326-
The constructor function is returned, or SkipTest is raised if none exists.
325+
The constructor function is returned (without binding **kwargs),
326+
or SkipTest is raised if none exists.
327327
"""
328328
assert isinstance(digestname, str), digestname
329329
fullname = f"_hashlib.openssl_{digestname}"
@@ -350,7 +350,7 @@ def wrapper(*args, **kwargs):
350350
test(*test_args, **test_kwargs)
351351
return func(*args, **kwargs)
352352
return wrapper
353-
return partial(_decorate_func_or_class, decorator_func)
353+
return functools.partial(_decorate_func_or_class, decorator_func)
354354

355355

356356
def requires_hashdigest(digestname, openssl=None, *, usedforsecurity=True):
@@ -430,7 +430,9 @@ class HashFunctionsTrait:
430430
'sha3_224', 'sha3_256', 'sha3_384', 'sha3_512',
431431
]
432432

433-
# Default 'usedforsecurity' to use when looking up a hash function.
433+
# Default 'usedforsecurity' to use when checking a hash function.
434+
# When the trait properties are callables (e.g., _md5.md5) and
435+
# not strings, they must be called with the same 'usedforsecurity'.
434436
usedforsecurity = True
435437

436438
@classmethod
@@ -549,46 +551,55 @@ def find_gil_minsize(modules_names, default=2048):
549551
def _block_openssl_hash_new(blocked_name):
550552
"""Block OpenSSL implementation of _hashlib.new()."""
551553
assert isinstance(blocked_name, str), blocked_name
554+
552555
# re-import '_hashlib' in case it was mocked
553556
if (_hashlib := try_import_module("_hashlib")) is None:
554557
return contextlib.nullcontext()
558+
555559
@functools.wraps(wrapped := _hashlib.new)
556-
def wrapper(name, data=b'', *, usedforsecurity=True, string=None):
560+
def _hashlib_new(name, data=b'', *, usedforsecurity=True, string=None):
557561
if name == blocked_name:
558562
raise _hashlib.UnsupportedDigestmodError(blocked_name)
559563
return wrapped(*args, **kwargs)
560-
_ensure_wrapper_signature(wrapper, wrapped)
561-
return unittest.mock.patch('_hashlib.new', wrapper)
564+
565+
_ensure_wrapper_signature(_hashlib_new, wrapped)
566+
return unittest.mock.patch('_hashlib.new', _hashlib_new)
562567

563568

564569
def _block_openssl_hmac_new(blocked_name):
565570
"""Block OpenSSL HMAC-HASH implementation."""
566571
assert isinstance(blocked_name, str), blocked_name
572+
567573
# re-import '_hashlib' in case it was mocked
568574
if (_hashlib := try_import_module("_hashlib")) is None:
569575
return contextlib.nullcontext()
576+
570577
@functools.wraps(wrapped := _hashlib.hmac_new)
571578
def wrapper(key, msg=b'', digestmod=None):
572579
if digestmod == blocked_name:
573580
raise _hashlib.UnsupportedDigestmodError(blocked_name)
574581
return wrapped(key, msg, digestmod)
582+
575583
_ensure_wrapper_signature(wrapper, wrapped)
576584
return unittest.mock.patch('_hashlib.hmac_new', wrapper)
577585

578586

579587
def _block_openssl_hmac_digest(blocked_name):
580588
"""Block OpenSSL HMAC-HASH one-shot digest implementation."""
581589
assert isinstance(blocked_name, str), blocked_name
590+
582591
# re-import '_hashlib' in case it was mocked
583592
if (_hashlib := try_import_module("_hashlib")) is None:
584593
return contextlib.nullcontext()
594+
585595
@functools.wraps(wrapped := _hashlib.hmac_digest)
586-
def wrapper(key, msg, digest):
596+
def _hashlib_hmac_digest(key, msg, digest):
587597
if digest == blocked_name:
588598
raise _hashlib.UnsupportedDigestmodError(blocked_name)
589599
return wrapped(key, msg, digestmod)
590-
_ensure_wrapper_signature(wrapper, wrapped)
591-
return unittest.mock.patch('_hashlib.hmac_digest', wrapper)
600+
601+
_ensure_wrapper_signature(_hashlib_hmac_digest, wrapped)
602+
return unittest.mock.patch('_hashlib.hmac_digest', _hashlib_hmac_digest)
592603

593604

594605
def _block_builtin_hash_new(name):
@@ -610,6 +621,7 @@ def _block_builtin_hash_new(name):
610621
get_builtin_constructor = getattr(hashlib, '__get_builtin_constructor')
611622
builtin_module_name = _EXPLICIT_CONSTRUCTORS[name].builtin_module_name
612623

624+
@functools.wraps(get_builtin_constructor)
613625
def get_builtin_constructor_mock(name):
614626
with import_helper.isolated_modules():
615627
sys = importlib.import_module("sys")
@@ -625,30 +637,36 @@ def get_builtin_constructor_mock(name):
625637

626638
def _block_builtin_hmac_new(blocked_name):
627639
assert isinstance(blocked_name, str), blocked_name
640+
628641
# re-import '_hmac' in case it was mocked
629642
if (_hmac := try_import_module("_hmac")) is None:
630643
return contextlib.nullcontext()
644+
631645
@functools.wraps(wrapped := _hmac.new)
632-
def wrapper(key, msg=None, digestmod=None):
646+
def _hmac_new(key, msg=None, digestmod=None):
633647
if digestmod == blocked_name:
634648
raise _hmac.UnknownHashError(blocked_name)
635649
return wrapped(key, msg, digestmod)
636-
_ensure_wrapper_signature(wrapper, wrapped)
637-
return unittest.mock.patch('_hmac.new', wrapper)
650+
651+
_ensure_wrapper_signature(_hmac_new, wrapped)
652+
return unittest.mock.patch('_hmac.new', _hmac_new)
638653

639654

640655
def _block_builtin_hmac_digest(blocked_name):
641656
assert isinstance(blocked_name, str), blocked_name
657+
642658
# re-import '_hmac' in case it was mocked
643659
if (_hmac := try_import_module("_hmac")) is None:
644660
return contextlib.nullcontext()
661+
645662
@functools.wraps(wrapped := _hmac.compute_digest)
646-
def wrapper(key, msg, digest):
663+
def _hmac_compute_digest(key, msg, digest):
647664
if digest == blocked_name:
648665
raise _hmac.UnknownHashError(blocked_name)
649666
return wrapped(key, msg, digest)
650-
_ensure_wrapper_signature(wrapper, wrapped)
651-
return unittest.mock.patch('_hmac.compute_digest', wrapper)
667+
668+
_ensure_wrapper_signature(_hmac_compute_digest, wrapped)
669+
return unittest.mock.patch('_hmac.compute_digest', _hmac_compute_digest)
652670

653671

654672
def _make_hash_constructor_blocker(name, dummy, implementation):

0 commit comments

Comments
 (0)