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,222 +0,0 @@
1
- import shutil
2
- import sys
3
- import tempfile
4
- import time
5
- import unittest
6
- from datetime import datetime, timezone
7
- from pathlib import Path
8
- from unittest.mock import MagicMock, patch
9
-
10
- from lionagi.libs.sys_util import SysUtil
11
-
12
-
13
- class TestSysUtil(unittest.TestCase):
14
-
15
- def test_sleep(self):
16
- start = time.time()
17
- SysUtil.sleep(0.1) # Sleep for 0.1 seconds
18
- end = time.time()
19
- self.assertTrue((end - start) >= 0.1)
20
-
21
- def test_get_now(self):
22
- # Test returning Unix timestamp
23
- timestamp = time.time()
24
- self.assertIsInstance(timestamp, float)
25
-
26
- # Test returning datetime object
27
- now = SysUtil.get_now(datetime_=True)
28
- self.assertIsInstance(now, datetime)
29
-
30
- def test_change_dict_key(self):
31
- dict_ = {"old_key": "value"}
32
- SysUtil.change_dict_key(dict_, "old_key", "new_key")
33
- self.assertIn("new_key", dict_)
34
- self.assertNotIn("old_key", dict_)
35
-
36
- def test_get_timestamp(self):
37
- timestamp = SysUtil.get_timestamp()
38
- self.assertIsInstance(timestamp, str)
39
- # Test custom separator
40
- custom_sep_timestamp = SysUtil.get_timestamp(sep="-")
41
- self.assertIn("-", custom_sep_timestamp)
42
-
43
- def test_create_copy(self):
44
- input_ = {"key": "value"}
45
- # Single copy
46
- single_copy = SysUtil.create_copy(input_)
47
- self.assertEqual(input_, single_copy)
48
- self.assertNotEqual(id(input_), id(single_copy))
49
- # Multiple copies
50
- copies = SysUtil.create_copy(input_, 2)
51
- self.assertIsInstance(copies, list)
52
- self.assertEqual(len(copies), 2)
53
- self.assertNotEqual(id(copies[0]), id(copies[1]))
54
-
55
- def test_create_id(self):
56
- id1 = SysUtil.create_id()
57
- id2 = SysUtil.create_id()
58
- self.assertIsInstance(id1, str)
59
- self.assertEqual(len(id1), 32)
60
- self.assertNotEqual(id1, id2)
61
-
62
- def test_get_bins(self):
63
- input_ = ["a" * 500, "b" * 1000, "c" * 500, "d" * 1000]
64
- bins = SysUtil.get_bins(input_)
65
- self.assertEqual(len(bins), 2)
66
- self.assertEqual(bins, [[0, 1], [2, 3]])
67
-
68
- def test_get_cpu_architecture(self):
69
- architecture = SysUtil.get_cpu_architecture()
70
- self.assertIn(architecture, ["apple_silicon", "other_cpu"])
71
-
72
- def test_is_package_installed(self):
73
- with patch("importlib.util.find_spec", return_value=None):
74
- self.assertFalse(SysUtil.is_package_installed("nonexistent_package"))
75
- with patch("importlib.util.find_spec", return_value=True):
76
- self.assertTrue(SysUtil.is_package_installed("existent_package"))
77
-
78
- @patch(
79
- "importlib.metadata.distributions",
80
- return_value=[type("", (), {"metadata": {"Name": "fake-package"}})()],
81
- )
82
- def test_list_installed_packages(self, mock_distributions):
83
- installed_packages = SysUtil.list_installed_packages()
84
- self.assertIn("fake-package", installed_packages)
85
-
86
- @patch("subprocess.check_call")
87
- def test_uninstall_package(self, mock_subprocess):
88
- SysUtil.uninstall_package("fake-package")
89
- mock_subprocess.assert_called_with(
90
- [sys.executable, "-m", "pip", "uninstall", "fake-package", "-y"]
91
- )
92
-
93
- @patch("subprocess.check_call")
94
- def test_update_package(self, mock_subprocess):
95
- SysUtil.update_package("fake-package")
96
- mock_subprocess.assert_called_with(
97
- [sys.executable, "-m", "pip", "install", "--upgrade", "fake-package"]
98
- )
99
-
100
- def test_split_path_file(self):
101
- """Test splitting a file path."""
102
- parent, name = SysUtil.split_path("/tmp/example.txt")
103
- self.assertEqual(parent, Path("/tmp"))
104
- self.assertEqual(name, "example.txt")
105
-
106
- def test_split_path_directory(self):
107
- """Test splitting a directory path."""
108
- parent, name = SysUtil.split_path("/tmp/example/")
109
- self.assertEqual(parent, Path("/tmp"))
110
- self.assertEqual(name, "example")
111
-
112
- def test_split_path_root(self):
113
- """Test splitting the root path."""
114
- parent, name = SysUtil.split_path("/")
115
- self.assertEqual(parent, Path("/"))
116
- self.assertEqual(name, "")
117
-
118
- def setUp(self):
119
- # Create a temporary directory
120
- self.test_dir = tempfile.mkdtemp()
121
-
122
- # Create some test files
123
- Path(self.test_dir, "test_file.txt").touch()
124
- Path(self.test_dir, "another_test_file.md").touch()
125
-
126
- def tearDown(self):
127
- # Remove the temporary directory after the test
128
- shutil.rmtree(self.test_dir)
129
-
130
- def test_list_files_no_extension(self):
131
- files = SysUtil.list_files(self.test_dir)
132
- self.assertEqual(len(files), 2) # Expecting 2 files
133
-
134
- def test_list_files_with_extension(self):
135
- files = SysUtil.list_files(self.test_dir, extension="txt")
136
- self.assertEqual(len(files), 1) # Expecting 1 .txt file
137
- self.assertTrue(files[0].name.endswith(".txt"))
138
-
139
- def test_change_existing_key(self):
140
- test_dict = {"old_key": "value"}
141
- SysUtil.change_dict_key(test_dict, "old_key", "new_key")
142
- self.assertIn("new_key", test_dict)
143
- self.assertNotIn("old_key", test_dict)
144
-
145
- def test_change_non_existing_key(self):
146
- test_dict = {"key": "value"}
147
- SysUtil.change_dict_key(test_dict, "non_existing_key", "new_key")
148
- self.assertNotIn("new_key", test_dict)
149
- self.assertIn("key", test_dict)
150
-
151
- def test_change_key_to_existing_key(self):
152
- test_dict = {"old_key": "value1", "new_key": "value2"}
153
- SysUtil.change_dict_key(test_dict, "old_key", "new_key")
154
- self.assertEqual(test_dict["new_key"], "value1")
155
-
156
- def test_default_separator(self):
157
- timestamp = SysUtil.get_timestamp()
158
- self.assertNotIn(":", timestamp)
159
- self.assertNotIn(".", timestamp)
160
-
161
- def test_custom_separator(self):
162
- timestamp = SysUtil.get_timestamp(sep="-")
163
- self.assertNotIn(":", timestamp)
164
- self.assertNotIn(".", timestamp)
165
- self.assertIn("-", timestamp)
166
-
167
- def test_valid_schema(self):
168
- test_dict = {"key1": 1, "key2": "value"}
169
- schema = {"key1": int, "key2": str}
170
- self.assertTrue(SysUtil.is_schema(test_dict, schema))
171
-
172
- def test_invalid_schema(self):
173
- test_dict = {"key1": "value", "key2": "value"}
174
- schema = {"key1": int, "key2": str}
175
- self.assertFalse(SysUtil.is_schema(test_dict, schema))
176
-
177
- def test_partial_schema(self):
178
- test_dict = {"key1": 1}
179
- schema = {"key1": int, "key2": str}
180
- self.assertFalse(SysUtil.is_schema(test_dict, schema))
181
-
182
- def test_single_copy(self):
183
- original = {"key": "value"}
184
- copy = SysUtil.create_copy(original)
185
- self.assertEqual(original, copy)
186
- self.assertNotEqual(id(original), id(copy))
187
-
188
- def test_multiple_copies(self):
189
- original = {"key": "value"}
190
- copies = SysUtil.create_copy(original, num=2)
191
- self.assertEqual(len(copies), 2)
192
- self.assertNotEqual(id(copies[0]), id(copies[1]))
193
-
194
- def test_invalid_num(self):
195
- with self.assertRaises(ValueError):
196
- SysUtil.create_copy({}, num=0)
197
-
198
- def test_id_length(self):
199
- id_ = SysUtil.create_id()
200
- self.assertEqual(len(id_), 32)
201
-
202
- def test_custom_length(self):
203
- id_ = SysUtil.create_id(n=16)
204
- self.assertEqual(len(id_), 16)
205
-
206
- def test_bins_with_small_strings(self):
207
- input_ = ["a", "b", "c", "d"]
208
- bins = SysUtil.get_bins(input_, upper=2)
209
- self.assertEqual(len(bins), 4)
210
-
211
- def test_bins_with_large_strings(self):
212
- input_ = ["a" * 1000, "b" * 1000, "c" * 1000]
213
- bins = SysUtil.get_bins(input_)
214
- self.assertEqual(len(bins), 3)
215
-
216
- def test_bins_with_empty_input(self):
217
- bins = SysUtil.get_bins([])
218
- self.assertEqual(len(bins), 0)
219
-
220
-
221
- if __name__ == "__main__":
222
- unittest.main()
File without changes
File without changes
@@ -1,208 +0,0 @@
1
- import json
2
- import unittest
3
- from datetime import datetime
4
-
5
- import pandas as pd
6
-
7
- from lionagi.core.collections.abc.component import (
8
- Component,
9
- LionTypeError,
10
- LionValueError,
11
- )
12
-
13
-
14
- class TestComponent(unittest.TestCase):
15
-
16
- def setUp(self):
17
- """Set up a basic Component instance for testing."""
18
- self.component = Component()
19
-
20
- def test_initialization(self):
21
- """Test basic initialization and attributes."""
22
- self.assertIsInstance(self.component.ln_id, str)
23
- self.assertIsInstance(self.component.timestamp, str)
24
- self.assertIsInstance(self.component.metadata, dict)
25
- self.assertIsNone(self.component.content)
26
- self.assertEqual(self.component.embedding, [])
27
-
28
- def test_setting_attributes(self):
29
- """Test setting and updating attributes."""
30
- self.component.content = 1
31
- self.assertEqual(self.component.content, 1)
32
- self.assertIn("content", self.component.metadata["last_updated"])
33
-
34
- def test_class_name(self):
35
- """Test the class_name property."""
36
- self.assertEqual(self.component.class_name, "Component")
37
-
38
- def test_to_dict(self):
39
- """Test converting to dictionary."""
40
- self.component.content = "example content"
41
- dict_repr = self.component.to_dict()
42
- self.assertEqual(dict_repr["content"], "example content")
43
- self.assertEqual(dict_repr["lion_class"], "Component")
44
-
45
- def test_to_json_str(self):
46
- """Test converting to JSON string."""
47
- self.component.content = "example content"
48
- json_str = self.component.to_json_str()
49
- self.assertIn('"content": "example content"', json_str)
50
-
51
- def test_to_xml(self):
52
- """Test converting to XML string."""
53
- self.component.content = "example content"
54
- xml_str = self.component.to_xml()
55
- self.assertIn("<content>example content</content>", xml_str)
56
-
57
- def test_to_pd_series(self):
58
- """Test converting to Pandas Series."""
59
- self.component.content = "example content"
60
- series = self.component.to_pd_series()
61
- self.assertEqual(series["content"], "example content")
62
-
63
- def test_from_obj_dict(self):
64
- """Test creating a Component from a dictionary."""
65
- dict_obj = {"a": 1, "b": 2}
66
- new_component = Component.from_obj(dict_obj)
67
- self.assertEqual(new_component.metadata["a"], 1)
68
- self.assertEqual(new_component.metadata["b"], 2)
69
-
70
- def test_from_obj_str(self):
71
- """Test creating a Component from a JSON string."""
72
- json_str = '{"a": 1, "b": 2}'
73
- new_component = Component.from_obj(json_str)
74
- self.assertEqual(new_component.metadata["a"], 1)
75
- self.assertEqual(new_component.metadata["b"], 2)
76
-
77
- def test_from_obj_fuzzy_str(self):
78
- """Test creating a Component from a fuzzy JSON string."""
79
- fuzzy_json_str = '{"name": "John", "age": 30, "city": ["New York", "DC", "LA"]'
80
- new_component = Component.from_obj(fuzzy_json_str, fuzzy_parse=True)
81
- self.assertEqual(new_component.metadata["name"], "John")
82
- self.assertEqual(new_component.metadata["age"], 30)
83
- self.assertEqual(new_component.metadata["city"], ["New York", "DC", "LA"])
84
-
85
- def test_from_obj_series(self):
86
- """Test creating a Component from a Pandas Series."""
87
- series_obj = pd.Series({"a": 1, "b": 2})
88
- new_component = Component.from_obj(series_obj)
89
- self.assertEqual(new_component.metadata["a"], 1)
90
- self.assertEqual(new_component.metadata["b"], 2)
91
-
92
- def test_from_obj_dataframe(self):
93
- """Test creating Components from a Pandas DataFrame."""
94
- df = pd.DataFrame({"a": [1, 2], "b": [3, 4]}, index=["row1", "row2"])
95
- components = Component.from_obj(df)
96
- self.assertEqual(len(components), 2)
97
- self.assertEqual(components[0].metadata["a"], 1)
98
- self.assertEqual(components[0].metadata["b"], 3)
99
- self.assertEqual(components[1].metadata["a"], 2)
100
- self.assertEqual(components[1].metadata["b"], 4)
101
-
102
- def test_metadata_manipulation(self):
103
- """Test manipulation of metadata."""
104
- self.component._meta_insert(["new_key"], "new_value")
105
- self.assertEqual(self.component.metadata["new_key"], "new_value")
106
- self.component._meta_set(["new_key"], "updated_value")
107
- self.assertEqual(self.component.metadata["new_key"], "updated_value")
108
- nested_value = {"a": 1, "b": 2}
109
- self.component._meta_insert(["nested", 0], nested_value)
110
- self.assertEqual(self.component.metadata["nested"][0], nested_value)
111
- self.assertEqual(self.component._meta_get(["nested", 0, "a"]), 1)
112
-
113
- def test_invalid_metadata_assignment(self):
114
- """Test invalid direct assignment to metadata."""
115
- with self.assertRaises(AttributeError):
116
- self.component.metadata = {}
117
-
118
- def test_field_annotations(self):
119
- """Test field annotations."""
120
- annotations = self.component._field_annotations
121
- self.assertIn("ln_id", annotations)
122
- self.assertIn("timestamp", annotations)
123
-
124
- def test_dynamic_field_addition(self):
125
- """Test adding fields dynamically to the Component."""
126
- self.component._add_field(
127
- "welcome", str, default="new value", value="hello world again"
128
- )
129
- self.assertEqual(
130
- self.component._get_field_attr("welcome", "default"), "new value"
131
- )
132
- self.assertEqual(getattr(self.component, "welcome"), "hello world again")
133
-
134
- def test_validation_error_handling(self):
135
- """Test handling of validation errors."""
136
- with self.assertRaises(LionValueError):
137
- Component.from_obj({"ln_id": 12345}) # Invalid ln_id type
138
-
139
- def test_str_repr_methods(self):
140
- """Test __str__ and __repr__ methods."""
141
- self.component.content = "example content"
142
- self.assertIn("example content", str(self.component))
143
- self.assertIn("example content", repr(self.component))
144
-
145
- def test_embedded_content(self):
146
- """Test embedded content handling."""
147
- embedding_str = "[1.0, 2.0, 3.0]"
148
- self.component.embedding = self.component._validate_embedding(embedding_str)
149
- self.assertEqual(self.component.embedding, [1.0, 2.0, 3.0])
150
-
151
- def test_invalid_embedded_content(self):
152
- """Test invalid embedded content handling."""
153
- with self.assertRaises(ValueError):
154
- self.component._validate_embedding("[1.0, 'invalid', 3.0]")
155
-
156
- def test_timestamp_format(self):
157
- """Test if the timestamp is in the correct format."""
158
- timestamp = self.component.timestamp
159
- try:
160
- datetime.strptime(timestamp, "%Y-%m-%dT%H:%M:%S.%f")
161
- except ValueError:
162
- self.fail("Timestamp is not in the correct format")
163
-
164
- def test_default_field_values(self):
165
- """Test the default values of fields."""
166
- default_fields = self.component._all_fields
167
- self.assertEqual(default_fields["embedding"].default, [])
168
- self.assertEqual(default_fields["metadata"].default_factory(), {})
169
- self.assertEqual(default_fields["extra_fields"].default_factory(), {})
170
- self.assertIsNone(default_fields["content"].default)
171
-
172
- def test_deeply_nested_metadata(self):
173
- """Test setting and getting deeply nested metadata."""
174
- nested_value = {"level1": {"level2": {"level3": "deep_value"}}}
175
- self.component._meta_insert(["nested", 0], nested_value)
176
- self.assertEqual(
177
- self.component._meta_get(["nested", 0, "level1", "level2", "level3"]),
178
- "deep_value",
179
- )
180
-
181
- def test_invalid_from_obj_type(self):
182
- """Test invalid type in from_obj method."""
183
- with self.assertRaises(LionTypeError):
184
- Component.from_obj(12345) # Invalid type
185
-
186
- def test_from_obj_pydantic_model(self):
187
- """Test creating a Component from a Pydantic BaseModel."""
188
- from pydantic import BaseModel
189
-
190
- class SampleModel(BaseModel):
191
- name: str
192
- age: int
193
-
194
- sample_instance = SampleModel(name="John Doe", age=30)
195
- new_component = Component.from_obj(sample_instance)
196
- self.assertEqual(new_component.metadata["name"], "John Doe")
197
- self.assertEqual(new_component.metadata["age"], 30)
198
-
199
- def test_json_serialization_deserialization(self):
200
- """Test JSON serialization and deserialization."""
201
- original_dict = self.component.to_dict()
202
- json_str = json.dumps(original_dict)
203
- new_component = Component.from_obj(json_str)
204
- self.assertEqual(original_dict, new_component.to_dict())
205
-
206
-
207
- if __name__ == "__main__":
208
- unittest.main()
@@ -1,139 +0,0 @@
1
- import unittest
2
-
3
- from lionagi import Node, pile, progression
4
- from lionagi.core.collections import Exchange
5
- from lionagi.core.collections.abc import Element
6
-
7
-
8
- class TestExchange(unittest.TestCase):
9
-
10
- def setUp(self):
11
- # Setup for creating initial nodes, piles, and progressions
12
- self.nodes = [Node(content=i) for i in range(10)]
13
- self.pile1 = pile(self.nodes)
14
- self.prog1 = progression(self.nodes[:5], name="left")
15
- self.prog2 = progression(self.nodes[5:], name="right")
16
- self.exchange = Exchange()
17
-
18
- def test_initialization(self):
19
- self.assertEqual(len(self.exchange.pile), 0)
20
- self.assertEqual(len(self.exchange.pending_ins), 0)
21
- self.assertEqual(len(self.exchange.pending_outs), 0)
22
-
23
- def test_include_in(self):
24
- sender_id = "sender1"
25
- for node in self.nodes[:5]:
26
- node.sender = sender_id
27
- self.exchange.include(node, "in")
28
-
29
- self.assertEqual(len(self.exchange.pile), 5)
30
- self.assertIn(sender_id, self.exchange.pending_ins)
31
- self.assertEqual(len(self.exchange.pending_ins[sender_id]), 5)
32
-
33
- def test_include_out(self):
34
- for node in self.nodes[:5]:
35
- self.exchange.include(node, "out")
36
-
37
- self.assertEqual(len(self.exchange.pile), 5)
38
- self.assertEqual(len(self.exchange.pending_outs), 5)
39
-
40
- def test_exclude(self):
41
- for node in self.nodes[:5]:
42
- self.exchange.include(node, "out")
43
-
44
- node_to_remove = self.nodes[0]
45
- self.exchange.exclude(node_to_remove)
46
- self.assertNotIn(node_to_remove, self.exchange.pile)
47
- self.assertNotIn(node_to_remove, self.exchange.pending_outs)
48
-
49
- def test_exclude_from_in(self):
50
- sender_id = "sender1"
51
- for node in self.nodes[:5]:
52
- node.sender = sender_id
53
- self.exchange.include(node, "in")
54
-
55
- node_to_remove = self.nodes[0]
56
- self.exchange.exclude(node_to_remove)
57
- self.assertNotIn(node_to_remove, self.exchange.pile)
58
- self.assertNotIn(node_to_remove, self.exchange.pending_ins[sender_id])
59
-
60
- def test_senders(self):
61
- sender_id = "sender1"
62
- for node in self.nodes[:5]:
63
- node.sender = sender_id
64
- self.exchange.include(node, "in")
65
-
66
- self.assertIn(sender_id, self.exchange.senders)
67
-
68
- def test_to_dict(self):
69
- for node in self.nodes[:5]:
70
- self.exchange.include(node, "out")
71
-
72
- exchange_dict = self.exchange.to_dict()
73
- self.assertIn("pile", exchange_dict)
74
- self.assertIn("pending_ins", exchange_dict)
75
- self.assertIn("pending_outs", exchange_dict)
76
-
77
- def test_bool(self):
78
- self.assertTrue(self.exchange)
79
-
80
- # Additional Tests for Edge Cases
81
- def test_include_non_sendable(self):
82
- non_sendable = Element()
83
- with self.assertRaises(AttributeError):
84
- self.exchange.include(non_sendable, "in")
85
-
86
- def test_exclude_nonexistent_item(self):
87
- non_existent_node = Node(content="nonexistent")
88
- result = self.exchange.exclude(non_existent_node)
89
- self.assertTrue(result)
90
-
91
- def test_include_multiple_items_in(self):
92
- sender_id = "sender2"
93
- new_nodes = [Node(content="new_node1"), Node(content="new_node2")]
94
- for new_node in new_nodes:
95
- new_node.sender = sender_id
96
- self.exchange.include(new_node, "in")
97
-
98
- self.assertEqual(len(self.exchange.pile), 2)
99
- self.assertEqual(len(self.exchange.pending_ins[sender_id]), 2)
100
-
101
- def test_include_multiple_items_out(self):
102
- new_nodes = [Node(content="new_node1"), Node(content="new_node2")]
103
- for new_node in new_nodes:
104
- self.exchange.include(new_node, "out")
105
-
106
- self.assertEqual(len(self.exchange.pile), 2)
107
- self.assertEqual(len(self.exchange.pending_outs), 2)
108
-
109
- def test_exclude_from_empty_exchange(self):
110
- result = self.exchange.exclude(Node(content="nonexistent"))
111
- self.assertTrue(result)
112
-
113
- def test_clear_empty_exchange(self):
114
- self.exchange.pile.clear()
115
- self.exchange.pending_ins.clear()
116
- self.exchange.pending_outs.clear()
117
- self.assertEqual(len(self.exchange.pile), 0)
118
- self.assertEqual(len(self.exchange.pending_ins), 0)
119
- self.assertEqual(len(self.exchange.pending_outs), 0)
120
-
121
- def test_clear_exchange(self):
122
- sender_id = "sender3"
123
- for node in self.nodes[:5]:
124
- node.sender = sender_id
125
- self.exchange.include(node, "in")
126
- for node in self.nodes[5:]:
127
- self.exchange.include(node, "out")
128
-
129
- self.exchange.pile.clear()
130
- self.exchange.pending_ins.clear()
131
- self.exchange.pending_outs.clear()
132
-
133
- self.assertEqual(len(self.exchange.pile), 0)
134
- self.assertEqual(len(self.exchange.pending_ins), 0)
135
- self.assertEqual(len(self.exchange.pending_outs), 0)
136
-
137
-
138
- if __name__ == "__main__":
139
- unittest.main()