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,146 +0,0 @@
1
- import unittest
2
-
3
- from lionagi import Node, flow, pile, progression
4
-
5
-
6
- class TestFlow(unittest.TestCase):
7
-
8
- def setUp(self):
9
- # Setup for creating initial nodes, piles, and progressions
10
- self.nodes = [Node(content=i) for i in range(10)]
11
- self.pile1 = pile(self.nodes)
12
- self.prog1 = progression(self.nodes[:5], name="left")
13
- self.prog2 = progression(self.nodes[5:], name="right")
14
- self.flow = flow([self.prog1, self.prog2])
15
-
16
- def test_initialization(self):
17
- self.assertEqual(len(self.flow.sequences), 2)
18
- self.assertIn("left", self.flow.registry)
19
- self.assertIn("right", self.flow.registry)
20
-
21
- def test_append_to_flow(self):
22
- new_node = Node(content="new_node")
23
- self.flow.append(new_node, "left")
24
- self.assertIn(new_node.ln_id, self.flow.get("left"))
25
-
26
- def test_exclude_from_flow(self):
27
- node_to_remove = self.nodes[0]
28
- self.flow.exclude("left", node_to_remove)
29
- self.assertNotIn(node_to_remove.ln_id, self.flow.get("left"))
30
-
31
- def test_get_sequence(self):
32
- seq = self.flow.get("left")
33
- self.assertEqual(seq, self.prog1)
34
- seq_default = self.flow.get("nonexistent", default=None)
35
- self.assertIsNone(seq_default)
36
-
37
- def test_register_sequence(self):
38
- new_prog = progression(self.nodes[2:4], name="middle")
39
- self.flow.register(new_prog)
40
- self.assertIn("middle", self.flow.registry)
41
-
42
- def test_popleft(self):
43
- first_node_id = self.prog1[0]
44
- removed_node_id = self.flow.popleft("left")
45
- self.assertEqual(first_node_id, removed_node_id)
46
- self.assertNotIn(removed_node_id, self.flow.get("left"))
47
-
48
- def test_shape_and_size(self):
49
- shape = self.flow.shape()
50
- self.assertEqual(shape["left"], 5)
51
- self.assertEqual(shape["right"], 5)
52
- size = self.flow.size()
53
- self.assertEqual(size, 10)
54
-
55
- def test_clear(self):
56
- self.flow.clear()
57
- self.assertEqual(len(self.flow.sequences), 0)
58
- self.assertEqual(len(self.flow.registry), 0)
59
-
60
- def test_iteration(self):
61
- items = list(self.flow)
62
- self.assertEqual(len(items), 2)
63
-
64
- def test_to_df(self):
65
- df = self.flow.to_df()
66
- self.assertEqual(df.shape[0], 2)
67
- self.assertEqual(df.columns.tolist(), ["order", "name"])
68
-
69
- def test_inclusion_check(self):
70
- self.assertTrue(self.prog1 in self.flow)
71
- self.assertTrue(self.prog2 in self.flow)
72
- try:
73
- a = Node(content="nonexistent") in self.flow
74
- except TypeError:
75
- pass
76
-
77
- # Additional Tests for Edge Cases
78
- def test_empty_flow_initialization(self):
79
- empty_flow = flow()
80
- self.assertEqual(len(empty_flow.sequences), 0)
81
- self.assertEqual(len(empty_flow.registry), 0)
82
-
83
- def test_append_to_nonexistent_sequence(self):
84
- new_node = Node(content="new_node")
85
- self.flow.append(new_node, "nonexistent")
86
- self.assertIn(new_node.ln_id, self.flow.get("nonexistent"))
87
-
88
- def test_exclude_nonexistent_item(self):
89
- non_existent_node = Node(content="nonexistent")
90
- result = self.flow.exclude("left", non_existent_node)
91
- self.assertTrue(result)
92
-
93
- def test_exclude_nonexistent_sequence(self):
94
- result = self.flow.exclude("nonexistent")
95
- self.assertFalse(result)
96
-
97
- def test_get_nonexistent_sequence(self):
98
- try:
99
- self.flow.get("nonexistent")
100
- except Exception as e:
101
- if e.__class__.__name__ == "LionTypeError":
102
- return
103
- raise AssertionError("LionTypeError not raised")
104
-
105
- def test_register_existing_sequence_name(self):
106
- with self.assertRaises(ValueError):
107
- self.flow.register(self.prog1, name="right")
108
-
109
- def test_popleft_nonexistent_sequence(self):
110
- try:
111
- self.flow.popleft("nonexistent")
112
- except Exception as e:
113
- if e.__class__.__name__ == "LionTypeError":
114
- return
115
- raise AssertionError("LionTypeError not raised")
116
-
117
- def test_append_multiple_items(self):
118
- new_nodes = [Node(content="new_node1"), Node(content="new_node2")]
119
- for new_node in new_nodes:
120
- self.flow.append(new_node, "left")
121
- for new_node in new_nodes:
122
- self.assertIn(new_node.ln_id, self.flow.get("left"))
123
-
124
- def test_remove_from_all_sequences(self):
125
- node_to_remove = self.nodes[0]
126
- self.flow.append(node_to_remove, "right")
127
- self.flow.remove(node_to_remove)
128
- self.assertNotIn(node_to_remove.ln_id, self.flow.get("right"))
129
-
130
- def test_shape_empty_flow(self):
131
- empty_flow = flow()
132
- self.assertEqual(empty_flow.shape(), {})
133
-
134
- def test_size_empty_flow(self):
135
- empty_flow = flow()
136
- self.assertEqual(empty_flow.size(), 0)
137
-
138
- def test_clear_empty_flow(self):
139
- empty_flow = flow()
140
- empty_flow.clear()
141
- self.assertEqual(len(empty_flow.sequences), 0)
142
- self.assertEqual(len(empty_flow.registry), 0)
143
-
144
-
145
- if __name__ == "__main__":
146
- unittest.main()
@@ -1,172 +0,0 @@
1
- import asyncio
2
- import unittest
3
-
4
- from lionagi import Node
5
- from lionagi.core.collections.pile import Pile
6
-
7
-
8
- class TestPile(unittest.TestCase):
9
-
10
- def setUp(self):
11
- """Create initial nodes and piles for testing."""
12
- self.nodes1 = [Node(content=i) for i in ["A", "B", "C"]]
13
- self.nodes2 = [Node(content=i) for i in ["D", "E", "F"]]
14
- self.p1 = Pile(self.nodes1)
15
- self.p2 = Pile(self.nodes2)
16
-
17
- def test_add_piles(self):
18
- """Test adding two piles."""
19
- combined_pile = self.p1 + self.p2
20
- self.assertEqual(len(combined_pile), 6)
21
- contents = [node.content for node in combined_pile.values()]
22
- self.assertListEqual(contents, ["A", "B", "C", "D", "E", "F"])
23
-
24
- def test_subtract_piles(self):
25
- """Test subtracting nodes from a pile."""
26
- with self.assertRaises(Exception):
27
- result_pile = self.p1 - self.nodes2[0] # D not in p1
28
-
29
- def test_containment(self):
30
- """Test containment check."""
31
- self.assertIn(self.nodes1[1], self.p1) # B in p1
32
- self.assertNotIn(self.nodes2[0], self.p1) # D not in p1
33
-
34
- def test_include_nodes(self):
35
- """Test including nodes in a pile."""
36
- self.p1.include(self.nodes2)
37
- self.assertEqual(len(self.p1), 6)
38
- contents = [node.content for node in self.p1.values()]
39
- self.assertListEqual(contents, ["A", "B", "C", "D", "E", "F"])
40
-
41
- def test_exclude_nodes(self):
42
- """Test excluding nodes from a pile."""
43
- self.p1.include(self.nodes2) # Include first to have something to exclude
44
- self.p1.exclude(self.nodes2)
45
- self.assertEqual(len(self.p1), 5)
46
- contents = [node.content for node in self.p1.values()]
47
- self.assertListEqual(contents, ["A", "B", "C", "E", "F"])
48
-
49
- def test_get_item_by_index(self):
50
- """Test getting an item by index."""
51
- node = self.p1[0]
52
- self.assertEqual(node.content, "A")
53
-
54
- def test_set_item_by_index(self):
55
- """Test setting an item at a specific index."""
56
- new_node = Node(content="Updated Node")
57
- self.p1[0] = new_node
58
- self.assertEqual(self.p1[0].content, "Updated Node")
59
-
60
- def test_insert_item(self):
61
- """Test inserting an item at a specific position."""
62
- new_node = Node(content="Inserted Node")
63
- self.p1.insert(0, new_node)
64
- self.assertEqual(self.p1[0].content, "Inserted Node")
65
- self.assertEqual(len(self.p1), 4)
66
-
67
- def test_homogenous(self):
68
- """Test if all items in the pile are of the same type."""
69
- self.assertTrue(self.p1.is_homogenous())
70
- with self.assertRaises(AttributeError):
71
- mixed_pile = Pile(self.nodes1 + [123]) # Adding an int to mix types
72
-
73
- def test_is_empty(self):
74
- """Test if the pile is empty."""
75
- empty_pile = Pile()
76
- self.assertTrue(empty_pile.is_empty())
77
- self.assertFalse(self.p1.is_empty())
78
-
79
- def test_pop_item(self):
80
- """Test popping an item from the pile."""
81
- popped_node = self.p1.pop(self.nodes1[0].ln_id)
82
- self.assertEqual(popped_node.content, "A")
83
- self.assertEqual(len(self.p1), 2)
84
-
85
- def test_clear_pile(self):
86
- """Test clearing the pile."""
87
- self.p1.clear()
88
- self.assertTrue(self.p1.is_empty())
89
-
90
- def test_update_pile(self):
91
- """Test updating the pile with another pile."""
92
- self.p1.update(self.p2)
93
- self.assertEqual(len(self.p1), 6)
94
- contents = [node.content for node in self.p1.values()]
95
- self.assertListEqual(contents, ["A", "B", "C", "D", "E", "F"])
96
-
97
- def test_to_dataframe(self):
98
- """Test converting the pile to a DataFrame."""
99
- df = self.p1.to_df()
100
- self.assertEqual(len(df), 3)
101
- self.assertListEqual(df["content"].tolist(), ["A", "B", "C"])
102
-
103
- def test_create_index(self):
104
- """Test creating an index for the pile."""
105
- with self.assertRaises(ValueError):
106
- self.p1.create_index(index_type="llama_index")
107
-
108
- def test_create_query_engine(self):
109
- """Test creating a query engine for the pile."""
110
- with self.assertRaises(ValueError):
111
- self.p1.create_query_engine(index_type="llama_index")
112
-
113
- def test_create_chat_engine(self):
114
- """Test creating a chat engine for the pile."""
115
- with self.assertRaises(ValueError):
116
- self.p1.create_chat_engine(index_type="llama_index")
117
-
118
- # async def test_query_pile(self):
119
- # """Test querying the pile."""
120
- # self.p1.create_query_engine(index_type="llama_index")
121
- # response = await self.p1.query_pile(query="test query")
122
- # self.assertIsInstance(response, str)
123
-
124
- # async def test_chat_pile(self):
125
- # """Test chatting with the pile."""
126
- # self.p1.create_chat_engine(index_type="llama_index")
127
- # response = await self.p1.chat_pile(query="test chat")
128
- # self.assertIsInstance(response, str)
129
-
130
- # async def test_embed_pile(self):
131
- # """Test embedding the items in the pile."""
132
- # await self.p1.embed_pile()
133
- # for node in self.p1.values():
134
- # self.assertIn("embedding", node._all_fields)
135
-
136
- def test_to_csv(self):
137
- """Test saving the pile to a CSV file."""
138
- self.p1.to_csv("test_pile.csv")
139
- with open("test_pile.csv", "r") as f:
140
- content = f.read()
141
- self.assertIn("content", content)
142
-
143
- def test_from_csv(self):
144
- """Test loading a pile from a CSV file."""
145
- self.p1.to_csv("test_pile.csv")
146
- loaded_pile = Pile.from_csv("test_pile.csv")
147
- self.assertEqual(len(loaded_pile), 3)
148
- self.assertEqual(loaded_pile[0].content, "A")
149
-
150
- def test_from_dataframe(self):
151
- """Test loading a pile from a DataFrame."""
152
- df = self.p1.to_df()
153
- loaded_pile = Pile.from_df(df)
154
- self.assertEqual(len(loaded_pile), 3)
155
- self.assertEqual(loaded_pile[0].content, "A")
156
-
157
- def test_as_query_tool(self):
158
- """Test creating a query tool for the pile."""
159
- with self.assertRaises(ValueError):
160
- tool = self.p1.as_query_tool(index_type="llama_index")
161
-
162
- def test_str_representation(self):
163
- """Test the string representation of the pile."""
164
- self.assertIsInstance(str(self.p1), str)
165
-
166
- def test_repr_representation(self):
167
- """Test the representation of the pile."""
168
- self.assertIsInstance(repr(self.p1), str)
169
-
170
-
171
- if __name__ == "__main__":
172
- unittest.main()
@@ -1,130 +0,0 @@
1
- import unittest
2
-
3
- from lionagi import Node
4
- from lionagi.core.collections import Progression
5
- from lionagi.core.collections.abc import ItemNotFoundError
6
-
7
-
8
- class TestProgression(unittest.TestCase):
9
-
10
- def setUp(self):
11
- self.nodes = [Node() for _ in range(5)]
12
- self.p = Progression(order=[node.ln_id for node in self.nodes])
13
-
14
- def test_initial_order(self):
15
- self.assertEqual(self.p.order, [node.ln_id for node in self.nodes])
16
-
17
- def test_append_node(self):
18
- new_node = Node()
19
- self.p.append(new_node)
20
- self.assertIn(new_node.ln_id, self.p.order)
21
- self.assertEqual(len(self.p), 6)
22
-
23
- def test_extend_single_node(self):
24
- new_node = Node()
25
- self.p.extend(new_node)
26
- self.assertIn(new_node.ln_id, self.p.order)
27
- self.assertEqual(len(self.p), 6)
28
-
29
- def test_extend_multiple_nodes(self):
30
- new_nodes = [Node() for _ in range(3)]
31
- self.p.extend(new_nodes)
32
- for node in new_nodes:
33
- self.assertIn(node.ln_id, self.p.order)
34
- self.assertEqual(len(self.p), 8)
35
-
36
- def test_include_node(self):
37
- new_node = Node()
38
- self.p.include(new_node)
39
- self.assertIn(new_node.ln_id, self.p.order)
40
-
41
- def test_getitem_slice(self):
42
- slice_result = self.p[1:5]
43
- self.assertEqual(slice_result.order, self.p.order[1:5])
44
-
45
- def test_setitem(self):
46
- new_node = Node()
47
- self.p[0] = new_node.ln_id
48
- self.assertEqual(self.p[0], new_node.ln_id)
49
-
50
- def test_add_node(self):
51
- new_node = Node()
52
- new_prog = self.p + new_node
53
- self.assertIn(new_node.ln_id, new_prog.order)
54
-
55
- def test_iadd_node(self):
56
- new_node = Node()
57
- self.p += new_node
58
- self.assertIn(new_node.ln_id, self.p.order)
59
-
60
- def test_subtract_node(self):
61
- node_to_remove = self.nodes[0]
62
- self.p -= node_to_remove.ln_id
63
- self.assertNotIn(node_to_remove.ln_id, self.p.order)
64
-
65
- def test_isubtract_node(self):
66
- node_to_remove = self.nodes[0]
67
- self.p -= node_to_remove.ln_id
68
- self.assertNotIn(node_to_remove.ln_id, self.p.order)
69
-
70
- def test_popleft(self):
71
- leftmost = self.p.order[0]
72
- self.assertEqual(self.p.popleft(), leftmost)
73
- self.assertNotIn(leftmost, self.p.order)
74
-
75
- def test_exclude_node(self):
76
- node_to_exclude = self.nodes[0]
77
- self.p.exclude(node_to_exclude.ln_id)
78
- self.assertNotIn(node_to_exclude.ln_id, self.p.order)
79
-
80
- def test_clear(self):
81
- self.p.clear()
82
- self.assertEqual(len(self.p), 0)
83
-
84
- def test_to_dict(self):
85
- p_dict = self.p.to_dict()
86
- self.assertEqual(p_dict["order"], self.p.order)
87
- self.assertEqual(p_dict["name"], self.p.name)
88
-
89
- def test_bool(self):
90
- self.assertTrue(bool(self.p))
91
-
92
- def test_remove_nonexistent_node(self):
93
- non_existent_node = Node()
94
- with self.assertRaises(ItemNotFoundError):
95
- self.p.remove(non_existent_node.ln_id)
96
-
97
- def test_pop_index_error(self):
98
- with self.assertRaises(ItemNotFoundError):
99
- self.p.pop(100)
100
-
101
- def test_popleft_index_error(self):
102
- empty_prog = Progression()
103
- with self.assertRaises(ItemNotFoundError):
104
- empty_prog.popleft()
105
-
106
- def test_iteration(self):
107
- nodes_list = [node.ln_id for node in self.nodes]
108
- for i, node in enumerate(self.p):
109
- self.assertEqual(node, nodes_list[i])
110
-
111
- def test_contains(self):
112
- node_to_check = self.nodes[0]
113
- self.assertIn(node_to_check.ln_id, self.p)
114
-
115
- def test_not_contains(self):
116
- non_existent_node = Node()
117
- self.assertNotIn(non_existent_node.ln_id, self.p)
118
-
119
- def test_equality(self):
120
- new_prog = Progression(order=[node.ln_id for node in self.nodes])
121
- self.assertEqual(self.p.order, new_prog.order)
122
-
123
- def test_inequality(self):
124
- new_node = Node()
125
- new_prog = self.p + new_node
126
- self.assertNotEqual(self.p.order, new_prog)
127
-
128
-
129
- if __name__ == "__main__":
130
- unittest.main()
File without changes
@@ -1,69 +0,0 @@
1
- import unittest
2
- from unittest.mock import AsyncMock, patch
3
-
4
- from pydantic import ValidationError
5
-
6
- from lionagi.core.collections.abc import Component, Condition, LionIDable, get_lion_id
7
- from lionagi.core.generic.edge import Edge
8
- from lionagi.core.generic.edge_condition import EdgeCondition
9
-
10
-
11
- class TestEdge(unittest.TestCase):
12
-
13
- def setUp(self):
14
- self.node1 = Component()
15
- self.node2 = Component()
16
- self.edge = Edge(head=self.node1.ln_id, tail=self.node2.ln_id)
17
-
18
- def test_initialization(self):
19
- """Test initialization of the Edge class."""
20
- self.assertEqual(self.edge.head, self.node1.ln_id)
21
- self.assertEqual(self.edge.tail, self.node2.ln_id)
22
- self.assertIsNone(self.edge.condition)
23
- self.assertIsNone(self.edge.label)
24
- self.assertFalse(self.edge.bundle)
25
-
26
- async def test_check_condition_without_condition(self):
27
- """Test check_condition raises ValueError when condition is not set."""
28
- with self.assertRaises(ValueError):
29
- await self.edge.check_condition({})
30
-
31
- @patch("lionagi.core.models.edge.EdgeCondition.applies", new_callable=AsyncMock)
32
- async def test_check_condition_with_condition(self, mock_applies):
33
- """Test check_condition with a set condition."""
34
- mock_applies.return_value = True
35
- condition = EdgeCondition()
36
- self.edge.condition = condition
37
- result = await self.edge.check_condition({})
38
- self.assertTrue(result)
39
- mock_applies.assert_awaited_once()
40
-
41
- def test_validate_head_tail(self):
42
- """Test the head and tail validation."""
43
- try:
44
- valid_id = get_lion_id("valid_head")
45
- except Exception as e:
46
- if e.__class__.__name__ == "LionTypeError":
47
- return
48
- self.assertEqual(Edge._validate_head_tail(valid_id), valid_id)
49
- with self.assertRaises(ValidationError):
50
- Edge._validate_head_tail("invalid_id")
51
-
52
- def test_string_condition_none(self):
53
- """Test string_condition method when condition is None."""
54
- self.assertIsNone(self.edge.string_condition())
55
-
56
- def test_len(self):
57
- """Test the __len__ method."""
58
- self.assertEqual(len(self.edge), 1)
59
-
60
- def test_contains(self):
61
- """Test the __contains__ method."""
62
- self.assertIn(self.node1.ln_id, self.edge)
63
- self.assertIn(self.node2.ln_id, self.edge)
64
- fake_node = Component()
65
- self.assertNotIn(fake_node.ln_id, self.edge)
66
-
67
-
68
- if __name__ == "__main__":
69
- unittest.main()
@@ -1,97 +0,0 @@
1
- import unittest
2
-
3
- from lionagi.core.collections.abc import ItemNotFoundError, LionTypeError
4
- from lionagi.core.generic import Edge, Graph, Node
5
- from lionagi.libs.ln_convert import to_list
6
-
7
-
8
- class TestGraph(unittest.TestCase):
9
-
10
- def setUp(self):
11
- """Set up a basic graph for testing."""
12
- self.node1 = Node()
13
- self.node2 = Node()
14
- self.node3 = Node()
15
- self.node4 = Node()
16
- self.g = Graph()
17
-
18
- def test_initial_size(self):
19
- """Test the initial size of the graph."""
20
- self.assertEqual(self.g.size(), 0)
21
-
22
- def test_initial_internal_edges(self):
23
- """Test the initial number of internal edges."""
24
- self.assertEqual(len(self.g.internal_edges), 0)
25
-
26
- def test_add_node_no_edge(self):
27
- """Test that adding nodes does not create any edges."""
28
- self.g.add_node([self.node1, self.node2, self.node3, self.node4])
29
- self.assertEqual(len(self.g.internal_edges), 0)
30
-
31
- def test_add_edges(self):
32
- """Test adding edges between nodes."""
33
- self.g.add_edge(self.node1, self.node2)
34
- self.g.add_edge(self.node2, self.node3)
35
- self.g.add_edge(self.node3, self.node4)
36
- self.assertEqual(len(self.g.internal_edges), 3)
37
-
38
- def test_get_node(self):
39
- """Test retrieving a node by its identifier."""
40
- self.g.add_node(self.node2)
41
- node5 = self.g.get_node(self.node2)
42
- self.assertEqual(node5, self.node2)
43
-
44
- def test_get_node_edges(self):
45
- """Test getting the edges of a node."""
46
- self.g.add_edge(self.node1, self.node2)
47
- self.assertEqual(len(self.g.get_node_edges(self.node1)), 1)
48
-
49
- def test_get_heads(self):
50
- """Test getting head nodes."""
51
- self.g.add_edge(self.node1, self.node2)
52
- self.g.add_edge(self.node2, self.node3)
53
- self.g.add_edge(self.node3, self.node4)
54
- self.assertEqual(len(self.g.get_heads()), 1)
55
-
56
- def test_is_acyclic(self):
57
- """Test if the graph is acyclic."""
58
- self.g.add_edge(self.node1, self.node2)
59
- self.g.add_edge(self.node2, self.node3)
60
- self.g.add_edge(self.node3, self.node4)
61
- self.assertTrue(self.g.is_acyclic())
62
-
63
- def test_remove_edge(self):
64
- """Test removing an edge from the graph."""
65
- self.g.add_edge(self.node1, self.node2)
66
- self.g.add_edge(self.node2, self.node3)
67
- self.g.add_edge(self.node3, self.node4)
68
- edge = self.g.internal_edges[0]
69
- self.g.remove_edge(edge)
70
- self.assertEqual(len(self.g.internal_edges), 2)
71
-
72
- def test_remove_nonexistent_edge(self):
73
- """Test removing a nonexistent edge."""
74
- self.g.add_edge(self.node1, self.node2)
75
- with self.assertRaises(ItemNotFoundError):
76
- self.g.remove_edge(edge=Edge(head=self.node2, tail=self.node3))
77
-
78
- def test_clear(self):
79
- """Test clearing all nodes and edges from the graph."""
80
- self.g.add_node([self.node1, self.node2, self.node3, self.node4])
81
- self.g.add_edge(self.node1, self.node2)
82
- self.g.add_edge(self.node2, self.node3)
83
- self.g.add_edge(self.node3, self.node4)
84
- self.g.clear()
85
- self.assertTrue(self.g.is_empty())
86
- self.assertEqual(len(self.g.internal_edges), 0)
87
-
88
- def test_display(self):
89
- """Test displaying the graph (visual check)."""
90
- self.g.add_edge(self.node1, self.node2)
91
- self.g.add_edge(self.node2, self.node3)
92
- self.g.add_edge(self.node3, self.node4)
93
- self.g.display() # This should display the graph visually
94
-
95
-
96
- if __name__ == "__main__":
97
- unittest.main()