lionagi 0.0.115__py3-none-any.whl → 0.0.204__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (123) hide show
  1. lionagi/__init__.py +1 -2
  2. lionagi/_services/__init__.py +5 -0
  3. lionagi/_services/anthropic.py +79 -0
  4. lionagi/_services/base_service.py +414 -0
  5. lionagi/_services/oai.py +98 -0
  6. lionagi/_services/openrouter.py +44 -0
  7. lionagi/_services/services.py +91 -0
  8. lionagi/_services/transformers.py +46 -0
  9. lionagi/bridge/langchain.py +26 -16
  10. lionagi/bridge/llama_index.py +50 -20
  11. lionagi/configs/oai_configs.py +2 -14
  12. lionagi/configs/openrouter_configs.py +2 -2
  13. lionagi/core/__init__.py +7 -8
  14. lionagi/core/branch/branch.py +589 -0
  15. lionagi/core/branch/branch_manager.py +139 -0
  16. lionagi/core/branch/conversation.py +484 -0
  17. lionagi/core/core_util.py +59 -0
  18. lionagi/core/flow/flow.py +19 -0
  19. lionagi/core/flow/flow_util.py +62 -0
  20. lionagi/core/instruction_set/__init__.py +0 -5
  21. lionagi/core/instruction_set/instruction_set.py +343 -0
  22. lionagi/core/messages/messages.py +176 -0
  23. lionagi/core/sessions/__init__.py +0 -5
  24. lionagi/core/sessions/session.py +428 -0
  25. lionagi/loaders/chunker.py +51 -47
  26. lionagi/loaders/load_util.py +2 -2
  27. lionagi/loaders/reader.py +45 -39
  28. lionagi/models/imodel.py +53 -0
  29. lionagi/schema/async_queue.py +158 -0
  30. lionagi/schema/base_node.py +318 -147
  31. lionagi/schema/base_tool.py +31 -1
  32. lionagi/schema/data_logger.py +74 -38
  33. lionagi/schema/data_node.py +57 -6
  34. lionagi/structures/graph.py +132 -10
  35. lionagi/structures/relationship.py +58 -20
  36. lionagi/structures/structure.py +36 -25
  37. lionagi/tests/test_utils/test_api_util.py +219 -0
  38. lionagi/tests/test_utils/test_call_util.py +785 -0
  39. lionagi/tests/test_utils/test_encrypt_util.py +323 -0
  40. lionagi/tests/test_utils/test_io_util.py +238 -0
  41. lionagi/tests/test_utils/test_nested_util.py +338 -0
  42. lionagi/tests/test_utils/test_sys_util.py +358 -0
  43. lionagi/tools/tool_manager.py +186 -0
  44. lionagi/tools/tool_util.py +266 -3
  45. lionagi/utils/__init__.py +21 -61
  46. lionagi/utils/api_util.py +359 -71
  47. lionagi/utils/call_util.py +839 -264
  48. lionagi/utils/encrypt_util.py +283 -16
  49. lionagi/utils/io_util.py +178 -93
  50. lionagi/utils/nested_util.py +672 -0
  51. lionagi/utils/pd_util.py +57 -0
  52. lionagi/utils/sys_util.py +284 -156
  53. lionagi/utils/url_util.py +55 -0
  54. lionagi/version.py +1 -1
  55. {lionagi-0.0.115.dist-info → lionagi-0.0.204.dist-info}/METADATA +21 -17
  56. lionagi-0.0.204.dist-info/RECORD +106 -0
  57. lionagi/core/conversations/__init__.py +0 -5
  58. lionagi/core/conversations/conversation.py +0 -107
  59. lionagi/core/flows/__init__.py +0 -8
  60. lionagi/core/flows/flow.py +0 -8
  61. lionagi/core/flows/flow_util.py +0 -62
  62. lionagi/core/instruction_set/instruction_sets.py +0 -7
  63. lionagi/core/sessions/sessions.py +0 -185
  64. lionagi/endpoints/__init__.py +0 -5
  65. lionagi/endpoints/audio.py +0 -17
  66. lionagi/endpoints/chatcompletion.py +0 -54
  67. lionagi/messages/__init__.py +0 -11
  68. lionagi/messages/instruction.py +0 -15
  69. lionagi/messages/message.py +0 -110
  70. lionagi/messages/response.py +0 -33
  71. lionagi/messages/system.py +0 -12
  72. lionagi/objs/__init__.py +0 -11
  73. lionagi/objs/abc_objs.py +0 -39
  74. lionagi/objs/async_queue.py +0 -135
  75. lionagi/objs/messenger.py +0 -85
  76. lionagi/objs/tool_manager.py +0 -253
  77. lionagi/services/__init__.py +0 -11
  78. lionagi/services/base_api_service.py +0 -230
  79. lionagi/services/oai.py +0 -34
  80. lionagi/services/openrouter.py +0 -31
  81. lionagi/tests/test_api_util.py +0 -46
  82. lionagi/tests/test_call_util.py +0 -115
  83. lionagi/tests/test_convert_util.py +0 -202
  84. lionagi/tests/test_encrypt_util.py +0 -33
  85. lionagi/tests/test_flat_util.py +0 -426
  86. lionagi/tests/test_sys_util.py +0 -0
  87. lionagi/utils/convert_util.py +0 -229
  88. lionagi/utils/flat_util.py +0 -599
  89. lionagi-0.0.115.dist-info/RECORD +0 -110
  90. /lionagi/{services → _services}/anyscale.py +0 -0
  91. /lionagi/{services → _services}/azure.py +0 -0
  92. /lionagi/{services → _services}/bedrock.py +0 -0
  93. /lionagi/{services → _services}/everlyai.py +0 -0
  94. /lionagi/{services → _services}/gemini.py +0 -0
  95. /lionagi/{services → _services}/gpt4all.py +0 -0
  96. /lionagi/{services → _services}/huggingface.py +0 -0
  97. /lionagi/{services → _services}/litellm.py +0 -0
  98. /lionagi/{services → _services}/localai.py +0 -0
  99. /lionagi/{services → _services}/mistralai.py +0 -0
  100. /lionagi/{services → _services}/ollama.py +0 -0
  101. /lionagi/{services → _services}/openllm.py +0 -0
  102. /lionagi/{services → _services}/perplexity.py +0 -0
  103. /lionagi/{services → _services}/predibase.py +0 -0
  104. /lionagi/{services → _services}/rungpt.py +0 -0
  105. /lionagi/{services → _services}/vllm.py +0 -0
  106. /lionagi/{services → _services}/xinference.py +0 -0
  107. /lionagi/{endpoints/assistants.py → agents/__init__.py} +0 -0
  108. /lionagi/{tools → agents}/planner.py +0 -0
  109. /lionagi/{tools → agents}/prompter.py +0 -0
  110. /lionagi/{tools → agents}/scorer.py +0 -0
  111. /lionagi/{tools → agents}/summarizer.py +0 -0
  112. /lionagi/{tools → agents}/validator.py +0 -0
  113. /lionagi/{endpoints/embeddings.py → core/branch/__init__.py} +0 -0
  114. /lionagi/{services/anthropic.py → core/branch/cluster.py} +0 -0
  115. /lionagi/{endpoints/finetune.py → core/flow/__init__.py} +0 -0
  116. /lionagi/{endpoints/image.py → core/messages/__init__.py} +0 -0
  117. /lionagi/{endpoints/moderation.py → models/__init__.py} +0 -0
  118. /lionagi/{endpoints/vision.py → models/base_model.py} +0 -0
  119. /lionagi/{objs → schema}/status_tracker.py +0 -0
  120. /lionagi/tests/{test_io_util.py → test_utils/__init__.py} +0 -0
  121. {lionagi-0.0.115.dist-info → lionagi-0.0.204.dist-info}/LICENSE +0 -0
  122. {lionagi-0.0.115.dist-info → lionagi-0.0.204.dist-info}/WHEEL +0 -0
  123. {lionagi-0.0.115.dist-info → lionagi-0.0.204.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,785 @@
1
+ # import unittest
2
+ # import asyncio
3
+ # import time
4
+ # import lionagi.utils.call_util as call_util
5
+ # from lionagi.utils.call_util import CallDecorator
6
+ # from lionagi.utils.call_util import Throttle
7
+
8
+
9
+ # class TestToList(unittest.TestCase):
10
+
11
+ # def test_empty_input(self):
12
+ # self.assertEqual(call_util.to_list([]), [])
13
+
14
+ # def test_single_element(self):
15
+ # self.assertEqual(call_util.to_list(5), [5])
16
+
17
+ # def test_list_input(self):
18
+ # self.assertEqual(call_util.to_list([1, [2, 3]], flatten=False), [1, [2, 3]])
19
+
20
+ # def test_nested_list(self):
21
+ # self.assertEqual(call_util.to_list([[1, 2], [3, 4]], flatten=True), [1, 2, 3, 4])
22
+
23
+ # def test_non_list_iterable(self):
24
+ # self.assertEqual(call_util.to_list((1, 2, 3)), [1, 2, 3])
25
+
26
+ # def test_string_handling(self):
27
+ # self.assertEqual(call_util.to_list("abc"), ["abc"])
28
+
29
+ # def test_drop_none(self):
30
+ # self.assertEqual(call_util.to_list([1, None, 2], dropna=True), [1, 2])
31
+
32
+ # class FaultyIterable:
33
+ # """An iterable class that raises an exception when iterated over."""
34
+
35
+ # def __iter__(self):
36
+ # return self
37
+
38
+ # def __next__(self):
39
+ # raise RuntimeError("Fault during iteration")
40
+
41
+ # def test_invalid_input(self):
42
+ # with self.assertRaises(ValueError):
43
+ # call_util.to_list(TestToList.FaultyIterable())
44
+
45
+
46
+ # class TestLCall(unittest.TestCase):
47
+
48
+ # def test_empty_input(self):
49
+ # self.assertEqual(call_util.lcall([], lambda x: x*2), [])
50
+
51
+ # def test_single_element(self):
52
+ # self.assertEqual(call_util.lcall(5, lambda x: x*2), [10])
53
+
54
+ # def test_list_input_with_simple_function(self):
55
+ # self.assertEqual(call_util.lcall([1, 2, 3], lambda x: x*2), [2, 4, 6])
56
+
57
+ # def test_flatten(self):
58
+ # self.assertEqual(call_util.lcall([[1, 2], [3, 4]], lambda x: x*2, flatten=True), [2, 4, 6, 8])
59
+
60
+ # def test_drop_none(self):
61
+ # self.assertEqual(call_util.lcall([1, None, 2], lambda x: x, dropna=True), [1, 2])
62
+
63
+ # def test_with_lambda_function(self):
64
+ # self.assertEqual(call_util.lcall([1, 2, 3], lambda x: x + 1), [2, 3, 4])
65
+
66
+ # def test_exception_handling(self):
67
+ # def faulty_func(x):
68
+ # raise ValueError("Faulty Function")
69
+ # with self.assertRaises(ValueError):
70
+ # call_util.lcall([1, 2, 3], faulty_func)
71
+
72
+ # def test_with_additional_arguments(self):
73
+ # self.assertEqual(call_util.lcall([1, 2, 3], lambda x, y: x + y, y=2), [3, 4, 5])
74
+
75
+
76
+ # class TestAlCall(unittest.IsolatedAsyncioTestCase):
77
+
78
+ # async def test_empty_input(self):
79
+ # result = await call_util.alcall([], lambda x: x*2)
80
+ # self.assertEqual(result, [])
81
+
82
+ # async def test_single_element_with_async_function(self):
83
+ # async def async_func(x):
84
+ # return x * 2
85
+ # result = await call_util.alcall(5, async_func)
86
+ # self.assertEqual(result, [10])
87
+
88
+ # async def test_list_input_with_sync_function(self):
89
+ # result = await call_util.alcall([1, 2, 3], lambda x: x*2)
90
+ # self.assertEqual(result, [2, 4, 6])
91
+
92
+ # async def test_flatten_with_async_function(self):
93
+ # async def async_func(x):
94
+ # return x * 2
95
+ # result = await call_util.alcall([[1, 2], [3, 4]], async_func, flatten=True)
96
+ # self.assertEqual(result, [2, 4, 6, 8])
97
+
98
+ # async def test_drop_none_with_sync_function(self):
99
+ # result = await call_util.alcall([1, None, 2], lambda x: x, dropna=True)
100
+ # self.assertEqual(result, [1, 2])
101
+
102
+ # async def test_exception_handling_in_async_function(self):
103
+ # async def faulty_func(x):
104
+ # raise ValueError("Faulty Function")
105
+ # with self.assertRaises(ValueError):
106
+ # await call_util.alcall([1, 2, 3], faulty_func)
107
+
108
+ # async def test_with_additional_arguments(self):
109
+ # async def async_func(x, y):
110
+ # return x + y
111
+ # result = await call_util.alcall([1, 2, 3], async_func, y=2)
112
+ # self.assertEqual(result, [3, 4, 5])
113
+
114
+
115
+ # class TestTCall(unittest.IsolatedAsyncioTestCase):
116
+
117
+ # async def test_sync_function_call(self):
118
+ # def sync_func(x):
119
+ # return x * 2
120
+ # result = await call_util.tcall(5, sync_func)
121
+ # self.assertEqual(result, 10)
122
+
123
+ # async def test_async_function_call(self):
124
+ # async def async_func(x):
125
+ # return x * 2
126
+ # result = await call_util.tcall(5, async_func)
127
+ # self.assertEqual(result, 10)
128
+
129
+ # async def test_with_delay(self):
130
+ # async def async_func(x):
131
+ # return x * 2
132
+ # start_time = asyncio.get_event_loop().time()
133
+ # await call_util.tcall(5, async_func, sleep=1)
134
+ # elapsed = asyncio.get_event_loop().time() - start_time
135
+ # self.assertTrue(elapsed >= 1)
136
+
137
+ # async def test_error_handling(self):
138
+ # async def async_func(x):
139
+ # raise ValueError("Test Error")
140
+ # with self.assertRaises(ValueError):
141
+ # await call_util.tcall(5, async_func, message="Custom Error Message")
142
+
143
+ # async def test_execution_timing(self):
144
+ # async def async_func(x):
145
+ # return x * 2
146
+ # result, duration = await call_util.tcall(5, async_func, include_timing=True)
147
+ # self.assertEqual(result, 10)
148
+ # self.assertIsInstance(duration, float)
149
+
150
+ # async def test_ignore_error(self):
151
+ # def sync_func(x):
152
+ # raise ValueError("Test Error")
153
+ # result = await call_util.tcall(5, sync_func, ignore_error=True)
154
+ # self.assertIsNone(result)
155
+
156
+ # async def test_with_additional_arguments(self):
157
+ # async def async_func(x, y):
158
+ # return x + y
159
+ # result = await call_util.tcall(5, async_func, y=3)
160
+ # self.assertEqual(result, 8)
161
+
162
+ # class TestMCall(unittest.IsolatedAsyncioTestCase):
163
+
164
+ # async def test_single_function_single_input(self):
165
+ # async def async_func(x):
166
+ # return x * 2
167
+ # result = await call_util.mcall(5, async_func)
168
+ # self.assertEqual(result, [10])
169
+
170
+ # async def test_list_of_functions_single_input(self):
171
+ # async def async_func1(x):
172
+ # return x * 2
173
+ # async def async_func2(x):
174
+ # return x + 3
175
+ # with self.assertRaises(AssertionError):
176
+ # await call_util.mcall(5, [async_func1, async_func2])
177
+
178
+ # async def test_single_function_list_of_inputs(self):
179
+ # async def async_func(x):
180
+ # return x * 2
181
+
182
+ # with self.assertRaises(AssertionError):
183
+ # await call_util.mcall([1, 2, 3], async_func)
184
+
185
+ # async def test_list_of_functions_list_of_inputs_explode_false(self):
186
+ # async def async_func1(x):
187
+ # return x * 2
188
+ # async def async_func2(x):
189
+ # return x + 3
190
+ # result = await call_util.mcall([1, 2], [async_func1, async_func2])
191
+ # self.assertEqual(result, [2, 5])
192
+
193
+ # async def test_list_of_functions_list_of_inputs_explode_true(self):
194
+ # async def async_func1(x):
195
+ # return x * 2
196
+ # async def async_func2(x):
197
+ # return x + 3
198
+ # result = await call_util.mcall([1, 2], [async_func1, async_func2], explode=True)
199
+ # self.assertEqual(result, [[2, 4], [4, 5]])
200
+
201
+ # async def test_flatten_and_dropna(self):
202
+ # async def async_func1(x):
203
+ # return x * 2
204
+ # async def async_func2(x):
205
+ # return x + 3
206
+ # result = await call_util.mcall([[1, None], [None, 2]], [async_func1, async_func2], flatten=True, dropna=True)
207
+ # self.assertEqual(result, [2, 5])
208
+
209
+ # async def test_exception_handling(self):
210
+ # async def async_func(x):
211
+ # if x == 2:
212
+ # raise ValueError("Test Error")
213
+ # return x * 2
214
+ # with self.assertRaises(ValueError):
215
+ # await call_util.mcall([1, 2], [async_func, async_func])
216
+
217
+ # async def test_with_additional_arguments(self):
218
+ # async def async_func(x, y):
219
+ # return x + y
220
+ # result = await call_util.mcall([1, 2], [async_func, async_func], y=2)
221
+ # self.assertEqual(result, [3, 4])
222
+
223
+ # class TestBCall(unittest.IsolatedAsyncioTestCase):
224
+
225
+ # async def test_empty_input_list(self):
226
+ # async def async_func(x):
227
+ # return x * 2
228
+ # result = await call_util.bcall([], async_func, batch_size=2)
229
+ # self.assertEqual(result, [])
230
+
231
+ # async def test_sync_function_call(self):
232
+ # def sync_func(x):
233
+ # return x * 2
234
+ # result = await call_util.bcall([1, 2, 3], sync_func, batch_size=2)
235
+ # self.assertEqual(result, [2, 4, 6])
236
+
237
+ # async def test_async_function_call(self):
238
+ # async def async_func(x):
239
+ # return x * 2
240
+ # result = await call_util.bcall([1, 2, 3], async_func, batch_size=2)
241
+ # self.assertEqual(result, [2, 4, 6])
242
+
243
+ # async def test_batch_processing(self):
244
+ # async def async_func(x):
245
+ # return x * 2
246
+ # # Test with 4 elements and a batch size of 2
247
+ # result = await call_util.bcall([1, 2, 3, 4], async_func, batch_size=2)
248
+ # self.assertEqual(result, [2, 4, 6, 8])
249
+
250
+ # async def test_exception_handling(self):
251
+ # async def async_func(x):
252
+ # if x == 2:
253
+ # raise ValueError("Test Error")
254
+ # return x * 2
255
+ # with self.assertRaises(ValueError):
256
+ # await call_util.bcall([1, 2, 3], async_func, batch_size=2)
257
+
258
+ # async def test_with_additional_arguments(self):
259
+ # async def async_func(x, y):
260
+ # return x + y
261
+ # result = await call_util.bcall([1, 2, 3], async_func, batch_size=2, y=3)
262
+ # self.assertEqual(result, [4, 5, 6])
263
+
264
+
265
+ # class TestRCall(unittest.IsolatedAsyncioTestCase):
266
+
267
+ # async def test_sync_function_without_timeout(self):
268
+ # def sync_func(x):
269
+ # return x * 2
270
+ # result = await call_util.rcall(sync_func, 5)
271
+ # self.assertEqual(result, 10)
272
+
273
+ # async def test_async_function_without_timeout(self):
274
+ # async def async_func(x):
275
+ # return x * 2
276
+ # result = await call_util.rcall(async_func, 5)
277
+ # self.assertEqual(result, 10)
278
+
279
+ # async def test_timeout(self):
280
+ # async def async_func(x):
281
+ # await asyncio.sleep(2)
282
+ # return x
283
+ # with self.assertRaises(asyncio.TimeoutError):
284
+ # await call_util.rcall(async_func, 5, timeout=1)
285
+
286
+ # async def test_timeout(self):
287
+ # def async_func(x):
288
+ # time.sleep(2)
289
+ # return x
290
+ # with self.assertRaises(asyncio.TimeoutError):
291
+ # await call_util.rcall(async_func, 5, timeout=1)
292
+
293
+ # async def test_retry_mechanism(self):
294
+ # attempt_count = 0
295
+ # def sync_func(x):
296
+ # nonlocal attempt_count
297
+ # attempt_count += 1
298
+ # raise ValueError("Test Error")
299
+ # with self.assertRaises(ValueError):
300
+ # await call_util.rcall(sync_func, 5, retries=3)
301
+ # self.assertEqual(attempt_count, 4) # Initial call + 3 retries
302
+
303
+ # async def test_default_value_on_exception(self):
304
+ # def sync_func(x):
305
+ # raise ValueError("Test Error")
306
+ # result = await call_util.rcall(sync_func, 5, default=10)
307
+ # self.assertEqual(result, 10)
308
+
309
+ # async def test_exception_propagation(self):
310
+ # def sync_func(x):
311
+ # raise ValueError("Test Error")
312
+ # with self.assertRaises(ValueError):
313
+ # await call_util.rcall(sync_func, 5)
314
+
315
+
316
+ # class TestCallDecorator(unittest.IsolatedAsyncioTestCase):
317
+
318
+ # def test_cache_decorator_sync(self):
319
+ # @CallDecorator.cache
320
+ # def sync_func(x):
321
+ # return x * 2
322
+
323
+ # first_call = sync_func(5)
324
+ # second_call = sync_func(5)
325
+
326
+ # self.assertEqual(first_call, 10)
327
+ # self.assertIs(first_call, second_call)
328
+
329
+ # async def test_cache_decorator_async(self):
330
+ # @CallDecorator.cache
331
+ # async def async_func(x):
332
+ # return x * 2
333
+
334
+ # first_call = await async_func(5)
335
+ # second_call = await async_func(5)
336
+
337
+ # self.assertEqual(first_call, 10)
338
+ # self.assertIs(first_call, second_call)
339
+
340
+ # def test_timeout_with_sync_function(self):
341
+ # @CallDecorator.timeout(1) # 1 second timeout
342
+ # def sync_func(x):
343
+ # time.sleep(2) # Sleep for 2 seconds, should trigger timeout
344
+ # return x
345
+
346
+ # with self.assertRaises(asyncio.TimeoutError):
347
+ # asyncio.run(sync_func(5))
348
+
349
+ # def test_no_timeout_with_sync_function(self):
350
+ # @CallDecorator.timeout(2) # 2 second timeout
351
+ # def sync_func(x):
352
+ # time.sleep(1) # Sleep for 1 second, within timeout
353
+ # return x
354
+
355
+ # result = sync_func(5)
356
+ # self.assertEqual(result, 5)
357
+
358
+ # async def test_timeout_with_async_function(self):
359
+ # @CallDecorator.timeout(1) # 1 second timeout
360
+ # async def async_func(x):
361
+ # await asyncio.sleep(2) # Sleep for 2 seconds, should trigger timeout
362
+ # return x
363
+
364
+ # with self.assertRaises(asyncio.TimeoutError):
365
+ # await async_func(5)
366
+
367
+ # async def test_no_timeout_with_async_function(self):
368
+ # @CallDecorator.timeout(2) # 2 second timeout
369
+ # async def async_func(x):
370
+ # await asyncio.sleep(1) # Sleep for 1 second, within timeout
371
+ # return x
372
+
373
+ # result = await async_func(5)
374
+ # self.assertEqual(result, 5)
375
+
376
+ # def test_successful_retry(self):
377
+ # attempt = 0
378
+
379
+ # @CallDecorator.retry(retries=3, initial_delay=1, backoff_factor=2)
380
+ # def test_func():
381
+ # nonlocal attempt
382
+ # attempt += 1
383
+ # if attempt < 3:
384
+ # raise ValueError("Test failure")
385
+ # return "Success"
386
+
387
+ # result = test_func()
388
+ # self.assertEqual(result, "Success")
389
+ # self.assertEqual(attempt, 3)
390
+
391
+ # def test_retry_limit(self):
392
+ # attempt = 0
393
+
394
+ # @CallDecorator.retry(retries=2, initial_delay=1, backoff_factor=2)
395
+ # def test_func():
396
+ # nonlocal attempt
397
+ # attempt += 1
398
+ # raise ValueError("Test failure")
399
+
400
+ # with self.assertRaises(ValueError):
401
+ # test_func()
402
+ # self.assertEqual(attempt, 3)
403
+
404
+ # def test_immediate_success(self):
405
+ # attempt = 0
406
+
407
+ # @CallDecorator.retry(retries=3, initial_delay=1, backoff_factor=2)
408
+ # def test_func():
409
+ # nonlocal attempt
410
+ # attempt += 1
411
+ # return "Success"
412
+
413
+
414
+ # result = test_func()
415
+ # self.assertEqual(result, "Success")
416
+ # self.assertEqual(attempt, 1)
417
+
418
+ # def test_retry_with_delays(self):
419
+ # attempt = 0
420
+ # start_time = time.time()
421
+
422
+ # @CallDecorator.retry(retries=3, initial_delay=1, backoff_factor=2)
423
+ # def test_func():
424
+ # nonlocal attempt
425
+ # attempt += 1
426
+ # if attempt < 3:
427
+ # raise ValueError("Test failure")
428
+ # return "Success"
429
+
430
+ # result = test_func()
431
+ # end_time = time.time()
432
+ # elapsed_time = end_time - start_time
433
+
434
+ # self.assertEqual(result, "Success")
435
+ # self.assertTrue(elapsed_time >= 3)
436
+ # self.assertEqual(attempt, 3)
437
+
438
+ # def test_default_value_on_exception(self):
439
+ # @CallDecorator.default(default_value="Default")
440
+ # def test_func():
441
+ # raise ValueError("Test failure")
442
+
443
+ # result = test_func()
444
+ # self.assertEqual(result, "Default")
445
+
446
+ # def test_no_exception(self):
447
+ # @CallDecorator.default(default_value="Default")
448
+ # def test_func():
449
+ # return "Success"
450
+
451
+ # result = test_func()
452
+ # self.assertEqual(result, "Success")
453
+
454
+ # def test_throttling_behavior(self):
455
+ # @CallDecorator.throttle(period=2) # 2 seconds throttle period
456
+ # def test_func():
457
+ # return time.time()
458
+
459
+ # start_time = time.time()
460
+ # first_call = test_func()
461
+ # second_call = test_func()
462
+ # end_time = time.time()
463
+
464
+ # self.assertLess(first_call - start_time, 1) # First call should be immediate
465
+ # self.assertGreaterEqual(second_call - first_call, 2) # Second call should be delayed
466
+ # self.assertLessEqual(end_time - start_time, 3) # Total time should be within reasonable bounds
467
+
468
+ # def test_successive_calls_outside_throttle_period(self):
469
+ # @CallDecorator.throttle(period=1) # 1 second throttle period
470
+ # def test_func():
471
+ # return time.time()
472
+
473
+ # first_call = test_func()
474
+ # time.sleep(1.1) # Sleep to exceed the throttle period
475
+ # second_call = test_func()
476
+
477
+ # self.assertGreaterEqual(second_call - first_call, 1) # Second call should not be delayed
478
+
479
+ # def test_throttling_with_different_inputs(self):
480
+ # @CallDecorator.throttle(period=2) # 2 seconds throttle period
481
+ # def test_func(x):
482
+ # return x
483
+
484
+ # first_call = test_func(1)
485
+ # time.sleep(0.5)
486
+ # second_call = test_func(2)
487
+
488
+ # self.assertEqual(first_call, 1)
489
+ # self.assertEqual(second_call, 2) # Should return the result of the first call due to throttling
490
+
491
+ # def test_preprocessing(self):
492
+ # def preprocess(x):
493
+ # return x * 2
494
+
495
+ # @CallDecorator.pre_post_process(preprocess, lambda x: x)
496
+ # def test_func(x):
497
+ # return x + 3
498
+
499
+ # result = test_func(2) # Preprocess: 2 * 2 -> 4, Func: 4 + 3
500
+ # self.assertEqual(result, 7)
501
+
502
+ # def test_postprocessing(self):
503
+ # def postprocess(x):
504
+ # return x * 3
505
+
506
+ # @CallDecorator.pre_post_process(lambda x: x, postprocess)
507
+ # def test_func(x):
508
+ # return x + 2
509
+
510
+ # result = test_func(2) # Func: 2 + 2 -> 4, Postprocess: 4 * 3
511
+ # self.assertEqual(result, 12)
512
+
513
+
514
+ # def test_preprocessing_and_postprocessing(self):
515
+ # def preprocess(x):
516
+ # return x * 2
517
+
518
+ # def postprocess(x):
519
+ # return x * 3
520
+
521
+ # @CallDecorator.pre_post_process(preprocess, postprocess)
522
+ # def test_func(x):
523
+ # return x + 1
524
+
525
+ # result = test_func(2) # Preprocess: 2 * 2 -> 4, Func: 4 + 1 -> 5, Postprocess: 5 * 3
526
+ # self.assertEqual(result, 15)
527
+
528
+ # def test_filtering_based_on_predicate(self):
529
+ # is_even = lambda x: x % 2 == 0
530
+
531
+ # @CallDecorator.filter(is_even)
532
+ # def test_func():
533
+ # return [1, 2, 3, 4, 5]
534
+
535
+ # result = test_func()
536
+ # self.assertEqual(result, [2, 4])
537
+
538
+ # def test_no_items_satisfy_predicate(self):
539
+ # is_negative = lambda x: x < 0
540
+
541
+ # @CallDecorator.filter(is_negative)
542
+ # def test_func():
543
+ # return [1, 2, 3, 4, 5]
544
+
545
+ # result = test_func()
546
+ # self.assertEqual(result, [])
547
+
548
+ # def test_all_items_satisfy_predicate(self):
549
+ # is_positive = lambda x: x > 0
550
+
551
+ # @CallDecorator.filter(is_positive)
552
+ # def test_func():
553
+ # return [1, 2, 3, 4, 5]
554
+
555
+ # result = test_func()
556
+ # self.assertEqual(result, [1, 2, 3, 4, 5])
557
+
558
+ # def test_mapping_function(self):
559
+ # double = lambda x: x * 2
560
+
561
+ # @CallDecorator.map(double)
562
+ # def test_func():
563
+ # return [1, 2, 3, 4, 5]
564
+
565
+ # result = test_func()
566
+ # self.assertEqual(result, [2, 4, 6, 8, 10])
567
+
568
+ # def test_empty_list(self):
569
+ # double = lambda x: x * 2
570
+
571
+ # @CallDecorator.map(double)
572
+ # def test_func():
573
+ # return []
574
+
575
+ # result = test_func()
576
+ # self.assertEqual(result, [])
577
+
578
+ # def test_mapping_with_different_data_types(self):
579
+ # to_string = lambda x: str(x)
580
+
581
+ # @CallDecorator.map(to_string)
582
+ # def test_func():
583
+ # return [1, 2.5, 'test', True]
584
+
585
+ # result = test_func()
586
+ # self.assertEqual(result, ['1', '2.5', 'test', 'True'])
587
+
588
+ # def test_reduction_function(self):
589
+ # sum_func = lambda x, y: x + y
590
+
591
+ # @CallDecorator.reduce(sum_func, 0)
592
+ # def test_func():
593
+ # return [1, 2, 3, 4, 5]
594
+
595
+ # result = test_func()
596
+ # self.assertEqual(result, 15) # Sum of 1, 2, 3, 4, 5
597
+
598
+ # def test_empty_list(self):
599
+ # sum_func = lambda x, y: x + y
600
+
601
+ # @CallDecorator.reduce(sum_func, 0)
602
+ # def test_func():
603
+ # return []
604
+
605
+ # result = test_func()
606
+ # self.assertEqual(result, 0) # Initial value
607
+
608
+ # def test_reduction_with_initial_value(self):
609
+ # sum_func = lambda x, y: x + y
610
+
611
+ # @CallDecorator.reduce(sum_func, 10)
612
+ # def test_func():
613
+ # return [1, 2, 3, 4, 5]
614
+
615
+ # result = test_func()
616
+ # self.assertEqual(result, 25) # 10 (initial) + Sum of 1, 2, 3, 4, 5
617
+
618
+ # def test_function_composition(self):
619
+ # double = lambda x: x * 2
620
+ # add_five = lambda x: x + 5
621
+
622
+ # @CallDecorator.compose(add_five, double) # First add_five, then double
623
+ # def test_func():
624
+ # return 3
625
+
626
+ # result = test_func()
627
+ # self.assertEqual(result, (3 + 5) * 2)
628
+
629
+ # def test_empty_function_list(self):
630
+ # @CallDecorator.compose()
631
+ # def test_func():
632
+ # return "test"
633
+
634
+ # result = test_func()
635
+ # self.assertEqual(result, "test")
636
+
637
+ # def test_error_handling_in_composition(self):
638
+ # def raise_error(x):
639
+ # raise ValueError("Error in function")
640
+
641
+ # @CallDecorator.compose(raise_error)
642
+ # def test_func():
643
+ # return 3
644
+
645
+ # with self.assertRaises(ValueError):
646
+ # test_func()
647
+
648
+ # def test_caching_behavior(self):
649
+ # @CallDecorator.memorize(maxsize=10)
650
+ # def test_func(x):
651
+ # return x * 2
652
+
653
+ # first_call = test_func(5)
654
+ # second_call = test_func(5)
655
+
656
+ # self.assertEqual(first_call, 10)
657
+ # self.assertIs(first_call, second_call) # Should return cached result
658
+
659
+ # def test_different_arguments(self):
660
+ # @CallDecorator.memorize(maxsize=10)
661
+ # def test_func(x):
662
+ # return x * 2
663
+
664
+ # first_call = test_func(5)
665
+ # second_call = test_func(6)
666
+
667
+ # self.assertNotEqual(first_call, second_call)
668
+ # self.assertIsNot(first_call, second_call)
669
+
670
+ # def test_cache_size_limit(self):
671
+ # @CallDecorator.memorize(maxsize=2)
672
+ # def test_func(x):
673
+ # return x * 2
674
+
675
+ # test_func(1) # Cache this
676
+ # test_func(2) # Cache this
677
+ # test_func(3) # Cache should evict the first entry (1)
678
+ # result = test_func(1) # Recompute as it should be evicted
679
+
680
+ # self.assertEqual(result, 2)
681
+
682
+ # def test_type_validation(self):
683
+ # @CallDecorator.validate(validate_type=int)
684
+ # def test_func():
685
+ # return 5
686
+
687
+ # result = test_func()
688
+ # self.assertEqual(result, 5)
689
+
690
+ # def test_type_conversion(self):
691
+ # @CallDecorator.validate(convert_type=str)
692
+ # def test_func():
693
+ # return 5
694
+
695
+ # result = test_func()
696
+ # self.assertEqual(result, "5")
697
+
698
+ # def test_error_handling_on_invalid_type(self):
699
+ # @CallDecorator.validate(validate_type=int)
700
+ # def test_func():
701
+ # return "not an int"
702
+
703
+ # with self.assertRaises(TypeError):
704
+ # test_func()
705
+
706
+ # def test_default_value_on_error(self):
707
+ # @CallDecorator.validate(validate_type=int, handle_error={'default': 0})
708
+ # def test_func():
709
+ # return "not an int"
710
+
711
+ # result = test_func()
712
+ # self.assertEqual(result, 0)
713
+
714
+ # async def test_concurrency_limit(self):
715
+ # current_concurrency = 0
716
+ # max_concurrent_calls = 0
717
+
718
+ # @CallDecorator.max_concurrency(limit=2)
719
+ # async def test_func():
720
+ # nonlocal current_concurrency, max_concurrent_calls
721
+ # current_concurrency += 1
722
+ # max_concurrent_calls = max(max_concurrent_calls, current_concurrency)
723
+ # await asyncio.sleep(0.1) # Simulate async work
724
+ # current_concurrency -= 1
725
+
726
+ # await asyncio.gather(*(test_func() for _ in range(5)))
727
+ # self.assertEqual(max_concurrent_calls, 2)
728
+
729
+ # async def test_function_completing_within_limit(self):
730
+ # @CallDecorator.max_concurrency(limit=2)
731
+ # async def test_func(x):
732
+ # await asyncio.sleep(0.1)
733
+ # return x
734
+
735
+ # results = await asyncio.gather(*(test_func(i) for i in range(5)))
736
+ # self.assertEqual(results, [0, 1, 2, 3, 4])
737
+
738
+
739
+ # class TestThrottleClass(unittest.TestCase):
740
+
741
+ # def test_throttling_behavior_sync(self):
742
+ # throttle_decorator = Throttle(2) # 2 seconds throttle period
743
+
744
+ # @throttle_decorator
745
+ # def test_func():
746
+ # return time.time()
747
+
748
+ # first_call_time = test_func()
749
+ # time.sleep(1) # Sleep less than the throttle period
750
+ # second_call_time = test_func()
751
+
752
+ # self.assertGreaterEqual(second_call_time - first_call_time, 2) # Second call should be throttled
753
+
754
+ # def test_throttling_behavior_async(self):
755
+ # throttle_decorator = Throttle(2) # 2 seconds throttle period
756
+
757
+ # @throttle_decorator
758
+ # async def test_func():
759
+ # return time.time()
760
+
761
+ # async def async_test():
762
+ # first_call_time = await test_func()
763
+ # await asyncio.sleep(1) # Sleep less than the throttle period
764
+ # second_call_time = await test_func()
765
+
766
+ # self.assertGreaterEqual(second_call_time - first_call_time, 2) # Second call should be throttled
767
+
768
+ # asyncio.run(async_test())
769
+
770
+ # def test_successive_calls_with_sufficient_delay(self):
771
+ # throttle_decorator = Throttle(1) # 1 second throttle period
772
+
773
+ # @throttle_decorator
774
+ # def test_func():
775
+ # return time.time()
776
+
777
+ # first_call_time = test_func()
778
+ # time.sleep(1.1) # Sleep more than the throttle period
779
+ # second_call_time = test_func()
780
+
781
+ # self.assertLess(second_call_time - first_call_time, 1.5) # Second call should not be throttled
782
+
783
+
784
+ # if __name__ == '__main__':
785
+ # unittest.main()