2
2
BaseNode Module
3
3
"""
4
4
5
- from abc import ABC , abstractmethod
6
- from typing import Optional , List
7
5
import re
6
+ from abc import ABC , abstractmethod
7
+ from typing import List , Optional
8
+
9
+ from ..utils import get_logger
8
10
9
11
10
12
class BaseNode (ABC ):
@@ -14,10 +16,11 @@ class BaseNode(ABC):
14
16
Attributes:
15
17
node_name (str): The unique identifier name for the node.
16
18
input (str): Boolean expression defining the input keys needed from the state.
17
- output (List[str]): List of
19
+ output (List[str]): List of
18
20
min_input_len (int): Minimum required number of input keys.
19
21
node_config (Optional[dict]): Additional configuration for the node.
20
-
22
+ logger (logging.Logger): The centralized root logger
23
+
21
24
Args:
22
25
node_name (str): Name for identifying the node.
23
26
node_type (str): Type of the node; must be 'node' or 'conditional_node'.
@@ -28,7 +31,7 @@ class BaseNode(ABC):
28
31
29
32
Raises:
30
33
ValueError: If `node_type` is not one of the allowed types.
31
-
34
+
32
35
Example:
33
36
>>> class MyNode(BaseNode):
34
37
... def execute(self, state):
@@ -40,18 +43,27 @@ class BaseNode(ABC):
40
43
{'key': 'value'}
41
44
"""
42
45
43
- def __init__ (self , node_name : str , node_type : str , input : str , output : List [str ],
44
- min_input_len : int = 1 , node_config : Optional [dict ] = None ):
46
+ def __init__ (
47
+ self ,
48
+ node_name : str ,
49
+ node_type : str ,
50
+ input : str ,
51
+ output : List [str ],
52
+ min_input_len : int = 1 ,
53
+ node_config : Optional [dict ] = None ,
54
+ ):
45
55
46
56
self .node_name = node_name
47
57
self .input = input
48
58
self .output = output
49
59
self .min_input_len = min_input_len
50
60
self .node_config = node_config
61
+ self .logger = get_logger ()
51
62
52
63
if node_type not in ["node" , "conditional_node" ]:
53
64
raise ValueError (
54
- f"node_type must be 'node' or 'conditional_node', got '{ node_type } '" )
65
+ f"node_type must be 'node' or 'conditional_node', got '{ node_type } '"
66
+ )
55
67
self .node_type = node_type
56
68
57
69
@abstractmethod
@@ -102,8 +114,7 @@ def get_input_keys(self, state: dict) -> List[str]:
102
114
self ._validate_input_keys (input_keys )
103
115
return input_keys
104
116
except ValueError as e :
105
- raise ValueError (
106
- f"Error parsing input keys for { self .node_name } : { str (e )} " )
117
+ raise ValueError (f"Error parsing input keys for { self .node_name } : { str (e )} " )
107
118
108
119
def _validate_input_keys (self , input_keys ):
109
120
"""
@@ -119,7 +130,8 @@ def _validate_input_keys(self, input_keys):
119
130
if len (input_keys ) < self .min_input_len :
120
131
raise ValueError (
121
132
f"""{ self .node_name } requires at least { self .min_input_len } input keys,
122
- got { len (input_keys )} .""" )
133
+ got { len (input_keys )} ."""
134
+ )
123
135
124
136
def _parse_input_keys (self , state : dict , expression : str ) -> List [str ]:
125
137
"""
@@ -142,67 +154,80 @@ def _parse_input_keys(self, state: dict, expression: str) -> List[str]:
142
154
raise ValueError ("Empty expression." )
143
155
144
156
# Check for adjacent state keys without an operator between them
145
- pattern = r'\b(' + '|' .join (re .escape (key ) for key in state .keys ()) + \
146
- r')(\b\s*\b)(' + '|' .join (re .escape (key )
147
- for key in state .keys ()) + r')\b'
157
+ pattern = (
158
+ r"\b("
159
+ + "|" .join (re .escape (key ) for key in state .keys ())
160
+ + r")(\b\s*\b)("
161
+ + "|" .join (re .escape (key ) for key in state .keys ())
162
+ + r")\b"
163
+ )
148
164
if re .search (pattern , expression ):
149
165
raise ValueError (
150
- "Adjacent state keys found without an operator between them." )
166
+ "Adjacent state keys found without an operator between them."
167
+ )
151
168
152
169
# Remove spaces
153
170
expression = expression .replace (" " , "" )
154
171
155
172
# Check for operators with empty adjacent tokens or at the start/end
156
- if expression [0 ] in '&|' or expression [- 1 ] in '&|' \
157
- or '&&' in expression or '||' in expression or \
158
- '&|' in expression or '|&' in expression :
173
+ if (
174
+ expression [0 ] in "&|"
175
+ or expression [- 1 ] in "&|"
176
+ or "&&" in expression
177
+ or "||" in expression
178
+ or "&|" in expression
179
+ or "|&" in expression
180
+ ):
159
181
raise ValueError ("Invalid operator usage." )
160
182
161
183
# Check for balanced parentheses and valid operator placement
162
184
open_parentheses = close_parentheses = 0
163
185
for i , char in enumerate (expression ):
164
- if char == '(' :
186
+ if char == "(" :
165
187
open_parentheses += 1
166
- elif char == ')' :
188
+ elif char == ")" :
167
189
close_parentheses += 1
168
190
# Check for invalid operator sequences
169
191
if char in "&|" and i + 1 < len (expression ) and expression [i + 1 ] in "&|" :
170
192
raise ValueError (
171
- "Invalid operator placement: operators cannot be adjacent." )
193
+ "Invalid operator placement: operators cannot be adjacent."
194
+ )
172
195
173
196
# Check for missing or balanced parentheses
174
197
if open_parentheses != close_parentheses :
175
- raise ValueError (
176
- "Missing or unbalanced parentheses in expression." )
198
+ raise ValueError ("Missing or unbalanced parentheses in expression." )
177
199
178
200
# Helper function to evaluate an expression without parentheses
179
201
def evaluate_simple_expression (exp : str ) -> List [str ]:
180
202
"""Evaluate an expression without parentheses."""
181
203
182
204
# Split the expression by the OR operator and process each segment
183
- for or_segment in exp .split ('|' ):
205
+ for or_segment in exp .split ("|" ):
184
206
185
207
# Check if all elements in an AND segment are in state
186
- and_segment = or_segment .split ('&' )
208
+ and_segment = or_segment .split ("&" )
187
209
if all (elem .strip () in state for elem in and_segment ):
188
- return [elem .strip () for elem in and_segment if elem .strip () in state ]
210
+ return [
211
+ elem .strip () for elem in and_segment if elem .strip () in state
212
+ ]
189
213
return []
190
214
191
215
# Helper function to evaluate expressions with parentheses
192
216
def evaluate_expression (expression : str ) -> List [str ]:
193
217
"""Evaluate an expression with parentheses."""
194
-
195
- while '(' in expression :
196
- start = expression .rfind ('(' )
197
- end = expression .find (')' , start )
198
- sub_exp = expression [start + 1 : end ]
218
+
219
+ while "(" in expression :
220
+ start = expression .rfind ("(" )
221
+ end = expression .find (")" , start )
222
+ sub_exp = expression [start + 1 : end ]
199
223
200
224
# Replace the evaluated part with a placeholder and then evaluate it
201
225
sub_result = evaluate_simple_expression (sub_exp )
202
226
203
227
# For simplicity in handling, join sub-results with OR to reprocess them later
204
- expression = expression [:start ] + \
205
- '|' .join (sub_result ) + expression [end + 1 :]
228
+ expression = (
229
+ expression [:start ] + "|" .join (sub_result ) + expression [end + 1 :]
230
+ )
206
231
return evaluate_simple_expression (expression )
207
232
208
233
result = evaluate_expression (expression )
0 commit comments