PyDecisionGraph 0.3.2.post1__cp315-cp315-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- decision_graph/__infra__.pxd +1 -0
- decision_graph/__init__.pxd +1 -0
- decision_graph/__init__.py +39 -0
- decision_graph/decision_tree/__init__.pxd +2 -0
- decision_graph/decision_tree/__init__.py +85 -0
- decision_graph/decision_tree/bake/__infra__.pxd +502 -0
- decision_graph/decision_tree/bake/__init__.pxd +502 -0
- decision_graph/decision_tree/bake/__init__.py +29 -0
- decision_graph/decision_tree/bake/c_action.cp315-win_amd64.pyd +0 -0
- decision_graph/decision_tree/bake/c_action.h +324 -0
- decision_graph/decision_tree/bake/c_action.pxd +54 -0
- decision_graph/decision_tree/bake/c_action.pyi +126 -0
- decision_graph/decision_tree/bake/c_action.pyx +65 -0
- decision_graph/decision_tree/bake/c_allocator_protocol.cp315-win_amd64.pyd +0 -0
- decision_graph/decision_tree/bake/c_allocator_protocol.pxd +24 -0
- decision_graph/decision_tree/bake/c_allocator_protocol.pyi +61 -0
- decision_graph/decision_tree/bake/c_allocator_protocol.pyx +109 -0
- decision_graph/decision_tree/bake/c_bake.cp315-win_amd64.pyd +0 -0
- decision_graph/decision_tree/bake/c_bake.h +629 -0
- decision_graph/decision_tree/bake/c_bake.pxd +52 -0
- decision_graph/decision_tree/bake/c_bake.pyi +151 -0
- decision_graph/decision_tree/bake/c_bake.pyx +142 -0
- decision_graph/decision_tree/bake/c_collections.cp315-win_amd64.pyd +0 -0
- decision_graph/decision_tree/bake/c_collections.h +692 -0
- decision_graph/decision_tree/bake/c_collections.pxd +52 -0
- decision_graph/decision_tree/bake/c_collections.pyi +193 -0
- decision_graph/decision_tree/bake/c_collections.pyx +161 -0
- decision_graph/decision_tree/bake/c_const.cp315-win_amd64.pyd +0 -0
- decision_graph/decision_tree/bake/c_const.h +395 -0
- decision_graph/decision_tree/bake/c_const.pxd +56 -0
- decision_graph/decision_tree/bake/c_const.pyi +305 -0
- decision_graph/decision_tree/bake/c_const.pyx +278 -0
- decision_graph/decision_tree/bake/c_edge.cp315-win_amd64.pyd +0 -0
- decision_graph/decision_tree/bake/c_edge.h +511 -0
- decision_graph/decision_tree/bake/c_edge.pxd +117 -0
- decision_graph/decision_tree/bake/c_edge.pyi +192 -0
- decision_graph/decision_tree/bake/c_edge.pyx +270 -0
- decision_graph/decision_tree/bake/c_eval.h +848 -0
- decision_graph/decision_tree/bake/c_eval.pxd +40 -0
- decision_graph/decision_tree/bake/c_expr.cp315-win_amd64.pyd +0 -0
- decision_graph/decision_tree/bake/c_expr.h +1900 -0
- decision_graph/decision_tree/bake/c_expr.pxd +129 -0
- decision_graph/decision_tree/bake/c_expr.pyi +280 -0
- decision_graph/decision_tree/bake/c_expr.pyx +272 -0
- decision_graph/decision_tree/bake/c_hierarchy.cp315-win_amd64.pyd +0 -0
- decision_graph/decision_tree/bake/c_hierarchy.h +731 -0
- decision_graph/decision_tree/bake/c_hierarchy.pxd +71 -0
- decision_graph/decision_tree/bake/c_hierarchy.pyi +409 -0
- decision_graph/decision_tree/bake/c_hierarchy.pyx +277 -0
- decision_graph/decision_tree/bake/c_logic_group.cp315-win_amd64.pyd +0 -0
- decision_graph/decision_tree/bake/c_logic_group.h +1226 -0
- decision_graph/decision_tree/bake/c_logic_group.pxd +162 -0
- decision_graph/decision_tree/bake/c_logic_group.pyi +264 -0
- decision_graph/decision_tree/bake/c_logic_group.pyx +308 -0
- decision_graph/decision_tree/bake/c_node.cp315-win_amd64.pyd +0 -0
- decision_graph/decision_tree/bake/c_node.h +2660 -0
- decision_graph/decision_tree/bake/c_node.pxd +381 -0
- decision_graph/decision_tree/bake/c_node.pyi +438 -0
- decision_graph/decision_tree/bake/c_node.pyx +639 -0
- decision_graph/decision_tree/bake/c_reconstruct.cp315-win_amd64.pyd +0 -0
- decision_graph/decision_tree/bake/c_reconstruct.pxd +63 -0
- decision_graph/decision_tree/bake/c_reconstruct.pyi +60 -0
- decision_graph/decision_tree/bake/c_reconstruct.pyx +252 -0
- decision_graph/decision_tree/bake/c_var.cp315-win_amd64.pyd +0 -0
- decision_graph/decision_tree/bake/c_var.h +2054 -0
- decision_graph/decision_tree/bake/c_var.pxd +205 -0
- decision_graph/decision_tree/bake/c_var.pyi +271 -0
- decision_graph/decision_tree/bake/c_var.pyx +228 -0
- decision_graph/decision_tree/capi/__infra__.pxd +33 -0
- decision_graph/decision_tree/capi/__init__.pxd +33 -0
- decision_graph/decision_tree/capi/__init__.py +57 -0
- decision_graph/decision_tree/capi/c_abc.cp315-win_amd64.pyd +0 -0
- decision_graph/decision_tree/capi/c_abc.pxd +246 -0
- decision_graph/decision_tree/capi/c_abc.pyi +770 -0
- decision_graph/decision_tree/capi/c_abc.pyx +1532 -0
- decision_graph/decision_tree/capi/c_collection.cp315-win_amd64.pyd +0 -0
- decision_graph/decision_tree/capi/c_collection.pxd +22 -0
- decision_graph/decision_tree/capi/c_collection.pyi +245 -0
- decision_graph/decision_tree/capi/c_collection.pyx +138 -0
- decision_graph/decision_tree/capi/c_node.cp315-win_amd64.pyd +0 -0
- decision_graph/decision_tree/capi/c_node.pxd +95 -0
- decision_graph/decision_tree/capi/c_node.pyi +492 -0
- decision_graph/decision_tree/capi/c_node.pyx +551 -0
- decision_graph/decision_tree/exc.py +189 -0
- decision_graph/decision_tree/native/__init__.py +57 -0
- decision_graph/decision_tree/native/abc.py +1167 -0
- decision_graph/decision_tree/native/collection.py +134 -0
- decision_graph/decision_tree/native/node.py +521 -0
- decision_graph/includes/decision_graph/decision_tree/bake/c_action.c +16320 -0
- decision_graph/includes/decision_graph/decision_tree/bake/c_action.h +324 -0
- decision_graph/includes/decision_graph/decision_tree/bake/c_allocator_protocol.c +12473 -0
- decision_graph/includes/decision_graph/decision_tree/bake/c_bake.c +16485 -0
- decision_graph/includes/decision_graph/decision_tree/bake/c_bake.h +629 -0
- decision_graph/includes/decision_graph/decision_tree/bake/c_collections.c +17381 -0
- decision_graph/includes/decision_graph/decision_tree/bake/c_collections.h +692 -0
- decision_graph/includes/decision_graph/decision_tree/bake/c_const.c +20815 -0
- decision_graph/includes/decision_graph/decision_tree/bake/c_const.h +395 -0
- decision_graph/includes/decision_graph/decision_tree/bake/c_edge.c +20696 -0
- decision_graph/includes/decision_graph/decision_tree/bake/c_edge.h +511 -0
- decision_graph/includes/decision_graph/decision_tree/bake/c_eval.h +848 -0
- decision_graph/includes/decision_graph/decision_tree/bake/c_expr.c +22065 -0
- decision_graph/includes/decision_graph/decision_tree/bake/c_expr.h +1900 -0
- decision_graph/includes/decision_graph/decision_tree/bake/c_hierarchy.c +23267 -0
- decision_graph/includes/decision_graph/decision_tree/bake/c_hierarchy.h +731 -0
- decision_graph/includes/decision_graph/decision_tree/bake/c_logic_group.c +22434 -0
- decision_graph/includes/decision_graph/decision_tree/bake/c_logic_group.h +1226 -0
- decision_graph/includes/decision_graph/decision_tree/bake/c_node.c +28385 -0
- decision_graph/includes/decision_graph/decision_tree/bake/c_node.h +2660 -0
- decision_graph/includes/decision_graph/decision_tree/bake/c_reconstruct.c +15955 -0
- decision_graph/includes/decision_graph/decision_tree/bake/c_var.c +16881 -0
- decision_graph/includes/decision_graph/decision_tree/bake/c_var.h +2054 -0
- decision_graph/includes/decision_graph/decision_tree/capi/c_abc.c +59196 -0
- decision_graph/includes/decision_graph/decision_tree/capi/c_collection.c +19967 -0
- decision_graph/includes/decision_graph/decision_tree/capi/c_node.c +39229 -0
- decision_graph/logic_group/__init__.py +25 -0
- decision_graph/logic_group/base.py +100 -0
- decision_graph/logic_group/pending_request.py +384 -0
- decision_graph/webui/__init__.py +24 -0
- decision_graph/webui/bake/__init__.py +65 -0
- decision_graph/webui/bake/app.py +488 -0
- decision_graph/webui/bake/static/d3.v7.min.js +2 -0
- decision_graph/webui/bake/static/script.js +1440 -0
- decision_graph/webui/bake/static/style.css +920 -0
- decision_graph/webui/bake/templates/index.html +183 -0
- decision_graph/webui/bake/templates/offline.html +184 -0
- decision_graph/webui/capi/__init__.py +54 -0
- decision_graph/webui/capi/app.py +366 -0
- decision_graph/webui/capi/main.py +53 -0
- decision_graph/webui/capi/static/d3.v7.min.js +2 -0
- decision_graph/webui/capi/static/script.js +1026 -0
- decision_graph/webui/capi/static/style.css +656 -0
- decision_graph/webui/capi/templates/index.html +93 -0
- decision_graph/webui/capi/templates/offline.html +94 -0
- decision_graph/webui/native/__init__.py +54 -0
- decision_graph/webui/native/app.py +366 -0
- decision_graph/webui/native/main.py +53 -0
- decision_graph/webui/native/static/d3.v7.min.js +2 -0
- decision_graph/webui/native/static/script.js +1026 -0
- decision_graph/webui/native/static/style.css +656 -0
- decision_graph/webui/native/templates/index.html +93 -0
- decision_graph/webui/native/templates/offline.html +94 -0
- pydecisiongraph-0.3.2.post1.dist-info/METADATA +136 -0
- pydecisiongraph-0.3.2.post1.dist-info/RECORD +148 -0
- pydecisiongraph-0.3.2.post1.dist-info/WHEEL +5 -0
- pydecisiongraph-0.3.2.post1.dist-info/licenses/LICENSE +373 -0
- pydecisiongraph-0.3.2.post1.dist-info/top_level.txt +2 -0
- tests/bake_c_evaluator.cp315-win_amd64.pyd +0 -0
- tests/bake_eval_probe.cp315-win_amd64.pyd +0 -0
|
@@ -0,0 +1,551 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import operator
|
|
3
|
+
import traceback
|
|
4
|
+
|
|
5
|
+
from cpython.mem cimport PyMem_Free
|
|
6
|
+
|
|
7
|
+
from .c_abc cimport LogicNodeFrame, LogicGroupStack, PlaceholderNode, ActionNode, LGM, NO_CONDITION, AUTO_CONDITION, NodeEdgeCondition
|
|
8
|
+
from .c_collection cimport LogicMapping, LogicSequence
|
|
9
|
+
from ..exc import NO_DEFAULT, TooManyChildren, TooFewChildren, EdgeValueError, ContextsNotFound, ExpressEvaluationError
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
cdef class NodeEvalPath(list):
|
|
13
|
+
def to_clipboard(self):
|
|
14
|
+
from pyperclip import copy as clipboard_copy
|
|
15
|
+
cdef LogicNode node
|
|
16
|
+
cdef list path = []
|
|
17
|
+
for node in self:
|
|
18
|
+
path.append(str(node.uid))
|
|
19
|
+
cdef str payload = json.dumps(path)
|
|
20
|
+
clipboard_copy(payload)
|
|
21
|
+
return payload
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
cdef class RootLogicNode(LogicNode):
|
|
25
|
+
def __cinit__(self, *, str name='Entry Point', object expression=None, type dtype=None, str repr=None, object uid=None, bint inherit_contexts=False, **kwargs):
|
|
26
|
+
self.expression = True if expression is None else expression
|
|
27
|
+
self.dtype = bool if dtype is None else dtype
|
|
28
|
+
self.repr = name if repr is None else repr
|
|
29
|
+
self.inherit_contexts = inherit_contexts
|
|
30
|
+
self._eval_path = []
|
|
31
|
+
|
|
32
|
+
cdef bint c_entry_check(self):
|
|
33
|
+
return True
|
|
34
|
+
|
|
35
|
+
cdef void c_on_enter(self):
|
|
36
|
+
cdef LogicGroupStack* active_groups
|
|
37
|
+
# Step 0: Append placeholder
|
|
38
|
+
self.c_append(PlaceholderNode(auto_connect=False), NO_CONDITION)
|
|
39
|
+
|
|
40
|
+
# Step 1: Pre-shelving enter
|
|
41
|
+
LGM.c_ln_enter(self)
|
|
42
|
+
|
|
43
|
+
# Step 2: Shelve LGM
|
|
44
|
+
if self.inherit_contexts:
|
|
45
|
+
active_groups = LGM._active_groups
|
|
46
|
+
LGM.c_shelve()
|
|
47
|
+
PyMem_Free(LGM._active_groups)
|
|
48
|
+
LGM._active_groups = active_groups
|
|
49
|
+
else:
|
|
50
|
+
LGM.c_shelve()
|
|
51
|
+
|
|
52
|
+
# Step 3: Mark as inspection_mode
|
|
53
|
+
LGM.inspection_mode = True
|
|
54
|
+
|
|
55
|
+
# Step 4: Post-shelving enter
|
|
56
|
+
LGM.c_ln_enter(self)
|
|
57
|
+
|
|
58
|
+
cdef void c_on_exit(self):
|
|
59
|
+
cdef LogicGroupStack* active_groups
|
|
60
|
+
self.c_consolidate_placeholder()
|
|
61
|
+
LGM.c_ln_exit(self)
|
|
62
|
+
# Prevent accidentally free the active_group when inherited
|
|
63
|
+
if self.inherit_contexts:
|
|
64
|
+
LGM._active_groups = NULL
|
|
65
|
+
LGM.c_unshelve()
|
|
66
|
+
LGM.c_ln_exit(self)
|
|
67
|
+
|
|
68
|
+
cdef void c_append(self, LogicNode child, NodeEdgeCondition condition):
|
|
69
|
+
if self.subordinates.size:
|
|
70
|
+
raise TooManyChildren()
|
|
71
|
+
|
|
72
|
+
if not (condition is AUTO_CONDITION or condition is NO_CONDITION):
|
|
73
|
+
raise EdgeValueError()
|
|
74
|
+
|
|
75
|
+
LogicNode.c_append(self, child, NO_CONDITION)
|
|
76
|
+
|
|
77
|
+
def __call__(self, object default=None):
|
|
78
|
+
self._eval_path.clear()
|
|
79
|
+
cdef object value = self.c_eval_recursively(self._eval_path, default)[0]
|
|
80
|
+
return value
|
|
81
|
+
|
|
82
|
+
def eval_recursively(self, list path=None, object default=NO_DEFAULT):
|
|
83
|
+
self._eval_path.clear()
|
|
84
|
+
|
|
85
|
+
cdef object v
|
|
86
|
+
cdef list p
|
|
87
|
+
if path is None:
|
|
88
|
+
v, p = self.c_eval_recursively(self._eval_path, default)
|
|
89
|
+
else:
|
|
90
|
+
v, p = self.c_eval_recursively(path, default)
|
|
91
|
+
self._eval_path.extend(p)
|
|
92
|
+
return v, p
|
|
93
|
+
|
|
94
|
+
def dry_run(self, bint enforce_dtype=False):
|
|
95
|
+
cdef LogicNode child
|
|
96
|
+
for child in self.descendants:
|
|
97
|
+
if isinstance(child, ActionNode):
|
|
98
|
+
continue
|
|
99
|
+
try:
|
|
100
|
+
child.c_eval(enforce_dtype)
|
|
101
|
+
except Exception as e:
|
|
102
|
+
raise ExpressEvaluationError(f"Failed to evaluate {self}, {traceback.format_exc()}") from e
|
|
103
|
+
|
|
104
|
+
cpdef BreakpointNode get_breakpoint(self):
|
|
105
|
+
for leaf in self.leaves:
|
|
106
|
+
if isinstance(leaf, BreakpointNode):
|
|
107
|
+
return leaf
|
|
108
|
+
return None
|
|
109
|
+
|
|
110
|
+
def to_html(self, str file_name=None, bint with_eval=True):
|
|
111
|
+
from ...webui.capi import to_html
|
|
112
|
+
to_html(self, file_name or f'{self.repr}.html', with_eval)
|
|
113
|
+
|
|
114
|
+
def show(self, **kwargs):
|
|
115
|
+
from ...webui.capi import show
|
|
116
|
+
show(self, **kwargs)
|
|
117
|
+
|
|
118
|
+
def watch(self, **kwargs):
|
|
119
|
+
from ...webui.capi import watch
|
|
120
|
+
watch(self, **kwargs)
|
|
121
|
+
|
|
122
|
+
property child:
|
|
123
|
+
def __get__(self) -> LogicNode:
|
|
124
|
+
cdef LogicNodeFrame* frame = self.subordinates.top
|
|
125
|
+
if frame:
|
|
126
|
+
return <LogicNode> <object> frame.logic_node
|
|
127
|
+
raise TooFewChildren()
|
|
128
|
+
|
|
129
|
+
property eval_path:
|
|
130
|
+
def __get__(self) -> NodeEvalPath:
|
|
131
|
+
return NodeEvalPath(self._eval_path)
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
cdef class ContextLogicExpression(LogicNode):
|
|
135
|
+
def __cinit__(self, *, LogicGroup logic_group=None, **kwargs):
|
|
136
|
+
if logic_group is None:
|
|
137
|
+
logic_group = LGM.active_group
|
|
138
|
+
if logic_group is None:
|
|
139
|
+
raise ContextsNotFound(f'Must assign a logic group or initialize {self.__class__.__name__} with in a LogicGroup with statement!')
|
|
140
|
+
|
|
141
|
+
self.logic_group = logic_group
|
|
142
|
+
|
|
143
|
+
@staticmethod
|
|
144
|
+
cdef inline object c_safe_eval(object v):
|
|
145
|
+
if isinstance(v, LogicNode):
|
|
146
|
+
return (<LogicNode> v).c_eval(False)
|
|
147
|
+
return v
|
|
148
|
+
|
|
149
|
+
@staticmethod
|
|
150
|
+
cdef inline str c_safe_alias(object v):
|
|
151
|
+
if isinstance(v, LogicNode):
|
|
152
|
+
return v.repr
|
|
153
|
+
return str(v)
|
|
154
|
+
|
|
155
|
+
# === Python Interfaces ===
|
|
156
|
+
|
|
157
|
+
def __getitem__(self, str key):
|
|
158
|
+
return AttrExpression(attr=key, logic_group=self.logic_group)
|
|
159
|
+
|
|
160
|
+
def __getattr__(self, str key) -> AttrExpression:
|
|
161
|
+
return AttrExpression(attr=key, logic_group=self.logic_group)
|
|
162
|
+
|
|
163
|
+
# math operation to invoke MathExpression
|
|
164
|
+
|
|
165
|
+
def __add__(self, object other):
|
|
166
|
+
return MathExpression(left=self, op=MathExpressionOperator.add, right=other, logic_group=self.logic_group)
|
|
167
|
+
|
|
168
|
+
def __sub__(self, object other):
|
|
169
|
+
return MathExpression(left=self, op=MathExpressionOperator.sub, right=other, logic_group=self.logic_group)
|
|
170
|
+
|
|
171
|
+
def __mul__(self, object other):
|
|
172
|
+
return MathExpression(left=self, op=MathExpressionOperator.mul, right=other, logic_group=self.logic_group)
|
|
173
|
+
|
|
174
|
+
def __truediv__(self, object other):
|
|
175
|
+
return MathExpression(left=self, op=MathExpressionOperator.truediv, right=other, logic_group=self.logic_group)
|
|
176
|
+
|
|
177
|
+
def __floordiv__(self, object other):
|
|
178
|
+
return MathExpression(left=self, op=MathExpressionOperator.floordiv, right=other, logic_group=self.logic_group)
|
|
179
|
+
|
|
180
|
+
def __pow__(self, object other):
|
|
181
|
+
return MathExpression(left=self, op=MathExpressionOperator.pow, right=other, logic_group=self.logic_group)
|
|
182
|
+
|
|
183
|
+
def __neg__(self):
|
|
184
|
+
return MathExpression(left=self, op=MathExpressionOperator.neg, repr=f'-{self.repr}', logic_group=self.logic_group)
|
|
185
|
+
|
|
186
|
+
# Comparison operation to invoke ComparisonExpression
|
|
187
|
+
|
|
188
|
+
def __eq__(self, object other):
|
|
189
|
+
return ComparisonExpression(left=self, op=ComparisonExpressionOperator.eq, right=other, logic_group=self.logic_group)
|
|
190
|
+
|
|
191
|
+
def __ne__(self, object other):
|
|
192
|
+
return ComparisonExpression(left=self, op=ComparisonExpressionOperator.ne, right=other, logic_group=self.logic_group)
|
|
193
|
+
|
|
194
|
+
def __gt__(self, object other):
|
|
195
|
+
return ComparisonExpression(left=self, op=ComparisonExpressionOperator.gt, right=other, logic_group=self.logic_group)
|
|
196
|
+
|
|
197
|
+
def __ge__(self, object other):
|
|
198
|
+
return ComparisonExpression(left=self, op=ComparisonExpressionOperator.ge, right=other, logic_group=self.logic_group)
|
|
199
|
+
|
|
200
|
+
def __lt__(self, object other):
|
|
201
|
+
return ComparisonExpression(left=self, op=ComparisonExpressionOperator.lt, right=other, logic_group=self.logic_group)
|
|
202
|
+
|
|
203
|
+
def __le__(self, object other):
|
|
204
|
+
return ComparisonExpression(left=self, op=ComparisonExpressionOperator.le, right=other, logic_group=self.logic_group)
|
|
205
|
+
|
|
206
|
+
# Logical operation to invoke LogicalExpression
|
|
207
|
+
|
|
208
|
+
def __and__(self, object other):
|
|
209
|
+
return LogicalExpression(left=self, op=LogicalExpressionOperator.and_, right=other, logic_group=self.logic_group)
|
|
210
|
+
|
|
211
|
+
def __or__(self, object other):
|
|
212
|
+
return LogicalExpression(left=self, op=LogicalExpressionOperator.or_, right=other, logic_group=self.logic_group)
|
|
213
|
+
|
|
214
|
+
def __invert__(self):
|
|
215
|
+
return LogicalExpression(left=self, op=LogicalExpressionOperator.not_, repr=f'~{self.repr}', logic_group=self.logic_group)
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
cdef class AttrExpression(ContextLogicExpression):
|
|
219
|
+
def __cinit__(self, *, str attr, **kwargs):
|
|
220
|
+
self.attr = attr
|
|
221
|
+
self.repr = kwargs['repr'] if 'repr' in kwargs else f'{self.logic_group.name}.{attr}'
|
|
222
|
+
|
|
223
|
+
cdef object c_eval(self, bint enforce_dtype):
|
|
224
|
+
if isinstance(self.logic_group, LogicMapping):
|
|
225
|
+
return (<LogicMapping> self.logic_group).c_get(self.attr)
|
|
226
|
+
else:
|
|
227
|
+
if self.attr in self.logic_group.contexts:
|
|
228
|
+
return self.logic_group.contexts[self.attr]
|
|
229
|
+
raise AttributeError(f'Attribute {self.attr} does not exist in {self.logic_group}')
|
|
230
|
+
|
|
231
|
+
def __getitem__(self, str key):
|
|
232
|
+
return AttrNestedExpression(attrs=[self.attr, key], logic_group=self.logic_group)
|
|
233
|
+
|
|
234
|
+
def __getattr__(self, str key) -> AttrNestedExpression:
|
|
235
|
+
return AttrNestedExpression(attrs=[self.attr, key], logic_group=self.logic_group)
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
cdef class AttrNestedExpression(ContextLogicExpression):
|
|
239
|
+
def __cinit__(self, *, list attrs, **kwargs):
|
|
240
|
+
self.attrs = attrs
|
|
241
|
+
self.repr = kwargs['repr'] if 'repr' in kwargs else f'{self.logic_group.name}.{".".join(attrs)}'
|
|
242
|
+
|
|
243
|
+
cdef object c_eval(self, bint enforce_dtype):
|
|
244
|
+
cdef object mapping
|
|
245
|
+
if isinstance(self.logic_group, LogicMapping):
|
|
246
|
+
mapping = (<LogicMapping> self.logic_group).data
|
|
247
|
+
else:
|
|
248
|
+
mapping = self.logic_group.contexts
|
|
249
|
+
|
|
250
|
+
cdef str attr
|
|
251
|
+
for attr in self.attrs:
|
|
252
|
+
mapping = mapping[attr]
|
|
253
|
+
return mapping
|
|
254
|
+
|
|
255
|
+
def __getitem__(self, str key):
|
|
256
|
+
return AttrNestedExpression(attrs=self.attrs + [key], logic_group=self.logic_group)
|
|
257
|
+
|
|
258
|
+
def __getattr__(self, str key) -> AttrExpression:
|
|
259
|
+
return AttrNestedExpression(attrs=self.attrs + [key], logic_group=self.logic_group)
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
cdef class GetterExpression(ContextLogicExpression):
|
|
263
|
+
def __cinit__(self, *, object key, **kwargs):
|
|
264
|
+
self.key = key
|
|
265
|
+
self.repr = kwargs['repr'] if 'repr' in kwargs else f'{self.logic_group.name}.{key}'
|
|
266
|
+
|
|
267
|
+
cdef object c_eval(self, bint enforce_dtype):
|
|
268
|
+
if isinstance(self.logic_group, LogicMapping):
|
|
269
|
+
return (<LogicMapping> self.logic_group).c_get(self.key)
|
|
270
|
+
elif isinstance(self.logic_group, LogicSequence):
|
|
271
|
+
return (<LogicSequence> self.logic_group).c_get(self.key)
|
|
272
|
+
else:
|
|
273
|
+
if self.key in self.logic_group.contexts:
|
|
274
|
+
return self.logic_group.contexts[self.key]
|
|
275
|
+
raise AttributeError(f'Attribute {self.key} does not exist in {self.logic_group}')
|
|
276
|
+
|
|
277
|
+
def __getitem__(self, str key):
|
|
278
|
+
return GetterNestedExpression(keys=[self.key, key], logic_group=self.logic_group)
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
cdef class GetterNestedExpression(ContextLogicExpression):
|
|
282
|
+
def __cinit__(self, *, list keys, **kwargs):
|
|
283
|
+
self.keys = keys
|
|
284
|
+
self.repr = kwargs['repr'] if 'repr' in kwargs else f'{self.logic_group.name}.{".".join(keys)}'
|
|
285
|
+
|
|
286
|
+
cdef object c_eval(self, bint enforce_dtype):
|
|
287
|
+
cdef object nested
|
|
288
|
+
if isinstance(self.logic_group, LogicMapping):
|
|
289
|
+
nested = (<LogicMapping> self.logic_group).data
|
|
290
|
+
elif isinstance(self.logic_group, LogicSequence):
|
|
291
|
+
return (<LogicSequence> self.logic_group).c_get(self.key)
|
|
292
|
+
else:
|
|
293
|
+
nested = self.logic_group.contexts
|
|
294
|
+
|
|
295
|
+
cdef object key
|
|
296
|
+
for key in self.keys:
|
|
297
|
+
nested = nested[key]
|
|
298
|
+
return nested
|
|
299
|
+
|
|
300
|
+
def __getitem__(self, str key):
|
|
301
|
+
return GetterNestedExpression(keys=self.keys + [key], logic_group=self.logic_group)
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
cdef class MathExpressionOperator:
|
|
305
|
+
add = MathExpressionOperator.__new__(MathExpressionOperator, 'add', '+')
|
|
306
|
+
sub = MathExpressionOperator.__new__(MathExpressionOperator, 'sub', '-')
|
|
307
|
+
mul = MathExpressionOperator.__new__(MathExpressionOperator, 'mul', '*')
|
|
308
|
+
truediv = MathExpressionOperator.__new__(MathExpressionOperator, 'truediv', '/')
|
|
309
|
+
floordiv = MathExpressionOperator.__new__(MathExpressionOperator, 'floordiv', '//')
|
|
310
|
+
pow = MathExpressionOperator.__new__(MathExpressionOperator, 'pow', '**')
|
|
311
|
+
neg = MathExpressionOperator.__new__(MathExpressionOperator, 'neg', '--')
|
|
312
|
+
|
|
313
|
+
def __cinit__(self, str name, str op):
|
|
314
|
+
self.name = name
|
|
315
|
+
self.value = op
|
|
316
|
+
|
|
317
|
+
def to_func(self):
|
|
318
|
+
return getattr(operator, self.name)
|
|
319
|
+
|
|
320
|
+
@classmethod
|
|
321
|
+
def from_str(cls, str op_str):
|
|
322
|
+
cdef MathExpressionOperator op
|
|
323
|
+
for op in [cls.add, cls.sub, cls.mul, cls.truediv, cls.floordiv, cls.pow, cls.neg]:
|
|
324
|
+
if op.name == op_str:
|
|
325
|
+
return op
|
|
326
|
+
elif op.value == op_str:
|
|
327
|
+
return op
|
|
328
|
+
raise ValueError(f'Unknown MathExpressionOperator: {op_str}')
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
cdef class MathExpression(ContextLogicExpression):
|
|
332
|
+
def __cinit__(self, *, object left, object op, object right=NO_DEFAULT, **kwargs):
|
|
333
|
+
self.left = left
|
|
334
|
+
self.right = right
|
|
335
|
+
self.dtype = kwargs.get('dtype', float)
|
|
336
|
+
cdef MathExpressionOperator _op
|
|
337
|
+
|
|
338
|
+
if isinstance(op, MathExpressionOperator):
|
|
339
|
+
_op = <MathExpressionOperator> op
|
|
340
|
+
self.op_name = kwargs.get('op_name', _op.name)
|
|
341
|
+
self.op_repr = kwargs.get('op_repr', _op.value)
|
|
342
|
+
self.op_func = _op.to_func()
|
|
343
|
+
self.repr = kwargs.get('repr', self.c_op_style_repr())
|
|
344
|
+
elif isinstance(op, str):
|
|
345
|
+
_op = MathExpressionOperator.from_str(op)
|
|
346
|
+
self.op_name = kwargs.get('op_name', _op.name)
|
|
347
|
+
self.op_repr = kwargs.get('op_name', _op.value)
|
|
348
|
+
self.op_func = _op.to_func()
|
|
349
|
+
self.repr = kwargs.get('repr', self.c_op_style_repr())
|
|
350
|
+
elif callable(op):
|
|
351
|
+
self.op_name = op.__name__
|
|
352
|
+
self.op_repr = op.__name__
|
|
353
|
+
self.op_func = op
|
|
354
|
+
self.repr = kwargs.get('repr', self.c_func_style_repr())
|
|
355
|
+
else:
|
|
356
|
+
raise TypeError(f'Expected op to be MathExpressionOperator, str or callable, got {type(op).__name__} instead.')
|
|
357
|
+
|
|
358
|
+
cdef str c_op_style_repr(self):
|
|
359
|
+
if self.right is NO_DEFAULT:
|
|
360
|
+
return f'{self.op_repr}{ContextLogicExpression.c_safe_alias(self.left)}'
|
|
361
|
+
return f'{ContextLogicExpression.c_safe_alias(self.left)} {self.op_repr} {ContextLogicExpression.c_safe_alias(self.right)}'
|
|
362
|
+
|
|
363
|
+
cdef str c_func_style_repr(self):
|
|
364
|
+
if self.right is NO_DEFAULT:
|
|
365
|
+
return f'{self.op_repr}({ContextLogicExpression.c_safe_alias(self.left)})'
|
|
366
|
+
return f'{self.op_repr}({ContextLogicExpression.c_safe_alias(self.left)}, {ContextLogicExpression.c_safe_alias(self.right)})'
|
|
367
|
+
|
|
368
|
+
cdef object c_eval(self, bint enforce_dtype):
|
|
369
|
+
if self.right is NO_DEFAULT:
|
|
370
|
+
return self.op_func(ContextLogicExpression.c_safe_eval(self.left))
|
|
371
|
+
return self.op_func(
|
|
372
|
+
ContextLogicExpression.c_safe_eval(self.left),
|
|
373
|
+
ContextLogicExpression.c_safe_eval(self.right)
|
|
374
|
+
)
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
cdef class ComparisonExpressionOperator:
|
|
378
|
+
eq = ComparisonExpressionOperator.__new__(ComparisonExpressionOperator, 'eq', '==', 1)
|
|
379
|
+
ne = ComparisonExpressionOperator.__new__(ComparisonExpressionOperator, 'ne', '!=', 2)
|
|
380
|
+
gt = ComparisonExpressionOperator.__new__(ComparisonExpressionOperator, 'gt', '>', 3)
|
|
381
|
+
ge = ComparisonExpressionOperator.__new__(ComparisonExpressionOperator, 'ge', '>=', 4)
|
|
382
|
+
lt = ComparisonExpressionOperator.__new__(ComparisonExpressionOperator, 'lt', '<', 5)
|
|
383
|
+
le = ComparisonExpressionOperator.__new__(ComparisonExpressionOperator, 'le', '<=', 6)
|
|
384
|
+
|
|
385
|
+
def __cinit__(self, str name, str op, uint8_t int_enum):
|
|
386
|
+
self.name = name
|
|
387
|
+
self.value = op
|
|
388
|
+
self.int_enum = int_enum
|
|
389
|
+
|
|
390
|
+
def to_func(self):
|
|
391
|
+
return getattr(operator, self.name)
|
|
392
|
+
|
|
393
|
+
@classmethod
|
|
394
|
+
def from_str(cls, str op_str):
|
|
395
|
+
cdef ComparisonExpressionOperator op
|
|
396
|
+
for op in [cls.eq, cls.ne, cls.gt, cls.ge, cls.lt, cls.le]:
|
|
397
|
+
if op.name == op_str:
|
|
398
|
+
return op
|
|
399
|
+
elif op.value == op_str:
|
|
400
|
+
return op
|
|
401
|
+
raise ValueError(f'Unknown ComparisonExpressionOperator: {op_str}')
|
|
402
|
+
|
|
403
|
+
|
|
404
|
+
cdef class ComparisonExpression(ContextLogicExpression):
|
|
405
|
+
def __cinit__(self, *, object left, object op, object right, **kwargs):
|
|
406
|
+
self.left = left
|
|
407
|
+
self.right = right
|
|
408
|
+
self.dtype = kwargs.get('dtype', bool)
|
|
409
|
+
cdef ComparisonExpressionOperator _op
|
|
410
|
+
|
|
411
|
+
if isinstance(op, ComparisonExpressionOperator):
|
|
412
|
+
_op = <ComparisonExpressionOperator> op
|
|
413
|
+
self.op_name = kwargs.get('op_name', _op.name)
|
|
414
|
+
self.op_repr = kwargs.get('op_repr', _op.value)
|
|
415
|
+
self.op_func = _op.to_func()
|
|
416
|
+
self.repr = kwargs.get('repr', self.c_op_style_repr())
|
|
417
|
+
self.op_enum = _op.int_enum
|
|
418
|
+
elif isinstance(op, str):
|
|
419
|
+
_op = ComparisonExpressionOperator.from_str(op)
|
|
420
|
+
self.op_name = kwargs.get('op_name', _op.name)
|
|
421
|
+
self.op_repr = kwargs.get('op_name', _op.value)
|
|
422
|
+
self.op_func = _op.to_func()
|
|
423
|
+
self.repr = kwargs.get('repr', self.c_op_style_repr())
|
|
424
|
+
self.op_enum = _op.int_enum
|
|
425
|
+
elif callable(op):
|
|
426
|
+
self.op_name = op.__name__
|
|
427
|
+
self.op_repr = op.__name__
|
|
428
|
+
self.op_func = op
|
|
429
|
+
self.repr = kwargs.get('repr', self.c_func_style_repr())
|
|
430
|
+
self.builtin = False
|
|
431
|
+
self.op_enum = 0
|
|
432
|
+
else:
|
|
433
|
+
raise TypeError(f'Expected op to be ComparisonExpressionOperator, str or callable, got {type(op).__name__} instead.')
|
|
434
|
+
|
|
435
|
+
cdef str c_op_style_repr(self):
|
|
436
|
+
if self.right is NO_DEFAULT:
|
|
437
|
+
return f'{self.op_repr}{ContextLogicExpression.c_safe_alias(self.left)}'
|
|
438
|
+
return f'{ContextLogicExpression.c_safe_alias(self.left)} {self.op_repr} {ContextLogicExpression.c_safe_alias(self.right)}'
|
|
439
|
+
|
|
440
|
+
cdef str c_func_style_repr(self):
|
|
441
|
+
if self.right is NO_DEFAULT:
|
|
442
|
+
return f'{self.op_repr}({ContextLogicExpression.c_safe_alias(self.left)})'
|
|
443
|
+
return f'{self.op_repr}({ContextLogicExpression.c_safe_alias(self.left)}, {ContextLogicExpression.c_safe_alias(self.right)})'
|
|
444
|
+
|
|
445
|
+
cdef object c_eval(self, bint enforce_dtype):
|
|
446
|
+
cdef object left = ContextLogicExpression.c_safe_eval(self.left)
|
|
447
|
+
cdef object right = ContextLogicExpression.c_safe_eval(self.right)
|
|
448
|
+
cdef uint8_t op_enum = self.op_enum
|
|
449
|
+
|
|
450
|
+
if op_enum == 0:
|
|
451
|
+
return self.op_func(left, right)
|
|
452
|
+
elif op_enum == 1:
|
|
453
|
+
return left == right
|
|
454
|
+
elif op_enum == 2:
|
|
455
|
+
return left != right
|
|
456
|
+
elif op_enum == 3:
|
|
457
|
+
return left > right
|
|
458
|
+
elif op_enum == 4:
|
|
459
|
+
return left >= right
|
|
460
|
+
elif op_enum == 5:
|
|
461
|
+
return left < right
|
|
462
|
+
elif op_enum == 6:
|
|
463
|
+
return left <= right
|
|
464
|
+
else:
|
|
465
|
+
raise RuntimeError(f'Invalid comparison op_enum {op_enum}')
|
|
466
|
+
|
|
467
|
+
|
|
468
|
+
cdef class LogicalExpressionOperator:
|
|
469
|
+
and_ = LogicalExpressionOperator.__new__(LogicalExpressionOperator, 'and_', '&', 1)
|
|
470
|
+
or_ = LogicalExpressionOperator.__new__(LogicalExpressionOperator, 'or_', '|', 2)
|
|
471
|
+
not_ = LogicalExpressionOperator.__new__(LogicalExpressionOperator, 'not_', '~', 3)
|
|
472
|
+
|
|
473
|
+
def __cinit__(self, str name, str op, uint8_t int_enum):
|
|
474
|
+
self.name = name
|
|
475
|
+
self.value = op
|
|
476
|
+
self.int_enum = int_enum
|
|
477
|
+
|
|
478
|
+
def to_func(self):
|
|
479
|
+
return getattr(operator, self.name)
|
|
480
|
+
|
|
481
|
+
@classmethod
|
|
482
|
+
def from_str(cls, str op_str):
|
|
483
|
+
cdef LogicalExpressionOperator op
|
|
484
|
+
for op in [cls.and_, cls.or_, cls.not_]:
|
|
485
|
+
if op.name == op_str:
|
|
486
|
+
return op
|
|
487
|
+
elif op.value == op_str:
|
|
488
|
+
return op
|
|
489
|
+
raise ValueError(f'Unknown LogicalExpressionOperator: {op_str}')
|
|
490
|
+
|
|
491
|
+
|
|
492
|
+
cdef class LogicalExpression(ContextLogicExpression):
|
|
493
|
+
def __cinit__(self, *, object left, object op, object right=NO_DEFAULT, **kwargs):
|
|
494
|
+
self.left = left
|
|
495
|
+
self.right = right
|
|
496
|
+
self.dtype = kwargs.get('dtype', bool)
|
|
497
|
+
cdef LogicalExpressionOperator _op
|
|
498
|
+
|
|
499
|
+
if isinstance(op, LogicalExpressionOperator):
|
|
500
|
+
_op = <LogicalExpressionOperator> op
|
|
501
|
+
self.op_name = kwargs.get('op_name', _op.name)
|
|
502
|
+
self.op_repr = kwargs.get('op_repr', _op.value)
|
|
503
|
+
self.op_func = _op.to_func()
|
|
504
|
+
self.repr = kwargs.get('repr', self.c_op_style_repr())
|
|
505
|
+
self.op_enum = _op.int_enum
|
|
506
|
+
elif isinstance(op, str):
|
|
507
|
+
_op = LogicalExpressionOperator.from_str(op)
|
|
508
|
+
self.op_name = kwargs.get('op_name', _op.name)
|
|
509
|
+
self.op_repr = kwargs.get('op_name', _op.value)
|
|
510
|
+
self.op_func = _op.to_func()
|
|
511
|
+
self.repr = kwargs.get('repr', self.c_op_style_repr())
|
|
512
|
+
self.op_enum = _op.int_enum
|
|
513
|
+
elif callable(op):
|
|
514
|
+
self.op_name = op.__name__
|
|
515
|
+
self.op_repr = op.__name__
|
|
516
|
+
self.op_func = op
|
|
517
|
+
self.repr = kwargs.get('repr', self.c_func_style_repr())
|
|
518
|
+
self.builtin = False
|
|
519
|
+
self.op_enum = 0
|
|
520
|
+
else:
|
|
521
|
+
raise TypeError(f'Expected op to be LogicalExpressionOperator, str or callable, got {type(op).__name__} instead.')
|
|
522
|
+
|
|
523
|
+
cdef str c_op_style_repr(self):
|
|
524
|
+
if self.right is NO_DEFAULT:
|
|
525
|
+
return f'{self.op_repr}{ContextLogicExpression.c_safe_alias(self.left)}'
|
|
526
|
+
return f'{ContextLogicExpression.c_safe_alias(self.left)} {self.op_repr} {ContextLogicExpression.c_safe_alias(self.right)}'
|
|
527
|
+
|
|
528
|
+
cdef str c_func_style_repr(self):
|
|
529
|
+
if self.right is NO_DEFAULT:
|
|
530
|
+
return f'{self.op_repr}({ContextLogicExpression.c_safe_alias(self.left)})'
|
|
531
|
+
return f'{self.op_repr}({ContextLogicExpression.c_safe_alias(self.left)}, {ContextLogicExpression.c_safe_alias(self.right)})'
|
|
532
|
+
|
|
533
|
+
cdef object c_eval(self, bint enforce_dtype):
|
|
534
|
+
cdef uint8_t op_enum = self.op_enum
|
|
535
|
+
|
|
536
|
+
if op_enum == 0:
|
|
537
|
+
return self.op_func(ContextLogicExpression.c_safe_eval(self.left), ContextLogicExpression.c_safe_eval(self.right))
|
|
538
|
+
|
|
539
|
+
cdef bint left = ContextLogicExpression.c_safe_eval(self.left)
|
|
540
|
+
|
|
541
|
+
if op_enum == 3:
|
|
542
|
+
return not left
|
|
543
|
+
|
|
544
|
+
cdef bint right = ContextLogicExpression.c_safe_eval(self.right)
|
|
545
|
+
|
|
546
|
+
if op_enum == 1:
|
|
547
|
+
return left and right
|
|
548
|
+
elif op_enum == 2:
|
|
549
|
+
return left or right
|
|
550
|
+
|
|
551
|
+
raise RuntimeError(f'Invalid comparison op_enum {op_enum}')
|