Last active
October 25, 2019 15:49
-
-
Save stavxyz/50b918092ca7e02429caeca210b1c2db to your computer and use it in GitHub Desktop.
args / kwargs hash - works in python 2 & 3. Useful for memoizers.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def _tob(_string, enc='utf8'): | |
if isinstance(_string, unicode): | |
return _string.encode(enc) | |
return b'' if _string is None else bytes(_string) | |
def args_hash(*args, **kw): | |
"""Calculate a hash value from string args and kwargs. | |
Given the same positional arguments and keyword | |
arguments, this function will produce the same | |
hash key. | |
""" | |
items = list(args) + [i for t in sorted(kw.items()) for i in t] | |
items = ('__NoneType__' if _i is None else _i | |
for _i in items) | |
# All items must be strings | |
args_string = '|'.join(items) | |
return hashlib.sha1(_tob(args_string)).hexdigest() | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from args_hash import args_hash | |
class TestArgsHash: | |
def test_kw_order_agnostic(self): | |
h1 = args_hash( | |
'one', 'two', 'three', four='4', five='five') | |
h2 = args_hash( | |
'one', 'two', 'three', five='five', four='4') | |
assert h1 | |
assert h2 | |
assert h1 == h2 | |
def test_empty_case(self): | |
h1 = args_hash() | |
h2 = args_hash() | |
assert h1 | |
assert h2 | |
assert h1 == h2 | |
def test_null_case(self): | |
h1 = args_hash(None) | |
h2 = args_hash(None) | |
assert h1 | |
assert h2 | |
assert h1 == h2 | |
def test_null_case_kw(self): | |
kw = {'': None} | |
h1 = args_hash(None, **kw) | |
h2 = args_hash(None, **kw) | |
assert h1 | |
assert h2 | |
assert h1 == h2 | |
def test_cannot_hash_non_string_int(self): | |
with pytest.raises(TypeError) as excinfo: | |
args_hash(1) | |
assert excinfo.type == TypeError | |
assert 'int found' in str(excinfo.value) | |
def test_cannot_hash_non_string_list(self): | |
with pytest.raises(TypeError) as excinfo: | |
args_hash([1]) | |
assert excinfo.type == TypeError | |
assert 'list found' in str(excinfo.value) | |
def test_cannot_hash_non_string_dict(self): | |
with pytest.raises(TypeError) as excinfo: | |
args_hash({'hello': 'world'}) | |
assert excinfo.type == TypeError | |
assert 'dict found' in str(excinfo.value) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment