Skip to content

Commit 2523bc2

Browse files
Евгений БлиновЕвгений Блинов
authored andcommitted
Add support for hashing lambda functions
1 parent 5f42cfd commit 2523bc2

2 files changed

Lines changed: 31 additions & 8 deletions

File tree

getsources/hash.py

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,34 @@
11
import hashlib
22
from typing import Any, Callable
3-
from ast import parse, Expr, Constant, get_source_segment
3+
from ast import parse, Expr, Constant, Lambda, get_source_segment, walk
4+
from types import FunctionType
45

56
from getsources import getclearsource
67

78
ALPHABET = '0123456789ABCDEFGHJKMNPQRSTVWXYZ'
89

910

10-
def get_body_text(source: str, skip_docstring: bool) -> str:
11+
def is_lambda(function: Callable[..., Any]):
12+
return isinstance(function, FunctionType) and function.__name__ == "<lambda>"
13+
14+
15+
def get_body_text(function: Callable[..., Any], source: str, skip_docstring: bool) -> str:
1116
tree = parse(source)
1217

13-
function_node = tree.body[0]
14-
body_nodes = function_node.body
15-
first = body_nodes[0]
18+
if is_lambda(function):
19+
body_nodes = []
20+
21+
for node in walk(tree):
22+
if isinstance(node, Lambda):
23+
body_nodes.append(node.body)
24+
25+
else:
26+
function_node = tree.body[0]
27+
body_nodes = function_node.body
28+
first = body_nodes[0]
1629

17-
if skip_docstring and body_nodes and (isinstance(first, Expr) and isinstance(first.value, Constant) and isinstance(first.value.value, str)):
18-
body_nodes = body_nodes[1:]
30+
if skip_docstring and body_nodes and (isinstance(first, Expr) and isinstance(first.value, Constant) and isinstance(first.value.value, str)):
31+
body_nodes = body_nodes[1:]
1932

2033
return '\n'.join([get_source_segment(source, statement) for statement in body_nodes])
2134

@@ -30,7 +43,7 @@ def getsourcehash(function: Callable[..., Any], size: int = 6, only_body: bool =
3043
if not only_body:
3144
interesting_part = source_code
3245
else:
33-
interesting_part = get_body_text(source_code, skip_docstring=skip_docstring)
46+
interesting_part = get_body_text(function, source_code, skip_docstring=skip_docstring)
3447

3548
digest = hashlib.sha256(interesting_part.encode('utf-8')).digest()
3649
number = int.from_bytes(digest, 'big')

tests/test_hash.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,3 +178,13 @@ def function():
178178

179179
with pytest.raises(ValueError, match=match('You can omit the docstring only if the `only_body=True` option is set.')):
180180
getsourcehash(function, only_body=False, skip_docstring=True)
181+
182+
183+
def test_hash_simple_lambda():
184+
lambda_hash = getsourcehash(lambda x: x)
185+
assert lambda_hash == '14FXP9'
186+
187+
188+
def test_hash_lambda_only_body():
189+
lambda_hash = getsourcehash(lambda x: x, only_body=True)
190+
assert lambda_hash == '91MJ41'

0 commit comments

Comments
 (0)