Skip to content

Commit 679f811

Browse files
committed
ensure backward compatibility
1 parent b35ce61 commit 679f811

File tree

15 files changed

+706
-387
lines changed

15 files changed

+706
-387
lines changed

Lib/hashlib.py

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,18 +141,39 @@ def __get_openssl_constructor(name):
141141
return __get_builtin_constructor(name)
142142

143143

144-
def __py_new(name, data=b'', **kwargs):
144+
def __data_argument(funcname, data_sentinel, kwargs):
145+
if '__data_sentinel' in kwargs:
146+
raise TypeError("'__data_sentinel' is not a valid keyword argument")
147+
if 'data' in kwargs and 'string' in kwargs:
148+
raise TypeError("'data' and 'string' are mutually exclusive "
149+
"and support for 'string' keyword parameter "
150+
"is slated for removal in a future version.")
151+
if data_sentinel is None:
152+
if 'data' in kwargs:
153+
# new(name, data=...)
154+
return kwargs.pop('data')
155+
elif 'string' in kwargs:
156+
# new(name, string=...)
157+
return kwargs.pop('string')
158+
return b''
159+
# new(name, data)
160+
return data_sentinel
161+
162+
163+
def __py_new(name, __data_sentinel=None, **kwargs):
145164
"""new(name, data=b'', **kwargs) - Return a new hashing object using the
146165
named algorithm; optionally initialized with data (which must be
147166
a bytes-like object).
148167
"""
168+
data = __data_argument('__py_new', __data_sentinel, kwargs)
149169
return __get_builtin_constructor(name)(data, **kwargs)
150170

151171

152-
def __hash_new(name, data=b'', **kwargs):
172+
def __hash_new(name, __data_sentinel=None, **kwargs):
153173
"""new(name, data=b'') - Return a new hashing object using the named algorithm;
154174
optionally initialized with data (which must be a bytes-like object).
155175
"""
176+
data = __data_argument('__hash_new', __data_sentinel, kwargs)
156177
if name in __block_openssl_constructor:
157178
# Prefer our builtin blake2 implementation.
158179
return __get_builtin_constructor(name)(data, **kwargs)

Lib/test/test_hashlib.py

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import itertools
1313
import logging
1414
import os
15+
import re
1516
import sys
1617
import sysconfig
1718
import tempfile
@@ -140,11 +141,12 @@ def __init__(self, *args, **kwargs):
140141
# of hashlib.new given the algorithm name.
141142
for algorithm, constructors in self.constructors_to_test.items():
142143
constructors.add(getattr(hashlib, algorithm))
143-
def _test_algorithm_via_hashlib_new(data=None, _alg=algorithm, **kwargs):
144-
if data is None:
144+
def c(_data=None, _alg=algorithm, **kwargs):
145+
if _data is None:
145146
return hashlib.new(_alg, **kwargs)
146-
return hashlib.new(_alg, data, **kwargs)
147-
constructors.add(_test_algorithm_via_hashlib_new)
147+
return hashlib.new(_alg, _data, **kwargs)
148+
c.__name__ = f'do_test_algorithm_via_hashlib_new_{algorithm}'
149+
constructors.add(c)
148150

149151
_hashlib = self._conditional_import_module('_hashlib')
150152
self._hashlib = _hashlib
@@ -251,8 +253,25 @@ def test_usedforsecurity_false(self):
251253

252254
def test_clinic_signature(self):
253255
for constructor in self.hash_constructors:
254-
with self.subTest(constructor):
256+
with self.subTest(constructor.__name__):
255257
constructor(data=b'')
258+
constructor(string=b'') # should be deprecated in the future
259+
260+
def test_clinic_signature_errors(self):
261+
conflicting_call = re.escape(
262+
"'data' and 'string' are mutually exclusive "
263+
"and support for 'string' keyword parameter "
264+
"is slated for removal in a future version."
265+
)
266+
duplicated_param = re.escape("given by name ('data') and position")
267+
for constructor in self.hash_constructors:
268+
with self.subTest(constructor.__name__):
269+
with self.assertRaisesRegex(TypeError, conflicting_call):
270+
constructor(b'', string=b'')
271+
with self.assertRaisesRegex(TypeError, conflicting_call):
272+
constructor(data=b'', string=b'')
273+
with self.assertRaisesRegex(TypeError, duplicated_param):
274+
constructor(b'', data=b'')
256275

257276
def test_unknown_hash(self):
258277
self.assertRaises(ValueError, hashlib.new, 'spam spam spam spam spam')
@@ -723,7 +742,6 @@ def check_blake2(self, constructor, salt_size, person_size, key_size,
723742
self.assertRaises(ValueError, constructor, node_offset=-1)
724743
self.assertRaises(OverflowError, constructor, node_offset=max_offset+1)
725744

726-
self.assertRaises(TypeError, constructor, string=b'')
727745
self.assertRaises(TypeError, constructor, '')
728746

729747
constructor(

0 commit comments

Comments
 (0)