lionagi 0.2.11__py3-none-any.whl → 0.3.1__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (153) hide show
  1. lionagi/core/action/function_calling.py +13 -6
  2. lionagi/core/action/tool.py +10 -9
  3. lionagi/core/action/tool_manager.py +18 -9
  4. lionagi/core/agent/README.md +1 -1
  5. lionagi/core/agent/base_agent.py +5 -2
  6. lionagi/core/agent/eval/README.md +1 -1
  7. lionagi/core/collections/README.md +1 -1
  8. lionagi/core/collections/_logger.py +16 -6
  9. lionagi/core/collections/abc/README.md +1 -1
  10. lionagi/core/collections/abc/component.py +35 -11
  11. lionagi/core/collections/abc/concepts.py +5 -3
  12. lionagi/core/collections/abc/exceptions.py +3 -1
  13. lionagi/core/collections/flow.py +16 -5
  14. lionagi/core/collections/model.py +34 -8
  15. lionagi/core/collections/pile.py +65 -28
  16. lionagi/core/collections/progression.py +1 -2
  17. lionagi/core/collections/util.py +11 -2
  18. lionagi/core/director/README.md +1 -1
  19. lionagi/core/engine/branch_engine.py +35 -10
  20. lionagi/core/engine/instruction_map_engine.py +14 -5
  21. lionagi/core/engine/sandbox_.py +3 -1
  22. lionagi/core/engine/script_engine.py +6 -2
  23. lionagi/core/executor/base_executor.py +10 -3
  24. lionagi/core/executor/graph_executor.py +12 -4
  25. lionagi/core/executor/neo4j_executor.py +18 -6
  26. lionagi/core/generic/edge.py +7 -2
  27. lionagi/core/generic/graph.py +23 -7
  28. lionagi/core/generic/node.py +14 -5
  29. lionagi/core/generic/tree_node.py +5 -1
  30. lionagi/core/mail/mail_manager.py +3 -1
  31. lionagi/core/mail/package.py +3 -1
  32. lionagi/core/message/action_request.py +9 -2
  33. lionagi/core/message/action_response.py +9 -3
  34. lionagi/core/message/instruction.py +8 -2
  35. lionagi/core/message/util.py +15 -5
  36. lionagi/core/report/base.py +12 -7
  37. lionagi/core/report/form.py +7 -4
  38. lionagi/core/report/report.py +10 -3
  39. lionagi/core/report/util.py +3 -1
  40. lionagi/core/rule/action.py +4 -1
  41. lionagi/core/rule/base.py +17 -6
  42. lionagi/core/rule/rulebook.py +8 -4
  43. lionagi/core/rule/string.py +3 -1
  44. lionagi/core/session/branch.py +15 -4
  45. lionagi/core/session/directive_mixin.py +11 -3
  46. lionagi/core/session/session.py +6 -2
  47. lionagi/core/unit/parallel_unit.py +9 -3
  48. lionagi/core/unit/template/action.py +1 -1
  49. lionagi/core/unit/template/predict.py +3 -1
  50. lionagi/core/unit/template/select.py +5 -3
  51. lionagi/core/unit/unit.py +38 -4
  52. lionagi/core/unit/unit_form.py +13 -15
  53. lionagi/core/unit/unit_mixin.py +45 -27
  54. lionagi/core/unit/util.py +7 -3
  55. lionagi/core/validator/validator.py +28 -15
  56. lionagi/core/work/work_edge.py +7 -3
  57. lionagi/core/work/work_task.py +11 -5
  58. lionagi/core/work/worker.py +20 -5
  59. lionagi/core/work/worker_engine.py +6 -2
  60. lionagi/core/work/worklog.py +3 -1
  61. lionagi/experimental/compressor/llm_compressor.py +20 -5
  62. lionagi/experimental/directive/README.md +1 -1
  63. lionagi/experimental/directive/parser/base_parser.py +41 -14
  64. lionagi/experimental/directive/parser/base_syntax.txt +23 -23
  65. lionagi/experimental/directive/template/base_template.py +14 -6
  66. lionagi/experimental/directive/tokenizer.py +3 -1
  67. lionagi/experimental/evaluator/README.md +1 -1
  68. lionagi/experimental/evaluator/ast_evaluator.py +6 -2
  69. lionagi/experimental/evaluator/base_evaluator.py +27 -16
  70. lionagi/integrations/bridge/autogen_/autogen_.py +7 -3
  71. lionagi/integrations/bridge/langchain_/documents.py +13 -10
  72. lionagi/integrations/bridge/llamaindex_/llama_pack.py +36 -12
  73. lionagi/integrations/bridge/llamaindex_/node_parser.py +8 -3
  74. lionagi/integrations/bridge/llamaindex_/reader.py +3 -1
  75. lionagi/integrations/bridge/llamaindex_/textnode.py +9 -3
  76. lionagi/integrations/bridge/pydantic_/pydantic_bridge.py +7 -1
  77. lionagi/integrations/bridge/transformers_/install_.py +3 -1
  78. lionagi/integrations/chunker/chunk.py +5 -2
  79. lionagi/integrations/loader/load.py +7 -3
  80. lionagi/integrations/loader/load_util.py +35 -16
  81. lionagi/integrations/provider/oai.py +13 -4
  82. lionagi/integrations/provider/openrouter.py +13 -4
  83. lionagi/integrations/provider/services.py +3 -1
  84. lionagi/integrations/provider/transformers.py +5 -3
  85. lionagi/integrations/storage/neo4j.py +23 -7
  86. lionagi/integrations/storage/storage_util.py +23 -7
  87. lionagi/integrations/storage/structure_excel.py +7 -2
  88. lionagi/integrations/storage/to_csv.py +8 -2
  89. lionagi/integrations/storage/to_excel.py +11 -3
  90. lionagi/libs/ln_api.py +41 -19
  91. lionagi/libs/ln_context.py +4 -4
  92. lionagi/libs/ln_convert.py +35 -14
  93. lionagi/libs/ln_dataframe.py +9 -3
  94. lionagi/libs/ln_func_call.py +53 -18
  95. lionagi/libs/ln_image.py +9 -5
  96. lionagi/libs/ln_knowledge_graph.py +21 -7
  97. lionagi/libs/ln_nested.py +57 -16
  98. lionagi/libs/ln_parse.py +45 -15
  99. lionagi/libs/ln_queue.py +8 -3
  100. lionagi/libs/ln_tokenize.py +19 -6
  101. lionagi/libs/ln_validate.py +14 -3
  102. lionagi/libs/sys_util.py +44 -12
  103. lionagi/lions/coder/coder.py +24 -8
  104. lionagi/lions/coder/util.py +6 -2
  105. lionagi/lions/researcher/data_source/google_.py +12 -4
  106. lionagi/lions/researcher/data_source/wiki_.py +3 -1
  107. lionagi/version.py +1 -1
  108. {lionagi-0.2.11.dist-info → lionagi-0.3.1.dist-info}/METADATA +6 -7
  109. lionagi-0.3.1.dist-info/RECORD +226 -0
  110. lionagi/tests/__init__.py +0 -0
  111. lionagi/tests/api/__init__.py +0 -0
  112. lionagi/tests/api/aws/__init__.py +0 -0
  113. lionagi/tests/api/aws/conftest.py +0 -25
  114. lionagi/tests/api/aws/test_aws_s3.py +0 -6
  115. lionagi/tests/integrations/__init__.py +0 -0
  116. lionagi/tests/libs/__init__.py +0 -0
  117. lionagi/tests/libs/test_api.py +0 -48
  118. lionagi/tests/libs/test_convert.py +0 -89
  119. lionagi/tests/libs/test_field_validators.py +0 -354
  120. lionagi/tests/libs/test_func_call.py +0 -701
  121. lionagi/tests/libs/test_nested.py +0 -382
  122. lionagi/tests/libs/test_parse.py +0 -171
  123. lionagi/tests/libs/test_queue.py +0 -68
  124. lionagi/tests/libs/test_sys_util.py +0 -222
  125. lionagi/tests/test_core/__init__.py +0 -0
  126. lionagi/tests/test_core/collections/__init__.py +0 -0
  127. lionagi/tests/test_core/collections/test_component.py +0 -208
  128. lionagi/tests/test_core/collections/test_exchange.py +0 -139
  129. lionagi/tests/test_core/collections/test_flow.py +0 -146
  130. lionagi/tests/test_core/collections/test_pile.py +0 -172
  131. lionagi/tests/test_core/collections/test_progression.py +0 -130
  132. lionagi/tests/test_core/generic/__init__.py +0 -0
  133. lionagi/tests/test_core/generic/test_edge.py +0 -69
  134. lionagi/tests/test_core/generic/test_graph.py +0 -97
  135. lionagi/tests/test_core/generic/test_node.py +0 -107
  136. lionagi/tests/test_core/generic/test_structure.py +0 -194
  137. lionagi/tests/test_core/generic/test_tree_node.py +0 -74
  138. lionagi/tests/test_core/graph/__init__.py +0 -0
  139. lionagi/tests/test_core/graph/test_graph.py +0 -71
  140. lionagi/tests/test_core/graph/test_tree.py +0 -76
  141. lionagi/tests/test_core/mail/__init__.py +0 -0
  142. lionagi/tests/test_core/mail/test_mail.py +0 -98
  143. lionagi/tests/test_core/test_branch.py +0 -116
  144. lionagi/tests/test_core/test_form.py +0 -47
  145. lionagi/tests/test_core/test_report.py +0 -106
  146. lionagi/tests/test_core/test_structure/__init__.py +0 -0
  147. lionagi/tests/test_core/test_structure/test_base_structure.py +0 -198
  148. lionagi/tests/test_core/test_structure/test_graph.py +0 -55
  149. lionagi/tests/test_core/test_structure/test_tree.py +0 -49
  150. lionagi/tests/test_core/test_validator.py +0 -112
  151. lionagi-0.2.11.dist-info/RECORD +0 -267
  152. {lionagi-0.2.11.dist-info → lionagi-0.3.1.dist-info}/LICENSE +0 -0
  153. {lionagi-0.2.11.dist-info → lionagi-0.3.1.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()
@@ -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()
@@ -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()