lionagi 0.2.10__py3-none-any.whl → 0.3.0__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- lionagi/core/action/function_calling.py +13 -6
- lionagi/core/action/tool.py +10 -9
- lionagi/core/action/tool_manager.py +18 -9
- lionagi/core/agent/README.md +1 -1
- lionagi/core/agent/base_agent.py +5 -2
- lionagi/core/agent/eval/README.md +1 -1
- lionagi/core/collections/README.md +1 -1
- lionagi/core/collections/_logger.py +16 -6
- lionagi/core/collections/abc/README.md +1 -1
- lionagi/core/collections/abc/component.py +35 -11
- lionagi/core/collections/abc/concepts.py +5 -3
- lionagi/core/collections/abc/exceptions.py +3 -1
- lionagi/core/collections/flow.py +16 -5
- lionagi/core/collections/model.py +34 -8
- lionagi/core/collections/pile.py +65 -28
- lionagi/core/collections/progression.py +1 -2
- lionagi/core/collections/util.py +11 -2
- lionagi/core/director/README.md +1 -1
- lionagi/core/engine/branch_engine.py +35 -10
- lionagi/core/engine/instruction_map_engine.py +14 -5
- lionagi/core/engine/sandbox_.py +3 -1
- lionagi/core/engine/script_engine.py +6 -2
- lionagi/core/executor/base_executor.py +10 -3
- lionagi/core/executor/graph_executor.py +12 -4
- lionagi/core/executor/neo4j_executor.py +18 -6
- lionagi/core/generic/edge.py +7 -2
- lionagi/core/generic/graph.py +23 -7
- lionagi/core/generic/node.py +14 -5
- lionagi/core/generic/tree_node.py +5 -1
- lionagi/core/mail/mail_manager.py +3 -1
- lionagi/core/mail/package.py +3 -1
- lionagi/core/message/action_request.py +9 -2
- lionagi/core/message/action_response.py +9 -3
- lionagi/core/message/instruction.py +8 -2
- lionagi/core/message/util.py +15 -5
- lionagi/core/report/base.py +12 -7
- lionagi/core/report/form.py +7 -4
- lionagi/core/report/report.py +10 -3
- lionagi/core/report/util.py +3 -1
- lionagi/core/rule/action.py +4 -1
- lionagi/core/rule/base.py +17 -6
- lionagi/core/rule/rulebook.py +8 -4
- lionagi/core/rule/string.py +3 -1
- lionagi/core/session/branch.py +15 -4
- lionagi/core/session/session.py +6 -2
- lionagi/core/unit/parallel_unit.py +9 -3
- lionagi/core/unit/template/action.py +1 -1
- lionagi/core/unit/template/predict.py +3 -1
- lionagi/core/unit/template/select.py +5 -3
- lionagi/core/unit/unit.py +50 -2
- lionagi/core/unit/unit_form.py +13 -15
- lionagi/core/unit/unit_mixin.py +45 -27
- lionagi/core/unit/util.py +7 -3
- lionagi/core/validator/validator.py +28 -15
- lionagi/core/work/work_edge.py +7 -3
- lionagi/core/work/work_task.py +11 -5
- lionagi/core/work/worker.py +20 -5
- lionagi/core/work/worker_engine.py +6 -2
- lionagi/core/work/worklog.py +3 -1
- lionagi/experimental/compressor/llm_compressor.py +20 -5
- lionagi/experimental/directive/README.md +1 -1
- lionagi/experimental/directive/parser/base_parser.py +41 -14
- lionagi/experimental/directive/parser/base_syntax.txt +23 -23
- lionagi/experimental/directive/template/base_template.py +14 -6
- lionagi/experimental/directive/tokenizer.py +3 -1
- lionagi/experimental/evaluator/README.md +1 -1
- lionagi/experimental/evaluator/ast_evaluator.py +6 -2
- lionagi/experimental/evaluator/base_evaluator.py +27 -16
- lionagi/integrations/bridge/autogen_/autogen_.py +7 -3
- lionagi/integrations/bridge/langchain_/documents.py +13 -10
- lionagi/integrations/bridge/llamaindex_/llama_pack.py +36 -12
- lionagi/integrations/bridge/llamaindex_/node_parser.py +8 -3
- lionagi/integrations/bridge/llamaindex_/reader.py +3 -1
- lionagi/integrations/bridge/llamaindex_/textnode.py +9 -3
- lionagi/integrations/bridge/pydantic_/pydantic_bridge.py +7 -1
- lionagi/integrations/bridge/transformers_/install_.py +3 -1
- lionagi/integrations/chunker/chunk.py +5 -2
- lionagi/integrations/loader/load.py +7 -3
- lionagi/integrations/loader/load_util.py +35 -16
- lionagi/integrations/provider/oai.py +13 -4
- lionagi/integrations/provider/openrouter.py +13 -4
- lionagi/integrations/provider/services.py +3 -1
- lionagi/integrations/provider/transformers.py +5 -3
- lionagi/integrations/storage/neo4j.py +23 -7
- lionagi/integrations/storage/storage_util.py +23 -7
- lionagi/integrations/storage/structure_excel.py +7 -2
- lionagi/integrations/storage/to_csv.py +8 -2
- lionagi/integrations/storage/to_excel.py +11 -3
- lionagi/libs/ln_api.py +41 -19
- lionagi/libs/ln_context.py +4 -4
- lionagi/libs/ln_convert.py +35 -14
- lionagi/libs/ln_dataframe.py +9 -3
- lionagi/libs/ln_func_call.py +53 -18
- lionagi/libs/ln_image.py +9 -5
- lionagi/libs/ln_knowledge_graph.py +21 -7
- lionagi/libs/ln_nested.py +57 -16
- lionagi/libs/ln_parse.py +45 -15
- lionagi/libs/ln_queue.py +8 -3
- lionagi/libs/ln_tokenize.py +19 -6
- lionagi/libs/ln_validate.py +14 -3
- lionagi/libs/sys_util.py +44 -12
- lionagi/lions/coder/coder.py +24 -8
- lionagi/lions/coder/util.py +6 -2
- lionagi/lions/researcher/data_source/google_.py +12 -4
- lionagi/lions/researcher/data_source/wiki_.py +3 -1
- lionagi/version.py +1 -1
- {lionagi-0.2.10.dist-info → lionagi-0.3.0.dist-info}/METADATA +6 -7
- lionagi-0.3.0.dist-info/RECORD +226 -0
- lionagi/tests/__init__.py +0 -0
- lionagi/tests/api/__init__.py +0 -0
- lionagi/tests/api/aws/__init__.py +0 -0
- lionagi/tests/api/aws/conftest.py +0 -25
- lionagi/tests/api/aws/test_aws_s3.py +0 -6
- lionagi/tests/integrations/__init__.py +0 -0
- lionagi/tests/libs/__init__.py +0 -0
- lionagi/tests/libs/test_api.py +0 -48
- lionagi/tests/libs/test_convert.py +0 -89
- lionagi/tests/libs/test_field_validators.py +0 -354
- lionagi/tests/libs/test_func_call.py +0 -701
- lionagi/tests/libs/test_nested.py +0 -382
- lionagi/tests/libs/test_parse.py +0 -171
- lionagi/tests/libs/test_queue.py +0 -68
- lionagi/tests/libs/test_sys_util.py +0 -222
- lionagi/tests/test_core/__init__.py +0 -0
- lionagi/tests/test_core/collections/__init__.py +0 -0
- lionagi/tests/test_core/collections/test_component.py +0 -208
- lionagi/tests/test_core/collections/test_exchange.py +0 -139
- lionagi/tests/test_core/collections/test_flow.py +0 -146
- lionagi/tests/test_core/collections/test_pile.py +0 -172
- lionagi/tests/test_core/collections/test_progression.py +0 -130
- lionagi/tests/test_core/generic/__init__.py +0 -0
- lionagi/tests/test_core/generic/test_edge.py +0 -69
- lionagi/tests/test_core/generic/test_graph.py +0 -97
- lionagi/tests/test_core/generic/test_node.py +0 -107
- lionagi/tests/test_core/generic/test_structure.py +0 -194
- lionagi/tests/test_core/generic/test_tree_node.py +0 -74
- lionagi/tests/test_core/graph/__init__.py +0 -0
- lionagi/tests/test_core/graph/test_graph.py +0 -71
- lionagi/tests/test_core/graph/test_tree.py +0 -76
- lionagi/tests/test_core/mail/__init__.py +0 -0
- lionagi/tests/test_core/mail/test_mail.py +0 -98
- lionagi/tests/test_core/test_branch.py +0 -116
- lionagi/tests/test_core/test_form.py +0 -47
- lionagi/tests/test_core/test_report.py +0 -106
- lionagi/tests/test_core/test_structure/__init__.py +0 -0
- lionagi/tests/test_core/test_structure/test_base_structure.py +0 -198
- lionagi/tests/test_core/test_structure/test_graph.py +0 -55
- lionagi/tests/test_core/test_structure/test_tree.py +0 -49
- lionagi/tests/test_core/test_validator.py +0 -112
- lionagi-0.2.10.dist-info/RECORD +0 -267
- {lionagi-0.2.10.dist-info → lionagi-0.3.0.dist-info}/LICENSE +0 -0
- {lionagi-0.2.10.dist-info → lionagi-0.3.0.dist-info}/WHEEL +0 -0
@@ -1,382 +0,0 @@
|
|
1
|
-
import unittest
|
2
|
-
|
3
|
-
from lionagi.libs.ln_nested import *
|
4
|
-
|
5
|
-
|
6
|
-
class TestNSet(unittest.TestCase):
|
7
|
-
def test_nset_on_dict(self):
|
8
|
-
"""Test setting a value in a nested dictionary."""
|
9
|
-
data = {"a": {"b": [10, 20]}}
|
10
|
-
nset(data, ["a", "b", 1], 99)
|
11
|
-
self.assertEqual(data, {"a": {"b": [10, 99]}})
|
12
|
-
|
13
|
-
def test_nset_on_list(self):
|
14
|
-
"""Test setting a value in a nested list."""
|
15
|
-
data = [0, [1, 2], 3]
|
16
|
-
nset(data, [1, 1], 99)
|
17
|
-
self.assertEqual(data, [0, [1, 99], 3])
|
18
|
-
|
19
|
-
def test_nset_with_empty_indices(self):
|
20
|
-
"""Test nset with an empty indices list."""
|
21
|
-
with self.assertRaises(ValueError):
|
22
|
-
nset({}, [], 1)
|
23
|
-
|
24
|
-
def test_nget_with_valid_path(self):
|
25
|
-
"""Test retrieving a value from a nested structure."""
|
26
|
-
data = {"a": {"b": [10, 20, 30]}}
|
27
|
-
self.assertEqual(nget(data, ["a", "b", 2]), 30)
|
28
|
-
|
29
|
-
def test_nget_with_default(self):
|
30
|
-
"""Test nget returning a default value when the path doesn't exist."""
|
31
|
-
data = {"a": 1}
|
32
|
-
self.assertEqual(nget(data, ["b"], default=99), 99)
|
33
|
-
|
34
|
-
def test_nget_raises_lookup_error(self):
|
35
|
-
"""Test nget raises LookupError when no default is provided and the path doesn't exist."""
|
36
|
-
with self.assertRaises(LookupError):
|
37
|
-
nget({"a": 1}, ["b"])
|
38
|
-
|
39
|
-
def test_flatten_and_unflatten_dict(self):
|
40
|
-
"""Test flattening and then unflattening a nested dictionary."""
|
41
|
-
original = {"a": {"b": {"c": 1}}}
|
42
|
-
flattened = flatten(original)
|
43
|
-
self.assertEqual(flattened, {"a[^_^]b[^_^]c": 1})
|
44
|
-
unflattened = unflatten(flattened)
|
45
|
-
self.assertEqual(original, unflattened)
|
46
|
-
|
47
|
-
def test_nfilter_dict(self):
|
48
|
-
"""Test filtering items in a dictionary."""
|
49
|
-
data = {"a": 1, "b": 2, "c": 3}
|
50
|
-
filtered = nfilter(data, lambda x: x[1] > 1)
|
51
|
-
self.assertEqual(filtered, {"b": 2, "c": 3})
|
52
|
-
|
53
|
-
def test_nfilter_list(self):
|
54
|
-
"""Test filtering items in a list."""
|
55
|
-
data = [1, 2, 3, 4]
|
56
|
-
filtered = nfilter(data, lambda x: x % 2 == 0)
|
57
|
-
self.assertEqual(filtered, [2, 4])
|
58
|
-
|
59
|
-
def test_ninsert_into_nested_dict(self):
|
60
|
-
"""Test inserting a value into a nested dictionary."""
|
61
|
-
data = {"a": {"b": [1, 2]}}
|
62
|
-
ninsert(data, ["a", "b", 2], 3)
|
63
|
-
self.assertEqual(data, {"a": {"b": [1, 2, 3]}})
|
64
|
-
|
65
|
-
def test_ninsert_into_nested_list(self):
|
66
|
-
"""Test inserting a value into a nested list."""
|
67
|
-
data = []
|
68
|
-
ninsert(data, [0, "a"], 1)
|
69
|
-
self.assertEqual(data, [{"a": 1}])
|
70
|
-
|
71
|
-
|
72
|
-
class TestNFilter(unittest.TestCase):
|
73
|
-
|
74
|
-
def test_filter_dictionary_with_condition(self):
|
75
|
-
test_dict = {"a": 1, "b": 2, "c": 3}
|
76
|
-
result = nfilter(test_dict, lambda item: item[1] > 1)
|
77
|
-
self.assertEqual(result, {"b": 2, "c": 3})
|
78
|
-
|
79
|
-
def test_filter_list_with_condition(self):
|
80
|
-
test_list = [1, 2, 3, 4]
|
81
|
-
result = nfilter(test_list, lambda x: x % 2 == 0)
|
82
|
-
self.assertEqual(result, [2, 4])
|
83
|
-
|
84
|
-
def test_filter_empty_dictionary(self):
|
85
|
-
self.assertEqual(nfilter({}, lambda item: item[1] > 1), {})
|
86
|
-
|
87
|
-
def test_filter_empty_list(self):
|
88
|
-
self.assertEqual(nfilter([], lambda x: x % 2 == 0), [])
|
89
|
-
|
90
|
-
def test_filter_all_items_fail_condition(self):
|
91
|
-
test_dict = {"a": 1, "b": 2, "c": 3}
|
92
|
-
self.assertEqual(nfilter(test_dict, lambda item: item[1] > 5), {})
|
93
|
-
|
94
|
-
def test_filter_all_items_pass_condition(self):
|
95
|
-
test_list = [1, 2, 3, 4]
|
96
|
-
self.assertEqual(nfilter(test_list, lambda x: x > 0), test_list)
|
97
|
-
|
98
|
-
def test_filter_nested_collections(self):
|
99
|
-
nested_dict = {"a": [1, 2, 3], "b": [4, 5]}
|
100
|
-
result = nfilter(nested_dict, lambda item: len(item[1]) > 2)
|
101
|
-
self.assertEqual(result, {"a": [1, 2, 3]})
|
102
|
-
|
103
|
-
def test_filter_invalid_collection_type(self):
|
104
|
-
with self.assertRaises(TypeError):
|
105
|
-
nfilter("not a dict or list", lambda x: x)
|
106
|
-
|
107
|
-
def test_filter_with_complex_conditions(self):
|
108
|
-
test_dict = {"a": 1, "b": 2, "c": 3, "d": 4}
|
109
|
-
# Condition: key is not 'a' and value is an even number
|
110
|
-
result = nfilter(test_dict, lambda item: item[0] != "a" and item[1] % 2 == 0)
|
111
|
-
self.assertEqual(result, {"b": 2, "d": 4})
|
112
|
-
|
113
|
-
|
114
|
-
class TestNSet(unittest.TestCase):
|
115
|
-
|
116
|
-
def test_set_value_in_nested_dict(self):
|
117
|
-
nested_dict = {"a": {"b": 1}}
|
118
|
-
nset(nested_dict, ["a", "b"], 2)
|
119
|
-
self.assertEqual(nested_dict["a"]["b"], 2)
|
120
|
-
|
121
|
-
def test_set_value_in_nested_list(self):
|
122
|
-
nested_list = [[1, 2], [3, 4]]
|
123
|
-
nset(nested_list, [1, 0], 5)
|
124
|
-
self.assertEqual(nested_list[1][0], 5)
|
125
|
-
|
126
|
-
def test_set_with_empty_indices_list(self):
|
127
|
-
with self.assertRaises(ValueError):
|
128
|
-
nset({}, [], 1)
|
129
|
-
|
130
|
-
def test_set_in_non_list_dict(self):
|
131
|
-
with self.assertRaises(TypeError):
|
132
|
-
nset(1, [0], "value")
|
133
|
-
|
134
|
-
def test_set_with_index_out_of_bounds(self):
|
135
|
-
test_list = [1, 2, 3]
|
136
|
-
nset(test_list, [5], 4)
|
137
|
-
self.assertEqual(test_list[5], 4)
|
138
|
-
|
139
|
-
def test_set_with_non_existent_dict_key(self):
|
140
|
-
test_dict = {"a": 1}
|
141
|
-
nset(test_dict, ["b"], 2)
|
142
|
-
self.assertEqual(test_dict["b"], 2)
|
143
|
-
|
144
|
-
def test_set_with_mixed_indices_types(self):
|
145
|
-
nested_structure = {"a": [1, {"b": 2}]}
|
146
|
-
nset(nested_structure, ["a", 1, "b"], 3)
|
147
|
-
self.assertEqual(nested_structure["a"][1]["b"], 3)
|
148
|
-
|
149
|
-
|
150
|
-
class TestNGet(unittest.TestCase):
|
151
|
-
|
152
|
-
def test_get_value_from_nested_dict(self):
|
153
|
-
nested_dict = {"a": {"b": 1}}
|
154
|
-
result = nget(nested_dict, ["a", "b"])
|
155
|
-
self.assertEqual(result, 1)
|
156
|
-
|
157
|
-
def test_get_value_from_nested_list(self):
|
158
|
-
nested_list = [[1, 2], [3, 4]]
|
159
|
-
result = nget(nested_list, [1, 0])
|
160
|
-
self.assertEqual(result, 3)
|
161
|
-
|
162
|
-
# def test_get_with_non_existent_key_index(self):
|
163
|
-
# nested_dict = {'a': 1}
|
164
|
-
# result = nget(nested_dict, ['b'])
|
165
|
-
# self.assertIsNone(result)
|
166
|
-
|
167
|
-
# nested_list = [1, 2, 3]
|
168
|
-
# result = nget(nested_list, [5])
|
169
|
-
# self.assertIsNone(result)
|
170
|
-
|
171
|
-
def test_get_with_mixed_indices(self):
|
172
|
-
nested_structure = {"a": [1, {"b": 2}]}
|
173
|
-
result = nget(nested_structure, ["a", 1, "b"])
|
174
|
-
self.assertEqual(result, 2)
|
175
|
-
|
176
|
-
# def test_get_with_invalid_structure_type(self): # result = nget(1, [0]) # Attempting to retrieve from an integer, not a list/dict # self.assertIsNone(result)
|
177
|
-
|
178
|
-
# def test_get_with_index_out_of_bounds(self): # test_list = [1, 2, 3] # result = nget(test_list, [5]) # self.assertIsNone(result)
|
179
|
-
|
180
|
-
|
181
|
-
class TestNMerge(unittest.TestCase):
|
182
|
-
|
183
|
-
def test_merge_list_of_dictionaries(self):
|
184
|
-
dict_list = [{"a": 1}, {"b": 2}]
|
185
|
-
result = nmerge(dict_list)
|
186
|
-
self.assertEqual(result, {"a": 1, "b": 2})
|
187
|
-
|
188
|
-
def test_merge_list_of_lists(self):
|
189
|
-
list_of_lists = [[1, 2], [3, 4]]
|
190
|
-
result = nmerge(list_of_lists)
|
191
|
-
self.assertEqual(result, [1, 2, 3, 4])
|
192
|
-
|
193
|
-
def test_merge_empty_list(self):
|
194
|
-
self.assertEqual(nmerge([]), {})
|
195
|
-
|
196
|
-
def test_dict_update_option(self):
|
197
|
-
dict_list = [{"a": 1}, {"a": 2, "b": 3}]
|
198
|
-
result = nmerge(dict_list, overwrite=True)
|
199
|
-
self.assertEqual(result, {"a": 2, "b": 3})
|
200
|
-
|
201
|
-
def test_dict_sequence_option(self):
|
202
|
-
dict_list = [{"a": 1}, {"a": 2}]
|
203
|
-
result = nmerge(dict_list, dict_sequence=True, sequence_separator="_")
|
204
|
-
self.assertIn("a", result)
|
205
|
-
self.assertIn("a_1", result)
|
206
|
-
|
207
|
-
def test_sort_list_option(self):
|
208
|
-
list_of_lists = [[3, 1], [4, 2]]
|
209
|
-
result = nmerge(list_of_lists, sort_list=True)
|
210
|
-
self.assertEqual(result, [1, 2, 3, 4])
|
211
|
-
|
212
|
-
def test_custom_sort_function(self):
|
213
|
-
list_of_lists = [["b", "a"], ["d", "c"]]
|
214
|
-
custom_sort_func = lambda x: x
|
215
|
-
result = nmerge(list_of_lists, sort_list=True, custom_sort=custom_sort_func)
|
216
|
-
self.assertEqual(result, ["a", "b", "c", "d"])
|
217
|
-
|
218
|
-
def test_inhomogeneous_type_error(self):
|
219
|
-
mixed_list = [{"a": 1}, [1, 2]]
|
220
|
-
with self.assertRaises(TypeError):
|
221
|
-
nmerge(mixed_list)
|
222
|
-
|
223
|
-
|
224
|
-
class TestFlatten(unittest.TestCase):
|
225
|
-
|
226
|
-
def test_flatten_nested_dict(self):
|
227
|
-
nested_dict = {"a": {"b": 1, "c": {"d": 2}}}
|
228
|
-
result = flatten(nested_dict)
|
229
|
-
self.assertEqual(result, {"a[^_^]b": 1, "a[^_^]c[^_^]d": 2})
|
230
|
-
|
231
|
-
def test_flatten_nested_list(self):
|
232
|
-
nested_list = [[1, 2], [3, [4, 5]]]
|
233
|
-
result = flatten(nested_list)
|
234
|
-
self.assertEqual(
|
235
|
-
result,
|
236
|
-
{
|
237
|
-
"0[^_^]0": 1,
|
238
|
-
"0[^_^]1": 2,
|
239
|
-
"1[^_^]0": 3,
|
240
|
-
"1[^_^]1[^_^]0": 4,
|
241
|
-
"1[^_^]1[^_^]1": 5,
|
242
|
-
},
|
243
|
-
)
|
244
|
-
|
245
|
-
def test_flatten_with_max_depth(self):
|
246
|
-
nested_dict = {"a": {"b": {"c": 1}}}
|
247
|
-
result = flatten(nested_dict, max_depth=1)
|
248
|
-
self.assertEqual(result, {"a[^_^]b": {"c": 1}})
|
249
|
-
|
250
|
-
def test_flatten_dict_only(self):
|
251
|
-
nested_mix = {"a": [1, 2], "b": {"c": 3}}
|
252
|
-
result = flatten(nested_mix, dict_only=True)
|
253
|
-
self.assertEqual(result, {"a": [1, 2], "b[^_^]c": 3})
|
254
|
-
|
255
|
-
def test_flatten_inplace(self):
|
256
|
-
nested_dict = {"a": {"b": 1}}
|
257
|
-
flatten(nested_dict, inplace=True)
|
258
|
-
self.assertEqual(nested_dict, {"a[^_^]b": 1})
|
259
|
-
|
260
|
-
def test_flatten_empty_structure(self):
|
261
|
-
self.assertEqual(flatten({}), {})
|
262
|
-
self.assertEqual(flatten([]), {})
|
263
|
-
|
264
|
-
def test_flatten_deeply_nested_structure(self):
|
265
|
-
deeply_nested = {"a": {"b": {"c": {"d": 1}}}}
|
266
|
-
result = flatten(deeply_nested)
|
267
|
-
self.assertEqual(result, {"a[^_^]b[^_^]c[^_^]d": 1})
|
268
|
-
|
269
|
-
|
270
|
-
class TestUnflatten(unittest.TestCase):
|
271
|
-
|
272
|
-
def test_unflatten_to_nested_dict(self):
|
273
|
-
flat_dict = {"a[^_^]b": 1, "a[^_^]c[^_^]d": 2}
|
274
|
-
result = unflatten(flat_dict)
|
275
|
-
self.assertEqual(result, {"a": {"b": 1, "c": {"d": 2}}})
|
276
|
-
|
277
|
-
def test_unflatten_to_nested_list(self):
|
278
|
-
flat_dict = {"0[^_^]0": 1, "0[^_^]1": 2, "1": [3, 4]}
|
279
|
-
result = unflatten(flat_dict)
|
280
|
-
self.assertEqual(result, [[1, 2], [3, 4]])
|
281
|
-
|
282
|
-
def test_unflatten_with_custom_separator(self):
|
283
|
-
flat_dict = {"a-b": 1, "a-c-d": 2}
|
284
|
-
result = unflatten(flat_dict, sep="-")
|
285
|
-
self.assertEqual(result, {"a": {"b": 1, "c": {"d": 2}}})
|
286
|
-
|
287
|
-
def test_unflatten_with_custom_logic(self):
|
288
|
-
flat_dict = {"a[^_^]1": "one", "a[^_^]2": "two"}
|
289
|
-
custom_logic = lambda key: int(key) if key.isdigit() else key
|
290
|
-
result = unflatten(flat_dict, custom_logic=custom_logic)
|
291
|
-
self.assertEqual(result, {"a": [None, "one", "two"]})
|
292
|
-
|
293
|
-
def test_unflatten_with_max_depth(self):
|
294
|
-
flat_dict = {"a[^_^]b[^_^]c": 1, "a[^_^]b[^_^]d": 2}
|
295
|
-
result = unflatten(flat_dict, max_depth=1)
|
296
|
-
self.assertEqual(result, {"a": {"b[^_^]c": 1, "b[^_^]d": 2}})
|
297
|
-
|
298
|
-
def test_unflatten_with_max_depth_int(self):
|
299
|
-
flat_dict = {"0[^_^]0[^_^]0": 1, "0[^_^]1[^_^]0": 2}
|
300
|
-
result = unflatten(flat_dict, max_depth=1)
|
301
|
-
self.assertEqual(result, [[{"0[^_^]0": 1}, {"1[^_^]0": 2}]])
|
302
|
-
|
303
|
-
def test_unflatten_empty_flat_dict(self):
|
304
|
-
self.assertEqual(unflatten({}), [])
|
305
|
-
|
306
|
-
def test_unflatten_to_mixed_structure(self):
|
307
|
-
flat_dict = {"0[^_^]0": 1, "1[^_^]key": 2}
|
308
|
-
result = unflatten(flat_dict)
|
309
|
-
self.assertEqual(result, [[1], {"key": 2}])
|
310
|
-
|
311
|
-
|
312
|
-
class TestNInsert(unittest.TestCase):
|
313
|
-
|
314
|
-
def test_insert_into_nested_dict(self):
|
315
|
-
obj = {}
|
316
|
-
ninsert(obj, ["a", "b"], 1)
|
317
|
-
self.assertEqual(obj, {"a": {"b": 1}})
|
318
|
-
|
319
|
-
def test_insert_into_nested_list(self):
|
320
|
-
obj = []
|
321
|
-
ninsert(obj, [0, 1], "value")
|
322
|
-
self.assertEqual(obj, [[None, "value"]])
|
323
|
-
|
324
|
-
def test_insert_with_mixed_paths(self):
|
325
|
-
obj = {"a": [{}]}
|
326
|
-
ninsert(obj, ["a", 0, "b"], 2)
|
327
|
-
self.assertEqual(obj, {"a": [{"b": 2}]})
|
328
|
-
|
329
|
-
def test_insert_with_max_depth(self):
|
330
|
-
obj = {}
|
331
|
-
ninsert(obj, ["a", "b", "c"], "value", max_depth=1)
|
332
|
-
self.assertEqual(obj, {"a": {"b[^_^]c": "value"}})
|
333
|
-
|
334
|
-
def test_insert_into_empty_structure(self):
|
335
|
-
obj = {}
|
336
|
-
ninsert(obj, ["a"], 1)
|
337
|
-
self.assertEqual(obj, {"a": 1})
|
338
|
-
|
339
|
-
|
340
|
-
class TestGetFlattenedKeys(unittest.TestCase):
|
341
|
-
|
342
|
-
def test_get_keys_from_nested_dict(self):
|
343
|
-
nested_dict = {"a": {"b": 1, "c": {"d": 2}}}
|
344
|
-
expected_keys = ["a[^_^]b", "a[^_^]c[^_^]d"]
|
345
|
-
self.assertEqual(set(get_flattened_keys(nested_dict)), set(expected_keys))
|
346
|
-
|
347
|
-
def test_get_keys_from_nested_list(self):
|
348
|
-
nested_list = [[1, 2], [3, [4, 5]]]
|
349
|
-
expected_keys = [
|
350
|
-
"0[^_^]0",
|
351
|
-
"0[^_^]1",
|
352
|
-
"1[^_^]0",
|
353
|
-
"1[^_^]1[^_^]0",
|
354
|
-
"1[^_^]1[^_^]1",
|
355
|
-
]
|
356
|
-
self.assertEqual(set(get_flattened_keys(nested_list)), set(expected_keys))
|
357
|
-
|
358
|
-
def test_get_keys_with_max_depth(self):
|
359
|
-
nested_dict = {"a": {"b": {"c": 1}}}
|
360
|
-
expected_keys = ["a[^_^]b"]
|
361
|
-
self.assertEqual(
|
362
|
-
set(get_flattened_keys(nested_dict, max_depth=1)), set(expected_keys)
|
363
|
-
)
|
364
|
-
|
365
|
-
def test_get_keys_dict_only(self):
|
366
|
-
nested_mix = {"a": [1, 2], "b": {"c": 3}}
|
367
|
-
expected_keys = ["a", "b[^_^]c"]
|
368
|
-
self.assertEqual(
|
369
|
-
set(get_flattened_keys(nested_mix, dict_only=True)), set(expected_keys)
|
370
|
-
)
|
371
|
-
|
372
|
-
def test_get_keys_from_empty_structure(self):
|
373
|
-
self.assertEqual(get_flattened_keys({}), [])
|
374
|
-
|
375
|
-
def test_keys_from_deeply_nested_structure(self):
|
376
|
-
deeply_nested = {"a": {"b": {"c": {"d": 1}}}}
|
377
|
-
expected_keys = ["a[^_^]b[^_^]c[^_^]d"]
|
378
|
-
self.assertEqual(set(get_flattened_keys(deeply_nested)), set(expected_keys))
|
379
|
-
|
380
|
-
|
381
|
-
if __name__ == "__main__":
|
382
|
-
unittest.main()
|
lionagi/tests/libs/test_parse.py
DELETED
@@ -1,171 +0,0 @@
|
|
1
|
-
import unittest
|
2
|
-
from unittest.mock import patch
|
3
|
-
|
4
|
-
from lionagi.libs.ln_parse import *
|
5
|
-
|
6
|
-
|
7
|
-
class TestFuzzyParseJson(unittest.TestCase):
|
8
|
-
|
9
|
-
def test_basic_json_parsing(self):
|
10
|
-
"""Test parsing of correctly formatted JSON strings."""
|
11
|
-
json_str = '{"name": "John", "age": 30}'
|
12
|
-
expected = {"name": "John", "age": 30}
|
13
|
-
self.assertEqual(ParseUtil.fuzzy_parse_json(json_str), expected)
|
14
|
-
|
15
|
-
def test_missing_closing_brackets(self):
|
16
|
-
"""Test JSON strings missing various closing brackets."""
|
17
|
-
test_cases = [
|
18
|
-
('{"name": "John", "age": 30', {"name": "John", "age": 30}),
|
19
|
-
('[{"name": "John", "age": 30}', [{"name": "John", "age": 30}]),
|
20
|
-
('{"people": [{"name": "John"', {"people": [{"name": "John"}]}),
|
21
|
-
]
|
22
|
-
for json_str, expected in test_cases:
|
23
|
-
with self.subTest(json_str=json_str):
|
24
|
-
self.assertEqual(ParseUtil.fuzzy_parse_json(json_str), expected)
|
25
|
-
|
26
|
-
def test_nested_structures(self):
|
27
|
-
"""Test with nested JSON objects and arrays."""
|
28
|
-
json_str = '{"data": [{"id": 1, "value": "A"}, {"id": 2, "value": "B"'
|
29
|
-
expected = {"data": [{"id": 1, "value": "A"}, {"id": 2, "value": "B"}]}
|
30
|
-
self.assertEqual(ParseUtil.fuzzy_parse_json(json_str), expected)
|
31
|
-
|
32
|
-
def test_strict_mode(self):
|
33
|
-
"""Test the function's behavior in strict mode."""
|
34
|
-
correct_json_str = '{"name": "John", "age": 30}'
|
35
|
-
malformed_json_str = '{"name": "John", "age": 30'
|
36
|
-
# Should work fine with correct JSON
|
37
|
-
self.assertEqual(
|
38
|
-
ParseUtil.fuzzy_parse_json(correct_json_str, strict=True),
|
39
|
-
{"name": "John", "age": 30},
|
40
|
-
)
|
41
|
-
|
42
|
-
def test_error_handling(self):
|
43
|
-
"""Test with irreparably malformed JSON."""
|
44
|
-
json_str = '{"name": "John", "age": 30 something wrong}'
|
45
|
-
with self.assertRaises(ValueError):
|
46
|
-
ParseUtil.fuzzy_parse_json(json_str)
|
47
|
-
|
48
|
-
def test_escape_chars_in_json(self):
|
49
|
-
"""Test escaping special characters in JSON strings."""
|
50
|
-
self.assertEqual(
|
51
|
-
ParseUtil.escape_chars_in_json("Line 1\nLine 2"), "Line 1\\nLine 2"
|
52
|
-
)
|
53
|
-
self.assertEqual(ParseUtil.escape_chars_in_json('Quote: "'), 'Quote: \\"')
|
54
|
-
|
55
|
-
def test_extract_code_block(self):
|
56
|
-
"""Test extracting and parsing code blocks from Markdown."""
|
57
|
-
markdown = '```python\nprint("Hello, world!")\n```'
|
58
|
-
result = ParseUtil.extract_json_block(
|
59
|
-
markdown, language="python", parser=lambda x: x
|
60
|
-
)
|
61
|
-
self.assertEqual(result, 'print("Hello, world!")')
|
62
|
-
|
63
|
-
def test_md_to_json(self):
|
64
|
-
"""Test extracting and validating JSON from Markdown content."""
|
65
|
-
markdown = '```json\n{"key": "value"}\n```'
|
66
|
-
result = ParseUtil.md_to_json(markdown, expected_keys=["key"])
|
67
|
-
self.assertEqual(result, {"key": "value"})
|
68
|
-
with self.assertRaises(ValueError):
|
69
|
-
ParseUtil.md_to_json(markdown, expected_keys=["missing_key"])
|
70
|
-
|
71
|
-
def test_jaro_distance(self):
|
72
|
-
"""Test Jaro distance calculations."""
|
73
|
-
self.assertAlmostEqual(
|
74
|
-
StringMatch.jaro_distance("martha", "marhta"), 0.9444444444444445, places=7
|
75
|
-
)
|
76
|
-
self.assertAlmostEqual(StringMatch.jaro_distance("", ""), 1.0)
|
77
|
-
self.assertAlmostEqual(StringMatch.jaro_distance("abc", "abc"), 1.0)
|
78
|
-
self.assertAlmostEqual(StringMatch.jaro_distance("abc", "def"), 0.0)
|
79
|
-
|
80
|
-
def test_jaro_winkler_similarity(self):
|
81
|
-
"""Test Jaro-Winkler similarity calculations."""
|
82
|
-
self.assertAlmostEqual(
|
83
|
-
StringMatch.jaro_winkler_similarity("dixon", "dicksonx", scaling=0.1),
|
84
|
-
0.8133333333333332,
|
85
|
-
places=7,
|
86
|
-
)
|
87
|
-
self.assertAlmostEqual(
|
88
|
-
StringMatch.jaro_winkler_similarity("martha", "marhta", scaling=0.1),
|
89
|
-
0.9611111111111111,
|
90
|
-
places=7,
|
91
|
-
)
|
92
|
-
self.assertAlmostEqual(
|
93
|
-
StringMatch.jaro_winkler_similarity("", "", scaling=0.1), 1.0
|
94
|
-
)
|
95
|
-
self.assertAlmostEqual(
|
96
|
-
StringMatch.jaro_winkler_similarity("abc", "abc", scaling=0.1), 1.0
|
97
|
-
)
|
98
|
-
self.assertAlmostEqual(
|
99
|
-
StringMatch.jaro_winkler_similarity("abc", "def", scaling=0.1), 0.0
|
100
|
-
)
|
101
|
-
|
102
|
-
def test_levenshtein_distance(self):
|
103
|
-
"""Test Levenshtein distance calculations."""
|
104
|
-
self.assertEqual(StringMatch.levenshtein_distance("kitten", "sitting"), 3)
|
105
|
-
self.assertEqual(StringMatch.levenshtein_distance("", ""), 0)
|
106
|
-
self.assertEqual(StringMatch.levenshtein_distance("book", "back"), 2)
|
107
|
-
self.assertEqual(StringMatch.levenshtein_distance("book", ""), 4)
|
108
|
-
self.assertEqual(StringMatch.levenshtein_distance("", "back"), 4)
|
109
|
-
|
110
|
-
def test_extract_google_style(self):
|
111
|
-
def sample_func():
|
112
|
-
"""
|
113
|
-
Sample function.
|
114
|
-
|
115
|
-
Args:
|
116
|
-
param1 (int): Description of param1.
|
117
|
-
param2 (str): Description of param2.
|
118
|
-
"""
|
119
|
-
pass
|
120
|
-
|
121
|
-
description, params = ParseUtil._extract_docstring_details_google(sample_func)
|
122
|
-
self.assertEqual(description, "Sample function.")
|
123
|
-
self.assertDictEqual(
|
124
|
-
params,
|
125
|
-
{"param1": "Description of param1.", "param2": "Description of param2."},
|
126
|
-
)
|
127
|
-
|
128
|
-
def test_extract_reST_style(self):
|
129
|
-
def sample_func():
|
130
|
-
"""
|
131
|
-
Sample function.
|
132
|
-
|
133
|
-
:param param1: Description of param1.
|
134
|
-
:type param1: int
|
135
|
-
:param param2: Description of param2.
|
136
|
-
:type param2: str
|
137
|
-
"""
|
138
|
-
pass
|
139
|
-
|
140
|
-
description, params = ParseUtil._extract_docstring_details_rest(sample_func)
|
141
|
-
self.assertEqual(description, "Sample function.")
|
142
|
-
self.assertDictEqual(
|
143
|
-
params,
|
144
|
-
{"param1": "Description of param1.", "param2": "Description of param2."},
|
145
|
-
)
|
146
|
-
|
147
|
-
@patch("lionagi.libs.ln_parse.ParseUtil._extract_docstring_details")
|
148
|
-
def test_func_to_schema(self, mock_extract):
|
149
|
-
mock_extract.return_value = (
|
150
|
-
"Function description",
|
151
|
-
{"param1": "Description of param1."},
|
152
|
-
)
|
153
|
-
|
154
|
-
def sample_func(param1: int) -> bool:
|
155
|
-
pass
|
156
|
-
|
157
|
-
schema = ParseUtil._func_to_schema(sample_func)
|
158
|
-
self.assertEqual(schema["function"]["name"], "sample_func")
|
159
|
-
self.assertEqual(schema["function"]["description"], "Function description")
|
160
|
-
self.assertIn("param1", schema["function"]["parameters"]["properties"])
|
161
|
-
self.assertEqual(
|
162
|
-
schema["function"]["parameters"]["properties"]["param1"]["type"], "number"
|
163
|
-
)
|
164
|
-
self.assertEqual(
|
165
|
-
schema["function"]["parameters"]["properties"]["param1"]["description"],
|
166
|
-
"Description of param1.",
|
167
|
-
)
|
168
|
-
|
169
|
-
|
170
|
-
if __name__ == "__main__":
|
171
|
-
unittest.main()
|
lionagi/tests/libs/test_queue.py
DELETED
@@ -1,68 +0,0 @@
|
|
1
|
-
import asyncio
|
2
|
-
import unittest
|
3
|
-
from unittest.mock import patch
|
4
|
-
|
5
|
-
from lionagi.libs.ln_queue import AsyncQueue
|
6
|
-
|
7
|
-
|
8
|
-
class TestAsyncQueue(unittest.TestCase):
|
9
|
-
def setUp(self):
|
10
|
-
self.loop = asyncio.new_event_loop()
|
11
|
-
asyncio.set_event_loop(self.loop)
|
12
|
-
self.queue = AsyncQueue(max_concurrent_tasks=3)
|
13
|
-
|
14
|
-
def tearDown(self):
|
15
|
-
self.loop.close()
|
16
|
-
|
17
|
-
def test_enqueue_dequeue(self):
|
18
|
-
async def test():
|
19
|
-
await self.queue.enqueue("task1")
|
20
|
-
result = await self.queue.dequeue()
|
21
|
-
self.assertEqual(result, "task1")
|
22
|
-
|
23
|
-
self.loop.run_until_complete(test())
|
24
|
-
|
25
|
-
def test_stop(self):
|
26
|
-
async def test():
|
27
|
-
await self.queue.stop()
|
28
|
-
self.assertTrue(self.queue.stopped())
|
29
|
-
|
30
|
-
self.loop.run_until_complete(test())
|
31
|
-
|
32
|
-
@patch("lionagi.libs.ln_func_call.rcall", autospec=True)
|
33
|
-
def test_process_requests(self, mock_rcall):
|
34
|
-
future = asyncio.Future()
|
35
|
-
future.set_result("Processed successfully")
|
36
|
-
mock_rcall.return_value = future
|
37
|
-
|
38
|
-
async def processor(task):
|
39
|
-
return f"Processed {task}"
|
40
|
-
|
41
|
-
async def add_tasks():
|
42
|
-
for i in range(5):
|
43
|
-
await self.queue.enqueue(f"task{i}")
|
44
|
-
# This ensures that the queue stops after all tasks are added
|
45
|
-
await self.queue.stop()
|
46
|
-
|
47
|
-
async def process():
|
48
|
-
await self.queue.process_requests(processor, retry_kwargs={"retries": 2})
|
49
|
-
|
50
|
-
self.loop.create_task(add_tasks())
|
51
|
-
self.loop.run_until_complete(process())
|
52
|
-
# mock_rcall.assert_called()
|
53
|
-
|
54
|
-
def test_concurrency_limit(self):
|
55
|
-
async def add_tasks():
|
56
|
-
for i in range(10):
|
57
|
-
await self.queue.enqueue(f"task{i}")
|
58
|
-
|
59
|
-
async def process():
|
60
|
-
await asyncio.sleep(0.1)
|
61
|
-
await self.queue.stop()
|
62
|
-
|
63
|
-
self.loop.run_until_complete(add_tasks())
|
64
|
-
self.loop.run_until_complete(process())
|
65
|
-
|
66
|
-
|
67
|
-
if __name__ == "__main__":
|
68
|
-
unittest.main()
|