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
@@ -5,10 +5,9 @@ Fixtures for mocking time, freezing time, and testing time-dependent code
|
|
5
5
|
across the provide-io ecosystem.
|
6
6
|
"""
|
7
7
|
|
8
|
-
import time
|
9
8
|
import datetime
|
9
|
+
import time
|
10
10
|
from typing import Any, Callable
|
11
|
-
from collections.abc import Generator
|
12
11
|
from unittest.mock import Mock, patch
|
13
12
|
|
14
13
|
import pytest
|
@@ -18,56 +17,57 @@ import pytest
|
|
18
17
|
def freeze_time():
|
19
18
|
"""
|
20
19
|
Fixture to freeze time at a specific point.
|
21
|
-
|
20
|
+
|
22
21
|
Returns:
|
23
22
|
Function that freezes time and returns a context manager.
|
24
23
|
"""
|
24
|
+
|
25
25
|
class FrozenTime:
|
26
26
|
def __init__(self, frozen_time: datetime.datetime | None = None):
|
27
27
|
self.frozen_time = frozen_time or datetime.datetime.now()
|
28
28
|
self.original_time = time.time
|
29
29
|
self.original_datetime = datetime.datetime
|
30
30
|
self.patches = []
|
31
|
-
|
31
|
+
|
32
32
|
def __enter__(self):
|
33
33
|
# Patch time.time()
|
34
|
-
time_patch = patch(
|
34
|
+
time_patch = patch("time.time", return_value=self.frozen_time.timestamp())
|
35
35
|
self.patches.append(time_patch)
|
36
36
|
time_patch.start()
|
37
|
-
|
37
|
+
|
38
38
|
# Patch datetime.datetime.now()
|
39
|
-
datetime_patch = patch(
|
39
|
+
datetime_patch = patch("datetime.datetime", wraps=datetime.datetime)
|
40
40
|
mock_datetime = datetime_patch.start()
|
41
41
|
mock_datetime.now.return_value = self.frozen_time
|
42
42
|
mock_datetime.utcnow.return_value = self.frozen_time
|
43
43
|
self.patches.append(datetime_patch)
|
44
|
-
|
44
|
+
|
45
45
|
return self
|
46
|
-
|
46
|
+
|
47
47
|
def __exit__(self, *args):
|
48
48
|
for p in self.patches:
|
49
49
|
p.stop()
|
50
|
-
|
50
|
+
|
51
51
|
def tick(self, seconds: float = 1.0):
|
52
52
|
"""Advance the frozen time by the specified seconds."""
|
53
53
|
self.frozen_time += datetime.timedelta(seconds=seconds)
|
54
54
|
# Update mocks
|
55
55
|
for p in self.patches:
|
56
|
-
if hasattr(p,
|
56
|
+
if hasattr(p, "return_value"):
|
57
57
|
p.return_value = self.frozen_time.timestamp()
|
58
|
-
|
58
|
+
|
59
59
|
def _freeze(at: datetime.datetime | None = None) -> FrozenTime:
|
60
60
|
"""
|
61
61
|
Freeze time at a specific point.
|
62
|
-
|
62
|
+
|
63
63
|
Args:
|
64
64
|
at: Optional datetime to freeze at (defaults to now)
|
65
|
-
|
65
|
+
|
66
66
|
Returns:
|
67
67
|
FrozenTime context manager
|
68
68
|
"""
|
69
69
|
return FrozenTime(at)
|
70
|
-
|
70
|
+
|
71
71
|
return _freeze
|
72
72
|
|
73
73
|
|
@@ -75,11 +75,11 @@ def freeze_time():
|
|
75
75
|
def mock_sleep():
|
76
76
|
"""
|
77
77
|
Mock time.sleep to speed up tests.
|
78
|
-
|
78
|
+
|
79
79
|
Returns:
|
80
80
|
Mock object that replaces time.sleep.
|
81
81
|
"""
|
82
|
-
with patch(
|
82
|
+
with patch("time.sleep") as mock:
|
83
83
|
# Make sleep instant by default
|
84
84
|
mock.return_value = None
|
85
85
|
yield mock
|
@@ -89,28 +89,30 @@ def mock_sleep():
|
|
89
89
|
def mock_sleep_with_callback():
|
90
90
|
"""
|
91
91
|
Mock time.sleep with a callback for each sleep call.
|
92
|
-
|
92
|
+
|
93
93
|
Returns:
|
94
94
|
Function to set up sleep mock with callback.
|
95
95
|
"""
|
96
|
+
|
96
97
|
def _mock_sleep(callback: Callable[[float], None] = None):
|
97
98
|
"""
|
98
99
|
Create a mock sleep with optional callback.
|
99
|
-
|
100
|
+
|
100
101
|
Args:
|
101
102
|
callback: Function called with sleep duration
|
102
|
-
|
103
|
+
|
103
104
|
Returns:
|
104
105
|
Mock sleep object
|
105
106
|
"""
|
107
|
+
|
106
108
|
def sleep_side_effect(seconds):
|
107
109
|
if callback:
|
108
110
|
callback(seconds)
|
109
111
|
return None
|
110
|
-
|
112
|
+
|
111
113
|
mock = Mock(side_effect=sleep_side_effect)
|
112
114
|
return mock
|
113
|
-
|
115
|
+
|
114
116
|
return _mock_sleep
|
115
117
|
|
116
118
|
|
@@ -118,60 +120,61 @@ def mock_sleep_with_callback():
|
|
118
120
|
def time_machine():
|
119
121
|
"""
|
120
122
|
Advanced time manipulation fixture.
|
121
|
-
|
123
|
+
|
122
124
|
Provides methods to:
|
123
125
|
- Freeze time
|
124
126
|
- Speed up/slow down time
|
125
127
|
- Jump to specific times
|
126
|
-
|
128
|
+
|
127
129
|
Returns:
|
128
130
|
TimeMachine instance for time manipulation.
|
129
131
|
"""
|
132
|
+
|
130
133
|
class TimeMachine:
|
131
134
|
def __init__(self):
|
132
135
|
self.current_time = time.time()
|
133
136
|
self.speed_multiplier = 1.0
|
134
137
|
self.patches = []
|
135
138
|
self.is_frozen = False
|
136
|
-
|
139
|
+
|
137
140
|
def freeze(self, at: float | None = None):
|
138
141
|
"""Freeze time at a specific timestamp."""
|
139
142
|
self.is_frozen = True
|
140
143
|
self.current_time = at or time.time()
|
141
|
-
|
142
|
-
patcher = patch(
|
144
|
+
|
145
|
+
patcher = patch("time.time", return_value=self.current_time)
|
143
146
|
mock = patcher.start()
|
144
147
|
self.patches.append(patcher)
|
145
148
|
return self
|
146
|
-
|
149
|
+
|
147
150
|
def unfreeze(self):
|
148
151
|
"""Unfreeze time."""
|
149
152
|
self.is_frozen = False
|
150
153
|
for p in self.patches:
|
151
154
|
p.stop()
|
152
155
|
self.patches.clear()
|
153
|
-
|
156
|
+
|
154
157
|
def jump(self, seconds: float):
|
155
158
|
"""Jump forward or backward in time."""
|
156
159
|
self.current_time += seconds
|
157
160
|
if self.is_frozen:
|
158
161
|
for p in self.patches:
|
159
|
-
if hasattr(p,
|
162
|
+
if hasattr(p, "return_value"):
|
160
163
|
p.return_value = self.current_time
|
161
|
-
|
164
|
+
|
162
165
|
def speed_up(self, factor: float):
|
163
166
|
"""Speed up time by a factor."""
|
164
167
|
self.speed_multiplier = factor
|
165
|
-
|
168
|
+
|
166
169
|
def slow_down(self, factor: float):
|
167
170
|
"""Slow down time by a factor."""
|
168
171
|
self.speed_multiplier = 1.0 / factor
|
169
|
-
|
172
|
+
|
170
173
|
def cleanup(self):
|
171
174
|
"""Clean up all patches."""
|
172
175
|
for p in self.patches:
|
173
176
|
p.stop()
|
174
|
-
|
177
|
+
|
175
178
|
machine = TimeMachine()
|
176
179
|
yield machine
|
177
180
|
machine.cleanup()
|
@@ -181,21 +184,22 @@ def time_machine():
|
|
181
184
|
def timer():
|
182
185
|
"""
|
183
186
|
Timer fixture for measuring execution time.
|
184
|
-
|
187
|
+
|
185
188
|
Returns:
|
186
189
|
Timer instance for measuring durations.
|
187
190
|
"""
|
191
|
+
|
188
192
|
class Timer:
|
189
193
|
def __init__(self):
|
190
194
|
self.start_time = None
|
191
195
|
self.end_time = None
|
192
196
|
self.durations = []
|
193
|
-
|
197
|
+
|
194
198
|
def start(self):
|
195
199
|
"""Start the timer."""
|
196
200
|
self.start_time = time.perf_counter()
|
197
201
|
return self
|
198
|
-
|
202
|
+
|
199
203
|
def stop(self) -> float:
|
200
204
|
"""Stop the timer and return duration."""
|
201
205
|
self.end_time = time.perf_counter()
|
@@ -204,16 +208,16 @@ def timer():
|
|
204
208
|
duration = self.end_time - self.start_time
|
205
209
|
self.durations.append(duration)
|
206
210
|
return duration
|
207
|
-
|
211
|
+
|
208
212
|
def __enter__(self):
|
209
213
|
"""Context manager entry."""
|
210
214
|
self.start()
|
211
215
|
return self
|
212
|
-
|
216
|
+
|
213
217
|
def __exit__(self, *args):
|
214
218
|
"""Context manager exit."""
|
215
219
|
self.stop()
|
216
|
-
|
220
|
+
|
217
221
|
@property
|
218
222
|
def elapsed(self) -> float:
|
219
223
|
"""Get elapsed time since start."""
|
@@ -222,20 +226,20 @@ def timer():
|
|
222
226
|
if self.end_time is None:
|
223
227
|
return time.perf_counter() - self.start_time
|
224
228
|
return self.end_time - self.start_time
|
225
|
-
|
229
|
+
|
226
230
|
@property
|
227
231
|
def average(self) -> float:
|
228
232
|
"""Get average duration from all measurements."""
|
229
233
|
if not self.durations:
|
230
234
|
return 0.0
|
231
235
|
return sum(self.durations) / len(self.durations)
|
232
|
-
|
236
|
+
|
233
237
|
def reset(self):
|
234
238
|
"""Reset the timer."""
|
235
239
|
self.start_time = None
|
236
240
|
self.end_time = None
|
237
241
|
self.durations.clear()
|
238
|
-
|
242
|
+
|
239
243
|
return Timer()
|
240
244
|
|
241
245
|
|
@@ -243,20 +247,20 @@ def timer():
|
|
243
247
|
def mock_datetime():
|
244
248
|
"""
|
245
249
|
Mock datetime module for testing.
|
246
|
-
|
250
|
+
|
247
251
|
Returns:
|
248
252
|
Mock datetime module with common methods mocked.
|
249
253
|
"""
|
250
|
-
with patch(
|
254
|
+
with patch("datetime.datetime") as mock_dt:
|
251
255
|
# Set up a fake "now"
|
252
256
|
fake_now = datetime.datetime(2024, 1, 1, 12, 0, 0)
|
253
257
|
mock_dt.now.return_value = fake_now
|
254
258
|
mock_dt.utcnow.return_value = fake_now
|
255
259
|
mock_dt.today.return_value = fake_now.date()
|
256
|
-
|
260
|
+
|
257
261
|
# Allow normal datetime construction
|
258
262
|
mock_dt.side_effect = lambda *args, **kwargs: datetime.datetime(*args, **kwargs)
|
259
|
-
|
263
|
+
|
260
264
|
yield mock_dt
|
261
265
|
|
262
266
|
|
@@ -264,27 +268,27 @@ def mock_datetime():
|
|
264
268
|
def time_travel():
|
265
269
|
"""
|
266
270
|
Fixture for traveling through time in tests.
|
267
|
-
|
271
|
+
|
268
272
|
Returns:
|
269
273
|
Function to travel to specific time points.
|
270
274
|
"""
|
271
275
|
original_time = time.time
|
272
276
|
current_offset = 0.0
|
273
|
-
|
277
|
+
|
274
278
|
def mock_time():
|
275
279
|
return original_time() + current_offset
|
276
|
-
|
280
|
+
|
277
281
|
def _travel_to(target: datetime.datetime):
|
278
282
|
"""
|
279
283
|
Travel to a specific point in time.
|
280
|
-
|
284
|
+
|
281
285
|
Args:
|
282
286
|
target: The datetime to travel to
|
283
287
|
"""
|
284
288
|
nonlocal current_offset
|
285
289
|
current_offset = target.timestamp() - original_time()
|
286
|
-
|
287
|
-
with patch(
|
290
|
+
|
291
|
+
with patch("time.time", mock_time):
|
288
292
|
yield _travel_to
|
289
293
|
|
290
294
|
|
@@ -292,38 +296,39 @@ def time_travel():
|
|
292
296
|
def rate_limiter_mock():
|
293
297
|
"""
|
294
298
|
Mock for testing rate-limited code.
|
295
|
-
|
299
|
+
|
296
300
|
Returns:
|
297
301
|
Mock rate limiter that can be controlled in tests.
|
298
302
|
"""
|
303
|
+
|
299
304
|
class MockRateLimiter:
|
300
305
|
def __init__(self):
|
301
306
|
self.calls = []
|
302
307
|
self.should_limit = False
|
303
308
|
self.limit_after = None
|
304
309
|
self.call_count = 0
|
305
|
-
|
310
|
+
|
306
311
|
def check(self) -> bool:
|
307
312
|
"""Check if rate limit is exceeded."""
|
308
313
|
self.call_count += 1
|
309
314
|
self.calls.append(time.time())
|
310
|
-
|
315
|
+
|
311
316
|
if self.limit_after and self.call_count > self.limit_after:
|
312
317
|
return False # Rate limited
|
313
|
-
|
318
|
+
|
314
319
|
return not self.should_limit
|
315
|
-
|
320
|
+
|
316
321
|
def reset(self):
|
317
322
|
"""Reset the rate limiter."""
|
318
323
|
self.calls.clear()
|
319
324
|
self.call_count = 0
|
320
325
|
self.should_limit = False
|
321
326
|
self.limit_after = None
|
322
|
-
|
327
|
+
|
323
328
|
def set_limit(self, after_calls: int):
|
324
329
|
"""Set to limit after N calls."""
|
325
330
|
self.limit_after = after_calls
|
326
|
-
|
331
|
+
|
327
332
|
return MockRateLimiter()
|
328
333
|
|
329
334
|
|
@@ -331,23 +336,24 @@ def rate_limiter_mock():
|
|
331
336
|
def benchmark_timer():
|
332
337
|
"""
|
333
338
|
Timer specifically for benchmarking code.
|
334
|
-
|
339
|
+
|
335
340
|
Returns:
|
336
341
|
Benchmark timer with statistics.
|
337
342
|
"""
|
343
|
+
|
338
344
|
class BenchmarkTimer:
|
339
345
|
def __init__(self):
|
340
346
|
self.measurements = []
|
341
|
-
|
347
|
+
|
342
348
|
def measure(self, func: Callable, *args, **kwargs) -> tuple[Any, float]:
|
343
349
|
"""
|
344
350
|
Measure execution time of a function.
|
345
|
-
|
351
|
+
|
346
352
|
Args:
|
347
353
|
func: Function to measure
|
348
354
|
*args: Function arguments
|
349
355
|
**kwargs: Function keyword arguments
|
350
|
-
|
356
|
+
|
351
357
|
Returns:
|
352
358
|
Tuple of (result, duration)
|
353
359
|
"""
|
@@ -356,29 +362,35 @@ def benchmark_timer():
|
|
356
362
|
duration = time.perf_counter() - start
|
357
363
|
self.measurements.append(duration)
|
358
364
|
return result, duration
|
359
|
-
|
365
|
+
|
360
366
|
@property
|
361
367
|
def min_time(self) -> float:
|
362
368
|
"""Get minimum execution time."""
|
363
369
|
return min(self.measurements) if self.measurements else 0.0
|
364
|
-
|
370
|
+
|
365
371
|
@property
|
366
372
|
def max_time(self) -> float:
|
367
373
|
"""Get maximum execution time."""
|
368
374
|
return max(self.measurements) if self.measurements else 0.0
|
369
|
-
|
375
|
+
|
370
376
|
@property
|
371
377
|
def avg_time(self) -> float:
|
372
378
|
"""Get average execution time."""
|
373
|
-
return
|
374
|
-
|
379
|
+
return (
|
380
|
+
sum(self.measurements) / len(self.measurements)
|
381
|
+
if self.measurements
|
382
|
+
else 0.0
|
383
|
+
)
|
384
|
+
|
375
385
|
def assert_faster_than(self, seconds: float):
|
376
386
|
"""Assert all measurements were faster than threshold."""
|
377
387
|
if not self.measurements:
|
378
388
|
raise AssertionError("No measurements taken")
|
379
389
|
if self.max_time > seconds:
|
380
|
-
raise AssertionError(
|
381
|
-
|
390
|
+
raise AssertionError(
|
391
|
+
f"Maximum time {self.max_time:.3f}s exceeded threshold {seconds:.3f}s"
|
392
|
+
)
|
393
|
+
|
382
394
|
return BenchmarkTimer()
|
383
395
|
|
384
396
|
|
@@ -386,24 +398,24 @@ def benchmark_timer():
|
|
386
398
|
def advance_time(mock_time: Mock, seconds: float):
|
387
399
|
"""
|
388
400
|
Advance a mocked time by specified seconds.
|
389
|
-
|
401
|
+
|
390
402
|
Args:
|
391
403
|
mock_time: The mock time object
|
392
404
|
seconds: Number of seconds to advance
|
393
405
|
"""
|
394
|
-
if hasattr(mock_time,
|
406
|
+
if hasattr(mock_time, "return_value"):
|
395
407
|
mock_time.return_value += seconds
|
396
408
|
|
397
409
|
|
398
410
|
__all__ = [
|
411
|
+
"advance_time",
|
412
|
+
"benchmark_timer",
|
399
413
|
"freeze_time",
|
414
|
+
"mock_datetime",
|
400
415
|
"mock_sleep",
|
401
416
|
"mock_sleep_with_callback",
|
417
|
+
"rate_limiter_mock",
|
402
418
|
"time_machine",
|
403
|
-
"timer",
|
404
|
-
"mock_datetime",
|
405
419
|
"time_travel",
|
406
|
-
"
|
407
|
-
|
408
|
-
"advance_time",
|
409
|
-
]
|
420
|
+
"timer",
|
421
|
+
]
|
@@ -7,24 +7,24 @@ network operations across any project that depends on provide.foundation.
|
|
7
7
|
|
8
8
|
from provide.foundation.testing.transport.fixtures import (
|
9
9
|
free_port,
|
10
|
-
mock_server,
|
11
10
|
httpx_mock_responses,
|
12
|
-
mock_websocket,
|
13
11
|
mock_dns_resolver,
|
14
|
-
|
12
|
+
mock_http_headers,
|
13
|
+
mock_server,
|
15
14
|
mock_ssl_context,
|
15
|
+
mock_websocket,
|
16
16
|
network_timeout,
|
17
|
-
|
17
|
+
tcp_client_server,
|
18
18
|
)
|
19
19
|
|
20
20
|
__all__ = [
|
21
21
|
"free_port",
|
22
|
-
"mock_server",
|
23
22
|
"httpx_mock_responses",
|
24
|
-
"mock_websocket",
|
25
23
|
"mock_dns_resolver",
|
26
|
-
"
|
24
|
+
"mock_http_headers",
|
25
|
+
"mock_server",
|
27
26
|
"mock_ssl_context",
|
27
|
+
"mock_websocket",
|
28
28
|
"network_timeout",
|
29
|
-
"
|
30
|
-
]
|
29
|
+
"tcp_client_server",
|
30
|
+
]
|