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,277 @@
|
|
|
1
|
+
from cpython.unicode cimport PyUnicode_AsUTF8, PyUnicode_FromString
|
|
2
|
+
from libc.stdint cimport uintptr_t
|
|
3
|
+
|
|
4
|
+
from .c_allocator_protocol cimport DCG_DEFAULT_ALLOCATOR
|
|
5
|
+
from .c_edge cimport NO_CONDITION
|
|
6
|
+
from .c_node cimport NODE_REGISTRY
|
|
7
|
+
from .c_var cimport c_dcg_ret_code_name, c_dcg_var_pyunpack
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
cdef class RootLogicNode(LogicNode):
|
|
11
|
+
def __init__(self, *, str name='Entry Point', bint inherit_contexts=False, **kwargs):
|
|
12
|
+
cdef dcg_root_node* node = c_dcg_node_new_root(PyUnicode_AsUTF8(name), DCG_DEFAULT_ALLOCATOR)
|
|
13
|
+
if not node:
|
|
14
|
+
raise MemoryError('Failed to allocate the RootLogicNode.')
|
|
15
|
+
|
|
16
|
+
self.header = &node.base
|
|
17
|
+
self.owner = True
|
|
18
|
+
self.name = name
|
|
19
|
+
node.inherit_contexts = inherit_contexts
|
|
20
|
+
# The record is the root's own field, so the view is taken once, over it:
|
|
21
|
+
# what it reads is whatever the last walk left there.
|
|
22
|
+
self.eval_path = NodeEvalPathView.c_from_header(&node.eval_path)
|
|
23
|
+
self.c_register_node()
|
|
24
|
+
|
|
25
|
+
# === Eval Protocol ===
|
|
26
|
+
|
|
27
|
+
cdef void c_eval(self):
|
|
28
|
+
if not self.header:
|
|
29
|
+
raise RuntimeError(f'<{self.__class__.__name__}> not initialized!')
|
|
30
|
+
|
|
31
|
+
cdef dcg_root_node* root = <dcg_root_node*> self.header
|
|
32
|
+
cdef int ret_code = c_dcg_root_node_eval(root)
|
|
33
|
+
self.c_check_eval_code(ret_code, root.eval_path.failed)
|
|
34
|
+
|
|
35
|
+
def eval(self):
|
|
36
|
+
self.c_eval()
|
|
37
|
+
|
|
38
|
+
cdef dcg_root_node* root = <dcg_root_node*> self.header
|
|
39
|
+
cdef dcg_node* leaf = root.eval_path.leaf
|
|
40
|
+
if not leaf:
|
|
41
|
+
raise RuntimeError(f'{self.__class__.__name__} reached no leaf and reported no error.')
|
|
42
|
+
|
|
43
|
+
return c_dcg_var_pyunpack(&leaf.out)
|
|
44
|
+
|
|
45
|
+
def __call__(self):
|
|
46
|
+
return self.eval()
|
|
47
|
+
|
|
48
|
+
# === Web UI ===
|
|
49
|
+
|
|
50
|
+
def to_html(self, str file_name=None, bint with_eval=True):
|
|
51
|
+
from ...webui.bake import to_html
|
|
52
|
+
to_html(self, file_name or f'{self.repr}.html', with_eval)
|
|
53
|
+
|
|
54
|
+
def show(self, **kwargs):
|
|
55
|
+
from ...webui.bake import show
|
|
56
|
+
show(self, **kwargs)
|
|
57
|
+
|
|
58
|
+
def watch(self, **kwargs):
|
|
59
|
+
from ...webui.bake import watch
|
|
60
|
+
watch(self, **kwargs)
|
|
61
|
+
|
|
62
|
+
# === Bake Protocol ===
|
|
63
|
+
|
|
64
|
+
cpdef object bake(self, bint validate_only=False):
|
|
65
|
+
# The protocol lives in a module above this one - the bake pass is asked
|
|
66
|
+
# of a root and reads every family to answer - so the reach is the
|
|
67
|
+
# module's Python door at call time, never a cimport (DEPENDENCY.md 4.3).
|
|
68
|
+
from .c_bake import c_dcg_bake_root
|
|
69
|
+
return c_dcg_bake_root(self, validate_only)
|
|
70
|
+
|
|
71
|
+
def get_breakpoint(self):
|
|
72
|
+
"""The breakpoint this graph left waiting, or None if it left none.
|
|
73
|
+
|
|
74
|
+
A breakpoint that has not resumed into anything yet is where a branch
|
|
75
|
+
stopped, and that is what this looks for - the place a build can take up
|
|
76
|
+
again. What makes a graph assemblable from several places is exactly
|
|
77
|
+
this: one function builds up to a break, this hands the break back, and
|
|
78
|
+
the next function takes it and builds the rest, so the two halves never
|
|
79
|
+
have to be in the same scope, or even the same function.
|
|
80
|
+
|
|
81
|
+
The search itself is the C layer's - ``c_dcg_node_get_breakpoint`` walks
|
|
82
|
+
the graph's own links. Nothing here needs the Python side to have kept a
|
|
83
|
+
wrapper for every node the walk crosses, which is what makes it work on a
|
|
84
|
+
graph the build only partly came through Python.
|
|
85
|
+
|
|
86
|
+
Returns:
|
|
87
|
+
The waiting breakpoint, or None when the graph has none.
|
|
88
|
+
"""
|
|
89
|
+
if not self.header:
|
|
90
|
+
raise RuntimeError(f'<{self.__class__.__name__}> not initialized!')
|
|
91
|
+
|
|
92
|
+
cdef dcg_breakpoint_node* found = c_dcg_node_get_breakpoint(self.header)
|
|
93
|
+
if not found:
|
|
94
|
+
return None
|
|
95
|
+
return NODE_REGISTRY[<uintptr_t> &found.base]
|
|
96
|
+
|
|
97
|
+
property inherit_contexts:
|
|
98
|
+
def __get__(self):
|
|
99
|
+
if not self.header:
|
|
100
|
+
raise RuntimeError(f'<{self.__class__.__name__}> not initialized!')
|
|
101
|
+
return bool((<dcg_root_node*> self.header).inherit_contexts)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
cdef class NodeEvalPathView:
|
|
105
|
+
def __init__(self, RootLogicNode node):
|
|
106
|
+
self.header = <const dcg_node_eval_path*> &(<dcg_root_node*> node.header).eval_path
|
|
107
|
+
|
|
108
|
+
@staticmethod
|
|
109
|
+
cdef inline NodeEvalPathView c_from_header(const dcg_node_eval_path* path):
|
|
110
|
+
cdef NodeEvalPathView view = NodeEvalPathView.__new__(NodeEvalPathView)
|
|
111
|
+
view.header = path
|
|
112
|
+
return view
|
|
113
|
+
|
|
114
|
+
def __repr__(self):
|
|
115
|
+
if not self.header:
|
|
116
|
+
return f'<{self.__class__.__name__} (Uninitialized)>'
|
|
117
|
+
cdef dcg_node_eval_path* path = <dcg_node_eval_path*> self.header
|
|
118
|
+
return f'<{self.__class__.__name__}(nodes={path.n_nodes}, code={self.code_name}, leaf={self.leaf})>'
|
|
119
|
+
|
|
120
|
+
def __len__(self):
|
|
121
|
+
if not self.header:
|
|
122
|
+
raise RuntimeError(f'<{self.__class__.__name__}> not initialized!')
|
|
123
|
+
return (<dcg_node_eval_path*> self.header).n_nodes
|
|
124
|
+
|
|
125
|
+
def __iter__(self):
|
|
126
|
+
if not self.header:
|
|
127
|
+
raise RuntimeError(f'<{self.__class__.__name__}> not initialized!')
|
|
128
|
+
cdef dcg_node_eval_path* path = <dcg_node_eval_path*> self.header
|
|
129
|
+
cdef size_t index
|
|
130
|
+
for index in range(path.n_nodes):
|
|
131
|
+
yield NODE_REGISTRY[<uintptr_t> path.node[index]]
|
|
132
|
+
|
|
133
|
+
def __getitem__(self, Py_ssize_t index):
|
|
134
|
+
cdef Py_ssize_t count = len(self)
|
|
135
|
+
if index < 0:
|
|
136
|
+
index += count
|
|
137
|
+
if index < 0 or index >= count:
|
|
138
|
+
raise IndexError(f'{self.__class__.__name__} index out of range')
|
|
139
|
+
return NODE_REGISTRY[<uintptr_t> (<dcg_node_eval_path*> self.header).node[index]]
|
|
140
|
+
|
|
141
|
+
# === Python Properties ===
|
|
142
|
+
|
|
143
|
+
property address:
|
|
144
|
+
def __get__(self):
|
|
145
|
+
if not self.header:
|
|
146
|
+
raise RuntimeError(f'<{self.__class__.__name__}> not initialized!')
|
|
147
|
+
return <uintptr_t> self.header
|
|
148
|
+
|
|
149
|
+
property nodes:
|
|
150
|
+
def __get__(self):
|
|
151
|
+
if not self.header:
|
|
152
|
+
raise RuntimeError(f'<{self.__class__.__name__}> not initialized!')
|
|
153
|
+
return list(self)
|
|
154
|
+
|
|
155
|
+
property capacity:
|
|
156
|
+
def __get__(self):
|
|
157
|
+
if not self.header:
|
|
158
|
+
raise RuntimeError(f'<{self.__class__.__name__}> not initialized!')
|
|
159
|
+
return (<dcg_node_eval_path*> self.header).capacity
|
|
160
|
+
|
|
161
|
+
property code:
|
|
162
|
+
def __get__(self):
|
|
163
|
+
if not self.header:
|
|
164
|
+
raise RuntimeError(f'<{self.__class__.__name__}> not initialized!')
|
|
165
|
+
return <int> (<dcg_node_eval_path*> self.header).code
|
|
166
|
+
|
|
167
|
+
property code_name:
|
|
168
|
+
def __get__(self):
|
|
169
|
+
if not self.header:
|
|
170
|
+
raise RuntimeError(f'<{self.__class__.__name__}> not initialized!')
|
|
171
|
+
return PyUnicode_FromString(c_dcg_ret_code_name((<dcg_node_eval_path*> self.header).code))
|
|
172
|
+
|
|
173
|
+
property leaf:
|
|
174
|
+
def __get__(self):
|
|
175
|
+
if not self.header:
|
|
176
|
+
raise RuntimeError(f'<{self.__class__.__name__}> not initialized!')
|
|
177
|
+
cdef dcg_node* leaf = (<dcg_node_eval_path*> self.header).leaf
|
|
178
|
+
return None if not leaf else NODE_REGISTRY[<uintptr_t> leaf]
|
|
179
|
+
|
|
180
|
+
property failed:
|
|
181
|
+
def __get__(self):
|
|
182
|
+
if not self.header:
|
|
183
|
+
raise RuntimeError(f'<{self.__class__.__name__}> not initialized!')
|
|
184
|
+
cdef dcg_node* failed = (<dcg_node_eval_path*> self.header).failed
|
|
185
|
+
return None if not failed else NODE_REGISTRY[<uintptr_t> failed]
|
|
186
|
+
|
|
187
|
+
property seq_id:
|
|
188
|
+
def __get__(self):
|
|
189
|
+
if not self.header:
|
|
190
|
+
raise RuntimeError(f'<{self.__class__.__name__}> not initialized!')
|
|
191
|
+
return (<dcg_node_eval_path*> self.header).seq_id
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
cdef class BreakpointNode(LogicNode):
|
|
195
|
+
def __init__(self, *, object break_from=None, str repr=None, bint autogen=True, **kwargs):
|
|
196
|
+
cdef dcg_logic_group* group = NULL
|
|
197
|
+
cdef dcg_breakpoint_node* node
|
|
198
|
+
if break_from:
|
|
199
|
+
group = <dcg_logic_group*> <uintptr_t> break_from.address
|
|
200
|
+
node = c_dcg_node_new_breakpoint(
|
|
201
|
+
group,
|
|
202
|
+
PyUnicode_AsUTF8(repr) if repr else NULL,
|
|
203
|
+
DCG_DEFAULT_ALLOCATOR,
|
|
204
|
+
)
|
|
205
|
+
if not node:
|
|
206
|
+
raise MemoryError('Failed to allocate the BreakpointNode.')
|
|
207
|
+
|
|
208
|
+
self.header = &node.base
|
|
209
|
+
self.owner = True
|
|
210
|
+
self.break_from = break_from
|
|
211
|
+
self.c_register_node()
|
|
212
|
+
|
|
213
|
+
# === Python Interfaces ===
|
|
214
|
+
|
|
215
|
+
@classmethod
|
|
216
|
+
def break_(cls, object break_from, **kwargs):
|
|
217
|
+
"""Break out of a group, and hand back the breakpoint that did it.
|
|
218
|
+
|
|
219
|
+
A break is a node: it takes the arm the build was about to fill, and the
|
|
220
|
+
build continues from IT rather than from the group it left. That is what
|
|
221
|
+
makes this the door for assembling a graph in pieces - one function
|
|
222
|
+
builds up to the break and returns, and the break it made is entered here
|
|
223
|
+
to carry on outside the group.
|
|
224
|
+
|
|
225
|
+
The breakpoint is built first and then installed, rather than made by the
|
|
226
|
+
install: the block that lands in the graph has to be the one this wrapper
|
|
227
|
+
holds, or the caller would be handed a handle on a node that is not in
|
|
228
|
+
the graph.
|
|
229
|
+
|
|
230
|
+
Args:
|
|
231
|
+
break_from: The group being broken out of.
|
|
232
|
+
**kwargs: Passed to the constructor.
|
|
233
|
+
|
|
234
|
+
Returns:
|
|
235
|
+
The breakpoint, now in the graph and waiting to resume into the next
|
|
236
|
+
node entered.
|
|
237
|
+
|
|
238
|
+
Raises:
|
|
239
|
+
RuntimeError: When the C layer cannot place it.
|
|
240
|
+
MemoryError: When the block cannot be allocated.
|
|
241
|
+
"""
|
|
242
|
+
cdef BreakpointNode breakpoint = cls(break_from=break_from, **kwargs)
|
|
243
|
+
|
|
244
|
+
cdef int ret_code = c_dcg_lgm_install_breakpoint(
|
|
245
|
+
LogicNode.c_get_manager(),
|
|
246
|
+
<dcg_breakpoint_node*> breakpoint.header,
|
|
247
|
+
)
|
|
248
|
+
if ret_code != dcg_ret_code.DCG_OK:
|
|
249
|
+
raise RuntimeError(f'c_dcg_lgm_install_breakpoint failed with err code: {ret_code}')
|
|
250
|
+
return breakpoint
|
|
251
|
+
|
|
252
|
+
def connect(self, LogicNode child):
|
|
253
|
+
"""Connect a node as what this breakpoint resumes into.
|
|
254
|
+
|
|
255
|
+
A breakpoint resumes into exactly one node, which is what its arm is for,
|
|
256
|
+
so a second connection is refused by the C layer rather than replacing
|
|
257
|
+
the first - see ``append``.
|
|
258
|
+
"""
|
|
259
|
+
self.append(child, NO_CONDITION)
|
|
260
|
+
|
|
261
|
+
# === Python Properties ===
|
|
262
|
+
|
|
263
|
+
property linked_to:
|
|
264
|
+
def __get__(self):
|
|
265
|
+
"""The node this breakpoint resumes into, or None while it waits."""
|
|
266
|
+
if not self.header:
|
|
267
|
+
raise RuntimeError(f'<{self.__class__.__name__}> not initialized!')
|
|
268
|
+
for child in self.children.values():
|
|
269
|
+
return child
|
|
270
|
+
return None
|
|
271
|
+
|
|
272
|
+
property await_connection:
|
|
273
|
+
def __get__(self):
|
|
274
|
+
if not self.header:
|
|
275
|
+
raise RuntimeError(f'<{self.__class__.__name__}> not initialized!')
|
|
276
|
+
cdef dcg_breakpoint_node* node = <dcg_breakpoint_node*> self.header
|
|
277
|
+
return node.await_connection
|
|
Binary file
|