forked from dflook/python-minifier
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathast_compare.py
More file actions
104 lines (77 loc) · 3.06 KB
/
ast_compare.py
File metadata and controls
104 lines (77 loc) · 3.06 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
import ast
from python_minifier.util import is_ast_node
class CompareError(RuntimeError):
"""
Raised when an AST compares unequal.
"""
def __init__(self, lnode, rnode, msg=None):
self.lnode = lnode
self.rnode = rnode
self.msg = msg
def __repr__(self):
return 'NodeError(%r, %r)' % (self.lnode, self.rnode)
def namespace(self, node):
if hasattr(node, 'namespace'):
if is_ast_node(node.namespace, (ast.FunctionDef, ast.ClassDef, 'AsyncFunctionDef')):
return self.namespace(node.namespace) + '.' + node.namespace.name
elif isinstance(node.namespace, ast.Module):
return ''
else:
return repr(node.namespace.__class__)
return None
def __str__(self):
error = ''
if self.msg:
error += self.msg
if self.namespace(self.lnode):
error += ' in namespace ' + self.namespace(self.lnode)
if self.lnode and hasattr(self.lnode, 'lineno'):
error += ' at source %i:%i' % (self.lnode.lineno, self.lnode.col_offset)
return error
def compare_ast(l_ast, r_ast):
"""
Compare Python Abstract Syntax Trees
>>> compare_ast(l_ast, r_ast)
If the AST's are not identical, an exception will be raised.
"""
def counter():
i = 0
while True:
yield i
i += 1
if type(l_ast) != type(r_ast):
raise CompareError(l_ast, r_ast, msg='Nodes do not match! %r != %r' % (l_ast, r_ast))
for field in set(l_ast._fields + r_ast._fields):
if field == 'kind' and isinstance(l_ast, ast.Constant):
continue
if isinstance(getattr(l_ast, field, None), list):
l_list = getattr(l_ast, field, None)
r_list = getattr(r_ast, field, None)
if len(l_list) != len(r_list):
raise CompareError(
l_list,
r_list,
'List does not have the same number of elements! len(%s.%s)=%r, len(%s.%s)=%r'
% (type(l_ast), field, len(l_list), type(r_ast), field, len(r_list)),
)
for i, l, r in zip(counter(), l_list, r_list):
if isinstance(l, ast.AST) or isinstance(r, ast.AST):
compare_ast(l, r)
elif l != r:
raise CompareError(
l_ast,
r_ast,
'Fields do not match! %s.%s[%i]=%r, %s.%s[%i]=%r'
% (type(l_ast), field, i, l, type(r_ast), field, i, r),
)
else:
l = getattr(l_ast, field, None)
r = getattr(r_ast, field, None)
if isinstance(l, ast.AST) or isinstance(r, ast.AST):
compare_ast(l, r)
elif l != r:
raise CompareError(
l_ast,
r_ast,
'Fields do not match! %s.%s=%r, %s.%s=%r' % (type(l_ast), field, l, type(r_ast), field, r),
)