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,10 @@ Advanced fixtures for concurrent execution, synchronization testing, deadlock de
|
|
5
5
|
and exception handling in threaded code.
|
6
6
|
"""
|
7
7
|
|
8
|
+
from concurrent.futures import ThreadPoolExecutor
|
8
9
|
import threading
|
9
10
|
import time
|
10
11
|
from typing import Any, Callable, Optional
|
11
|
-
from concurrent.futures import ThreadPoolExecutor
|
12
12
|
|
13
13
|
import pytest
|
14
14
|
|
@@ -17,24 +17,27 @@ import pytest
|
|
17
17
|
def concurrent_executor():
|
18
18
|
"""
|
19
19
|
Helper for executing functions concurrently in tests.
|
20
|
-
|
20
|
+
|
21
21
|
Returns:
|
22
22
|
Concurrent execution helper.
|
23
23
|
"""
|
24
|
+
|
24
25
|
class ConcurrentExecutor:
|
25
26
|
def __init__(self):
|
26
27
|
self.results = []
|
27
28
|
self.exceptions = []
|
28
|
-
|
29
|
-
def run_concurrent(
|
29
|
+
|
30
|
+
def run_concurrent(
|
31
|
+
self, func: Callable, args_list: list[tuple], max_workers: int = 4
|
32
|
+
) -> list[Any]:
|
30
33
|
"""
|
31
34
|
Run function concurrently with different arguments.
|
32
|
-
|
35
|
+
|
33
36
|
Args:
|
34
37
|
func: Function to execute
|
35
38
|
args_list: List of argument tuples
|
36
39
|
max_workers: Maximum concurrent workers
|
37
|
-
|
40
|
+
|
38
41
|
Returns:
|
39
42
|
List of results in order
|
40
43
|
"""
|
@@ -46,7 +49,7 @@ def concurrent_executor():
|
|
46
49
|
else:
|
47
50
|
future = executor.submit(func, args)
|
48
51
|
futures.append(future)
|
49
|
-
|
52
|
+
|
50
53
|
results = []
|
51
54
|
for future in futures:
|
52
55
|
try:
|
@@ -56,24 +59,24 @@ def concurrent_executor():
|
|
56
59
|
except Exception as e:
|
57
60
|
self.exceptions.append(e)
|
58
61
|
results.append(None)
|
59
|
-
|
62
|
+
|
60
63
|
return results
|
61
|
-
|
64
|
+
|
62
65
|
def run_parallel(self, funcs: list[Callable], timeout: float = 10) -> list[Any]:
|
63
66
|
"""
|
64
67
|
Run different functions in parallel.
|
65
|
-
|
68
|
+
|
66
69
|
Args:
|
67
70
|
funcs: List of functions to execute
|
68
71
|
timeout: Timeout for each function
|
69
|
-
|
72
|
+
|
70
73
|
Returns:
|
71
74
|
List of results
|
72
75
|
"""
|
73
76
|
with ThreadPoolExecutor(max_workers=len(funcs)) as executor:
|
74
77
|
futures = [executor.submit(func) for func in funcs]
|
75
78
|
results = []
|
76
|
-
|
79
|
+
|
77
80
|
for future in futures:
|
78
81
|
try:
|
79
82
|
result = future.result(timeout=timeout)
|
@@ -81,9 +84,9 @@ def concurrent_executor():
|
|
81
84
|
except Exception as e:
|
82
85
|
self.exceptions.append(e)
|
83
86
|
results.append(None)
|
84
|
-
|
87
|
+
|
85
88
|
return results
|
86
|
-
|
89
|
+
|
87
90
|
return ConcurrentExecutor()
|
88
91
|
|
89
92
|
|
@@ -91,18 +94,19 @@ def concurrent_executor():
|
|
91
94
|
def thread_synchronizer():
|
92
95
|
"""
|
93
96
|
Helper for synchronizing test threads.
|
94
|
-
|
97
|
+
|
95
98
|
Returns:
|
96
99
|
Thread synchronization helper.
|
97
100
|
"""
|
101
|
+
|
98
102
|
class ThreadSynchronizer:
|
99
103
|
def __init__(self):
|
100
104
|
self.checkpoints = {}
|
101
|
-
|
105
|
+
|
102
106
|
def checkpoint(self, name: str, thread_id: Optional[int] = None):
|
103
107
|
"""
|
104
108
|
Record that a thread reached a checkpoint.
|
105
|
-
|
109
|
+
|
106
110
|
Args:
|
107
111
|
name: Checkpoint name
|
108
112
|
thread_id: Optional thread ID (uses current if None)
|
@@ -111,16 +115,18 @@ def thread_synchronizer():
|
|
111
115
|
if name not in self.checkpoints:
|
112
116
|
self.checkpoints[name] = []
|
113
117
|
self.checkpoints[name].append((thread_id, time.time()))
|
114
|
-
|
115
|
-
def wait_for_checkpoint(
|
118
|
+
|
119
|
+
def wait_for_checkpoint(
|
120
|
+
self, name: str, count: int, timeout: float = 5.0
|
121
|
+
) -> bool:
|
116
122
|
"""
|
117
123
|
Wait for N threads to reach a checkpoint.
|
118
|
-
|
124
|
+
|
119
125
|
Args:
|
120
126
|
name: Checkpoint name
|
121
127
|
count: Number of threads to wait for
|
122
128
|
timeout: Maximum wait time
|
123
|
-
|
129
|
+
|
124
130
|
Returns:
|
125
131
|
True if checkpoint reached, False if timeout
|
126
132
|
"""
|
@@ -130,25 +136,28 @@ def thread_synchronizer():
|
|
130
136
|
return True
|
131
137
|
time.sleep(0.01)
|
132
138
|
return False
|
133
|
-
|
139
|
+
|
134
140
|
def get_order(self, checkpoint: str) -> list[int]:
|
135
141
|
"""
|
136
142
|
Get order in which threads reached checkpoint.
|
137
|
-
|
143
|
+
|
138
144
|
Args:
|
139
145
|
checkpoint: Checkpoint name
|
140
|
-
|
146
|
+
|
141
147
|
Returns:
|
142
148
|
List of thread IDs in order
|
143
149
|
"""
|
144
150
|
if checkpoint not in self.checkpoints:
|
145
151
|
return []
|
146
|
-
return [
|
147
|
-
|
152
|
+
return [
|
153
|
+
tid
|
154
|
+
for tid, _ in sorted(self.checkpoints[checkpoint], key=lambda x: x[1])
|
155
|
+
]
|
156
|
+
|
148
157
|
def clear(self):
|
149
158
|
"""Clear all checkpoints."""
|
150
159
|
self.checkpoints.clear()
|
151
|
-
|
160
|
+
|
152
161
|
return ThreadSynchronizer()
|
153
162
|
|
154
163
|
|
@@ -156,15 +165,16 @@ def thread_synchronizer():
|
|
156
165
|
def deadlock_detector():
|
157
166
|
"""
|
158
167
|
Helper for detecting potential deadlocks in tests.
|
159
|
-
|
168
|
+
|
160
169
|
Returns:
|
161
170
|
Deadlock detection helper.
|
162
171
|
"""
|
172
|
+
|
163
173
|
class DeadlockDetector:
|
164
174
|
def __init__(self):
|
165
175
|
self.locks_held = {} # thread_id -> set of locks
|
166
176
|
self.lock = threading.Lock()
|
167
|
-
|
177
|
+
|
168
178
|
def acquire(self, lock_name: str, thread_id: Optional[int] = None):
|
169
179
|
"""Record lock acquisition."""
|
170
180
|
thread_id = thread_id or threading.get_ident()
|
@@ -172,18 +182,18 @@ def deadlock_detector():
|
|
172
182
|
if thread_id not in self.locks_held:
|
173
183
|
self.locks_held[thread_id] = set()
|
174
184
|
self.locks_held[thread_id].add(lock_name)
|
175
|
-
|
185
|
+
|
176
186
|
def release(self, lock_name: str, thread_id: Optional[int] = None):
|
177
187
|
"""Record lock release."""
|
178
188
|
thread_id = thread_id or threading.get_ident()
|
179
189
|
with self.lock:
|
180
190
|
if thread_id in self.locks_held:
|
181
191
|
self.locks_held[thread_id].discard(lock_name)
|
182
|
-
|
192
|
+
|
183
193
|
def check_circular_wait(self) -> bool:
|
184
194
|
"""
|
185
195
|
Check for potential circular wait conditions.
|
186
|
-
|
196
|
+
|
187
197
|
Returns:
|
188
198
|
True if potential deadlock detected
|
189
199
|
"""
|
@@ -191,16 +201,15 @@ def deadlock_detector():
|
|
191
201
|
with self.lock:
|
192
202
|
# Check if multiple threads hold multiple locks
|
193
203
|
multi_lock_threads = [
|
194
|
-
tid for tid, locks in self.locks_held.items()
|
195
|
-
if len(locks) > 1
|
204
|
+
tid for tid, locks in self.locks_held.items() if len(locks) > 1
|
196
205
|
]
|
197
206
|
return len(multi_lock_threads) > 1
|
198
|
-
|
207
|
+
|
199
208
|
def get_held_locks(self) -> dict[int, set[str]]:
|
200
209
|
"""Get current lock holdings."""
|
201
210
|
with self.lock:
|
202
211
|
return self.locks_held.copy()
|
203
|
-
|
212
|
+
|
204
213
|
return DeadlockDetector()
|
205
214
|
|
206
215
|
|
@@ -208,56 +217,62 @@ def deadlock_detector():
|
|
208
217
|
def thread_exception_handler():
|
209
218
|
"""
|
210
219
|
Capture exceptions from threads for testing.
|
211
|
-
|
220
|
+
|
212
221
|
Returns:
|
213
222
|
Exception handler for threads.
|
214
223
|
"""
|
224
|
+
|
215
225
|
class ThreadExceptionHandler:
|
216
226
|
def __init__(self):
|
217
227
|
self.exceptions = []
|
218
228
|
self.lock = threading.Lock()
|
219
|
-
|
229
|
+
|
220
230
|
def handle(self, func: Callable) -> Callable:
|
221
231
|
"""
|
222
232
|
Wrap function to capture exceptions.
|
223
|
-
|
233
|
+
|
224
234
|
Args:
|
225
235
|
func: Function to wrap
|
226
|
-
|
236
|
+
|
227
237
|
Returns:
|
228
238
|
Wrapped function
|
229
239
|
"""
|
240
|
+
|
230
241
|
def wrapper(*args, **kwargs):
|
231
242
|
try:
|
232
243
|
return func(*args, **kwargs)
|
233
244
|
except Exception as e:
|
234
245
|
with self.lock:
|
235
|
-
self.exceptions.append(
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
246
|
+
self.exceptions.append(
|
247
|
+
{
|
248
|
+
"thread": threading.current_thread().name,
|
249
|
+
"exception": e,
|
250
|
+
"time": time.time(),
|
251
|
+
}
|
252
|
+
)
|
240
253
|
raise
|
241
|
-
|
254
|
+
|
242
255
|
return wrapper
|
243
|
-
|
256
|
+
|
244
257
|
def get_exceptions(self) -> list[dict]:
|
245
258
|
"""Get all captured exceptions."""
|
246
259
|
with self.lock:
|
247
260
|
return self.exceptions.copy()
|
248
|
-
|
261
|
+
|
249
262
|
def assert_no_exceptions(self):
|
250
263
|
"""Assert no exceptions were raised."""
|
251
264
|
with self.lock:
|
252
265
|
if self.exceptions:
|
253
|
-
raise AssertionError(
|
254
|
-
|
266
|
+
raise AssertionError(
|
267
|
+
f"Thread exceptions occurred: {self.exceptions}"
|
268
|
+
)
|
269
|
+
|
255
270
|
return ThreadExceptionHandler()
|
256
271
|
|
257
272
|
|
258
273
|
__all__ = [
|
259
274
|
"concurrent_executor",
|
260
|
-
"thread_synchronizer",
|
261
275
|
"deadlock_detector",
|
262
276
|
"thread_exception_handler",
|
263
|
-
|
277
|
+
"thread_synchronizer",
|
278
|
+
]
|
@@ -8,30 +8,26 @@ and concurrent operations across the provide-io ecosystem.
|
|
8
8
|
|
9
9
|
# Re-export all fixtures from specialized modules
|
10
10
|
from provide.foundation.testing.threading.basic_fixtures import (
|
11
|
-
test_thread,
|
12
|
-
thread_pool,
|
13
11
|
mock_thread,
|
12
|
+
test_thread,
|
14
13
|
thread_local_storage,
|
14
|
+
thread_pool,
|
15
15
|
)
|
16
|
-
|
17
|
-
from provide.foundation.testing.threading.sync_fixtures import (
|
18
|
-
thread_barrier,
|
19
|
-
thread_event,
|
20
|
-
thread_condition,
|
21
|
-
)
|
22
|
-
|
23
16
|
from provide.foundation.testing.threading.data_fixtures import (
|
24
|
-
thread_safe_list,
|
25
17
|
thread_safe_counter,
|
18
|
+
thread_safe_list,
|
26
19
|
)
|
27
|
-
|
28
20
|
from provide.foundation.testing.threading.execution_fixtures import (
|
29
21
|
concurrent_executor,
|
30
|
-
thread_synchronizer,
|
31
22
|
deadlock_detector,
|
32
23
|
thread_exception_handler,
|
24
|
+
thread_synchronizer,
|
25
|
+
)
|
26
|
+
from provide.foundation.testing.threading.sync_fixtures import (
|
27
|
+
thread_barrier,
|
28
|
+
thread_condition,
|
29
|
+
thread_event,
|
33
30
|
)
|
34
|
-
|
35
31
|
|
36
32
|
__all__ = [
|
37
33
|
# Basic threading fixtures
|
@@ -51,4 +47,4 @@ __all__ = [
|
|
51
47
|
"thread_synchronizer",
|
52
48
|
"deadlock_detector",
|
53
49
|
"thread_exception_handler",
|
54
|
-
]
|
50
|
+
]
|
@@ -13,29 +13,31 @@ import pytest
|
|
13
13
|
def thread_barrier():
|
14
14
|
"""
|
15
15
|
Create a barrier for thread synchronization.
|
16
|
-
|
16
|
+
|
17
17
|
Returns:
|
18
18
|
Function to create barriers for N threads.
|
19
19
|
"""
|
20
20
|
barriers = []
|
21
|
-
|
22
|
-
def _create_barrier(
|
21
|
+
|
22
|
+
def _create_barrier(
|
23
|
+
n_threads: int, timeout: float | None = None
|
24
|
+
) -> threading.Barrier:
|
23
25
|
"""
|
24
26
|
Create a barrier for synchronizing threads.
|
25
|
-
|
27
|
+
|
26
28
|
Args:
|
27
29
|
n_threads: Number of threads to synchronize
|
28
30
|
timeout: Optional timeout for barrier
|
29
|
-
|
31
|
+
|
30
32
|
Returns:
|
31
33
|
Barrier instance
|
32
34
|
"""
|
33
35
|
barrier = threading.Barrier(n_threads, timeout=timeout)
|
34
36
|
barriers.append(barrier)
|
35
37
|
return barrier
|
36
|
-
|
38
|
+
|
37
39
|
yield _create_barrier
|
38
|
-
|
40
|
+
|
39
41
|
# Cleanup: abort all barriers
|
40
42
|
for barrier in barriers:
|
41
43
|
try:
|
@@ -48,20 +50,20 @@ def thread_barrier():
|
|
48
50
|
def thread_event():
|
49
51
|
"""
|
50
52
|
Create thread events for signaling.
|
51
|
-
|
53
|
+
|
52
54
|
Returns:
|
53
55
|
Function to create thread events.
|
54
56
|
"""
|
55
57
|
events = []
|
56
|
-
|
58
|
+
|
57
59
|
def _create_event() -> threading.Event:
|
58
60
|
"""Create a thread event."""
|
59
61
|
event = threading.Event()
|
60
62
|
events.append(event)
|
61
63
|
return event
|
62
|
-
|
64
|
+
|
63
65
|
yield _create_event
|
64
|
-
|
66
|
+
|
65
67
|
# Cleanup: set all events to release waiting threads
|
66
68
|
for event in events:
|
67
69
|
event.set()
|
@@ -71,27 +73,28 @@ def thread_event():
|
|
71
73
|
def thread_condition():
|
72
74
|
"""
|
73
75
|
Create condition variables for thread coordination.
|
74
|
-
|
76
|
+
|
75
77
|
Returns:
|
76
78
|
Function to create condition variables.
|
77
79
|
"""
|
78
|
-
|
80
|
+
|
81
|
+
def _create_condition(lock: threading.Lock | None = None) -> threading.Condition:
|
79
82
|
"""
|
80
83
|
Create a condition variable.
|
81
|
-
|
84
|
+
|
82
85
|
Args:
|
83
86
|
lock: Optional lock to use (creates new if None)
|
84
|
-
|
87
|
+
|
85
88
|
Returns:
|
86
89
|
Condition variable
|
87
90
|
"""
|
88
91
|
return threading.Condition(lock)
|
89
|
-
|
92
|
+
|
90
93
|
return _create_condition
|
91
94
|
|
92
95
|
|
93
96
|
__all__ = [
|
94
97
|
"thread_barrier",
|
95
|
-
"thread_event",
|
96
98
|
"thread_condition",
|
97
|
-
|
99
|
+
"thread_event",
|
100
|
+
]
|
@@ -6,27 +6,27 @@ time-dependent code across any project that depends on provide.foundation.
|
|
6
6
|
"""
|
7
7
|
|
8
8
|
from provide.foundation.testing.time.fixtures import (
|
9
|
+
advance_time,
|
10
|
+
benchmark_timer,
|
9
11
|
freeze_time,
|
12
|
+
mock_datetime,
|
10
13
|
mock_sleep,
|
11
14
|
mock_sleep_with_callback,
|
15
|
+
rate_limiter_mock,
|
12
16
|
time_machine,
|
13
|
-
timer,
|
14
|
-
mock_datetime,
|
15
17
|
time_travel,
|
16
|
-
|
17
|
-
benchmark_timer,
|
18
|
-
advance_time,
|
18
|
+
timer,
|
19
19
|
)
|
20
20
|
|
21
21
|
__all__ = [
|
22
|
+
"advance_time",
|
23
|
+
"benchmark_timer",
|
22
24
|
"freeze_time",
|
25
|
+
"mock_datetime",
|
23
26
|
"mock_sleep",
|
24
27
|
"mock_sleep_with_callback",
|
28
|
+
"rate_limiter_mock",
|
25
29
|
"time_machine",
|
26
|
-
"timer",
|
27
|
-
"mock_datetime",
|
28
30
|
"time_travel",
|
29
|
-
"
|
30
|
-
|
31
|
-
"advance_time",
|
32
|
-
]
|
31
|
+
"timer",
|
32
|
+
]
|