lionagi 0.1.1__py3-none-any.whl → 0.1.2__py3-none-any.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.
- lionagi/core/execute/structure_executor.py +21 -1
- lionagi/core/flow/monoflow/ReAct.py +3 -1
- lionagi/core/flow/monoflow/followup.py +3 -1
- lionagi/core/generic/component.py +197 -120
- lionagi/core/generic/condition.py +2 -0
- lionagi/core/generic/edge.py +33 -33
- lionagi/core/graph/graph.py +1 -1
- lionagi/core/tool/tool_manager.py +10 -9
- lionagi/experimental/report/form.py +64 -0
- lionagi/experimental/report/report.py +138 -0
- lionagi/experimental/report/util.py +47 -0
- lionagi/experimental/tool/schema.py +3 -3
- lionagi/experimental/tool/tool_manager.py +1 -1
- lionagi/experimental/validator/rule.py +139 -0
- lionagi/experimental/validator/validator.py +56 -0
- lionagi/experimental/work/__init__.py +10 -0
- lionagi/experimental/work/async_queue.py +54 -0
- lionagi/experimental/work/schema.py +60 -17
- lionagi/experimental/work/work_function.py +55 -77
- lionagi/experimental/work/worker.py +56 -12
- lionagi/experimental/work2/__init__.py +0 -0
- lionagi/experimental/work2/form.py +371 -0
- lionagi/experimental/work2/report.py +289 -0
- lionagi/experimental/work2/schema.py +30 -0
- lionagi/experimental/{work → work2}/tests.py +1 -1
- lionagi/experimental/work2/util.py +0 -0
- lionagi/experimental/work2/work.py +0 -0
- lionagi/experimental/work2/work_function.py +89 -0
- lionagi/experimental/work2/worker.py +12 -0
- lionagi/integrations/storage/storage_util.py +4 -4
- lionagi/integrations/storage/structure_excel.py +268 -0
- lionagi/integrations/storage/to_excel.py +18 -9
- lionagi/libs/__init__.py +4 -0
- lionagi/tests/test_core/generic/__init__.py +0 -0
- lionagi/tests/test_core/generic/test_component.py +89 -0
- lionagi/version.py +1 -1
- {lionagi-0.1.1.dist-info → lionagi-0.1.2.dist-info}/METADATA +1 -1
- {lionagi-0.1.1.dist-info → lionagi-0.1.2.dist-info}/RECORD +43 -27
- lionagi/experimental/work/_logger.py +0 -25
- /lionagi/experimental/{work/exchange.py → report/__init__.py} +0 -0
- /lionagi/experimental/{work/util.py → validator/__init__.py} +0 -0
- {lionagi-0.1.1.dist-info → lionagi-0.1.2.dist-info}/LICENSE +0 -0
- {lionagi-0.1.1.dist-info → lionagi-0.1.2.dist-info}/WHEEL +0 -0
- {lionagi-0.1.1.dist-info → lionagi-0.1.2.dist-info}/top_level.txt +0 -0
@@ -288,7 +288,7 @@ class StructureExecutor(BaseExecutor, Graph):
|
|
288
288
|
while self.pending_ins[key]:
|
289
289
|
mail: BaseMail = self.pending_ins[key].popleft()
|
290
290
|
try:
|
291
|
-
if mail == "end":
|
291
|
+
if mail.category == "end":
|
292
292
|
self.execute_stop = True
|
293
293
|
return
|
294
294
|
next_nodes = await self._handle_mail(mail)
|
@@ -312,3 +312,23 @@ class StructureExecutor(BaseExecutor, Graph):
|
|
312
312
|
while not self.execute_stop:
|
313
313
|
await self.forward()
|
314
314
|
await AsyncUtil.sleep(refresh_time)
|
315
|
+
|
316
|
+
def to_excel(self, structure_name, dir="structure_storage"):
|
317
|
+
"""
|
318
|
+
Exports the current structure to an Excel file using a specified structure name and directory.
|
319
|
+
|
320
|
+
This method utilizes the `to_excel` function from the `lionagi.integrations.storage.to_excel` module,
|
321
|
+
saving the current structure instance into an Excel file format. The Excel file will contain details
|
322
|
+
about nodes, edges, and other relevant data as separate sheets within the file.
|
323
|
+
|
324
|
+
Args:
|
325
|
+
structure_name (str): The name to assign to the structure within the Excel file. This name is
|
326
|
+
used as part of the file naming convention.
|
327
|
+
dir (str, optional): The directory where the Excel file will be saved. Defaults to "structure_storage".
|
328
|
+
|
329
|
+
Raises:
|
330
|
+
Exception: Propagates any exceptions raised by the `to_excel` function, which might occur during
|
331
|
+
the file writing process or data formatting.
|
332
|
+
"""
|
333
|
+
from lionagi.integrations.storage.to_excel import to_excel
|
334
|
+
to_excel(self, structure_name, dir)
|
@@ -145,7 +145,9 @@ class MonoReAct(MonoChat):
|
|
145
145
|
if not self.branch.tool_manager.has_tools:
|
146
146
|
raise ValueError("No tools found. You need to register tools.")
|
147
147
|
|
148
|
-
|
148
|
+
if tools is None:
|
149
|
+
tools = True
|
150
|
+
config = self.branch.tool_manager.parse_tool(tools=tools, **kwargs)
|
149
151
|
config["tool_parsed"] = True
|
150
152
|
config["tool_choice"] = tool_choice
|
151
153
|
return config
|
@@ -137,7 +137,9 @@ class MonoFollowup(MonoChat):
|
|
137
137
|
if not self.branch.tool_manager.has_tools:
|
138
138
|
raise ValueError("No tools found. You need to register tools.")
|
139
139
|
|
140
|
-
|
140
|
+
if tools is None:
|
141
|
+
tools = True
|
142
|
+
config = self.branch.tool_manager.parse_tool(tools=tools, **kwargs)
|
141
143
|
config["tool_parsed"] = True
|
142
144
|
config["tool_choice"] = tool_choice
|
143
145
|
return config
|
@@ -1,13 +1,12 @@
|
|
1
|
-
"""
|
1
|
+
"""base components in lionagi"""
|
2
2
|
|
3
3
|
from abc import ABC
|
4
4
|
from functools import singledispatchmethod
|
5
|
-
from typing import Any, TypeVar
|
6
|
-
|
5
|
+
from typing import Any, TypeVar, Type
|
7
6
|
from pydantic import AliasChoices, BaseModel, Field, ValidationError
|
8
7
|
from pandas import DataFrame, Series
|
9
8
|
|
10
|
-
from lionagi.libs import SysUtil,
|
9
|
+
from lionagi.libs import SysUtil, convert, ParseUtil, nested, func_call
|
11
10
|
|
12
11
|
|
13
12
|
T = TypeVar("T")
|
@@ -28,24 +27,38 @@ class BaseComponent(BaseModel, ABC):
|
|
28
27
|
validation_alias=AliasChoices("node_id", "ID", "id"),
|
29
28
|
description="A 32-char unique hash identifier for the node.",
|
30
29
|
)
|
31
|
-
|
32
30
|
timestamp: str = Field(
|
33
31
|
default_factory=lambda: SysUtil.get_timestamp(sep=None),
|
34
32
|
description="The timestamp of when the node was created.",
|
35
33
|
)
|
36
34
|
|
35
|
+
extra_fields: dict[str, Any] = Field(
|
36
|
+
default_factory=dict,
|
37
|
+
validation_alias=AliasChoices(
|
38
|
+
"extra", "additional_fields", "schema_extra", "extra_schema"
|
39
|
+
),
|
40
|
+
description="Additional fields for the component.",
|
41
|
+
)
|
42
|
+
|
37
43
|
class Config:
|
38
44
|
"""Model configuration settings."""
|
39
45
|
|
40
46
|
extra = "allow"
|
41
47
|
arbitrary_types_allowed = True
|
42
48
|
populate_by_name = True
|
43
|
-
|
44
|
-
|
45
|
-
|
49
|
+
|
50
|
+
@property
|
51
|
+
def class_name(self) -> str:
|
52
|
+
"""
|
53
|
+
Retrieve the name of the class.
|
54
|
+
|
55
|
+
Returns:
|
56
|
+
str: The name of the class.
|
57
|
+
"""
|
58
|
+
return self._class_name()
|
46
59
|
|
47
60
|
@classmethod
|
48
|
-
def
|
61
|
+
def _class_name(cls) -> str:
|
49
62
|
"""
|
50
63
|
Retrieve the name of the class.
|
51
64
|
|
@@ -54,6 +67,101 @@ class BaseComponent(BaseModel, ABC):
|
|
54
67
|
"""
|
55
68
|
return cls.__name__
|
56
69
|
|
70
|
+
def to_json_str(self, *args, **kwargs) -> str:
|
71
|
+
"""
|
72
|
+
Convert the component to a JSON string.
|
73
|
+
|
74
|
+
Returns:
|
75
|
+
str: The JSON string representation of the component.
|
76
|
+
"""
|
77
|
+
dict_ = self.to_dict(*args, **kwargs)
|
78
|
+
return convert.to_str(dict_)
|
79
|
+
|
80
|
+
def to_dict(self, *args, **kwargs) -> dict[str, Any]:
|
81
|
+
"""
|
82
|
+
Convert the component to a dictionary.
|
83
|
+
|
84
|
+
Returns:
|
85
|
+
dict[str, Any]: The dictionary representation of the component.
|
86
|
+
"""
|
87
|
+
dict_ = self.model_dump(*args, by_alias=True, **kwargs)
|
88
|
+
for field_name in list(self.extra_fields.keys()):
|
89
|
+
if field_name not in dict_:
|
90
|
+
dict_[field_name] = getattr(self, field_name, None)
|
91
|
+
dict_.pop("extra_fields", None)
|
92
|
+
return dict_
|
93
|
+
|
94
|
+
def to_xml(self, *args, **kwargs) -> str:
|
95
|
+
"""
|
96
|
+
Convert the component to an XML string.
|
97
|
+
|
98
|
+
Returns:
|
99
|
+
str: The XML string representation of the component.
|
100
|
+
"""
|
101
|
+
import xml.etree.ElementTree as ET
|
102
|
+
|
103
|
+
root = ET.Element(self.__class__.__name__)
|
104
|
+
|
105
|
+
def convert(dict_obj: dict, parent: ET.Element) -> None:
|
106
|
+
for key, val in dict_obj.items():
|
107
|
+
if isinstance(val, dict):
|
108
|
+
element = ET.SubElement(parent, key)
|
109
|
+
convert(val, element)
|
110
|
+
else:
|
111
|
+
element = ET.SubElement(parent, key)
|
112
|
+
element.text = str(val)
|
113
|
+
|
114
|
+
convert(self.to_dict(*args, **kwargs), root)
|
115
|
+
return ET.tostring(root, encoding="unicode")
|
116
|
+
|
117
|
+
def to_pd_series(self, *args, pd_kwargs: dict | None = None, **kwargs) -> Series:
|
118
|
+
"""
|
119
|
+
Convert the node to a Pandas Series.
|
120
|
+
|
121
|
+
Args:
|
122
|
+
pd_kwargs (dict | None): Additional keyword arguments for Pandas Series.
|
123
|
+
|
124
|
+
Returns:
|
125
|
+
Series: The Pandas Series representation of the node.
|
126
|
+
"""
|
127
|
+
pd_kwargs = {} if pd_kwargs is None else pd_kwargs
|
128
|
+
dict_ = self.to_dict(*args, **kwargs)
|
129
|
+
return Series(dict_, **pd_kwargs)
|
130
|
+
|
131
|
+
def _add_field(
|
132
|
+
self,
|
133
|
+
field_name: str,
|
134
|
+
annotation: Any | Type | None = Any,
|
135
|
+
default: Any | None = None,
|
136
|
+
value: Any | None = None,
|
137
|
+
field: Any = None,
|
138
|
+
**kwargs,
|
139
|
+
) -> None:
|
140
|
+
"""
|
141
|
+
Add a field to the model after initialization.
|
142
|
+
|
143
|
+
Args:
|
144
|
+
field_name (str): The name of the field.
|
145
|
+
annotation (Any | Type | None): The type annotation for the field.
|
146
|
+
default (Any | None): The default value for the field.
|
147
|
+
value (Any | None): The initial value for the field.
|
148
|
+
field (Any): The Field object for the field.
|
149
|
+
**kwargs: Additional keyword arguments for the Field object.
|
150
|
+
"""
|
151
|
+
field = field or Field(default=default, **kwargs)
|
152
|
+
self.extra_fields[field_name] = field
|
153
|
+
if annotation:
|
154
|
+
self.extra_fields[field_name].annotation = annotation
|
155
|
+
|
156
|
+
if not value and (a := self._get_field_attr(field_name, "default", None)):
|
157
|
+
value = a
|
158
|
+
|
159
|
+
self.__setattr__(field_name, value)
|
160
|
+
|
161
|
+
@property
|
162
|
+
def _all_fields(self):
|
163
|
+
return {**self.model_fields, **self.extra_fields}
|
164
|
+
|
57
165
|
@property
|
58
166
|
def _field_annotations(self) -> dict:
|
59
167
|
"""
|
@@ -62,21 +170,20 @@ class BaseComponent(BaseModel, ABC):
|
|
62
170
|
Returns:
|
63
171
|
dict: A dictionary mapping field names to their annotations.
|
64
172
|
"""
|
65
|
-
return self._get_field_annotation(list(self.model_fields.keys()))
|
66
173
|
|
67
|
-
|
174
|
+
return self._get_field_annotation(list(self._all_fields.keys()))
|
175
|
+
|
176
|
+
def _get_field_attr(self, k: str, attr: str, default: Any = False) -> Any:
|
68
177
|
"""
|
69
178
|
Get the value of a field attribute.
|
70
179
|
|
71
180
|
Args:
|
72
181
|
k (str): The field name.
|
73
182
|
attr (str): The attribute name.
|
74
|
-
default (Any): Default value to return if the attribute is not
|
75
|
-
found.
|
183
|
+
default (Any): Default value to return if the attribute is not found.
|
76
184
|
|
77
185
|
Returns:
|
78
|
-
Any: The value of the field attribute, or the default value if not
|
79
|
-
found.
|
186
|
+
Any: The value of the field attribute, or the default value if not found.
|
80
187
|
|
81
188
|
Raises:
|
82
189
|
ValueError: If the field does not have the specified attribute.
|
@@ -84,8 +191,9 @@ class BaseComponent(BaseModel, ABC):
|
|
84
191
|
try:
|
85
192
|
if not self._field_has_attr(k, attr):
|
86
193
|
raise ValueError(f"field {k} has no attribute {attr}")
|
87
|
-
|
88
|
-
|
194
|
+
|
195
|
+
field = self._all_fields[k]
|
196
|
+
a = getattr(field, attr, None)
|
89
197
|
if not a:
|
90
198
|
try:
|
91
199
|
a = field.json_schema_extra[attr]
|
@@ -99,7 +207,7 @@ class BaseComponent(BaseModel, ABC):
|
|
99
207
|
raise e
|
100
208
|
|
101
209
|
@singledispatchmethod
|
102
|
-
def _get_field_annotation(self, field_name:
|
210
|
+
def _get_field_annotation(self, field_name: Any) -> Any:
|
103
211
|
"""
|
104
212
|
Get the annotation for a field.
|
105
213
|
|
@@ -112,7 +220,7 @@ class BaseComponent(BaseModel, ABC):
|
|
112
220
|
raise TypeError(f"Unsupported type {type(field_name)}")
|
113
221
|
|
114
222
|
@_get_field_annotation.register(str)
|
115
|
-
def _(self, field_name) -> dict[str, Any]:
|
223
|
+
def _(self, field_name: str) -> dict[str, Any]:
|
116
224
|
"""
|
117
225
|
Get the annotation for a field as a dictionary.
|
118
226
|
|
@@ -120,10 +228,9 @@ class BaseComponent(BaseModel, ABC):
|
|
120
228
|
field_name (str): The name of the field.
|
121
229
|
|
122
230
|
Returns:
|
123
|
-
dict[str, Any]: A dictionary mapping the field name to its
|
124
|
-
annotation.
|
231
|
+
dict[str, Any]: A dictionary mapping the field name to its annotation.
|
125
232
|
"""
|
126
|
-
dict_ = {field_name: self.
|
233
|
+
dict_ = {field_name: self._all_fields[field_name].annotation}
|
127
234
|
for k, v in dict_.items():
|
128
235
|
if "|" in str(v):
|
129
236
|
v = str(v)
|
@@ -134,37 +241,20 @@ class BaseComponent(BaseModel, ABC):
|
|
134
241
|
return dict_
|
135
242
|
|
136
243
|
@_get_field_annotation.register(list)
|
137
|
-
def _(self, field_name) -> dict[str, Any]:
|
138
|
-
"""
|
139
|
-
Get the annotations for multiple fields as a dictionary.
|
140
|
-
|
141
|
-
Args:
|
142
|
-
field_name (list): A list or tuple of field names.
|
143
|
-
|
144
|
-
Returns:
|
145
|
-
dict[str, Any]: A dictionary mapping field names to their
|
146
|
-
annotations.
|
147
|
-
"""
|
148
|
-
dict_ = {}
|
149
|
-
for i in field_name:
|
150
|
-
dict_.update(self._get_field_annotation(i))
|
151
|
-
return dict_
|
152
|
-
|
153
244
|
@_get_field_annotation.register(tuple)
|
154
|
-
def _(self,
|
245
|
+
def _(self, field_names: list | tuple) -> dict[str, Any]:
|
155
246
|
"""
|
156
247
|
Get the annotations for multiple fields as a dictionary.
|
157
248
|
|
158
249
|
Args:
|
159
|
-
|
250
|
+
field_names (list | tuple): A list or tuple of field names.
|
160
251
|
|
161
252
|
Returns:
|
162
|
-
dict[str, Any]: A dictionary mapping field names to their
|
163
|
-
annotations.
|
253
|
+
dict[str, Any]: A dictionary mapping field names to their annotations.
|
164
254
|
"""
|
165
255
|
dict_ = {}
|
166
|
-
for
|
167
|
-
dict_.update(self._get_field_annotation(
|
256
|
+
for field_name in field_names:
|
257
|
+
dict_.update(self._get_field_annotation(field_name))
|
168
258
|
return dict_
|
169
259
|
|
170
260
|
def _field_has_attr(self, k: str, attr: str) -> bool:
|
@@ -178,7 +268,7 @@ class BaseComponent(BaseModel, ABC):
|
|
178
268
|
Returns:
|
179
269
|
bool: True if the field has the attribute, False otherwise.
|
180
270
|
"""
|
181
|
-
field = self.
|
271
|
+
field = self._all_fields.get(k, None)
|
182
272
|
if field is None:
|
183
273
|
raise ValueError(f"Field {k} not found in model fields.")
|
184
274
|
|
@@ -186,65 +276,16 @@ class BaseComponent(BaseModel, ABC):
|
|
186
276
|
if not a:
|
187
277
|
try:
|
188
278
|
a = (
|
189
|
-
self.
|
190
|
-
and attr in self.
|
279
|
+
self._all_fields[k].json_schema_extra[attr] is not None
|
280
|
+
and attr in self._all_fields[k].json_schema_extra
|
191
281
|
)
|
192
282
|
return a if isinstance(a, bool) else False
|
193
283
|
except Exception:
|
194
284
|
return False
|
195
285
|
return a
|
196
286
|
|
197
|
-
def
|
198
|
-
""
|
199
|
-
Convert the component to a JSON string.
|
200
|
-
|
201
|
-
Returns:
|
202
|
-
str: The JSON string representation of the component.
|
203
|
-
"""
|
204
|
-
return self.model_dump_json(*args, by_alias=True, **kwargs)
|
205
|
-
|
206
|
-
def to_dict(self, *args, **kwargs) -> dict[str, Any]:
|
207
|
-
"""
|
208
|
-
Convert the component to a dictionary.
|
209
|
-
|
210
|
-
Returns:
|
211
|
-
dict[str, Any]: The dictionary representation of the component.
|
212
|
-
"""
|
213
|
-
return self.model_dump(*args, by_alias=True, **kwargs)
|
214
|
-
|
215
|
-
def to_xml(self) -> str:
|
216
|
-
"""
|
217
|
-
Convert the component to an XML string.
|
218
|
-
|
219
|
-
Returns:
|
220
|
-
str: The XML string representation of the component.
|
221
|
-
"""
|
222
|
-
import xml.etree.ElementTree as ET
|
223
|
-
|
224
|
-
root = ET.Element(self.__class__.__name__)
|
225
|
-
|
226
|
-
def convert(dict_obj, parent):
|
227
|
-
for key, val in dict_obj.items():
|
228
|
-
if isinstance(val, dict):
|
229
|
-
element = ET.SubElement(parent, key)
|
230
|
-
convert(val, element)
|
231
|
-
else:
|
232
|
-
element = ET.SubElement(parent, key)
|
233
|
-
element.text = str(val)
|
234
|
-
|
235
|
-
convert(self.to_dict(), root)
|
236
|
-
return ET.tostring(root, encoding="unicode")
|
237
|
-
|
238
|
-
def to_pd_series(self, *args, pd_kwargs: dict | None = None, **kwargs) -> Series:
|
239
|
-
"""
|
240
|
-
Convert the node to a Pandas Series.
|
241
|
-
|
242
|
-
Returns:
|
243
|
-
Series: The Pandas Series representation of the node.
|
244
|
-
"""
|
245
|
-
pd_kwargs = {} if pd_kwargs is None else pd_kwargs
|
246
|
-
dict_ = self.to_dict(*args, **kwargs)
|
247
|
-
return Series(dict_, **pd_kwargs)
|
287
|
+
def __str__(self):
|
288
|
+
return f"{self.__class__.__name__}({self.to_json_str()})"
|
248
289
|
|
249
290
|
|
250
291
|
class BaseNode(BaseComponent):
|
@@ -264,7 +305,7 @@ class BaseNode(BaseComponent):
|
|
264
305
|
|
265
306
|
metadata: dict[str, Any] = Field(
|
266
307
|
default_factory=dict,
|
267
|
-
|
308
|
+
validation_alias="meta",
|
268
309
|
description="Additional metadata for the node.",
|
269
310
|
)
|
270
311
|
|
@@ -276,20 +317,36 @@ class BaseNode(BaseComponent):
|
|
276
317
|
|
277
318
|
Args:
|
278
319
|
obj (Any): The object to create the node from.
|
320
|
+
*args: Additional positional arguments.
|
321
|
+
**kwargs: Additional keyword arguments.
|
279
322
|
|
280
323
|
Raises:
|
281
324
|
NotImplementedError: If the object type is not supported.
|
282
325
|
"""
|
326
|
+
if not isinstance(obj, (dict, str, list, Series, DataFrame, BaseModel)):
|
327
|
+
type_ = str(type(obj))
|
328
|
+
if "llama_index" in type_:
|
329
|
+
return cls.from_obj(obj.to_dict())
|
330
|
+
elif "langchain" in type_:
|
331
|
+
langchain_json = obj.to_json()
|
332
|
+
langchain_dict = {
|
333
|
+
"lc_id": langchain_json["id"],
|
334
|
+
**langchain_json["kwargs"],
|
335
|
+
}
|
336
|
+
return cls.from_obj(langchain_dict)
|
337
|
+
|
283
338
|
raise NotImplementedError(f"Unsupported type: {type(obj)}")
|
284
339
|
|
285
340
|
@from_obj.register(dict)
|
286
341
|
@classmethod
|
287
|
-
def _from_dict(cls, obj, *args, **kwargs) -> T:
|
342
|
+
def _from_dict(cls, obj: dict, *args, **kwargs) -> T:
|
288
343
|
"""
|
289
344
|
Create a node instance from a dictionary.
|
290
345
|
|
291
346
|
Args:
|
292
347
|
obj (dict): The dictionary to create the node from.
|
348
|
+
*args: Additional positional arguments.
|
349
|
+
**kwargs: Additional keyword arguments.
|
293
350
|
|
294
351
|
Returns:
|
295
352
|
T: The created node instance.
|
@@ -298,13 +355,15 @@ class BaseNode(BaseComponent):
|
|
298
355
|
|
299
356
|
@from_obj.register(str)
|
300
357
|
@classmethod
|
301
|
-
def _from_str(cls, obj, *args, fuzzy_parse=False, **kwargs) -> T:
|
358
|
+
def _from_str(cls, obj: str, *args, fuzzy_parse: bool = False, **kwargs) -> T:
|
302
359
|
"""
|
303
360
|
Create a node instance from a JSON string.
|
304
361
|
|
305
362
|
Args:
|
306
363
|
obj (str): The JSON string to create the node from.
|
364
|
+
*args: Additional positional arguments.
|
307
365
|
fuzzy_parse (bool): Whether to perform fuzzy parsing.
|
366
|
+
**kwargs: Additional keyword arguments.
|
308
367
|
|
309
368
|
Returns:
|
310
369
|
T: The created node instance.
|
@@ -317,12 +376,14 @@ class BaseNode(BaseComponent):
|
|
317
376
|
|
318
377
|
@from_obj.register(list)
|
319
378
|
@classmethod
|
320
|
-
def _from_list(cls, obj, *args, **kwargs) -> list[T]:
|
379
|
+
def _from_list(cls, obj: list, *args, **kwargs) -> list[T]:
|
321
380
|
"""
|
322
381
|
Create a list of node instances from a list of objects.
|
323
382
|
|
324
383
|
Args:
|
325
384
|
obj (list): The list of objects to create nodes from.
|
385
|
+
*args: Additional positional arguments.
|
386
|
+
**kwargs: Additional keyword arguments.
|
326
387
|
|
327
388
|
Returns:
|
328
389
|
list[T]: The list of created node instances.
|
@@ -331,37 +392,51 @@ class BaseNode(BaseComponent):
|
|
331
392
|
|
332
393
|
@from_obj.register(Series)
|
333
394
|
@classmethod
|
334
|
-
def _from_pd_series(
|
395
|
+
def _from_pd_series(
|
396
|
+
cls, obj: Series, *args, pd_kwargs: dict | None = None, **kwargs
|
397
|
+
) -> T:
|
335
398
|
"""
|
336
399
|
Create a node instance from a Pandas Series.
|
337
400
|
|
338
401
|
Args:
|
339
402
|
obj (Series): The Pandas Series to create the node from.
|
403
|
+
*args: Additional positional arguments.
|
404
|
+
pd_kwargs (dict | None): Additional keyword arguments for Pandas Series.
|
405
|
+
**kwargs: Additional keyword arguments.
|
340
406
|
|
341
407
|
Returns:
|
342
408
|
T: The created node instance.
|
343
409
|
"""
|
344
|
-
|
345
|
-
pd_kwargs = {}
|
410
|
+
pd_kwargs = pd_kwargs or {}
|
346
411
|
return cls.from_obj(obj.to_dict(**pd_kwargs), *args, **kwargs)
|
347
412
|
|
348
413
|
@from_obj.register(DataFrame)
|
349
414
|
@classmethod
|
350
|
-
def _from_pd_dataframe(
|
415
|
+
def _from_pd_dataframe(
|
416
|
+
cls, obj: DataFrame, *args, pd_kwargs: dict | None = None, **kwargs
|
417
|
+
) -> list[T]:
|
351
418
|
"""
|
352
419
|
Create a list of node instances from a Pandas DataFrame.
|
353
420
|
|
354
421
|
Args:
|
355
422
|
obj (DataFrame): The Pandas DataFrame to create nodes from.
|
423
|
+
*args: Additional positional arguments.
|
424
|
+
pd_kwargs (dict | None): Additional keyword arguments for Pandas DataFrame.
|
425
|
+
**kwargs: Additional keyword arguments.
|
356
426
|
|
357
427
|
Returns:
|
358
428
|
list[T]: The list of created node instances.
|
359
429
|
"""
|
360
430
|
if pd_kwargs is None:
|
361
431
|
pd_kwargs = {}
|
362
|
-
|
363
|
-
|
364
|
-
|
432
|
+
|
433
|
+
_objs = []
|
434
|
+
for index, row in obj.iterrows():
|
435
|
+
_obj = cls.from_obj(row, *args, **pd_kwargs, **kwargs)
|
436
|
+
_obj.metadata["df_index"] = index
|
437
|
+
_objs.append(_obj)
|
438
|
+
|
439
|
+
return _objs
|
365
440
|
|
366
441
|
@from_obj.register(BaseModel)
|
367
442
|
@classmethod
|
@@ -375,27 +450,29 @@ class BaseNode(BaseComponent):
|
|
375
450
|
Returns:
|
376
451
|
T: The created node instance.
|
377
452
|
"""
|
378
|
-
|
379
|
-
pydantic_kwargs = {"by_alias": True}
|
380
|
-
|
381
|
-
config_ = {}
|
453
|
+
pydantic_kwargs = pydantic_kwargs or {"by_alias": True}
|
382
454
|
try:
|
383
|
-
config_ =
|
384
|
-
|
385
|
-
|
455
|
+
config_ = {}
|
456
|
+
try:
|
457
|
+
config_ = obj.model_dump(**pydantic_kwargs)
|
458
|
+
except:
|
459
|
+
config_ = obj.to_dict(**pydantic_kwargs)
|
460
|
+
else:
|
461
|
+
config_ = obj.dict(**pydantic_kwargs)
|
462
|
+
except Exception as e:
|
463
|
+
raise ValueError(f"Invalid Pydantic model for deserialization: {e}") from e
|
386
464
|
|
387
465
|
return cls.from_obj(config_ | kwargs)
|
388
466
|
|
389
467
|
def meta_get(
|
390
|
-
self, key: str, indices: list[str | int] = None, default: Any = None
|
468
|
+
self, key: str, indices: list[str | int] | None = None, default: Any = None
|
391
469
|
) -> Any:
|
392
470
|
"""
|
393
471
|
Get a value from the metadata dictionary.
|
394
472
|
|
395
473
|
Args:
|
396
474
|
key (str): The key to retrieve the value for.
|
397
|
-
indices (list[str | int]): Optional list of indices for nested
|
398
|
-
retrieval.
|
475
|
+
indices (list[str | int] | None): Optional list of indices for nested retrieval.
|
399
476
|
default (Any): The default value to return if the key is not found.
|
400
477
|
|
401
478
|
Returns:
|
@@ -452,4 +529,4 @@ class BaseNode(BaseComponent):
|
|
452
529
|
"""
|
453
530
|
self.metadata = nested.nmerge(
|
454
531
|
[self.metadata, additional_metadata], overwrite=overwrite, **kwargs
|
455
|
-
)
|
532
|
+
)
|
@@ -1,5 +1,6 @@
|
|
1
1
|
from abc import ABC, abstractmethod
|
2
2
|
from enum import Enum
|
3
|
+
from typing import Callable
|
3
4
|
from pydantic import BaseModel, Field
|
4
5
|
|
5
6
|
|
@@ -14,6 +15,7 @@ class ConditionSource(str, Enum):
|
|
14
15
|
|
15
16
|
STRUCTURE = "structure"
|
16
17
|
EXECUTABLE = "executable"
|
18
|
+
RULE = "rule"
|
17
19
|
|
18
20
|
|
19
21
|
class Condition(BaseModel, ABC):
|