moira-client
101 строка · 2.5 Кб
1import ast
2
3
4class ConvertError(Exception):
5pass
6
7
8def _parse_cmp_op(node):
9if isinstance(node, ast.Lt):
10return '<'
11if isinstance(node, ast.Gt):
12return '>'
13if isinstance(node, ast.LtE):
14return '<='
15if isinstance(node, ast.GtE):
16return '>='
17if isinstance(node, ast.Eq):
18return '=='
19if isinstance(node, ast.NotEq):
20return '!='
21
22raise ConvertError('unknown op node={}'.format(ast.dump(node)))
23
24
25def _parse_logic_op(node):
26if isinstance(node, ast.Or):
27return '||'
28if isinstance(node, ast.And):
29return '&&'
30raise ConvertError('unknown logic op node={}'.format(ast.dump(node)))
31
32
33def _parse_comparator(node):
34if isinstance(node, ast.Num):
35return node.n
36elif isinstance(node, ast.Name):
37return node.id
38if isinstance(node, ast.BoolOp):
39return _parse_boolop(node)
40elif isinstance(node, ast.Compare):
41return _parse_compare(node)
42raise ConvertError('unknown comparator node={}'.format(ast.dump(node)))
43
44
45def _parse_boolop(node):
46need_parens = len(node.values) > 1
47cmps = []
48for v in node.values:
49r = _parse_comparator(v)
50if need_parens:
51r = '(' + r + ')'
52cmps.append(r)
53
54op = _parse_logic_op(node.op)
55op = f' {op} '
56return op.join(cmps)
57
58
59def _parse_compare(node):
60if len(node.ops) != 1 or len(node.comparators) != 1:
61raise ConvertError('multiple ops/comparators {}'.format(ast.dump(node.body)))
62
63op = _parse_cmp_op(node.ops[0])
64right = _parse_comparator(node.comparators[0])
65left = node.left.id
66return f'{left} {op} {right}'
67
68
69def _parse_ifnode(node):
70cond = _parse_comparator(node.test)
71
72if isinstance(node.orelse, ast.IfExp):
73else_ = _parse_ifnode(node.orelse)
74else_ = '(' + else_ + ')'
75else:
76else_ = node.orelse.id
77
78if_ = node.body.id
79
80return f'({cond}) ? {if_} : {else_}'
81
82
83def _convert_expression(expr):
84node = ast.parse(expr, mode='eval')
85if not isinstance(node, ast.Expression):
86raise ConvertError('unknown root node={}'.format(ast.dump(node)))
87
88if not isinstance(node.body, ast.IfExp):
89raise ConvertError('unknown if node={}'.format(ast.dump(node.body)))
90
91return _parse_ifnode(node.body)
92
93
94def convert_python_expression(expr):
95"""
96converts old python moira expression to new govaluate expression
97"""
98try:
99return _convert_expression(expr)
100except Exception as e:
101raise ConvertError("convert error") from e
102