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.
Files changed (148) hide show
  1. decision_graph/__infra__.pxd +1 -0
  2. decision_graph/__init__.pxd +1 -0
  3. decision_graph/__init__.py +39 -0
  4. decision_graph/decision_tree/__init__.pxd +2 -0
  5. decision_graph/decision_tree/__init__.py +85 -0
  6. decision_graph/decision_tree/bake/__infra__.pxd +502 -0
  7. decision_graph/decision_tree/bake/__init__.pxd +502 -0
  8. decision_graph/decision_tree/bake/__init__.py +29 -0
  9. decision_graph/decision_tree/bake/c_action.cp315-win_amd64.pyd +0 -0
  10. decision_graph/decision_tree/bake/c_action.h +324 -0
  11. decision_graph/decision_tree/bake/c_action.pxd +54 -0
  12. decision_graph/decision_tree/bake/c_action.pyi +126 -0
  13. decision_graph/decision_tree/bake/c_action.pyx +65 -0
  14. decision_graph/decision_tree/bake/c_allocator_protocol.cp315-win_amd64.pyd +0 -0
  15. decision_graph/decision_tree/bake/c_allocator_protocol.pxd +24 -0
  16. decision_graph/decision_tree/bake/c_allocator_protocol.pyi +61 -0
  17. decision_graph/decision_tree/bake/c_allocator_protocol.pyx +109 -0
  18. decision_graph/decision_tree/bake/c_bake.cp315-win_amd64.pyd +0 -0
  19. decision_graph/decision_tree/bake/c_bake.h +629 -0
  20. decision_graph/decision_tree/bake/c_bake.pxd +52 -0
  21. decision_graph/decision_tree/bake/c_bake.pyi +151 -0
  22. decision_graph/decision_tree/bake/c_bake.pyx +142 -0
  23. decision_graph/decision_tree/bake/c_collections.cp315-win_amd64.pyd +0 -0
  24. decision_graph/decision_tree/bake/c_collections.h +692 -0
  25. decision_graph/decision_tree/bake/c_collections.pxd +52 -0
  26. decision_graph/decision_tree/bake/c_collections.pyi +193 -0
  27. decision_graph/decision_tree/bake/c_collections.pyx +161 -0
  28. decision_graph/decision_tree/bake/c_const.cp315-win_amd64.pyd +0 -0
  29. decision_graph/decision_tree/bake/c_const.h +395 -0
  30. decision_graph/decision_tree/bake/c_const.pxd +56 -0
  31. decision_graph/decision_tree/bake/c_const.pyi +305 -0
  32. decision_graph/decision_tree/bake/c_const.pyx +278 -0
  33. decision_graph/decision_tree/bake/c_edge.cp315-win_amd64.pyd +0 -0
  34. decision_graph/decision_tree/bake/c_edge.h +511 -0
  35. decision_graph/decision_tree/bake/c_edge.pxd +117 -0
  36. decision_graph/decision_tree/bake/c_edge.pyi +192 -0
  37. decision_graph/decision_tree/bake/c_edge.pyx +270 -0
  38. decision_graph/decision_tree/bake/c_eval.h +848 -0
  39. decision_graph/decision_tree/bake/c_eval.pxd +40 -0
  40. decision_graph/decision_tree/bake/c_expr.cp315-win_amd64.pyd +0 -0
  41. decision_graph/decision_tree/bake/c_expr.h +1900 -0
  42. decision_graph/decision_tree/bake/c_expr.pxd +129 -0
  43. decision_graph/decision_tree/bake/c_expr.pyi +280 -0
  44. decision_graph/decision_tree/bake/c_expr.pyx +272 -0
  45. decision_graph/decision_tree/bake/c_hierarchy.cp315-win_amd64.pyd +0 -0
  46. decision_graph/decision_tree/bake/c_hierarchy.h +731 -0
  47. decision_graph/decision_tree/bake/c_hierarchy.pxd +71 -0
  48. decision_graph/decision_tree/bake/c_hierarchy.pyi +409 -0
  49. decision_graph/decision_tree/bake/c_hierarchy.pyx +277 -0
  50. decision_graph/decision_tree/bake/c_logic_group.cp315-win_amd64.pyd +0 -0
  51. decision_graph/decision_tree/bake/c_logic_group.h +1226 -0
  52. decision_graph/decision_tree/bake/c_logic_group.pxd +162 -0
  53. decision_graph/decision_tree/bake/c_logic_group.pyi +264 -0
  54. decision_graph/decision_tree/bake/c_logic_group.pyx +308 -0
  55. decision_graph/decision_tree/bake/c_node.cp315-win_amd64.pyd +0 -0
  56. decision_graph/decision_tree/bake/c_node.h +2660 -0
  57. decision_graph/decision_tree/bake/c_node.pxd +381 -0
  58. decision_graph/decision_tree/bake/c_node.pyi +438 -0
  59. decision_graph/decision_tree/bake/c_node.pyx +639 -0
  60. decision_graph/decision_tree/bake/c_reconstruct.cp315-win_amd64.pyd +0 -0
  61. decision_graph/decision_tree/bake/c_reconstruct.pxd +63 -0
  62. decision_graph/decision_tree/bake/c_reconstruct.pyi +60 -0
  63. decision_graph/decision_tree/bake/c_reconstruct.pyx +252 -0
  64. decision_graph/decision_tree/bake/c_var.cp315-win_amd64.pyd +0 -0
  65. decision_graph/decision_tree/bake/c_var.h +2054 -0
  66. decision_graph/decision_tree/bake/c_var.pxd +205 -0
  67. decision_graph/decision_tree/bake/c_var.pyi +271 -0
  68. decision_graph/decision_tree/bake/c_var.pyx +228 -0
  69. decision_graph/decision_tree/capi/__infra__.pxd +33 -0
  70. decision_graph/decision_tree/capi/__init__.pxd +33 -0
  71. decision_graph/decision_tree/capi/__init__.py +57 -0
  72. decision_graph/decision_tree/capi/c_abc.cp315-win_amd64.pyd +0 -0
  73. decision_graph/decision_tree/capi/c_abc.pxd +246 -0
  74. decision_graph/decision_tree/capi/c_abc.pyi +770 -0
  75. decision_graph/decision_tree/capi/c_abc.pyx +1532 -0
  76. decision_graph/decision_tree/capi/c_collection.cp315-win_amd64.pyd +0 -0
  77. decision_graph/decision_tree/capi/c_collection.pxd +22 -0
  78. decision_graph/decision_tree/capi/c_collection.pyi +245 -0
  79. decision_graph/decision_tree/capi/c_collection.pyx +138 -0
  80. decision_graph/decision_tree/capi/c_node.cp315-win_amd64.pyd +0 -0
  81. decision_graph/decision_tree/capi/c_node.pxd +95 -0
  82. decision_graph/decision_tree/capi/c_node.pyi +492 -0
  83. decision_graph/decision_tree/capi/c_node.pyx +551 -0
  84. decision_graph/decision_tree/exc.py +189 -0
  85. decision_graph/decision_tree/native/__init__.py +57 -0
  86. decision_graph/decision_tree/native/abc.py +1167 -0
  87. decision_graph/decision_tree/native/collection.py +134 -0
  88. decision_graph/decision_tree/native/node.py +521 -0
  89. decision_graph/includes/decision_graph/decision_tree/bake/c_action.c +16320 -0
  90. decision_graph/includes/decision_graph/decision_tree/bake/c_action.h +324 -0
  91. decision_graph/includes/decision_graph/decision_tree/bake/c_allocator_protocol.c +12473 -0
  92. decision_graph/includes/decision_graph/decision_tree/bake/c_bake.c +16485 -0
  93. decision_graph/includes/decision_graph/decision_tree/bake/c_bake.h +629 -0
  94. decision_graph/includes/decision_graph/decision_tree/bake/c_collections.c +17381 -0
  95. decision_graph/includes/decision_graph/decision_tree/bake/c_collections.h +692 -0
  96. decision_graph/includes/decision_graph/decision_tree/bake/c_const.c +20815 -0
  97. decision_graph/includes/decision_graph/decision_tree/bake/c_const.h +395 -0
  98. decision_graph/includes/decision_graph/decision_tree/bake/c_edge.c +20696 -0
  99. decision_graph/includes/decision_graph/decision_tree/bake/c_edge.h +511 -0
  100. decision_graph/includes/decision_graph/decision_tree/bake/c_eval.h +848 -0
  101. decision_graph/includes/decision_graph/decision_tree/bake/c_expr.c +22065 -0
  102. decision_graph/includes/decision_graph/decision_tree/bake/c_expr.h +1900 -0
  103. decision_graph/includes/decision_graph/decision_tree/bake/c_hierarchy.c +23267 -0
  104. decision_graph/includes/decision_graph/decision_tree/bake/c_hierarchy.h +731 -0
  105. decision_graph/includes/decision_graph/decision_tree/bake/c_logic_group.c +22434 -0
  106. decision_graph/includes/decision_graph/decision_tree/bake/c_logic_group.h +1226 -0
  107. decision_graph/includes/decision_graph/decision_tree/bake/c_node.c +28385 -0
  108. decision_graph/includes/decision_graph/decision_tree/bake/c_node.h +2660 -0
  109. decision_graph/includes/decision_graph/decision_tree/bake/c_reconstruct.c +15955 -0
  110. decision_graph/includes/decision_graph/decision_tree/bake/c_var.c +16881 -0
  111. decision_graph/includes/decision_graph/decision_tree/bake/c_var.h +2054 -0
  112. decision_graph/includes/decision_graph/decision_tree/capi/c_abc.c +59196 -0
  113. decision_graph/includes/decision_graph/decision_tree/capi/c_collection.c +19967 -0
  114. decision_graph/includes/decision_graph/decision_tree/capi/c_node.c +39229 -0
  115. decision_graph/logic_group/__init__.py +25 -0
  116. decision_graph/logic_group/base.py +100 -0
  117. decision_graph/logic_group/pending_request.py +384 -0
  118. decision_graph/webui/__init__.py +24 -0
  119. decision_graph/webui/bake/__init__.py +65 -0
  120. decision_graph/webui/bake/app.py +488 -0
  121. decision_graph/webui/bake/static/d3.v7.min.js +2 -0
  122. decision_graph/webui/bake/static/script.js +1440 -0
  123. decision_graph/webui/bake/static/style.css +920 -0
  124. decision_graph/webui/bake/templates/index.html +183 -0
  125. decision_graph/webui/bake/templates/offline.html +184 -0
  126. decision_graph/webui/capi/__init__.py +54 -0
  127. decision_graph/webui/capi/app.py +366 -0
  128. decision_graph/webui/capi/main.py +53 -0
  129. decision_graph/webui/capi/static/d3.v7.min.js +2 -0
  130. decision_graph/webui/capi/static/script.js +1026 -0
  131. decision_graph/webui/capi/static/style.css +656 -0
  132. decision_graph/webui/capi/templates/index.html +93 -0
  133. decision_graph/webui/capi/templates/offline.html +94 -0
  134. decision_graph/webui/native/__init__.py +54 -0
  135. decision_graph/webui/native/app.py +366 -0
  136. decision_graph/webui/native/main.py +53 -0
  137. decision_graph/webui/native/static/d3.v7.min.js +2 -0
  138. decision_graph/webui/native/static/script.js +1026 -0
  139. decision_graph/webui/native/static/style.css +656 -0
  140. decision_graph/webui/native/templates/index.html +93 -0
  141. decision_graph/webui/native/templates/offline.html +94 -0
  142. pydecisiongraph-0.3.2.post1.dist-info/METADATA +136 -0
  143. pydecisiongraph-0.3.2.post1.dist-info/RECORD +148 -0
  144. pydecisiongraph-0.3.2.post1.dist-info/WHEEL +5 -0
  145. pydecisiongraph-0.3.2.post1.dist-info/licenses/LICENSE +373 -0
  146. pydecisiongraph-0.3.2.post1.dist-info/top_level.txt +2 -0
  147. tests/bake_c_evaluator.cp315-win_amd64.pyd +0 -0
  148. tests/bake_eval_probe.cp315-win_amd64.pyd +0 -0
@@ -0,0 +1,770 @@
1
+ import logging
2
+ import uuid
3
+ from collections.abc import Iterable, Callable, Generator
4
+ from typing import Any, Never, final
5
+
6
+ from decision_graph.decision_tree.exc import NO_DEFAULT
7
+
8
+ LOGGER: logging.Logger
9
+
10
+
11
+ class Singleton(object):
12
+ """Lightweight base to mark extension types as singletons.
13
+
14
+ Used internally by Cython classes to ensure only one instance of certain
15
+ helper types is created per process. Users typically won't need this.
16
+ """
17
+
18
+
19
+ # Edge condition types
20
+ class NodeEdgeCondition(Singleton):
21
+ """Represents an edge condition in a decision graph.
22
+
23
+ This is the base type for all concrete condition markers. Most users
24
+ don't create these directly; instead, use the pre-created constants
25
+ like ``TRUE_CONDITION``, ``FALSE_CONDITION``, ``ELSE_CONDITION``, or
26
+ let conditions be inferred automatically when building graphs.
27
+ """
28
+
29
+ @property
30
+ def value(self) -> Any: ...
31
+
32
+
33
+ class ConditionElse(NodeEdgeCondition):
34
+ """Represents an explicit "else" branch in decision trees.
35
+
36
+ It matches when none of the other registered conditions match.
37
+ """
38
+
39
+
40
+ class ConditionAny(NodeEdgeCondition):
41
+ """Represents an unconditioned branch (always eligible as a fallback)."""
42
+
43
+
44
+ class ConditionAuto(NodeEdgeCondition):
45
+ """Marker used internally to request auto-inference of the edge condition."""
46
+
47
+
48
+ class BinaryCondition(NodeEdgeCondition):
49
+ """Base type for binary True/False conditions."""
50
+
51
+
52
+ class ConditionTrue(BinaryCondition):
53
+ """The boolean True branch condition.
54
+
55
+ Notes:
56
+ - Truthy when converted to ``bool``.
57
+ - ``int(ConditionTrue)`` equals ``1``.
58
+ - Unary negation or bitwise invert toggles to ``FALSE_CONDITION``.
59
+ """
60
+
61
+
62
+ class ConditionFalse(BinaryCondition):
63
+ """The boolean False branch condition.
64
+
65
+ Notes:
66
+ - Falsy when converted to ``bool``.
67
+ - ``int(ConditionFalse)`` equals ``0``.
68
+ - Unary negation or bitwise invert toggles to ``TRUE_CONDITION``.
69
+ """
70
+
71
+
72
+ # Pre-created condition singletons exposed by the module
73
+ NO_CONDITION: ConditionAny
74
+ ELSE_CONDITION: ConditionElse
75
+ AUTO_CONDITION: ConditionAuto
76
+ TRUE_CONDITION: ConditionTrue
77
+ FALSE_CONDITION: ConditionFalse
78
+
79
+
80
+ class SkipContextsBlock:
81
+ """Context manager that may skip executing the body of a with-block.
82
+
83
+ - If the entry check passes, ``__enter__`` returns ``self`` and normal
84
+ execution proceeds until ``__exit__`` is called.
85
+ - If the entry check fails, execution of the block is prevented via
86
+ tracing hooks and an internal control-flow exception; ``__exit__`` then
87
+ suppresses that exception so the program continues after the block.
88
+
89
+ Attributes:
90
+ default_entry_check (bool): If True, the block executes by default.
91
+ """
92
+
93
+ default_entry_check: bool
94
+
95
+ @final
96
+ def __enter__(self) -> SkipContextsBlock: ...
97
+
98
+ @final
99
+ def __exit__(
100
+ self,
101
+ exc_type: type[BaseException] | None,
102
+ exc_value: BaseException | None,
103
+ exc_traceback,
104
+ ) -> bool | None: ...
105
+
106
+
107
+ class LogicExpression(SkipContextsBlock):
108
+ """Represents a logical or mathematical expression with deferred eval.
109
+
110
+ The expression can be a static value, an exception to raise on evaluation,
111
+ or a callable returning a value. An optional ``dtype`` can be provided to
112
+ enforce or check the evaluated type.
113
+
114
+ This class supports boolean logic (``&``, ``|``, comparisons) and basic
115
+ arithmetic operators that produce new ``LogicExpression`` instances.
116
+
117
+ Attributes:
118
+ expression (object): The underlying expression (value, exception, or callable).
119
+ dtype (type | None): Optional type to enforce on evaluation, if requested.
120
+ repr (str): String representation for debugging and logging.
121
+ uid (uuid.UUID): Unique identifier for the LogicExpression instance.
122
+ """
123
+
124
+ expression: object
125
+ dtype: type | None
126
+ repr: str
127
+ uid: uuid.UUID
128
+
129
+ def __init__(
130
+ self,
131
+ *,
132
+ expression: float | int | bool | Exception | Callable[[], Any] = None,
133
+ dtype: type = None,
134
+ repr: str = None,
135
+ uid: uuid.UUID = None,
136
+ **kwargs,
137
+ ) -> None:
138
+ """
139
+ Initialize the LogicExpression.
140
+
141
+ Args:
142
+ expression (Union[Any, Callable[[], Any]]): A callable or static value.
143
+ dtype (type, optional): The expected type of the evaluated value (e.g. float, int, or bool).
144
+ repr (str, optional): A string representation of the expression.
145
+ uid (uuid.UUID, optional): Unique identifier for the expression. If None, a new UUID is generated.
146
+ kwargs: __cinit__ extra kwargs guardian of for subclassing support, not used is this base class.
147
+ """
148
+
149
+ def eval(self, enforce_dtype: bool = False) -> Any:
150
+ """Evaluate the expression and return the resulting value.
151
+
152
+ If ``enforce_dtype`` is True and a ``dtype`` was provided, the result
153
+ is cast using ``self.dtype(value)``.
154
+ """
155
+
156
+ @classmethod
157
+ def cast(
158
+ cls,
159
+ value: int | float | bool | Exception | LogicExpression | Callable[[], Any],
160
+ dtype: type = None,
161
+ ) -> LogicExpression:
162
+ """
163
+ Cast a value into a LogicExpression.
164
+ If the value is already a LogicExpression, it is returned as-is (same instance).
165
+
166
+ Returns:
167
+ LogicExpression: The resulting LogicExpression instance.
168
+
169
+ Raises:
170
+ TypeError: If the value type is unsupported.
171
+ """
172
+
173
+ def __bool__(self) -> bool:
174
+ """Evaluate the expression and return its boolean value."""
175
+
176
+ def __and__(self, other: LogicExpression | bool) -> LogicExpression:
177
+ """Return a new LogicExpression representing logical AND with ``other``."""
178
+
179
+ def __eq__(self, other: object) -> LogicExpression:
180
+ """Return a new LogicExpression representing equality comparison to ``other``."""
181
+
182
+ def __or__(self, other: LogicExpression | bool) -> LogicExpression:
183
+ """Return a new LogicExpression representing logical OR with ``other``."""
184
+
185
+ def __add__(self, other: object) -> LogicExpression:
186
+ """Return a new LogicExpression representing addition with ``other``."""
187
+
188
+ def __sub__(self, other: object) -> LogicExpression:
189
+ """Return a new LogicExpression representing subtraction with ``other``."""
190
+
191
+ def __mul__(self, other: object) -> LogicExpression:
192
+ """Return a new LogicExpression representing multiplication with ``other``."""
193
+
194
+ def __truediv__(self, other: object) -> LogicExpression:
195
+ """Return a new LogicExpression representing true division with ``other``."""
196
+
197
+ def __floordiv__(self, other: object) -> LogicExpression:
198
+ """Return a new LogicExpression representing floor division with ``other``."""
199
+
200
+ def __pow__(self, other: object) -> LogicExpression:
201
+ """Return a new LogicExpression representing exponentiation with ``other``."""
202
+
203
+ def __lt__(self, other: object) -> LogicExpression:
204
+ """Return a new LogicExpression representing less-than comparison to ``other``."""
205
+
206
+ def __le__(self, other: object) -> LogicExpression:
207
+ """Return a new LogicExpression representing less-than-or-equal comparison to ``other``."""
208
+
209
+ def __gt__(self, other: object) -> LogicExpression:
210
+ """Return a new LogicExpression representing greater-than comparison to ``other``."""
211
+
212
+ def __ge__(self, other: object) -> LogicExpression:
213
+ """Return a new LogicExpression representing greater-than-or-equal comparison to ``other``."""
214
+
215
+ def __repr__(self) -> str:
216
+ """Return the string representation of the LogicExpression."""
217
+
218
+
219
+ class LogicGroupManager(Singleton):
220
+ """Singleton manager for LogicGroup instances and runtime expression context.
221
+
222
+ Handles caching and reuse of ``LogicGroup`` objects and manages runtime
223
+ stacks for active groups and nodes while building or evaluating decision
224
+ graphs.
225
+
226
+ Also supports shelving/unshelving state to create decision sub-graphs
227
+ (for example, across function calls) without interfering with the main
228
+ active state.
229
+
230
+ Attributes:
231
+ inspection_mode (bool): If True, generate layout without executing actions.
232
+ vigilant_mode (bool): If True, perform stricter validation and avoid auto-generated nodes.
233
+ """
234
+
235
+ inspection_mode: bool
236
+ vigilant_mode: bool
237
+
238
+ def __call__(self, name: str, cls: type[LogicGroup], **kwargs) -> LogicGroup:
239
+ """Get or create a cached LogicGroup instance with the given name.
240
+
241
+ Useful for closed-loop operations that need to reuse the same logic group.
242
+
243
+ Args:
244
+ name (str): The name of the logic group.
245
+ cls (type[LogicGroup]): The LogicGroup subclass to instantiate if not cached.
246
+ **kwargs: Additional keyword arguments to pass to the LogicGroup constructor.
247
+
248
+ Returns:
249
+ LogicGroup: The cached or newly created LogicGroup instance.
250
+ """
251
+
252
+ def __contains__(self, instance: LogicGroup) -> bool:
253
+ """Return True if the given LogicGroup instance is cached by this manager."""
254
+
255
+ def shelve(self) -> None:
256
+ """Shelve the current active group and node stacks and breakpoint stacks for later restoration.
257
+
258
+ This is useful for creating isolated decision sub-graphs without interfering with the others graphs' state.
259
+
260
+ With RootLogicNode contexts, the LGM automatically shelved and unshelved. See ``RootLogicNode`` for details.
261
+ """
262
+
263
+ def unshelve(self) -> None:
264
+ """Restore the most recently shelved active group and node stacks."""
265
+
266
+ def clear(self) -> None:
267
+ """Clear all cached LogicGroup instances and reset runtime stacks."""
268
+
269
+ @property
270
+ def active_group(self) -> LogicGroup | None:
271
+ """The currently active LogicGroup, or None if no group context is entered."""
272
+
273
+ @property
274
+ def active_node(self) -> LogicNode | None:
275
+ """The currently active LogicNode expression, or None if no expression context is entered."""
276
+
277
+
278
+ # Global instance of the manager
279
+ LGM: LogicGroupManager
280
+
281
+
282
+ class LogicGroup:
283
+ """A minimal context manager to scope logic groups and break operations.
284
+
285
+ A logic group is a lightweight context that records its name and an
286
+ optional parent, and it provides a ``Break`` exception type for orderly
287
+ early exit via ``LogicGroup.break_``.
288
+
289
+ In runtime mode, breaking from a logic group propagates through nested
290
+ groups and moves the execution cursor to the first line after the block;
291
+ during this process, on-exit hooks of nested groups and nodes run.
292
+
293
+ In inspection mode, breaking does not raise immediately. Instead, missing
294
+ branches are auto-filled with ``NoAction`` to allow layout evaluation to
295
+ continue, especially when a break occurs before the other branch is built.
296
+
297
+ Attributes:
298
+ name (str): The name of the logic group.
299
+ parent (LogicGroup | None): The parent logic group, if any.
300
+ Break (type[BaseException]): The exception type used for breaks.
301
+ contexts (dict[str, Any]): Context-specific storage for the group.
302
+ """
303
+
304
+ name: str
305
+ parent: LogicGroup | None
306
+ Break: type[BaseException]
307
+ contexts: dict[str, Any]
308
+
309
+ def __init__(self, *, name: str = None, parent: LogicGroup = None, contexts: dict = None, **kwargs):
310
+ """Initialize a LogicGroup with the given name, parent, and contexts.
311
+
312
+ Args:
313
+ name (str): The name of the logic group. If None, a unique name is assigned.
314
+ parent (LogicGroup | None): The parent logic group, if any.
315
+ contexts (dict[str, Any] | None): Optional context-specific storage.
316
+ kwargs: __cinit__ extra kwargs guardian of for subclassing support, not used is this base class.
317
+ """
318
+
319
+ def __repr__(self) -> str: ...
320
+
321
+ def __enter__(self) -> LogicGroup:
322
+ """Enter the logic group context and mark it as active."""
323
+ ...
324
+
325
+ def __exit__(
326
+ self,
327
+ exc_type: type[BaseException] | None,
328
+ exc_value: BaseException | None,
329
+ exc_traceback,
330
+ ) -> bool | None:
331
+ """Exit the logic group context, handling Break exceptions gracefully."""
332
+ ...
333
+
334
+ @classmethod
335
+ def break_(cls, scope: LogicGroup = None) -> None:
336
+ """Break out from the given ``scope`` (or the active scope if None).
337
+
338
+ In inspection mode, the break is recorded to be connected to the next
339
+ entered node. In runtime mode, this propagates break through nested
340
+ groups until the target scope is exited.
341
+ """
342
+ ...
343
+
344
+ def break_active(self) -> None:
345
+ """Break out from the currently active logic group only (top of stack)."""
346
+
347
+ def break_inspection(self) -> None:
348
+ """Record a break while in inspection mode without raising immediately."""
349
+
350
+ def break_runtime(self) -> None:
351
+ """Propagate a break through nested groups until the target scope is exited."""
352
+
353
+
354
+ class LogicNode(LogicExpression):
355
+ """A decision node that branches to children based on an evaluated value.
356
+
357
+ Each child is registered against an edge condition, and the node supports
358
+ auto-inference of binary conditions for succinct graph construction.
359
+
360
+ Attributes:
361
+ parent (LogicNode | None): The parent node, if any.
362
+ condition_to_parent (NodeEdgeCondition): The edge condition leading to this node from its parent.
363
+ children (dict[NodeEdgeCondition, LogicNode]): Mapping of edge conditions to child nodes.
364
+ labels (list[str]): LogicGroup names this node belongs to.
365
+ autogen (bool): Whether this node was auto-generated to fill a missing branch.
366
+ """
367
+
368
+ parent: LogicNode | None
369
+ condition_to_parent: NodeEdgeCondition
370
+ children: dict[NodeEdgeCondition, LogicNode]
371
+ labels: list[str]
372
+ autogen: bool
373
+
374
+ def __init__(self, *, expression: object = None, dtype: type = None, repr: str = None, uid: uuid.UUID = None, **kwargs):
375
+ """
376
+ Initialize the LogicExpression.
377
+
378
+ Args:
379
+ expression (Union[Any, Callable[[], Any]]): A callable or static value.
380
+ dtype (type, optional): The expected type of the evaluated value (e.g. float, int, or bool).
381
+ repr (str, optional): A string representation of the expression.
382
+ uid (uuid.UUID, optional): Unique identifier for the expression. If None, a new UUID is generated.
383
+ kwargs: __cinit__ extra kwargs guardian of for subclassing support, not used is this base class.
384
+ """
385
+
386
+ def __rshift__(self, other: LogicNode) -> LogicNode:
387
+ """
388
+ Convenience for ``append`` to support chaining, e.g.::
389
+
390
+ >>> node1 = LogicNode(expression=...)
391
+ >>> node2 = LogicNode(expression=...)
392
+ >>> node1 >> node2
393
+
394
+ Returns the ``other`` node so calls can be chained.
395
+ """
396
+
397
+ def __call__(self, default: Any = NO_DEFAULT) -> Any:
398
+ """Evaluate the tree from this node and return the final action/value.
399
+
400
+ If ``default`` is not provided, a ``NoAction`` node will be used as the
401
+ fallback terminal.
402
+
403
+ You can pass ``NO_DEFAULT`` to explicitly require a matching branch;
404
+ if no edge matches, a ``ValueError`` will be raised.
405
+ See ``eval_recursively`` for details.
406
+ """
407
+ ...
408
+
409
+ def append(self, child: LogicNode, condition: NodeEdgeCondition = AUTO_CONDITION) -> None:
410
+ """Append a child node with the given edge condition.
411
+
412
+ If ``condition`` is ``AUTO_CONDITION``, the condition is inferred
413
+ automatically based on existing children (for binary branching).
414
+
415
+ Raises:
416
+ ValueError: If an invalid condition is provided (e.g., ``None``).
417
+ KeyError: If the condition is already used by another child.
418
+ EdgeValueError: If condition inference fails due to incompatible existing children.
419
+ TooManyChildren: If inference fails due to too many existing children.
420
+ """
421
+
422
+ def overwrite(self, new_node: LogicNode, condition: NodeEdgeCondition) -> None:
423
+ """Overwrite the child node for the given edge condition.
424
+
425
+ If ``condition`` is ``AUTO_CONDITION``, the condition is inferred
426
+ automatically based on existing children (for binary branching).
427
+
428
+ Raises:
429
+ ValueError: If an invalid condition is provided (e.g., ``None``).
430
+ KeyError: If there is no existing child for the given condition.
431
+ EdgeValueError: If condition inference fails due to incompatible existing children.
432
+ TooManyChildren: If inference fails due to too many existing children.
433
+ """
434
+
435
+ def replace(self, original_node: LogicNode, new_node: LogicNode) -> None:
436
+ """Replace an existing child node with a new node.
437
+
438
+ Raises:
439
+ RuntimeError: If the original node is currently active.
440
+ LookupError: If the stack is out of sync with the node's children.
441
+ NodeNotFountError: If the original node is not a child of this node.
442
+ """
443
+
444
+ def eval_recursively(
445
+ self,
446
+ path: list[LogicNode] = None,
447
+ default: Any = NO_DEFAULT,
448
+ ) -> tuple[Any, list[LogicNode]]:
449
+ """Evaluate the decision tree recursively from this node.
450
+
451
+ Args:
452
+ path (list[LogicNode] | None): If provided, a list to record the
453
+ sequence of nodes traversed during evaluation.
454
+ default (Any): The default value or action to use if no matching
455
+ child is found. Use ``NO_DEFAULT`` to request an error when no
456
+ branch matches.
457
+ Returns:
458
+ tuple[Any, list[LogicNode]]: The resulting value/action and the
459
+ path list of nodes traversed during evaluation.
460
+ """
461
+
462
+ def list_labels(self) -> dict[str, list[LogicNode]]:
463
+ """List all LogicGroup names in the subtree rooted at this node.
464
+
465
+ Returns:
466
+ dict[str, list[LogicNode]]: A mapping from label strings (logic group names)
467
+ to lists of nodes that have that label.
468
+ """
469
+
470
+ @property
471
+ def leaves(self) -> Generator[LogicNode]:
472
+ """An iterable of all leaf nodes in the subtree rooted at this node."""
473
+
474
+ @property
475
+ def is_leaf(self) -> bool:
476
+ """True if this node has no children; otherwise False."""
477
+
478
+ @property
479
+ def child_stack(self) -> Iterable[LogicNode]:
480
+ """An iterable of all child nodes in the subtree rooted at this node."""
481
+
482
+ @property
483
+ def descendants(self) -> Generator[LogicNode, None, None]:
484
+ """A generator yielding all descendant nodes in the subtree rooted at this node."""
485
+ ...
486
+
487
+
488
+ class BreakpointNode(LogicNode):
489
+ """A logic node that represents a breakpoint in the decision tree, used for breaking out of logic groups.
490
+
491
+ This node is auto-generated and can connect to at most one child node.
492
+ To connect as branch to a BreakpointNode, there are 2 ways:
493
+ - A managed style, powered by LGM, where the BreakpointNode connects to the next entered node, outside the LogicGroup this BreakpointNode from. after a break is recorded.
494
+ - or a manual way, using with clause. Which entered the BreakpointNode context, and then continue to build the rest of the branch. In this way the LGM will relinquish the management of this node. This could be potentially dangerous, but provides a way to join external branches.
495
+
496
+ During evaluation, if connected, it delegates to the child's evaluation; otherwise, it returns its default expression (NoAction) in vigilant mode.
497
+
498
+ Attributes:
499
+ break_from (LogicGroup): The logic group from which this breakpoint breaks.
500
+ await_connection (bool): Whether to wait for a connection to a child node during inspection.
501
+ """
502
+
503
+ break_from: LogicGroup
504
+ await_connection: bool
505
+
506
+ def __init__(self, *, break_from: LogicGroup = None, expression: Any = None, repr: str = None, **kwargs):
507
+ """
508
+ Initialize the BreakpointNode.
509
+
510
+ Args:
511
+ break_from (LogicGroup): The logic group from which this breakpoint breaks. Defaults to None.
512
+ expression (Any): The default expression for this breakpoint node. Defaults to a new unique dangling NoAction node.
513
+ str (str): A string representation of the expression. Auto-generated if None.
514
+ """
515
+
516
+ @classmethod
517
+ def break_(cls, break_from: LogicGroup, **kwargs) -> BreakpointNode:
518
+ """
519
+ Create a BreakpointNode that breaks from the given logic group, for full manual control.
520
+ This method also auto connects the BreakpointNode to the active node in the LGM upon creation.
521
+
522
+ Args:
523
+ break_from (LogicGroup): The logic group from which this breakpoint breaks.
524
+ kwargs: Additional keyword arguments to pass to the BreakpointNode constructor.
525
+ """
526
+
527
+ def connect(self, child: LogicNode) -> None:
528
+ """
529
+ Connect a child node to this BreakpointNode.
530
+
531
+ Raises:
532
+ TooManyChildren: If a child is already connected.
533
+ """
534
+
535
+ @property
536
+ def linked_to(self) -> LogicNode:
537
+ """
538
+ The child node connected to this BreakpointNode.
539
+
540
+ Returns:
541
+ LogicNode: The connected child node, if there is one, otherwise return None.
542
+ """
543
+
544
+
545
+ class ActionNode(LogicNode):
546
+ """A terminal node that can execute an optional ``action`` upon selection."""
547
+
548
+ action: Callable[[], Any] | None
549
+
550
+ def __init__(
551
+ self,
552
+ *,
553
+ action: Callable[[], Any] = None,
554
+ expression: object = None,
555
+ dtype: type = None,
556
+ repr: str = None,
557
+ auto_connect: bool = True,
558
+ **kwargs,
559
+ ) -> None:
560
+ """
561
+ Initialize the ActionNode.
562
+
563
+ Args:
564
+ action (Callable[[], Any] | None): An optional callable to execute when this action is selected (post-eval).
565
+ expression (Union[Any, Callable[[], Any]]): A callable or static value (on-eval).
566
+ dtype (type, optional): The expected type of the evaluated value (e.g. float, int, or bool).
567
+ repr (str, optional): A string representation of the expression.
568
+ auto_connect (bool): If True, automatically connect this action node to the active node in the LGM upon creation.
569
+ kwargs: __cinit__ extra kwargs guardian of for subclassing support.
570
+ """
571
+
572
+ def __enter__(self) -> Never:
573
+ """
574
+ ActionNode does not support the context manager protocol.
575
+
576
+ Raises:
577
+ NodeContextError: Using ``with ActionNode()`` is invalid.
578
+ """
579
+
580
+ def append(self, child: LogicNode, condition: NodeEdgeCondition = AUTO_CONDITION) -> Never:
581
+ """
582
+ Appending children to an ActionNode is not supported.
583
+
584
+ Since ActionNodes are terminal, ``replace`` and ``overwrite`` are also
585
+ not applicable and will fail naturally if attempted.
586
+
587
+ Raises:
588
+ TooManyChildren: Always raised to signal invalid operation.
589
+ """
590
+
591
+
592
+ class PlaceholderNode(ActionNode):
593
+ """An action node that serves as a placeholder in the decision tree.
594
+
595
+ This node is auto-generated and during evaluation returns itself in vigilant mode, otherwise returns a NoAction instance.
596
+ """
597
+
598
+
599
+ class NoAction(ActionNode):
600
+ """An action node whose evaluation returns itself and performs no action.
601
+
602
+ attributes:
603
+ sig (int): The signature marker for the no-action. Defaults to ``0``. Internal c fields is a ``ssize_t``
604
+ """
605
+
606
+ sig: int
607
+
608
+ def __init__(
609
+ self,
610
+ *,
611
+ sig: int = 0,
612
+ action: Callable[[], Any] = None,
613
+ expression: object = None,
614
+ dtype: type = None,
615
+ repr: str = None,
616
+ auto_connect: bool = True,
617
+ autogen: bool = False,
618
+ **kwargs,
619
+ ) -> None:
620
+ """
621
+ Initialize a NoAction node.
622
+
623
+ Args:
624
+ sig (int): The signature marker for the no-action. Defaults to ``0``.
625
+ action (Callable[[], Any] | None): An optional callable to execute when this action is selected (post-eval).
626
+ expression (Union[Any, Callable[[], Any]]): A callable or static value (on-eval).
627
+ dtype (type, optional): The expected type of the evaluated value (e.g. float, int, or bool).
628
+ repr (str, optional): A string representation of the expression.
629
+ auto_connect (bool): If True, automatically connect this action node to the active node in the LGM upon creation.
630
+ autogen (bool): If True, marks this node as auto-generated.
631
+ kwargs: __cinit__ extra kwargs guardian of for subclassing support.
632
+ """
633
+
634
+ def __int__(self): ...
635
+
636
+
637
+ class LongAction(ActionNode):
638
+ """An action node variant carrying a positive ``sig`` marker.
639
+
640
+ Attributes:
641
+ sig (int): The signature marker for the long action. Defaults to ``1``.
642
+ """
643
+
644
+ sig: int
645
+
646
+ def __init__(
647
+ self,
648
+ *,
649
+ sig: int = 1,
650
+ action: Callable[[], Any] = None,
651
+ expression: object = None,
652
+ dtype: type = None,
653
+ repr: str = None,
654
+ auto_connect: bool = True,
655
+ **kwargs,
656
+ ) -> None:
657
+ """
658
+ Initialize a LongAction node.
659
+
660
+ Args:
661
+ sig (int): The signature marker for the long action. Defaults to ``1``.
662
+ action (Callable[[], Any] | None): An optional callable to execute when this action is selected (post-eval).
663
+ expression (Union[Any, Callable[[], Any]]): A callable or static value (on-eval).
664
+ dtype (type, optional): The expected type of the evaluated value (e.g. float, int, or bool).
665
+ repr (str, optional): A string representation of the expression.
666
+ auto_connect (bool): If True, automatically connect this action node to the active node in the LGM upon creation.
667
+ kwargs: __cinit__ extra kwargs guardian of for subclassing support.
668
+ """
669
+
670
+ def __int__(self): ...
671
+
672
+
673
+ class ShortAction(ActionNode):
674
+ """An action node variant carrying a negative ``sig`` marker.
675
+
676
+ Attributes:
677
+ sig (int): The signature marker for the long action. Defaults to ``-1``.
678
+ """
679
+
680
+ sig: int
681
+
682
+ def __init__(
683
+ self,
684
+ *,
685
+ sig: int = -1,
686
+ action: Callable[[], Any] = None,
687
+ expression: object = None,
688
+ dtype: type = None,
689
+ repr: str = None,
690
+ auto_connect: bool = True,
691
+ **kwargs,
692
+ ) -> None:
693
+ """
694
+ Initialize a ShortAction node.
695
+
696
+ Args:
697
+ sig (int): The signature marker for the short action. Defaults to ``-1``.
698
+ action (Callable[[], Any] | None): An optional callable to execute when this action is selected (post-eval).
699
+ expression (Union[Any, Callable[[], Any]]): A callable or static value (on-eval).
700
+ dtype (type, optional): The expected type of the evaluated value (e.g. float, int, or bool).
701
+ repr (str, optional): A string representation of the expression.
702
+ auto_connect (bool): If True, automatically connect this action node to the active node in the LGM upon creation.
703
+ kwargs: __cinit__ extra kwargs guardian of for subclassing support.
704
+ """
705
+
706
+ def __int__(self): ...
707
+
708
+
709
+ class CancelAction(ActionNode):
710
+ """An action node whose evaluation returns itself and performs cancel action."""
711
+
712
+ sig: int
713
+
714
+ def __init__(
715
+ self,
716
+ *,
717
+ sig: int = 0,
718
+ action: Callable[[], Any] = None,
719
+ expression: object = None,
720
+ dtype: type = None,
721
+ repr: str = None,
722
+ auto_connect: bool = True,
723
+ **kwargs,
724
+ ) -> None:
725
+ """
726
+ Initialize a CancelAction node.
727
+
728
+ Args:
729
+ sig (int): The signature marker for the cancel action. Defaults to ``0``.
730
+ action (Callable[[], Any] | None): An optional callable to execute when this action is selected (post-eval).
731
+ expression (Union[Any, Callable[[], Any]]): A callable or static value (on-eval).
732
+ dtype (type, optional): The expected type of the evaluated value (e.g. float, int, or bool).
733
+ repr (str, optional): A string representation of the expression.
734
+ auto_connect (bool): If True, automatically connect this action node to the active node in the LGM upon creation.
735
+ kwargs: __cinit__ extra kwargs guardian of for subclassing support.
736
+ """
737
+
738
+ def __int__(self): ...
739
+
740
+
741
+ class ClearAction(ActionNode):
742
+ """An action node whose evaluation returns itself and performs fully unwind (clear position) action."""
743
+
744
+ sig: int
745
+
746
+ def __init__(
747
+ self,
748
+ *,
749
+ sig: int = 0,
750
+ action: Callable[[], Any] = None,
751
+ expression: object = None,
752
+ dtype: type = None,
753
+ repr: str = None,
754
+ auto_connect: bool = True,
755
+ **kwargs,
756
+ ) -> None:
757
+ """
758
+ Initialize a ClearAction node.
759
+
760
+ Args:
761
+ sig (int): The signature marker for the clear action. Defaults to ``0``.
762
+ action (Callable[[], Any] | None): An optional callable to execute when this action is selected (post-eval).
763
+ expression (Union[Any, Callable[[], Any]]): A callable or static value (on-eval).
764
+ dtype (type, optional): The expected type of the evaluated value (e.g. float, int, or bool).
765
+ repr (str, optional): A string representation of the expression.
766
+ auto_connect (bool): If True, automatically connect this action node to the active node in the LGM upon creation.
767
+ kwargs: __cinit__ extra kwargs guardian of for subclassing support.
768
+ """
769
+
770
+ def __int__(self): ...