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