provide-foundation 0.0.0.dev2__py3-none-any.whl → 0.0.0.dev3__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.
- provide/foundation/__init__.py +20 -20
- provide/foundation/archive/__init__.py +1 -1
- provide/foundation/archive/base.py +15 -14
- provide/foundation/archive/bzip2.py +40 -40
- provide/foundation/archive/gzip.py +42 -42
- provide/foundation/archive/operations.py +90 -91
- provide/foundation/archive/tar.py +33 -31
- provide/foundation/archive/zip.py +52 -50
- provide/foundation/asynctools/__init__.py +20 -0
- provide/foundation/asynctools/core.py +126 -0
- provide/foundation/cli/__init__.py +2 -2
- provide/foundation/cli/commands/deps.py +4 -4
- provide/foundation/cli/commands/logs/__init__.py +2 -2
- provide/foundation/cli/commands/logs/generate.py +2 -2
- provide/foundation/cli/commands/logs/query.py +3 -3
- provide/foundation/cli/commands/logs/send.py +2 -2
- provide/foundation/cli/commands/logs/tail.py +2 -2
- provide/foundation/cli/decorators.py +0 -1
- provide/foundation/cli/testing.py +0 -5
- provide/foundation/cli/utils.py +1 -2
- provide/foundation/config/__init__.py +19 -19
- provide/foundation/config/base.py +2 -2
- provide/foundation/config/converters.py +81 -83
- provide/foundation/config/defaults.py +1 -1
- provide/foundation/config/env.py +2 -1
- provide/foundation/config/loader.py +1 -1
- provide/foundation/config/sync.py +8 -6
- provide/foundation/config/types.py +5 -5
- provide/foundation/config/validators.py +4 -4
- provide/foundation/console/output.py +7 -7
- provide/foundation/context/core.py +19 -17
- provide/foundation/crypto/certificates/__init__.py +9 -5
- provide/foundation/crypto/certificates/base.py +2 -2
- provide/foundation/crypto/certificates/certificate.py +48 -19
- provide/foundation/crypto/certificates/factory.py +26 -18
- provide/foundation/crypto/certificates/generator.py +24 -23
- provide/foundation/crypto/certificates/loader.py +24 -16
- provide/foundation/crypto/certificates/operations.py +17 -10
- provide/foundation/crypto/certificates/trust.py +21 -21
- provide/foundation/env/__init__.py +28 -0
- provide/foundation/env/core.py +218 -0
- provide/foundation/errors/__init__.py +3 -2
- provide/foundation/errors/decorators.py +0 -3
- provide/foundation/errors/types.py +0 -1
- provide/foundation/eventsets/display.py +13 -14
- provide/foundation/eventsets/registry.py +61 -31
- provide/foundation/eventsets/resolver.py +50 -46
- provide/foundation/eventsets/sets/das.py +8 -8
- provide/foundation/eventsets/sets/database.py +14 -14
- provide/foundation/eventsets/sets/http.py +21 -21
- provide/foundation/eventsets/sets/llm.py +16 -16
- provide/foundation/eventsets/sets/task_queue.py +13 -13
- provide/foundation/eventsets/types.py +7 -7
- provide/foundation/file/directory.py +1 -1
- provide/foundation/file/lock.py +2 -3
- provide/foundation/hub/components.py +19 -21
- provide/foundation/hub/config.py +25 -19
- provide/foundation/hub/discovery.py +5 -4
- provide/foundation/hub/handlers.py +13 -5
- provide/foundation/hub/lifecycle.py +10 -9
- provide/foundation/hub/manager.py +3 -0
- provide/foundation/hub/processors.py +8 -3
- provide/foundation/integrations/__init__.py +1 -1
- provide/foundation/integrations/openobserve/client.py +2 -2
- provide/foundation/integrations/openobserve/commands.py +9 -9
- provide/foundation/integrations/openobserve/config.py +2 -2
- provide/foundation/integrations/openobserve/otlp.py +2 -2
- provide/foundation/integrations/openobserve/search.py +1 -2
- provide/foundation/integrations/openobserve/streaming.py +1 -1
- provide/foundation/logger/__init__.py +0 -1
- provide/foundation/logger/config/base.py +1 -1
- provide/foundation/logger/config/logging.py +19 -19
- provide/foundation/logger/config/telemetry.py +11 -13
- provide/foundation/logger/factories.py +2 -2
- provide/foundation/logger/processors/main.py +12 -10
- provide/foundation/logger/ratelimit/limiters.py +4 -4
- provide/foundation/logger/ratelimit/processor.py +1 -1
- provide/foundation/logger/setup/coordinator.py +38 -24
- provide/foundation/logger/setup/processors.py +3 -3
- provide/foundation/logger/setup/testing.py +14 -0
- provide/foundation/logger/trace.py +5 -5
- provide/foundation/metrics/__init__.py +1 -1
- provide/foundation/metrics/otel.py +3 -1
- provide/foundation/observability/__init__.py +1 -1
- provide/foundation/process/__init__.py +1 -1
- provide/foundation/process/exit.py +6 -5
- provide/foundation/process/lifecycle.py +41 -18
- provide/foundation/resilience/__init__.py +6 -5
- provide/foundation/resilience/circuit.py +32 -30
- provide/foundation/resilience/decorators.py +58 -42
- provide/foundation/resilience/fallback.py +55 -40
- provide/foundation/resilience/retry.py +67 -65
- provide/foundation/serialization/__init__.py +16 -0
- provide/foundation/serialization/core.py +70 -0
- provide/foundation/streams/config.py +8 -9
- provide/foundation/streams/console.py +3 -3
- provide/foundation/streams/core.py +2 -2
- provide/foundation/streams/file.py +1 -1
- provide/foundation/testing/__init__.py +22 -7
- provide/foundation/testing/archive/__init__.py +7 -7
- provide/foundation/testing/archive/fixtures.py +58 -54
- provide/foundation/testing/cli.py +3 -6
- provide/foundation/testing/common/__init__.py +13 -13
- provide/foundation/testing/common/fixtures.py +27 -30
- provide/foundation/testing/file/__init__.py +15 -15
- provide/foundation/testing/file/content_fixtures.py +65 -92
- provide/foundation/testing/file/directory_fixtures.py +19 -19
- provide/foundation/testing/file/fixtures.py +14 -17
- provide/foundation/testing/file/special_fixtures.py +34 -42
- provide/foundation/testing/logger.py +28 -23
- provide/foundation/testing/mocking/__init__.py +21 -21
- provide/foundation/testing/mocking/fixtures.py +80 -67
- provide/foundation/testing/process/__init__.py +23 -23
- provide/foundation/testing/process/async_fixtures.py +89 -80
- provide/foundation/testing/process/fixtures.py +11 -13
- provide/foundation/testing/process/subprocess_fixtures.py +41 -40
- provide/foundation/testing/threading/__init__.py +17 -17
- provide/foundation/testing/threading/basic_fixtures.py +21 -17
- provide/foundation/testing/threading/data_fixtures.py +18 -16
- provide/foundation/testing/threading/execution_fixtures.py +67 -52
- provide/foundation/testing/threading/fixtures.py +10 -14
- provide/foundation/testing/threading/sync_fixtures.py +21 -18
- provide/foundation/testing/time/__init__.py +11 -11
- provide/foundation/testing/time/fixtures.py +91 -79
- provide/foundation/testing/transport/__init__.py +9 -9
- provide/foundation/testing/transport/fixtures.py +54 -54
- provide/foundation/time/__init__.py +18 -0
- provide/foundation/time/core.py +63 -0
- provide/foundation/tools/__init__.py +2 -2
- provide/foundation/tools/base.py +68 -67
- provide/foundation/tools/cache.py +62 -69
- provide/foundation/tools/downloader.py +51 -56
- provide/foundation/tools/installer.py +51 -57
- provide/foundation/tools/registry.py +38 -45
- provide/foundation/tools/resolver.py +70 -68
- provide/foundation/tools/verifier.py +39 -50
- provide/foundation/tracer/spans.py +1 -13
- provide/foundation/transport/__init__.py +26 -33
- provide/foundation/transport/base.py +32 -30
- provide/foundation/transport/client.py +44 -49
- provide/foundation/transport/config.py +11 -13
- provide/foundation/transport/errors.py +13 -27
- provide/foundation/transport/http.py +69 -55
- provide/foundation/transport/middleware.py +86 -81
- provide/foundation/transport/registry.py +29 -27
- provide/foundation/transport/types.py +6 -6
- provide/foundation/utils/deps.py +3 -2
- provide/foundation/utils/parsing.py +7 -7
- {provide_foundation-0.0.0.dev2.dist-info → provide_foundation-0.0.0.dev3.dist-info}/METADATA +2 -2
- provide_foundation-0.0.0.dev3.dist-info/RECORD +233 -0
- provide_foundation-0.0.0.dev2.dist-info/RECORD +0 -225
- {provide_foundation-0.0.0.dev2.dist-info → provide_foundation-0.0.0.dev3.dist-info}/WHEEL +0 -0
- {provide_foundation-0.0.0.dev2.dist-info → provide_foundation-0.0.0.dev3.dist-info}/entry_points.txt +0 -0
- {provide_foundation-0.0.0.dev2.dist-info → provide_foundation-0.0.0.dev3.dist-info}/licenses/LICENSE +0 -0
- {provide_foundation-0.0.0.dev2.dist-info → provide_foundation-0.0.0.dev3.dist-info}/top_level.txt +0 -0
@@ -1,13 +1,13 @@
|
|
1
1
|
"""
|
2
2
|
Async-specific test fixtures for process testing.
|
3
3
|
|
4
|
-
Provides fixtures for testing async operations, event loops, and
|
4
|
+
Provides fixtures for testing async operations, event loops, and
|
5
5
|
async context management across the provide-io ecosystem.
|
6
6
|
"""
|
7
7
|
|
8
8
|
import asyncio
|
9
|
-
from unittest.mock import AsyncMock
|
10
9
|
from collections.abc import AsyncGenerator, Callable
|
10
|
+
from unittest.mock import AsyncMock
|
11
11
|
|
12
12
|
import pytest
|
13
13
|
|
@@ -16,22 +16,22 @@ import pytest
|
|
16
16
|
async def clean_event_loop() -> AsyncGenerator[None, None]:
|
17
17
|
"""
|
18
18
|
Ensure clean event loop for async tests.
|
19
|
-
|
19
|
+
|
20
20
|
Cancels all pending tasks after the test to prevent event loop issues.
|
21
|
-
|
21
|
+
|
22
22
|
Yields:
|
23
23
|
None - fixture for test setup/teardown.
|
24
24
|
"""
|
25
25
|
yield
|
26
|
-
|
26
|
+
|
27
27
|
# Clean up any pending tasks
|
28
28
|
loop = asyncio.get_event_loop()
|
29
29
|
pending = asyncio.all_tasks(loop)
|
30
|
-
|
30
|
+
|
31
31
|
for task in pending:
|
32
32
|
if not task.done():
|
33
33
|
task.cancel()
|
34
|
-
|
34
|
+
|
35
35
|
# Wait for all tasks to complete cancellation
|
36
36
|
if pending:
|
37
37
|
await asyncio.gather(*pending, return_exceptions=True)
|
@@ -41,23 +41,24 @@ async def clean_event_loop() -> AsyncGenerator[None, None]:
|
|
41
41
|
def async_timeout() -> Callable[[float], asyncio.Task]:
|
42
42
|
"""
|
43
43
|
Provide configurable timeout wrapper for async operations.
|
44
|
-
|
44
|
+
|
45
45
|
Returns:
|
46
46
|
A function that wraps async operations with a timeout.
|
47
47
|
"""
|
48
|
+
|
48
49
|
def _timeout_wrapper(coro, seconds: float = 5.0):
|
49
50
|
"""
|
50
51
|
Wrap a coroutine with a timeout.
|
51
|
-
|
52
|
+
|
52
53
|
Args:
|
53
54
|
coro: Coroutine to wrap
|
54
55
|
seconds: Timeout in seconds
|
55
|
-
|
56
|
+
|
56
57
|
Returns:
|
57
58
|
Result of the coroutine or raises asyncio.TimeoutError
|
58
59
|
"""
|
59
60
|
return asyncio.wait_for(coro, timeout=seconds)
|
60
|
-
|
61
|
+
|
61
62
|
return _timeout_wrapper
|
62
63
|
|
63
64
|
|
@@ -65,16 +66,16 @@ def async_timeout() -> Callable[[float], asyncio.Task]:
|
|
65
66
|
def event_loop_policy():
|
66
67
|
"""
|
67
68
|
Set event loop policy for tests to avoid conflicts.
|
68
|
-
|
69
|
+
|
69
70
|
Returns:
|
70
71
|
New event loop policy for isolated testing.
|
71
72
|
"""
|
72
73
|
policy = asyncio.get_event_loop_policy()
|
73
74
|
new_policy = asyncio.DefaultEventLoopPolicy()
|
74
75
|
asyncio.set_event_loop_policy(new_policy)
|
75
|
-
|
76
|
+
|
76
77
|
yield new_policy
|
77
|
-
|
78
|
+
|
78
79
|
# Restore original policy
|
79
80
|
asyncio.set_event_loop_policy(policy)
|
80
81
|
|
@@ -83,18 +84,19 @@ def event_loop_policy():
|
|
83
84
|
async def async_context_manager():
|
84
85
|
"""
|
85
86
|
Factory for creating mock async context managers.
|
86
|
-
|
87
|
+
|
87
88
|
Returns:
|
88
89
|
Function that creates configured async context manager mocks.
|
89
90
|
"""
|
91
|
+
|
90
92
|
def _create_async_cm(enter_value=None, exit_value=None):
|
91
93
|
"""
|
92
94
|
Create a mock async context manager.
|
93
|
-
|
95
|
+
|
94
96
|
Args:
|
95
97
|
enter_value: Value to return from __aenter__
|
96
98
|
exit_value: Value to return from __aexit__
|
97
|
-
|
99
|
+
|
98
100
|
Returns:
|
99
101
|
AsyncMock configured as context manager
|
100
102
|
"""
|
@@ -102,7 +104,7 @@ async def async_context_manager():
|
|
102
104
|
mock_cm.__aenter__ = AsyncMock(return_value=enter_value)
|
103
105
|
mock_cm.__aexit__ = AsyncMock(return_value=exit_value)
|
104
106
|
return mock_cm
|
105
|
-
|
107
|
+
|
106
108
|
return _create_async_cm
|
107
109
|
|
108
110
|
|
@@ -110,37 +112,39 @@ async def async_context_manager():
|
|
110
112
|
async def async_iterator():
|
111
113
|
"""
|
112
114
|
Factory for creating mock async iterators.
|
113
|
-
|
115
|
+
|
114
116
|
Returns:
|
115
117
|
Function that creates async iterator mocks with specified values.
|
116
118
|
"""
|
119
|
+
|
117
120
|
def _create_async_iter(values):
|
118
121
|
"""
|
119
122
|
Create a mock async iterator.
|
120
|
-
|
123
|
+
|
121
124
|
Args:
|
122
125
|
values: List of values to yield
|
123
|
-
|
126
|
+
|
124
127
|
Returns:
|
125
128
|
Async iterator that yields the specified values
|
126
129
|
"""
|
130
|
+
|
127
131
|
class AsyncIterator:
|
128
132
|
def __init__(self, vals):
|
129
133
|
self.vals = vals
|
130
134
|
self.index = 0
|
131
|
-
|
135
|
+
|
132
136
|
def __aiter__(self):
|
133
137
|
return self
|
134
|
-
|
138
|
+
|
135
139
|
async def __anext__(self):
|
136
140
|
if self.index >= len(self.vals):
|
137
141
|
raise StopAsyncIteration
|
138
142
|
value = self.vals[self.index]
|
139
143
|
self.index += 1
|
140
144
|
return value
|
141
|
-
|
145
|
+
|
142
146
|
return AsyncIterator(values)
|
143
|
-
|
147
|
+
|
144
148
|
return _create_async_iter
|
145
149
|
|
146
150
|
|
@@ -148,7 +152,7 @@ async def async_iterator():
|
|
148
152
|
def async_queue():
|
149
153
|
"""
|
150
154
|
Create an async queue for testing producer/consumer patterns.
|
151
|
-
|
155
|
+
|
152
156
|
Returns:
|
153
157
|
asyncio.Queue instance for testing.
|
154
158
|
"""
|
@@ -159,7 +163,7 @@ def async_queue():
|
|
159
163
|
async def async_lock():
|
160
164
|
"""
|
161
165
|
Create an async lock for testing synchronization.
|
162
|
-
|
166
|
+
|
163
167
|
Returns:
|
164
168
|
asyncio.Lock instance for testing.
|
165
169
|
"""
|
@@ -170,20 +174,20 @@ async def async_lock():
|
|
170
174
|
def mock_async_sleep():
|
171
175
|
"""
|
172
176
|
Mock asyncio.sleep to speed up tests.
|
173
|
-
|
177
|
+
|
174
178
|
Returns:
|
175
179
|
Mock that replaces asyncio.sleep with instant return.
|
176
180
|
"""
|
177
181
|
original_sleep = asyncio.sleep
|
178
|
-
|
182
|
+
|
179
183
|
async def instant_sleep(seconds):
|
180
184
|
"""Sleep replacement that returns immediately."""
|
181
185
|
return None
|
182
|
-
|
186
|
+
|
183
187
|
asyncio.sleep = instant_sleep
|
184
|
-
|
188
|
+
|
185
189
|
yield instant_sleep
|
186
|
-
|
190
|
+
|
187
191
|
# Restore original
|
188
192
|
asyncio.sleep = original_sleep
|
189
193
|
|
@@ -192,23 +196,24 @@ def mock_async_sleep():
|
|
192
196
|
def async_gather_helper():
|
193
197
|
"""
|
194
198
|
Helper for testing asyncio.gather operations.
|
195
|
-
|
199
|
+
|
196
200
|
Returns:
|
197
201
|
Function to gather async results with error handling.
|
198
202
|
"""
|
203
|
+
|
199
204
|
async def _gather(*coroutines, return_exceptions: bool = False):
|
200
205
|
"""
|
201
206
|
Gather results from multiple coroutines.
|
202
|
-
|
207
|
+
|
203
208
|
Args:
|
204
209
|
*coroutines: Coroutines to gather
|
205
210
|
return_exceptions: Whether to return exceptions as results
|
206
|
-
|
211
|
+
|
207
212
|
Returns:
|
208
213
|
List of results from coroutines
|
209
214
|
"""
|
210
215
|
return await asyncio.gather(*coroutines, return_exceptions=return_exceptions)
|
211
|
-
|
216
|
+
|
212
217
|
return _gather
|
213
218
|
|
214
219
|
|
@@ -216,59 +221,58 @@ def async_gather_helper():
|
|
216
221
|
def async_task_group():
|
217
222
|
"""
|
218
223
|
Manage a group of async tasks with cleanup.
|
219
|
-
|
224
|
+
|
220
225
|
Returns:
|
221
226
|
AsyncTaskGroup instance for managing tasks.
|
222
227
|
"""
|
228
|
+
|
223
229
|
class AsyncTaskGroup:
|
224
230
|
def __init__(self):
|
225
231
|
self.tasks = []
|
226
|
-
|
232
|
+
|
227
233
|
def create_task(self, coro):
|
228
234
|
"""Create and track a task."""
|
229
235
|
task = asyncio.create_task(coro)
|
230
236
|
self.tasks.append(task)
|
231
237
|
return task
|
232
|
-
|
238
|
+
|
233
239
|
async def wait_all(self, timeout: float = None):
|
234
240
|
"""Wait for all tasks to complete."""
|
235
241
|
if not self.tasks:
|
236
242
|
return []
|
237
|
-
|
243
|
+
|
238
244
|
done, pending = await asyncio.wait(
|
239
|
-
self.tasks,
|
240
|
-
timeout=timeout,
|
241
|
-
return_when=asyncio.ALL_COMPLETED
|
245
|
+
self.tasks, timeout=timeout, return_when=asyncio.ALL_COMPLETED
|
242
246
|
)
|
243
|
-
|
247
|
+
|
244
248
|
if pending:
|
245
249
|
for task in pending:
|
246
250
|
task.cancel()
|
247
|
-
|
251
|
+
|
248
252
|
results = []
|
249
253
|
for task in done:
|
250
254
|
try:
|
251
255
|
results.append(task.result())
|
252
256
|
except Exception as e:
|
253
257
|
results.append(e)
|
254
|
-
|
258
|
+
|
255
259
|
return results
|
256
|
-
|
260
|
+
|
257
261
|
async def cancel_all(self):
|
258
262
|
"""Cancel all tasks."""
|
259
263
|
for task in self.tasks:
|
260
264
|
if not task.done():
|
261
265
|
task.cancel()
|
262
|
-
|
266
|
+
|
263
267
|
if self.tasks:
|
264
268
|
await asyncio.gather(*self.tasks, return_exceptions=True)
|
265
|
-
|
269
|
+
|
266
270
|
async def __aenter__(self):
|
267
271
|
return self
|
268
|
-
|
272
|
+
|
269
273
|
async def __aexit__(self, *args):
|
270
274
|
await self.cancel_all()
|
271
|
-
|
275
|
+
|
272
276
|
return AsyncTaskGroup()
|
273
277
|
|
274
278
|
|
@@ -276,31 +280,34 @@ def async_task_group():
|
|
276
280
|
def async_condition_waiter():
|
277
281
|
"""
|
278
282
|
Helper for waiting on async conditions in tests.
|
279
|
-
|
283
|
+
|
280
284
|
Returns:
|
281
285
|
Function to wait for conditions with timeout.
|
282
286
|
"""
|
283
|
-
|
287
|
+
|
288
|
+
async def _wait_for(
|
289
|
+
condition: Callable[[], bool], timeout: float = 5.0, interval: float = 0.1
|
290
|
+
):
|
284
291
|
"""
|
285
292
|
Wait for a condition to become true.
|
286
|
-
|
293
|
+
|
287
294
|
Args:
|
288
295
|
condition: Function that returns True when condition is met
|
289
296
|
timeout: Maximum wait time
|
290
297
|
interval: Check interval
|
291
|
-
|
298
|
+
|
292
299
|
Returns:
|
293
300
|
True if condition met, False if timeout
|
294
301
|
"""
|
295
302
|
start = asyncio.get_event_loop().time()
|
296
|
-
|
303
|
+
|
297
304
|
while asyncio.get_event_loop().time() - start < timeout:
|
298
305
|
if condition():
|
299
306
|
return True
|
300
307
|
await asyncio.sleep(interval)
|
301
|
-
|
308
|
+
|
302
309
|
return False
|
303
|
-
|
310
|
+
|
304
311
|
return _wait_for
|
305
312
|
|
306
313
|
|
@@ -308,20 +315,21 @@ def async_condition_waiter():
|
|
308
315
|
def async_pipeline():
|
309
316
|
"""
|
310
317
|
Create an async pipeline for testing data flow.
|
311
|
-
|
318
|
+
|
312
319
|
Returns:
|
313
320
|
AsyncPipeline instance for chaining async operations.
|
314
321
|
"""
|
322
|
+
|
315
323
|
class AsyncPipeline:
|
316
324
|
def __init__(self):
|
317
325
|
self.stages = []
|
318
326
|
self.results = []
|
319
|
-
|
327
|
+
|
320
328
|
def add_stage(self, func: Callable):
|
321
329
|
"""Add a processing stage."""
|
322
330
|
self.stages.append(func)
|
323
331
|
return self
|
324
|
-
|
332
|
+
|
325
333
|
async def process(self, data):
|
326
334
|
"""Process data through all stages."""
|
327
335
|
result = data
|
@@ -332,17 +340,17 @@ def async_pipeline():
|
|
332
340
|
result = stage(result)
|
333
341
|
self.results.append(result)
|
334
342
|
return result
|
335
|
-
|
343
|
+
|
336
344
|
async def process_batch(self, items: list):
|
337
345
|
"""Process multiple items."""
|
338
346
|
tasks = [self.process(item) for item in items]
|
339
347
|
return await asyncio.gather(*tasks)
|
340
|
-
|
348
|
+
|
341
349
|
def clear(self):
|
342
350
|
"""Clear stages and results."""
|
343
351
|
self.stages.clear()
|
344
352
|
self.results.clear()
|
345
|
-
|
353
|
+
|
346
354
|
return AsyncPipeline()
|
347
355
|
|
348
356
|
|
@@ -350,56 +358,57 @@ def async_pipeline():
|
|
350
358
|
def async_rate_limiter():
|
351
359
|
"""
|
352
360
|
Create an async rate limiter for testing.
|
353
|
-
|
361
|
+
|
354
362
|
Returns:
|
355
363
|
AsyncRateLimiter instance for controlling request rates.
|
356
364
|
"""
|
365
|
+
|
357
366
|
class AsyncRateLimiter:
|
358
367
|
def __init__(self, rate: int = 10, per: float = 1.0):
|
359
368
|
self.rate = rate
|
360
369
|
self.per = per
|
361
370
|
self.allowance = rate
|
362
371
|
self.last_check = asyncio.get_event_loop().time()
|
363
|
-
|
372
|
+
|
364
373
|
async def acquire(self):
|
365
374
|
"""Acquire permission to proceed."""
|
366
375
|
current = asyncio.get_event_loop().time()
|
367
376
|
time_passed = current - self.last_check
|
368
377
|
self.last_check = current
|
369
|
-
|
378
|
+
|
370
379
|
self.allowance += time_passed * (self.rate / self.per)
|
371
380
|
if self.allowance > self.rate:
|
372
381
|
self.allowance = self.rate
|
373
|
-
|
382
|
+
|
374
383
|
if self.allowance < 1.0:
|
375
384
|
sleep_time = (1.0 - self.allowance) * (self.per / self.rate)
|
376
385
|
await asyncio.sleep(sleep_time)
|
377
386
|
self.allowance = 0.0
|
378
387
|
else:
|
379
388
|
self.allowance -= 1.0
|
380
|
-
|
389
|
+
|
381
390
|
async def __aenter__(self):
|
382
391
|
await self.acquire()
|
383
392
|
return self
|
384
|
-
|
393
|
+
|
385
394
|
async def __aexit__(self, *args):
|
386
395
|
pass
|
387
|
-
|
396
|
+
|
388
397
|
return AsyncRateLimiter()
|
389
398
|
|
390
399
|
|
391
400
|
__all__ = [
|
392
|
-
"
|
393
|
-
"async_timeout",
|
394
|
-
"event_loop_policy",
|
401
|
+
"async_condition_waiter",
|
395
402
|
"async_context_manager",
|
403
|
+
"async_gather_helper",
|
396
404
|
"async_iterator",
|
397
|
-
"async_queue",
|
398
405
|
"async_lock",
|
399
|
-
"mock_async_sleep",
|
400
|
-
"async_gather_helper",
|
401
|
-
"async_task_group",
|
402
|
-
"async_condition_waiter",
|
403
406
|
"async_pipeline",
|
407
|
+
"async_queue",
|
404
408
|
"async_rate_limiter",
|
405
|
-
|
409
|
+
"async_task_group",
|
410
|
+
"async_timeout",
|
411
|
+
"clean_event_loop",
|
412
|
+
"event_loop_policy",
|
413
|
+
"mock_async_sleep",
|
414
|
+
]
|
@@ -8,30 +8,28 @@ async subprocess mocking across the provide-io ecosystem.
|
|
8
8
|
|
9
9
|
# Re-export all fixtures from specialized modules
|
10
10
|
from provide.foundation.testing.process.async_fixtures import (
|
11
|
-
|
12
|
-
async_timeout,
|
13
|
-
event_loop_policy,
|
11
|
+
async_condition_waiter,
|
14
12
|
async_context_manager,
|
13
|
+
async_gather_helper,
|
15
14
|
async_iterator,
|
16
|
-
async_queue,
|
17
15
|
async_lock,
|
18
|
-
mock_async_sleep,
|
19
|
-
async_gather_helper,
|
20
|
-
async_task_group,
|
21
|
-
async_condition_waiter,
|
22
16
|
async_pipeline,
|
17
|
+
async_queue,
|
23
18
|
async_rate_limiter,
|
19
|
+
async_task_group,
|
20
|
+
async_timeout,
|
21
|
+
clean_event_loop,
|
22
|
+
event_loop_policy,
|
23
|
+
mock_async_sleep,
|
24
24
|
)
|
25
|
-
|
26
25
|
from provide.foundation.testing.process.subprocess_fixtures import (
|
27
|
-
|
26
|
+
async_mock_server,
|
28
27
|
async_stream_reader,
|
29
28
|
async_subprocess,
|
30
|
-
async_mock_server,
|
31
29
|
async_test_client,
|
30
|
+
mock_async_process,
|
32
31
|
)
|
33
32
|
|
34
|
-
|
35
33
|
__all__ = [
|
36
34
|
# Async fixtures
|
37
35
|
"clean_event_loop",
|
@@ -53,4 +51,4 @@ __all__ = [
|
|
53
51
|
"async_subprocess",
|
54
52
|
"async_mock_server",
|
55
53
|
"async_test_client",
|
56
|
-
]
|
54
|
+
]
|