lionagi 0.1.2__py3-none-any.whl → 0.2.0__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/__init__.py +60 -5
- lionagi/core/__init__.py +0 -25
- lionagi/core/_setting/_setting.py +59 -0
- lionagi/core/action/__init__.py +14 -0
- lionagi/core/action/function_calling.py +136 -0
- lionagi/core/action/manual.py +1 -0
- lionagi/core/action/node.py +109 -0
- lionagi/core/action/tool.py +114 -0
- lionagi/core/action/tool_manager.py +356 -0
- lionagi/core/agent/base_agent.py +27 -13
- lionagi/core/agent/eval/evaluator.py +1 -0
- lionagi/core/agent/eval/vote.py +40 -0
- lionagi/core/agent/learn/learner.py +59 -0
- lionagi/core/agent/plan/unit_template.py +1 -0
- lionagi/core/collections/__init__.py +17 -0
- lionagi/core/{generic/data_logger.py → collections/_logger.py} +69 -55
- lionagi/core/collections/abc/__init__.py +53 -0
- lionagi/core/collections/abc/component.py +615 -0
- lionagi/core/collections/abc/concepts.py +297 -0
- lionagi/core/collections/abc/exceptions.py +150 -0
- lionagi/core/collections/abc/util.py +45 -0
- lionagi/core/collections/exchange.py +161 -0
- lionagi/core/collections/flow.py +426 -0
- lionagi/core/collections/model.py +419 -0
- lionagi/core/collections/pile.py +913 -0
- lionagi/core/collections/progression.py +236 -0
- lionagi/core/collections/util.py +64 -0
- lionagi/core/director/direct.py +314 -0
- lionagi/core/director/director.py +2 -0
- lionagi/core/{execute/branch_executor.py → engine/branch_engine.py} +134 -97
- lionagi/core/{execute/instruction_map_executor.py → engine/instruction_map_engine.py} +80 -55
- lionagi/{experimental/directive/evaluator → core/engine}/script_engine.py +17 -1
- lionagi/core/executor/base_executor.py +90 -0
- lionagi/core/{execute/structure_executor.py → executor/graph_executor.py} +62 -66
- lionagi/core/{execute → executor}/neo4j_executor.py +70 -67
- lionagi/core/generic/__init__.py +3 -33
- lionagi/core/generic/edge.py +29 -79
- lionagi/core/generic/edge_condition.py +16 -0
- lionagi/core/generic/graph.py +236 -0
- lionagi/core/generic/hyperedge.py +1 -0
- lionagi/core/generic/node.py +156 -221
- lionagi/core/generic/tree.py +48 -0
- lionagi/core/generic/tree_node.py +79 -0
- lionagi/core/mail/__init__.py +12 -0
- lionagi/core/mail/mail.py +25 -0
- lionagi/core/mail/mail_manager.py +139 -58
- lionagi/core/mail/package.py +45 -0
- lionagi/core/mail/start_mail.py +36 -0
- lionagi/core/message/__init__.py +19 -0
- lionagi/core/message/action_request.py +133 -0
- lionagi/core/message/action_response.py +135 -0
- lionagi/core/message/assistant_response.py +95 -0
- lionagi/core/message/instruction.py +234 -0
- lionagi/core/message/message.py +101 -0
- lionagi/core/message/system.py +86 -0
- lionagi/core/message/util.py +283 -0
- lionagi/core/report/__init__.py +4 -0
- lionagi/core/report/base.py +217 -0
- lionagi/core/report/form.py +231 -0
- lionagi/core/report/report.py +166 -0
- lionagi/core/report/util.py +28 -0
- lionagi/core/rule/_default.py +16 -0
- lionagi/core/rule/action.py +99 -0
- lionagi/core/rule/base.py +238 -0
- lionagi/core/rule/boolean.py +56 -0
- lionagi/core/rule/choice.py +47 -0
- lionagi/core/rule/mapping.py +96 -0
- lionagi/core/rule/number.py +71 -0
- lionagi/core/rule/rulebook.py +109 -0
- lionagi/core/rule/string.py +52 -0
- lionagi/core/rule/util.py +35 -0
- lionagi/core/session/branch.py +431 -0
- lionagi/core/session/directive_mixin.py +287 -0
- lionagi/core/session/session.py +229 -903
- lionagi/core/structure/__init__.py +1 -0
- lionagi/core/structure/chain.py +1 -0
- lionagi/core/structure/forest.py +1 -0
- lionagi/core/structure/graph.py +1 -0
- lionagi/core/structure/tree.py +1 -0
- lionagi/core/unit/__init__.py +5 -0
- lionagi/core/unit/parallel_unit.py +245 -0
- lionagi/core/unit/template/action.py +81 -0
- lionagi/core/unit/template/base.py +51 -0
- lionagi/core/unit/template/plan.py +84 -0
- lionagi/core/unit/template/predict.py +109 -0
- lionagi/core/unit/template/score.py +124 -0
- lionagi/core/unit/template/select.py +104 -0
- lionagi/core/unit/unit.py +362 -0
- lionagi/core/unit/unit_form.py +305 -0
- lionagi/core/unit/unit_mixin.py +1168 -0
- lionagi/core/unit/util.py +71 -0
- lionagi/core/validator/validator.py +364 -0
- lionagi/core/work/work.py +74 -0
- lionagi/core/work/work_function.py +92 -0
- lionagi/core/work/work_queue.py +81 -0
- lionagi/core/work/worker.py +195 -0
- lionagi/core/work/worklog.py +124 -0
- lionagi/experimental/compressor/base.py +46 -0
- lionagi/experimental/compressor/llm_compressor.py +247 -0
- lionagi/experimental/compressor/llm_summarizer.py +61 -0
- lionagi/experimental/compressor/util.py +70 -0
- lionagi/experimental/directive/__init__.py +19 -0
- lionagi/experimental/directive/parser/base_parser.py +69 -2
- lionagi/experimental/directive/{template_ → template}/base_template.py +17 -1
- lionagi/{libs/ln_tokenizer.py → experimental/directive/tokenizer.py} +16 -0
- lionagi/experimental/{directive/evaluator → evaluator}/ast_evaluator.py +16 -0
- lionagi/experimental/{directive/evaluator → evaluator}/base_evaluator.py +16 -0
- lionagi/experimental/knowledge/base.py +10 -0
- lionagi/experimental/memory/__init__.py +0 -0
- lionagi/experimental/strategies/__init__.py +0 -0
- lionagi/experimental/strategies/base.py +1 -0
- lionagi/integrations/bridge/langchain_/documents.py +4 -0
- lionagi/integrations/bridge/llamaindex_/index.py +30 -0
- lionagi/integrations/bridge/llamaindex_/llama_index_bridge.py +6 -0
- lionagi/integrations/chunker/chunk.py +161 -24
- lionagi/integrations/config/oai_configs.py +34 -3
- lionagi/integrations/config/openrouter_configs.py +14 -2
- lionagi/integrations/loader/load.py +122 -21
- lionagi/integrations/loader/load_util.py +6 -77
- lionagi/integrations/provider/_mapping.py +46 -0
- lionagi/integrations/provider/litellm.py +2 -1
- lionagi/integrations/provider/mlx_service.py +16 -9
- lionagi/integrations/provider/oai.py +91 -4
- lionagi/integrations/provider/ollama.py +6 -5
- lionagi/integrations/provider/openrouter.py +115 -8
- lionagi/integrations/provider/services.py +2 -2
- lionagi/integrations/provider/transformers.py +18 -22
- lionagi/integrations/storage/__init__.py +3 -3
- lionagi/integrations/storage/neo4j.py +52 -60
- lionagi/integrations/storage/storage_util.py +44 -46
- lionagi/integrations/storage/structure_excel.py +43 -26
- lionagi/integrations/storage/to_excel.py +11 -4
- lionagi/libs/__init__.py +22 -1
- lionagi/libs/ln_api.py +75 -20
- lionagi/libs/ln_context.py +37 -0
- lionagi/libs/ln_convert.py +21 -9
- lionagi/libs/ln_func_call.py +69 -28
- lionagi/libs/ln_image.py +107 -0
- lionagi/libs/ln_nested.py +26 -11
- lionagi/libs/ln_parse.py +82 -23
- lionagi/libs/ln_queue.py +16 -0
- lionagi/libs/ln_tokenize.py +164 -0
- lionagi/libs/ln_validate.py +16 -0
- lionagi/libs/special_tokens.py +172 -0
- lionagi/libs/sys_util.py +95 -24
- lionagi/lions/coder/code_form.py +13 -0
- lionagi/lions/coder/coder.py +50 -3
- lionagi/lions/coder/util.py +30 -25
- lionagi/tests/libs/test_func_call.py +23 -21
- lionagi/tests/libs/test_nested.py +36 -21
- lionagi/tests/libs/test_parse.py +1 -1
- lionagi/tests/test_core/collections/__init__.py +0 -0
- lionagi/tests/test_core/collections/test_component.py +206 -0
- lionagi/tests/test_core/collections/test_exchange.py +138 -0
- lionagi/tests/test_core/collections/test_flow.py +145 -0
- lionagi/tests/test_core/collections/test_pile.py +171 -0
- lionagi/tests/test_core/collections/test_progression.py +129 -0
- lionagi/tests/test_core/generic/test_edge.py +67 -0
- lionagi/tests/test_core/generic/test_graph.py +96 -0
- lionagi/tests/test_core/generic/test_node.py +106 -0
- lionagi/tests/test_core/generic/test_tree_node.py +73 -0
- lionagi/tests/test_core/test_branch.py +115 -294
- lionagi/tests/test_core/test_form.py +46 -0
- lionagi/tests/test_core/test_report.py +105 -0
- lionagi/tests/test_core/test_validator.py +111 -0
- lionagi/version.py +1 -1
- lionagi-0.2.0.dist-info/LICENSE +202 -0
- lionagi-0.2.0.dist-info/METADATA +272 -0
- lionagi-0.2.0.dist-info/RECORD +240 -0
- lionagi/core/branch/base.py +0 -653
- lionagi/core/branch/branch.py +0 -474
- lionagi/core/branch/flow_mixin.py +0 -96
- lionagi/core/branch/util.py +0 -323
- lionagi/core/direct/__init__.py +0 -19
- lionagi/core/direct/cot.py +0 -123
- lionagi/core/direct/plan.py +0 -164
- lionagi/core/direct/predict.py +0 -166
- lionagi/core/direct/react.py +0 -171
- lionagi/core/direct/score.py +0 -279
- lionagi/core/direct/select.py +0 -170
- lionagi/core/direct/sentiment.py +0 -1
- lionagi/core/direct/utils.py +0 -110
- lionagi/core/direct/vote.py +0 -64
- lionagi/core/execute/base_executor.py +0 -47
- lionagi/core/flow/baseflow.py +0 -23
- lionagi/core/flow/monoflow/ReAct.py +0 -240
- lionagi/core/flow/monoflow/__init__.py +0 -9
- lionagi/core/flow/monoflow/chat.py +0 -95
- lionagi/core/flow/monoflow/chat_mixin.py +0 -253
- lionagi/core/flow/monoflow/followup.py +0 -215
- lionagi/core/flow/polyflow/__init__.py +0 -1
- lionagi/core/flow/polyflow/chat.py +0 -251
- lionagi/core/form/action_form.py +0 -26
- lionagi/core/form/field_validator.py +0 -287
- lionagi/core/form/form.py +0 -302
- lionagi/core/form/mixin.py +0 -214
- lionagi/core/form/scored_form.py +0 -13
- lionagi/core/generic/action.py +0 -26
- lionagi/core/generic/component.py +0 -532
- lionagi/core/generic/condition.py +0 -46
- lionagi/core/generic/mail.py +0 -90
- lionagi/core/generic/mailbox.py +0 -36
- lionagi/core/generic/relation.py +0 -70
- lionagi/core/generic/signal.py +0 -22
- lionagi/core/generic/structure.py +0 -362
- lionagi/core/generic/transfer.py +0 -20
- lionagi/core/generic/work.py +0 -40
- lionagi/core/graph/graph.py +0 -126
- lionagi/core/graph/tree.py +0 -190
- lionagi/core/mail/schema.py +0 -63
- lionagi/core/messages/schema.py +0 -325
- lionagi/core/tool/__init__.py +0 -5
- lionagi/core/tool/tool.py +0 -28
- lionagi/core/tool/tool_manager.py +0 -283
- lionagi/experimental/report/form.py +0 -64
- lionagi/experimental/report/report.py +0 -138
- lionagi/experimental/report/util.py +0 -47
- lionagi/experimental/tool/function_calling.py +0 -43
- lionagi/experimental/tool/manual.py +0 -66
- lionagi/experimental/tool/schema.py +0 -59
- lionagi/experimental/tool/tool_manager.py +0 -138
- lionagi/experimental/tool/util.py +0 -16
- lionagi/experimental/validator/rule.py +0 -139
- lionagi/experimental/validator/validator.py +0 -56
- lionagi/experimental/work/__init__.py +0 -10
- lionagi/experimental/work/async_queue.py +0 -54
- lionagi/experimental/work/schema.py +0 -73
- lionagi/experimental/work/work_function.py +0 -67
- lionagi/experimental/work/worker.py +0 -56
- lionagi/experimental/work2/form.py +0 -371
- lionagi/experimental/work2/report.py +0 -289
- lionagi/experimental/work2/schema.py +0 -30
- lionagi/experimental/work2/tests.py +0 -72
- lionagi/experimental/work2/work_function.py +0 -89
- lionagi/experimental/work2/worker.py +0 -12
- lionagi/integrations/bridge/llamaindex_/get_index.py +0 -294
- lionagi/tests/test_core/generic/test_component.py +0 -89
- lionagi/tests/test_core/test_base_branch.py +0 -426
- lionagi/tests/test_core/test_chat_flow.py +0 -63
- lionagi/tests/test_core/test_mail_manager.py +0 -75
- lionagi/tests/test_core/test_prompts.py +0 -51
- lionagi/tests/test_core/test_session.py +0 -254
- lionagi/tests/test_core/test_session_base_util.py +0 -313
- lionagi/tests/test_core/test_tool_manager.py +0 -95
- lionagi-0.1.2.dist-info/LICENSE +0 -9
- lionagi-0.1.2.dist-info/METADATA +0 -174
- lionagi-0.1.2.dist-info/RECORD +0 -206
- /lionagi/core/{branch → _setting}/__init__.py +0 -0
- /lionagi/core/{execute → agent/eval}/__init__.py +0 -0
- /lionagi/core/{flow → agent/learn}/__init__.py +0 -0
- /lionagi/core/{form → agent/plan}/__init__.py +0 -0
- /lionagi/core/{branch/executable_branch.py → agent/plan/plan.py} +0 -0
- /lionagi/core/{graph → director}/__init__.py +0 -0
- /lionagi/core/{messages → engine}/__init__.py +0 -0
- /lionagi/{experimental/directive/evaluator → core/engine}/sandbox_.py +0 -0
- /lionagi/{experimental/directive/evaluator → core/executor}/__init__.py +0 -0
- /lionagi/{experimental/directive/template_ → core/rule}/__init__.py +0 -0
- /lionagi/{experimental/report → core/unit/template}/__init__.py +0 -0
- /lionagi/{experimental/tool → core/validator}/__init__.py +0 -0
- /lionagi/{experimental/validator → core/work}/__init__.py +0 -0
- /lionagi/experimental/{work2 → compressor}/__init__.py +0 -0
- /lionagi/{core/flow/mono_chat_mixin.py → experimental/directive/template/__init__.py} +0 -0
- /lionagi/experimental/directive/{schema.py → template/schema.py} +0 -0
- /lionagi/experimental/{work2/util.py → evaluator/__init__.py} +0 -0
- /lionagi/experimental/{work2/work.py → knowledge/__init__.py} +0 -0
- /lionagi/{tests/libs/test_async.py → experimental/knowledge/graph.py} +0 -0
- {lionagi-0.1.2.dist-info → lionagi-0.2.0.dist-info}/WHEEL +0 -0
- {lionagi-0.1.2.dist-info → lionagi-0.2.0.dist-info}/top_level.txt +0 -0
@@ -39,7 +39,7 @@ class TestNSet(unittest.TestCase):
|
|
39
39
|
"""Test flattening and then unflattening a nested dictionary."""
|
40
40
|
original = {"a": {"b": {"c": 1}}}
|
41
41
|
flattened = flatten(original)
|
42
|
-
self.assertEqual(flattened, {"
|
42
|
+
self.assertEqual(flattened, {"a[^_^]b[^_^]c": 1})
|
43
43
|
unflattened = unflatten(flattened)
|
44
44
|
self.assertEqual(original, unflattened)
|
45
45
|
|
@@ -225,27 +225,36 @@ class TestFlatten(unittest.TestCase):
|
|
225
225
|
def test_flatten_nested_dict(self):
|
226
226
|
nested_dict = {"a": {"b": 1, "c": {"d": 2}}}
|
227
227
|
result = flatten(nested_dict)
|
228
|
-
self.assertEqual(result, {"
|
228
|
+
self.assertEqual(result, {"a[^_^]b": 1, "a[^_^]c[^_^]d": 2})
|
229
229
|
|
230
230
|
def test_flatten_nested_list(self):
|
231
231
|
nested_list = [[1, 2], [3, [4, 5]]]
|
232
232
|
result = flatten(nested_list)
|
233
|
-
self.assertEqual(
|
233
|
+
self.assertEqual(
|
234
|
+
result,
|
235
|
+
{
|
236
|
+
"0[^_^]0": 1,
|
237
|
+
"0[^_^]1": 2,
|
238
|
+
"1[^_^]0": 3,
|
239
|
+
"1[^_^]1[^_^]0": 4,
|
240
|
+
"1[^_^]1[^_^]1": 5,
|
241
|
+
},
|
242
|
+
)
|
234
243
|
|
235
244
|
def test_flatten_with_max_depth(self):
|
236
245
|
nested_dict = {"a": {"b": {"c": 1}}}
|
237
246
|
result = flatten(nested_dict, max_depth=1)
|
238
|
-
self.assertEqual(result, {"
|
247
|
+
self.assertEqual(result, {"a[^_^]b": {"c": 1}})
|
239
248
|
|
240
249
|
def test_flatten_dict_only(self):
|
241
250
|
nested_mix = {"a": [1, 2], "b": {"c": 3}}
|
242
251
|
result = flatten(nested_mix, dict_only=True)
|
243
|
-
self.assertEqual(result, {"a": [1, 2], "
|
252
|
+
self.assertEqual(result, {"a": [1, 2], "b[^_^]c": 3})
|
244
253
|
|
245
254
|
def test_flatten_inplace(self):
|
246
255
|
nested_dict = {"a": {"b": 1}}
|
247
256
|
flatten(nested_dict, inplace=True)
|
248
|
-
self.assertEqual(nested_dict, {"
|
257
|
+
self.assertEqual(nested_dict, {"a[^_^]b": 1})
|
249
258
|
|
250
259
|
def test_flatten_empty_structure(self):
|
251
260
|
self.assertEqual(flatten({}), {})
|
@@ -254,18 +263,18 @@ class TestFlatten(unittest.TestCase):
|
|
254
263
|
def test_flatten_deeply_nested_structure(self):
|
255
264
|
deeply_nested = {"a": {"b": {"c": {"d": 1}}}}
|
256
265
|
result = flatten(deeply_nested)
|
257
|
-
self.assertEqual(result, {"
|
266
|
+
self.assertEqual(result, {"a[^_^]b[^_^]c[^_^]d": 1})
|
258
267
|
|
259
268
|
|
260
269
|
class TestUnflatten(unittest.TestCase):
|
261
270
|
|
262
271
|
def test_unflatten_to_nested_dict(self):
|
263
|
-
flat_dict = {"
|
272
|
+
flat_dict = {"a[^_^]b": 1, "a[^_^]c[^_^]d": 2}
|
264
273
|
result = unflatten(flat_dict)
|
265
274
|
self.assertEqual(result, {"a": {"b": 1, "c": {"d": 2}}})
|
266
275
|
|
267
276
|
def test_unflatten_to_nested_list(self):
|
268
|
-
flat_dict = {"
|
277
|
+
flat_dict = {"0[^_^]0": 1, "0[^_^]1": 2, "1": [3, 4]}
|
269
278
|
result = unflatten(flat_dict)
|
270
279
|
self.assertEqual(result, [[1, 2], [3, 4]])
|
271
280
|
|
@@ -275,26 +284,26 @@ class TestUnflatten(unittest.TestCase):
|
|
275
284
|
self.assertEqual(result, {"a": {"b": 1, "c": {"d": 2}}})
|
276
285
|
|
277
286
|
def test_unflatten_with_custom_logic(self):
|
278
|
-
flat_dict = {"
|
287
|
+
flat_dict = {"a[^_^]1": "one", "a[^_^]2": "two"}
|
279
288
|
custom_logic = lambda key: int(key) if key.isdigit() else key
|
280
289
|
result = unflatten(flat_dict, custom_logic=custom_logic)
|
281
290
|
self.assertEqual(result, {"a": [None, "one", "two"]})
|
282
291
|
|
283
292
|
def test_unflatten_with_max_depth(self):
|
284
|
-
flat_dict = {"
|
293
|
+
flat_dict = {"a[^_^]b[^_^]c": 1, "a[^_^]b[^_^]d": 2}
|
285
294
|
result = unflatten(flat_dict, max_depth=1)
|
286
|
-
self.assertEqual(result, {"a": {"
|
295
|
+
self.assertEqual(result, {"a": {"b[^_^]c": 1, "b[^_^]d": 2}})
|
287
296
|
|
288
297
|
def test_unflatten_with_max_depth_int(self):
|
289
|
-
flat_dict = {"
|
298
|
+
flat_dict = {"0[^_^]0[^_^]0": 1, "0[^_^]1[^_^]0": 2}
|
290
299
|
result = unflatten(flat_dict, max_depth=1)
|
291
|
-
self.assertEqual(result, [[{"
|
300
|
+
self.assertEqual(result, [[{"0[^_^]0": 1}, {"1[^_^]0": 2}]])
|
292
301
|
|
293
302
|
def test_unflatten_empty_flat_dict(self):
|
294
303
|
self.assertEqual(unflatten({}), [])
|
295
304
|
|
296
305
|
def test_unflatten_to_mixed_structure(self):
|
297
|
-
flat_dict = {"
|
306
|
+
flat_dict = {"0[^_^]0": 1, "1[^_^]key": 2}
|
298
307
|
result = unflatten(flat_dict)
|
299
308
|
self.assertEqual(result, [[1], {"key": 2}])
|
300
309
|
|
@@ -319,7 +328,7 @@ class TestNInsert(unittest.TestCase):
|
|
319
328
|
def test_insert_with_max_depth(self):
|
320
329
|
obj = {}
|
321
330
|
ninsert(obj, ["a", "b", "c"], "value", max_depth=1)
|
322
|
-
self.assertEqual(obj, {"a": {"
|
331
|
+
self.assertEqual(obj, {"a": {"b[^_^]c": "value"}})
|
323
332
|
|
324
333
|
def test_insert_into_empty_structure(self):
|
325
334
|
obj = {}
|
@@ -331,24 +340,30 @@ class TestGetFlattenedKeys(unittest.TestCase):
|
|
331
340
|
|
332
341
|
def test_get_keys_from_nested_dict(self):
|
333
342
|
nested_dict = {"a": {"b": 1, "c": {"d": 2}}}
|
334
|
-
expected_keys = ["
|
343
|
+
expected_keys = ["a[^_^]b", "a[^_^]c[^_^]d"]
|
335
344
|
self.assertEqual(set(get_flattened_keys(nested_dict)), set(expected_keys))
|
336
345
|
|
337
346
|
def test_get_keys_from_nested_list(self):
|
338
347
|
nested_list = [[1, 2], [3, [4, 5]]]
|
339
|
-
expected_keys = [
|
348
|
+
expected_keys = [
|
349
|
+
"0[^_^]0",
|
350
|
+
"0[^_^]1",
|
351
|
+
"1[^_^]0",
|
352
|
+
"1[^_^]1[^_^]0",
|
353
|
+
"1[^_^]1[^_^]1",
|
354
|
+
]
|
340
355
|
self.assertEqual(set(get_flattened_keys(nested_list)), set(expected_keys))
|
341
356
|
|
342
357
|
def test_get_keys_with_max_depth(self):
|
343
358
|
nested_dict = {"a": {"b": {"c": 1}}}
|
344
|
-
expected_keys = ["
|
359
|
+
expected_keys = ["a[^_^]b"]
|
345
360
|
self.assertEqual(
|
346
361
|
set(get_flattened_keys(nested_dict, max_depth=1)), set(expected_keys)
|
347
362
|
)
|
348
363
|
|
349
364
|
def test_get_keys_dict_only(self):
|
350
365
|
nested_mix = {"a": [1, 2], "b": {"c": 3}}
|
351
|
-
expected_keys = ["a", "
|
366
|
+
expected_keys = ["a", "b[^_^]c"]
|
352
367
|
self.assertEqual(
|
353
368
|
set(get_flattened_keys(nested_mix, dict_only=True)), set(expected_keys)
|
354
369
|
)
|
@@ -358,7 +373,7 @@ class TestGetFlattenedKeys(unittest.TestCase):
|
|
358
373
|
|
359
374
|
def test_keys_from_deeply_nested_structure(self):
|
360
375
|
deeply_nested = {"a": {"b": {"c": {"d": 1}}}}
|
361
|
-
expected_keys = ["
|
376
|
+
expected_keys = ["a[^_^]b[^_^]c[^_^]d"]
|
362
377
|
self.assertEqual(set(get_flattened_keys(deeply_nested)), set(expected_keys))
|
363
378
|
|
364
379
|
|
lionagi/tests/libs/test_parse.py
CHANGED
@@ -55,7 +55,7 @@ class TestFuzzyParseJson(unittest.TestCase):
|
|
55
55
|
def test_extract_code_block(self):
|
56
56
|
"""Test extracting and parsing code blocks from Markdown."""
|
57
57
|
markdown = '```python\nprint("Hello, world!")\n```'
|
58
|
-
result = ParseUtil.
|
58
|
+
result = ParseUtil.extract_json_block(
|
59
59
|
markdown, language="python", parser=lambda x: x
|
60
60
|
)
|
61
61
|
self.assertEqual(result, 'print("Hello, world!")')
|
File without changes
|
@@ -0,0 +1,206 @@
|
|
1
|
+
import unittest
|
2
|
+
from lionagi.core.collections.abc.component import (
|
3
|
+
Component,
|
4
|
+
LionValueError,
|
5
|
+
LionTypeError,
|
6
|
+
)
|
7
|
+
import pandas as pd
|
8
|
+
from datetime import datetime
|
9
|
+
import json
|
10
|
+
|
11
|
+
|
12
|
+
class TestComponent(unittest.TestCase):
|
13
|
+
|
14
|
+
def setUp(self):
|
15
|
+
"""Set up a basic Component instance for testing."""
|
16
|
+
self.component = Component()
|
17
|
+
|
18
|
+
def test_initialization(self):
|
19
|
+
"""Test basic initialization and attributes."""
|
20
|
+
self.assertIsInstance(self.component.ln_id, str)
|
21
|
+
self.assertIsInstance(self.component.timestamp, str)
|
22
|
+
self.assertIsInstance(self.component.metadata, dict)
|
23
|
+
self.assertIsNone(self.component.content)
|
24
|
+
self.assertEqual(self.component.embedding, [])
|
25
|
+
|
26
|
+
def test_setting_attributes(self):
|
27
|
+
"""Test setting and updating attributes."""
|
28
|
+
self.component.content = 1
|
29
|
+
self.assertEqual(self.component.content, 1)
|
30
|
+
self.assertIn("content", self.component.metadata["last_updated"])
|
31
|
+
|
32
|
+
def test_class_name(self):
|
33
|
+
"""Test the class_name property."""
|
34
|
+
self.assertEqual(self.component.class_name, "Component")
|
35
|
+
|
36
|
+
def test_to_dict(self):
|
37
|
+
"""Test converting to dictionary."""
|
38
|
+
self.component.content = "example content"
|
39
|
+
dict_repr = self.component.to_dict()
|
40
|
+
self.assertEqual(dict_repr["content"], "example content")
|
41
|
+
self.assertEqual(dict_repr["lion_class"], "Component")
|
42
|
+
|
43
|
+
def test_to_json_str(self):
|
44
|
+
"""Test converting to JSON string."""
|
45
|
+
self.component.content = "example content"
|
46
|
+
json_str = self.component.to_json_str()
|
47
|
+
self.assertIn('"content": "example content"', json_str)
|
48
|
+
|
49
|
+
def test_to_xml(self):
|
50
|
+
"""Test converting to XML string."""
|
51
|
+
self.component.content = "example content"
|
52
|
+
xml_str = self.component.to_xml()
|
53
|
+
self.assertIn("<content>example content</content>", xml_str)
|
54
|
+
|
55
|
+
def test_to_pd_series(self):
|
56
|
+
"""Test converting to Pandas Series."""
|
57
|
+
self.component.content = "example content"
|
58
|
+
series = self.component.to_pd_series()
|
59
|
+
self.assertEqual(series["content"], "example content")
|
60
|
+
|
61
|
+
def test_from_obj_dict(self):
|
62
|
+
"""Test creating a Component from a dictionary."""
|
63
|
+
dict_obj = {"a": 1, "b": 2}
|
64
|
+
new_component = Component.from_obj(dict_obj)
|
65
|
+
self.assertEqual(new_component.metadata["a"], 1)
|
66
|
+
self.assertEqual(new_component.metadata["b"], 2)
|
67
|
+
|
68
|
+
def test_from_obj_str(self):
|
69
|
+
"""Test creating a Component from a JSON string."""
|
70
|
+
json_str = '{"a": 1, "b": 2}'
|
71
|
+
new_component = Component.from_obj(json_str)
|
72
|
+
self.assertEqual(new_component.metadata["a"], 1)
|
73
|
+
self.assertEqual(new_component.metadata["b"], 2)
|
74
|
+
|
75
|
+
def test_from_obj_fuzzy_str(self):
|
76
|
+
"""Test creating a Component from a fuzzy JSON string."""
|
77
|
+
fuzzy_json_str = '{"name": "John", "age": 30, "city": ["New York", "DC", "LA"]'
|
78
|
+
new_component = Component.from_obj(fuzzy_json_str, fuzzy_parse=True)
|
79
|
+
self.assertEqual(new_component.metadata["name"], "John")
|
80
|
+
self.assertEqual(new_component.metadata["age"], 30)
|
81
|
+
self.assertEqual(new_component.metadata["city"], ["New York", "DC", "LA"])
|
82
|
+
|
83
|
+
def test_from_obj_series(self):
|
84
|
+
"""Test creating a Component from a Pandas Series."""
|
85
|
+
series_obj = pd.Series({"a": 1, "b": 2})
|
86
|
+
new_component = Component.from_obj(series_obj)
|
87
|
+
self.assertEqual(new_component.metadata["a"], 1)
|
88
|
+
self.assertEqual(new_component.metadata["b"], 2)
|
89
|
+
|
90
|
+
def test_from_obj_dataframe(self):
|
91
|
+
"""Test creating Components from a Pandas DataFrame."""
|
92
|
+
df = pd.DataFrame({"a": [1, 2], "b": [3, 4]}, index=["row1", "row2"])
|
93
|
+
components = Component.from_obj(df)
|
94
|
+
self.assertEqual(len(components), 2)
|
95
|
+
self.assertEqual(components[0].metadata["a"], 1)
|
96
|
+
self.assertEqual(components[0].metadata["b"], 3)
|
97
|
+
self.assertEqual(components[1].metadata["a"], 2)
|
98
|
+
self.assertEqual(components[1].metadata["b"], 4)
|
99
|
+
|
100
|
+
def test_metadata_manipulation(self):
|
101
|
+
"""Test manipulation of metadata."""
|
102
|
+
self.component._meta_insert(["new_key"], "new_value")
|
103
|
+
self.assertEqual(self.component.metadata["new_key"], "new_value")
|
104
|
+
self.component._meta_set(["new_key"], "updated_value")
|
105
|
+
self.assertEqual(self.component.metadata["new_key"], "updated_value")
|
106
|
+
nested_value = {"a": 1, "b": 2}
|
107
|
+
self.component._meta_insert(["nested", 0], nested_value)
|
108
|
+
self.assertEqual(self.component.metadata["nested"][0], nested_value)
|
109
|
+
self.assertEqual(self.component._meta_get(["nested", 0, "a"]), 1)
|
110
|
+
|
111
|
+
def test_invalid_metadata_assignment(self):
|
112
|
+
"""Test invalid direct assignment to metadata."""
|
113
|
+
with self.assertRaises(AttributeError):
|
114
|
+
self.component.metadata = {}
|
115
|
+
|
116
|
+
def test_field_annotations(self):
|
117
|
+
"""Test field annotations."""
|
118
|
+
annotations = self.component._field_annotations
|
119
|
+
self.assertIn("ln_id", annotations)
|
120
|
+
self.assertIn("timestamp", annotations)
|
121
|
+
|
122
|
+
def test_dynamic_field_addition(self):
|
123
|
+
"""Test adding fields dynamically to the Component."""
|
124
|
+
self.component._add_field(
|
125
|
+
"welcome", str, default="new value", value="hello world again"
|
126
|
+
)
|
127
|
+
self.assertEqual(
|
128
|
+
self.component._get_field_attr("welcome", "default"), "new value"
|
129
|
+
)
|
130
|
+
self.assertEqual(getattr(self.component, "welcome"), "hello world again")
|
131
|
+
|
132
|
+
def test_validation_error_handling(self):
|
133
|
+
"""Test handling of validation errors."""
|
134
|
+
with self.assertRaises(LionValueError):
|
135
|
+
Component.from_obj({"ln_id": 12345}) # Invalid ln_id type
|
136
|
+
|
137
|
+
def test_str_repr_methods(self):
|
138
|
+
"""Test __str__ and __repr__ methods."""
|
139
|
+
self.component.content = "example content"
|
140
|
+
self.assertIn("example content", str(self.component))
|
141
|
+
self.assertIn("example content", repr(self.component))
|
142
|
+
|
143
|
+
def test_embedded_content(self):
|
144
|
+
"""Test embedded content handling."""
|
145
|
+
embedding_str = "[1.0, 2.0, 3.0]"
|
146
|
+
self.component.embedding = self.component._validate_embedding(embedding_str)
|
147
|
+
self.assertEqual(self.component.embedding, [1.0, 2.0, 3.0])
|
148
|
+
|
149
|
+
def test_invalid_embedded_content(self):
|
150
|
+
"""Test invalid embedded content handling."""
|
151
|
+
with self.assertRaises(ValueError):
|
152
|
+
self.component._validate_embedding("[1.0, 'invalid', 3.0]")
|
153
|
+
|
154
|
+
def test_timestamp_format(self):
|
155
|
+
"""Test if the timestamp is in the correct format."""
|
156
|
+
timestamp = self.component.timestamp
|
157
|
+
try:
|
158
|
+
datetime.strptime(timestamp, "%Y-%m-%dT%H:%M:%S.%f")
|
159
|
+
except ValueError:
|
160
|
+
self.fail("Timestamp is not in the correct format")
|
161
|
+
|
162
|
+
def test_default_field_values(self):
|
163
|
+
"""Test the default values of fields."""
|
164
|
+
default_fields = self.component._all_fields
|
165
|
+
self.assertEqual(default_fields["embedding"].default, [])
|
166
|
+
self.assertEqual(default_fields["metadata"].default_factory(), {})
|
167
|
+
self.assertEqual(default_fields["extra_fields"].default_factory(), {})
|
168
|
+
self.assertIsNone(default_fields["content"].default)
|
169
|
+
|
170
|
+
def test_deeply_nested_metadata(self):
|
171
|
+
"""Test setting and getting deeply nested metadata."""
|
172
|
+
nested_value = {"level1": {"level2": {"level3": "deep_value"}}}
|
173
|
+
self.component._meta_insert(["nested", 0], nested_value)
|
174
|
+
self.assertEqual(
|
175
|
+
self.component._meta_get(["nested", 0, "level1", "level2", "level3"]),
|
176
|
+
"deep_value",
|
177
|
+
)
|
178
|
+
|
179
|
+
def test_invalid_from_obj_type(self):
|
180
|
+
"""Test invalid type in from_obj method."""
|
181
|
+
with self.assertRaises(LionTypeError):
|
182
|
+
Component.from_obj(12345) # Invalid type
|
183
|
+
|
184
|
+
def test_from_obj_pydantic_model(self):
|
185
|
+
"""Test creating a Component from a Pydantic BaseModel."""
|
186
|
+
from pydantic import BaseModel
|
187
|
+
|
188
|
+
class SampleModel(BaseModel):
|
189
|
+
name: str
|
190
|
+
age: int
|
191
|
+
|
192
|
+
sample_instance = SampleModel(name="John Doe", age=30)
|
193
|
+
new_component = Component.from_obj(sample_instance)
|
194
|
+
self.assertEqual(new_component.metadata["name"], "John Doe")
|
195
|
+
self.assertEqual(new_component.metadata["age"], 30)
|
196
|
+
|
197
|
+
def test_json_serialization_deserialization(self):
|
198
|
+
"""Test JSON serialization and deserialization."""
|
199
|
+
original_dict = self.component.to_dict()
|
200
|
+
json_str = json.dumps(original_dict)
|
201
|
+
new_component = Component.from_obj(json_str)
|
202
|
+
self.assertEqual(original_dict, new_component.to_dict())
|
203
|
+
|
204
|
+
|
205
|
+
if __name__ == "__main__":
|
206
|
+
unittest.main()
|
@@ -0,0 +1,138 @@
|
|
1
|
+
import unittest
|
2
|
+
from lionagi import Node, pile, progression
|
3
|
+
from lionagi.core.collections.abc import Element
|
4
|
+
from lionagi.core.collections import Exchange
|
5
|
+
|
6
|
+
|
7
|
+
class TestExchange(unittest.TestCase):
|
8
|
+
|
9
|
+
def setUp(self):
|
10
|
+
# Setup for creating initial nodes, piles, and progressions
|
11
|
+
self.nodes = [Node(content=i) for i in range(10)]
|
12
|
+
self.pile1 = pile(self.nodes)
|
13
|
+
self.prog1 = progression(self.nodes[:5], name="left")
|
14
|
+
self.prog2 = progression(self.nodes[5:], name="right")
|
15
|
+
self.exchange = Exchange()
|
16
|
+
|
17
|
+
def test_initialization(self):
|
18
|
+
self.assertEqual(len(self.exchange.pile), 0)
|
19
|
+
self.assertEqual(len(self.exchange.pending_ins), 0)
|
20
|
+
self.assertEqual(len(self.exchange.pending_outs), 0)
|
21
|
+
|
22
|
+
def test_include_in(self):
|
23
|
+
sender_id = "sender1"
|
24
|
+
for node in self.nodes[:5]:
|
25
|
+
node.sender = sender_id
|
26
|
+
self.exchange.include(node, "in")
|
27
|
+
|
28
|
+
self.assertEqual(len(self.exchange.pile), 5)
|
29
|
+
self.assertIn(sender_id, self.exchange.pending_ins)
|
30
|
+
self.assertEqual(len(self.exchange.pending_ins[sender_id]), 5)
|
31
|
+
|
32
|
+
def test_include_out(self):
|
33
|
+
for node in self.nodes[:5]:
|
34
|
+
self.exchange.include(node, "out")
|
35
|
+
|
36
|
+
self.assertEqual(len(self.exchange.pile), 5)
|
37
|
+
self.assertEqual(len(self.exchange.pending_outs), 5)
|
38
|
+
|
39
|
+
def test_exclude(self):
|
40
|
+
for node in self.nodes[:5]:
|
41
|
+
self.exchange.include(node, "out")
|
42
|
+
|
43
|
+
node_to_remove = self.nodes[0]
|
44
|
+
self.exchange.exclude(node_to_remove)
|
45
|
+
self.assertNotIn(node_to_remove, self.exchange.pile)
|
46
|
+
self.assertNotIn(node_to_remove, self.exchange.pending_outs)
|
47
|
+
|
48
|
+
def test_exclude_from_in(self):
|
49
|
+
sender_id = "sender1"
|
50
|
+
for node in self.nodes[:5]:
|
51
|
+
node.sender = sender_id
|
52
|
+
self.exchange.include(node, "in")
|
53
|
+
|
54
|
+
node_to_remove = self.nodes[0]
|
55
|
+
self.exchange.exclude(node_to_remove)
|
56
|
+
self.assertNotIn(node_to_remove, self.exchange.pile)
|
57
|
+
self.assertNotIn(node_to_remove, self.exchange.pending_ins[sender_id])
|
58
|
+
|
59
|
+
def test_senders(self):
|
60
|
+
sender_id = "sender1"
|
61
|
+
for node in self.nodes[:5]:
|
62
|
+
node.sender = sender_id
|
63
|
+
self.exchange.include(node, "in")
|
64
|
+
|
65
|
+
self.assertIn(sender_id, self.exchange.senders)
|
66
|
+
|
67
|
+
def test_to_dict(self):
|
68
|
+
for node in self.nodes[:5]:
|
69
|
+
self.exchange.include(node, "out")
|
70
|
+
|
71
|
+
exchange_dict = self.exchange.to_dict()
|
72
|
+
self.assertIn("pile", exchange_dict)
|
73
|
+
self.assertIn("pending_ins", exchange_dict)
|
74
|
+
self.assertIn("pending_outs", exchange_dict)
|
75
|
+
|
76
|
+
def test_bool(self):
|
77
|
+
self.assertTrue(self.exchange)
|
78
|
+
|
79
|
+
# Additional Tests for Edge Cases
|
80
|
+
def test_include_non_sendable(self):
|
81
|
+
non_sendable = Element()
|
82
|
+
with self.assertRaises(AttributeError):
|
83
|
+
self.exchange.include(non_sendable, "in")
|
84
|
+
|
85
|
+
def test_exclude_nonexistent_item(self):
|
86
|
+
non_existent_node = Node(content="nonexistent")
|
87
|
+
result = self.exchange.exclude(non_existent_node)
|
88
|
+
self.assertTrue(result)
|
89
|
+
|
90
|
+
def test_include_multiple_items_in(self):
|
91
|
+
sender_id = "sender2"
|
92
|
+
new_nodes = [Node(content="new_node1"), Node(content="new_node2")]
|
93
|
+
for new_node in new_nodes:
|
94
|
+
new_node.sender = sender_id
|
95
|
+
self.exchange.include(new_node, "in")
|
96
|
+
|
97
|
+
self.assertEqual(len(self.exchange.pile), 2)
|
98
|
+
self.assertEqual(len(self.exchange.pending_ins[sender_id]), 2)
|
99
|
+
|
100
|
+
def test_include_multiple_items_out(self):
|
101
|
+
new_nodes = [Node(content="new_node1"), Node(content="new_node2")]
|
102
|
+
for new_node in new_nodes:
|
103
|
+
self.exchange.include(new_node, "out")
|
104
|
+
|
105
|
+
self.assertEqual(len(self.exchange.pile), 2)
|
106
|
+
self.assertEqual(len(self.exchange.pending_outs), 2)
|
107
|
+
|
108
|
+
def test_exclude_from_empty_exchange(self):
|
109
|
+
result = self.exchange.exclude(Node(content="nonexistent"))
|
110
|
+
self.assertTrue(result)
|
111
|
+
|
112
|
+
def test_clear_empty_exchange(self):
|
113
|
+
self.exchange.pile.clear()
|
114
|
+
self.exchange.pending_ins.clear()
|
115
|
+
self.exchange.pending_outs.clear()
|
116
|
+
self.assertEqual(len(self.exchange.pile), 0)
|
117
|
+
self.assertEqual(len(self.exchange.pending_ins), 0)
|
118
|
+
self.assertEqual(len(self.exchange.pending_outs), 0)
|
119
|
+
|
120
|
+
def test_clear_exchange(self):
|
121
|
+
sender_id = "sender3"
|
122
|
+
for node in self.nodes[:5]:
|
123
|
+
node.sender = sender_id
|
124
|
+
self.exchange.include(node, "in")
|
125
|
+
for node in self.nodes[5:]:
|
126
|
+
self.exchange.include(node, "out")
|
127
|
+
|
128
|
+
self.exchange.pile.clear()
|
129
|
+
self.exchange.pending_ins.clear()
|
130
|
+
self.exchange.pending_outs.clear()
|
131
|
+
|
132
|
+
self.assertEqual(len(self.exchange.pile), 0)
|
133
|
+
self.assertEqual(len(self.exchange.pending_ins), 0)
|
134
|
+
self.assertEqual(len(self.exchange.pending_outs), 0)
|
135
|
+
|
136
|
+
|
137
|
+
if __name__ == "__main__":
|
138
|
+
unittest.main()
|
@@ -0,0 +1,145 @@
|
|
1
|
+
import unittest
|
2
|
+
from lionagi import Node, pile, progression, flow
|
3
|
+
|
4
|
+
|
5
|
+
class TestFlow(unittest.TestCase):
|
6
|
+
|
7
|
+
def setUp(self):
|
8
|
+
# Setup for creating initial nodes, piles, and progressions
|
9
|
+
self.nodes = [Node(content=i) for i in range(10)]
|
10
|
+
self.pile1 = pile(self.nodes)
|
11
|
+
self.prog1 = progression(self.nodes[:5], name="left")
|
12
|
+
self.prog2 = progression(self.nodes[5:], name="right")
|
13
|
+
self.flow = flow([self.prog1, self.prog2])
|
14
|
+
|
15
|
+
def test_initialization(self):
|
16
|
+
self.assertEqual(len(self.flow.sequences), 2)
|
17
|
+
self.assertIn("left", self.flow.registry)
|
18
|
+
self.assertIn("right", self.flow.registry)
|
19
|
+
|
20
|
+
def test_append_to_flow(self):
|
21
|
+
new_node = Node(content="new_node")
|
22
|
+
self.flow.append(new_node, "left")
|
23
|
+
self.assertIn(new_node.ln_id, self.flow.get("left"))
|
24
|
+
|
25
|
+
def test_exclude_from_flow(self):
|
26
|
+
node_to_remove = self.nodes[0]
|
27
|
+
self.flow.exclude("left", node_to_remove)
|
28
|
+
self.assertNotIn(node_to_remove.ln_id, self.flow.get("left"))
|
29
|
+
|
30
|
+
def test_get_sequence(self):
|
31
|
+
seq = self.flow.get("left")
|
32
|
+
self.assertEqual(seq, self.prog1)
|
33
|
+
seq_default = self.flow.get("nonexistent", default=None)
|
34
|
+
self.assertIsNone(seq_default)
|
35
|
+
|
36
|
+
def test_register_sequence(self):
|
37
|
+
new_prog = progression(self.nodes[2:4], name="middle")
|
38
|
+
self.flow.register(new_prog)
|
39
|
+
self.assertIn("middle", self.flow.registry)
|
40
|
+
|
41
|
+
def test_popleft(self):
|
42
|
+
first_node_id = self.prog1[0]
|
43
|
+
removed_node_id = self.flow.popleft("left")
|
44
|
+
self.assertEqual(first_node_id, removed_node_id)
|
45
|
+
self.assertNotIn(removed_node_id, self.flow.get("left"))
|
46
|
+
|
47
|
+
def test_shape_and_size(self):
|
48
|
+
shape = self.flow.shape()
|
49
|
+
self.assertEqual(shape["left"], 5)
|
50
|
+
self.assertEqual(shape["right"], 5)
|
51
|
+
size = self.flow.size()
|
52
|
+
self.assertEqual(size, 10)
|
53
|
+
|
54
|
+
def test_clear(self):
|
55
|
+
self.flow.clear()
|
56
|
+
self.assertEqual(len(self.flow.sequences), 0)
|
57
|
+
self.assertEqual(len(self.flow.registry), 0)
|
58
|
+
|
59
|
+
def test_iteration(self):
|
60
|
+
items = list(self.flow)
|
61
|
+
self.assertEqual(len(items), 2)
|
62
|
+
|
63
|
+
def test_to_df(self):
|
64
|
+
df = self.flow.to_df()
|
65
|
+
self.assertEqual(df.shape[0], 2)
|
66
|
+
self.assertEqual(df.columns.tolist(), ["order", "name"])
|
67
|
+
|
68
|
+
def test_inclusion_check(self):
|
69
|
+
self.assertTrue(self.prog1 in self.flow)
|
70
|
+
self.assertTrue(self.prog2 in self.flow)
|
71
|
+
try:
|
72
|
+
a = Node(content="nonexistent") in self.flow
|
73
|
+
except TypeError:
|
74
|
+
pass
|
75
|
+
|
76
|
+
# Additional Tests for Edge Cases
|
77
|
+
def test_empty_flow_initialization(self):
|
78
|
+
empty_flow = flow()
|
79
|
+
self.assertEqual(len(empty_flow.sequences), 0)
|
80
|
+
self.assertEqual(len(empty_flow.registry), 0)
|
81
|
+
|
82
|
+
def test_append_to_nonexistent_sequence(self):
|
83
|
+
new_node = Node(content="new_node")
|
84
|
+
self.flow.append(new_node, "nonexistent")
|
85
|
+
self.assertIn(new_node.ln_id, self.flow.get("nonexistent"))
|
86
|
+
|
87
|
+
def test_exclude_nonexistent_item(self):
|
88
|
+
non_existent_node = Node(content="nonexistent")
|
89
|
+
result = self.flow.exclude("left", non_existent_node)
|
90
|
+
self.assertTrue(result)
|
91
|
+
|
92
|
+
def test_exclude_nonexistent_sequence(self):
|
93
|
+
result = self.flow.exclude("nonexistent")
|
94
|
+
self.assertFalse(result)
|
95
|
+
|
96
|
+
def test_get_nonexistent_sequence(self):
|
97
|
+
try:
|
98
|
+
self.flow.get("nonexistent")
|
99
|
+
except Exception as e:
|
100
|
+
if e.__class__.__name__ == "LionTypeError":
|
101
|
+
return
|
102
|
+
raise AssertionError("LionTypeError not raised")
|
103
|
+
|
104
|
+
def test_register_existing_sequence_name(self):
|
105
|
+
with self.assertRaises(ValueError):
|
106
|
+
self.flow.register(self.prog1, name="right")
|
107
|
+
|
108
|
+
def test_popleft_nonexistent_sequence(self):
|
109
|
+
try:
|
110
|
+
self.flow.popleft("nonexistent")
|
111
|
+
except Exception as e:
|
112
|
+
if e.__class__.__name__ == "LionTypeError":
|
113
|
+
return
|
114
|
+
raise AssertionError("LionTypeError not raised")
|
115
|
+
|
116
|
+
def test_append_multiple_items(self):
|
117
|
+
new_nodes = [Node(content="new_node1"), Node(content="new_node2")]
|
118
|
+
for new_node in new_nodes:
|
119
|
+
self.flow.append(new_node, "left")
|
120
|
+
for new_node in new_nodes:
|
121
|
+
self.assertIn(new_node.ln_id, self.flow.get("left"))
|
122
|
+
|
123
|
+
def test_remove_from_all_sequences(self):
|
124
|
+
node_to_remove = self.nodes[0]
|
125
|
+
self.flow.append(node_to_remove, "right")
|
126
|
+
self.flow.remove(node_to_remove)
|
127
|
+
self.assertNotIn(node_to_remove.ln_id, self.flow.get("right"))
|
128
|
+
|
129
|
+
def test_shape_empty_flow(self):
|
130
|
+
empty_flow = flow()
|
131
|
+
self.assertEqual(empty_flow.shape(), {})
|
132
|
+
|
133
|
+
def test_size_empty_flow(self):
|
134
|
+
empty_flow = flow()
|
135
|
+
self.assertEqual(empty_flow.size(), 0)
|
136
|
+
|
137
|
+
def test_clear_empty_flow(self):
|
138
|
+
empty_flow = flow()
|
139
|
+
empty_flow.clear()
|
140
|
+
self.assertEqual(len(empty_flow.sequences), 0)
|
141
|
+
self.assertEqual(len(empty_flow.registry), 0)
|
142
|
+
|
143
|
+
|
144
|
+
if __name__ == "__main__":
|
145
|
+
unittest.main()
|