1
1
import ast
2
+ import operator
2
3
import re
3
4
from typing import Callable
4
5
@@ -40,6 +41,23 @@ def decorated(*args, **kwargs) -> bool:
40
41
return decorated
41
42
42
43
44
+ def build_custom_operator (operator ) -> Callable :
45
+ def custom_comparator (left : Callable , right : Callable ) -> Callable :
46
+ def decorated (* args , ** kwargs ) -> bool :
47
+ return bool (operator (left (* args , ** kwargs ), right (* args , ** kwargs )))
48
+
49
+ return decorated
50
+
51
+ return custom_comparator
52
+
53
+
54
+ def build_constant (constant ) -> Callable :
55
+ def decorated (* args , ** kwargs ):
56
+ return constant
57
+
58
+ return decorated
59
+
60
+
43
61
def custom_or (left : Callable , right : Callable ) -> Callable :
44
62
def decorated (* args , ** kwargs ) -> bool :
45
63
return left (* args , ** kwargs ) or right (* args , ** kwargs ) # type: ignore[no-any-return]
@@ -49,7 +67,7 @@ def decorated(*args, **kwargs) -> bool:
49
67
return decorated
50
68
51
69
52
- def build_expression (node , variable_hook , operator_mapping ):
70
+ def build_expression (node , variable_hook , operator_mapping ): # noqa: C901
53
71
if isinstance (node , ast .BoolOp ):
54
72
# Handle `and` / `or` operations
55
73
operator_fn = operator_mapping [type (node .op )]
@@ -58,13 +76,23 @@ def build_expression(node, variable_hook, operator_mapping):
58
76
right_expr = build_expression (right , variable_hook , operator_mapping )
59
77
left_expr = operator_fn (left_expr , right_expr )
60
78
return left_expr
79
+ elif isinstance (node , ast .Compare ):
80
+ operator_fn = operator_mapping [type (node .ops [0 ])]
81
+ left_expr = build_expression (node .left , variable_hook , operator_mapping )
82
+ for right in node .comparators :
83
+ right_expr = build_expression (right , variable_hook , operator_mapping )
84
+ left_expr = operator_fn (left_expr , right_expr )
85
+ return left_expr
61
86
elif isinstance (node , ast .UnaryOp ) and isinstance (node .op , ast .Not ):
62
87
# Handle `not` operation
63
88
operand_expr = build_expression (node .operand , variable_hook , operator_mapping )
64
89
return operator_mapping [type (node .op )](operand_expr )
65
90
elif isinstance (node , ast .Name ):
66
91
# Handle variables by calling the variable_hook
67
92
return variable_hook (node .id )
93
+ elif isinstance (node , ast .Constant ):
94
+ # Handle constants by returning the value
95
+ return build_constant (node .value )
68
96
else :
69
97
raise ValueError (f"Unsupported expression structure: { node .__class__ .__name__ } " )
70
98
@@ -80,4 +108,14 @@ def parse_boolean_expr(expr, variable_hook, operator_mapping):
80
108
return build_expression (tree .body , variable_hook , operator_mapping )
81
109
82
110
83
- operator_mapping = {ast .Or : custom_or , ast .And : custom_and , ast .Not : custom_not }
111
+ operator_mapping = {
112
+ ast .Or : custom_or ,
113
+ ast .And : custom_and ,
114
+ ast .Not : custom_not ,
115
+ ast .GtE : build_custom_operator (operator .ge ),
116
+ ast .Gt : build_custom_operator (operator .gt ),
117
+ ast .LtE : build_custom_operator (operator .le ),
118
+ ast .Lt : build_custom_operator (operator .lt ),
119
+ ast .Eq : build_custom_operator (operator .eq ),
120
+ ast .NotEq : build_custom_operator (operator .ne ),
121
+ }
0 commit comments