provide-foundation 0.0.0.dev0__py3-none-any.whl → 0.0.0.dev2__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.
Files changed (161) hide show
  1. provide/foundation/__init__.py +41 -23
  2. provide/foundation/archive/__init__.py +23 -0
  3. provide/foundation/archive/base.py +70 -0
  4. provide/foundation/archive/bzip2.py +157 -0
  5. provide/foundation/archive/gzip.py +159 -0
  6. provide/foundation/archive/operations.py +334 -0
  7. provide/foundation/archive/tar.py +164 -0
  8. provide/foundation/archive/zip.py +203 -0
  9. provide/foundation/cli/__init__.py +2 -2
  10. provide/foundation/cli/commands/deps.py +13 -7
  11. provide/foundation/cli/commands/logs/__init__.py +1 -1
  12. provide/foundation/cli/commands/logs/query.py +1 -1
  13. provide/foundation/cli/commands/logs/send.py +1 -1
  14. provide/foundation/cli/commands/logs/tail.py +1 -1
  15. provide/foundation/cli/decorators.py +11 -10
  16. provide/foundation/cli/main.py +1 -1
  17. provide/foundation/cli/testing.py +2 -35
  18. provide/foundation/cli/utils.py +21 -17
  19. provide/foundation/config/__init__.py +35 -2
  20. provide/foundation/config/base.py +2 -2
  21. provide/foundation/config/converters.py +479 -0
  22. provide/foundation/config/defaults.py +67 -0
  23. provide/foundation/config/env.py +4 -19
  24. provide/foundation/config/loader.py +9 -3
  25. provide/foundation/config/sync.py +19 -4
  26. provide/foundation/console/input.py +5 -5
  27. provide/foundation/console/output.py +35 -13
  28. provide/foundation/context/__init__.py +8 -4
  29. provide/foundation/context/core.py +85 -109
  30. provide/foundation/core.py +1 -2
  31. provide/foundation/crypto/__init__.py +2 -0
  32. provide/foundation/crypto/certificates/__init__.py +34 -0
  33. provide/foundation/crypto/certificates/base.py +173 -0
  34. provide/foundation/crypto/certificates/certificate.py +290 -0
  35. provide/foundation/crypto/certificates/factory.py +213 -0
  36. provide/foundation/crypto/certificates/generator.py +138 -0
  37. provide/foundation/crypto/certificates/loader.py +130 -0
  38. provide/foundation/crypto/certificates/operations.py +198 -0
  39. provide/foundation/crypto/certificates/trust.py +107 -0
  40. provide/foundation/errors/__init__.py +2 -3
  41. provide/foundation/errors/decorators.py +0 -231
  42. provide/foundation/errors/types.py +0 -97
  43. provide/foundation/eventsets/__init__.py +0 -0
  44. provide/foundation/eventsets/display.py +84 -0
  45. provide/foundation/eventsets/registry.py +160 -0
  46. provide/foundation/eventsets/resolver.py +192 -0
  47. provide/foundation/eventsets/sets/das.py +128 -0
  48. provide/foundation/eventsets/sets/database.py +125 -0
  49. provide/foundation/eventsets/sets/http.py +153 -0
  50. provide/foundation/eventsets/sets/llm.py +139 -0
  51. provide/foundation/eventsets/sets/task_queue.py +107 -0
  52. provide/foundation/eventsets/types.py +70 -0
  53. provide/foundation/file/directory.py +13 -22
  54. provide/foundation/file/lock.py +3 -1
  55. provide/foundation/hub/components.py +77 -515
  56. provide/foundation/hub/config.py +151 -0
  57. provide/foundation/hub/discovery.py +62 -0
  58. provide/foundation/hub/handlers.py +81 -0
  59. provide/foundation/hub/lifecycle.py +194 -0
  60. provide/foundation/hub/manager.py +4 -4
  61. provide/foundation/hub/processors.py +44 -0
  62. provide/foundation/integrations/__init__.py +11 -0
  63. provide/foundation/{observability → integrations}/openobserve/__init__.py +10 -7
  64. provide/foundation/{observability → integrations}/openobserve/auth.py +1 -1
  65. provide/foundation/{observability → integrations}/openobserve/client.py +12 -12
  66. provide/foundation/{observability → integrations}/openobserve/commands.py +3 -3
  67. provide/foundation/integrations/openobserve/config.py +37 -0
  68. provide/foundation/{observability → integrations}/openobserve/formatters.py +1 -1
  69. provide/foundation/{observability → integrations}/openobserve/otlp.py +1 -1
  70. provide/foundation/{observability → integrations}/openobserve/search.py +2 -2
  71. provide/foundation/{observability → integrations}/openobserve/streaming.py +4 -4
  72. provide/foundation/logger/__init__.py +3 -10
  73. provide/foundation/logger/config/logging.py +68 -298
  74. provide/foundation/logger/config/telemetry.py +41 -121
  75. provide/foundation/logger/core.py +0 -2
  76. provide/foundation/logger/custom_processors.py +1 -0
  77. provide/foundation/logger/factories.py +11 -2
  78. provide/foundation/logger/processors/main.py +20 -84
  79. provide/foundation/logger/setup/__init__.py +5 -1
  80. provide/foundation/logger/setup/coordinator.py +76 -24
  81. provide/foundation/logger/setup/processors.py +2 -9
  82. provide/foundation/logger/trace.py +27 -0
  83. provide/foundation/metrics/otel.py +10 -10
  84. provide/foundation/observability/__init__.py +2 -2
  85. provide/foundation/process/__init__.py +9 -0
  86. provide/foundation/process/exit.py +47 -0
  87. provide/foundation/process/lifecycle.py +115 -59
  88. provide/foundation/resilience/__init__.py +35 -0
  89. provide/foundation/resilience/circuit.py +164 -0
  90. provide/foundation/resilience/decorators.py +220 -0
  91. provide/foundation/resilience/fallback.py +193 -0
  92. provide/foundation/resilience/retry.py +325 -0
  93. provide/foundation/streams/config.py +79 -0
  94. provide/foundation/streams/console.py +7 -8
  95. provide/foundation/streams/core.py +6 -3
  96. provide/foundation/streams/file.py +12 -2
  97. provide/foundation/testing/__init__.py +84 -2
  98. provide/foundation/testing/archive/__init__.py +24 -0
  99. provide/foundation/testing/archive/fixtures.py +217 -0
  100. provide/foundation/testing/cli.py +30 -17
  101. provide/foundation/testing/common/__init__.py +32 -0
  102. provide/foundation/testing/common/fixtures.py +236 -0
  103. provide/foundation/testing/file/__init__.py +40 -0
  104. provide/foundation/testing/file/content_fixtures.py +316 -0
  105. provide/foundation/testing/file/directory_fixtures.py +107 -0
  106. provide/foundation/testing/file/fixtures.py +52 -0
  107. provide/foundation/testing/file/special_fixtures.py +153 -0
  108. provide/foundation/testing/logger.py +117 -11
  109. provide/foundation/testing/mocking/__init__.py +46 -0
  110. provide/foundation/testing/mocking/fixtures.py +331 -0
  111. provide/foundation/testing/process/__init__.py +48 -0
  112. provide/foundation/testing/process/async_fixtures.py +405 -0
  113. provide/foundation/testing/process/fixtures.py +56 -0
  114. provide/foundation/testing/process/subprocess_fixtures.py +209 -0
  115. provide/foundation/testing/threading/__init__.py +38 -0
  116. provide/foundation/testing/threading/basic_fixtures.py +101 -0
  117. provide/foundation/testing/threading/data_fixtures.py +99 -0
  118. provide/foundation/testing/threading/execution_fixtures.py +263 -0
  119. provide/foundation/testing/threading/fixtures.py +54 -0
  120. provide/foundation/testing/threading/sync_fixtures.py +97 -0
  121. provide/foundation/testing/time/__init__.py +32 -0
  122. provide/foundation/testing/time/fixtures.py +409 -0
  123. provide/foundation/testing/transport/__init__.py +30 -0
  124. provide/foundation/testing/transport/fixtures.py +280 -0
  125. provide/foundation/tools/__init__.py +58 -0
  126. provide/foundation/tools/base.py +348 -0
  127. provide/foundation/tools/cache.py +268 -0
  128. provide/foundation/tools/downloader.py +224 -0
  129. provide/foundation/tools/installer.py +254 -0
  130. provide/foundation/tools/registry.py +223 -0
  131. provide/foundation/tools/resolver.py +321 -0
  132. provide/foundation/tools/verifier.py +186 -0
  133. provide/foundation/tracer/otel.py +7 -11
  134. provide/foundation/tracer/spans.py +2 -2
  135. provide/foundation/transport/__init__.py +155 -0
  136. provide/foundation/transport/base.py +171 -0
  137. provide/foundation/transport/client.py +266 -0
  138. provide/foundation/transport/config.py +140 -0
  139. provide/foundation/transport/errors.py +79 -0
  140. provide/foundation/transport/http.py +232 -0
  141. provide/foundation/transport/middleware.py +360 -0
  142. provide/foundation/transport/registry.py +167 -0
  143. provide/foundation/transport/types.py +45 -0
  144. provide/foundation/utils/deps.py +14 -12
  145. provide/foundation/utils/parsing.py +49 -4
  146. {provide_foundation-0.0.0.dev0.dist-info → provide_foundation-0.0.0.dev2.dist-info}/METADATA +5 -28
  147. provide_foundation-0.0.0.dev2.dist-info/RECORD +225 -0
  148. provide/foundation/cli/commands/logs/generate_old.py +0 -569
  149. provide/foundation/crypto/certificates.py +0 -896
  150. provide/foundation/logger/emoji/__init__.py +0 -44
  151. provide/foundation/logger/emoji/matrix.py +0 -209
  152. provide/foundation/logger/emoji/sets.py +0 -458
  153. provide/foundation/logger/emoji/types.py +0 -56
  154. provide/foundation/logger/setup/emoji_resolver.py +0 -64
  155. provide_foundation-0.0.0.dev0.dist-info/RECORD +0 -149
  156. /provide/foundation/{observability → integrations}/openobserve/exceptions.py +0 -0
  157. /provide/foundation/{observability → integrations}/openobserve/models.py +0 -0
  158. {provide_foundation-0.0.0.dev0.dist-info → provide_foundation-0.0.0.dev2.dist-info}/WHEEL +0 -0
  159. {provide_foundation-0.0.0.dev0.dist-info → provide_foundation-0.0.0.dev2.dist-info}/entry_points.txt +0 -0
  160. {provide_foundation-0.0.0.dev0.dist-info → provide_foundation-0.0.0.dev2.dist-info}/licenses/LICENSE +0 -0
  161. {provide_foundation-0.0.0.dev0.dist-info → provide_foundation-0.0.0.dev2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,101 @@
1
+ """
2
+ Basic threading test fixtures.
3
+
4
+ Core fixtures for creating threads, thread pools, mocks, and thread-local storage.
5
+ """
6
+
7
+ import threading
8
+ from concurrent.futures import ThreadPoolExecutor
9
+ from typing import Any, Callable
10
+ from unittest.mock import Mock
11
+
12
+ import pytest
13
+
14
+
15
+ @pytest.fixture
16
+ def test_thread():
17
+ """
18
+ Create a test thread with automatic cleanup.
19
+
20
+ Returns:
21
+ Function to create and manage test threads.
22
+ """
23
+ threads = []
24
+
25
+ def _create_thread(target: Callable, args: tuple = (), kwargs: dict = None, daemon: bool = True) -> threading.Thread:
26
+ """
27
+ Create a test thread.
28
+
29
+ Args:
30
+ target: Function to run in thread
31
+ args: Positional arguments for target
32
+ kwargs: Keyword arguments for target
33
+ daemon: Whether thread should be daemon
34
+
35
+ Returns:
36
+ Started thread instance
37
+ """
38
+ kwargs = kwargs or {}
39
+ thread = threading.Thread(target=target, args=args, kwargs=kwargs, daemon=daemon)
40
+ threads.append(thread)
41
+ thread.start()
42
+ return thread
43
+
44
+ yield _create_thread
45
+
46
+ # Cleanup: wait for all threads to complete
47
+ for thread in threads:
48
+ if thread.is_alive():
49
+ thread.join(timeout=1.0)
50
+
51
+
52
+ @pytest.fixture
53
+ def thread_pool():
54
+ """
55
+ Create a thread pool executor for testing.
56
+
57
+ Returns:
58
+ ThreadPoolExecutor instance with automatic cleanup.
59
+ """
60
+ executor = ThreadPoolExecutor(max_workers=4)
61
+ yield executor
62
+ executor.shutdown(wait=True, cancel_futures=True)
63
+
64
+
65
+ @pytest.fixture
66
+ def mock_thread():
67
+ """
68
+ Create a mock thread for testing without actual threading.
69
+
70
+ Returns:
71
+ Mock thread object.
72
+ """
73
+ mock = Mock(spec=threading.Thread)
74
+ mock.is_alive.return_value = False
75
+ mock.daemon = False
76
+ mock.name = "MockThread"
77
+ mock.ident = 12345
78
+ mock.start = Mock()
79
+ mock.join = Mock()
80
+ mock.run = Mock()
81
+
82
+ return mock
83
+
84
+
85
+ @pytest.fixture
86
+ def thread_local_storage():
87
+ """
88
+ Create thread-local storage for testing.
89
+
90
+ Returns:
91
+ Thread-local storage object.
92
+ """
93
+ return threading.local()
94
+
95
+
96
+ __all__ = [
97
+ "test_thread",
98
+ "thread_pool",
99
+ "mock_thread",
100
+ "thread_local_storage",
101
+ ]
@@ -0,0 +1,99 @@
1
+ """
2
+ Thread-safe data structure test fixtures.
3
+
4
+ Fixtures for thread-safe lists, counters, and other data structures for testing.
5
+ """
6
+
7
+ import threading
8
+ from typing import Any
9
+
10
+ import pytest
11
+
12
+
13
+ @pytest.fixture
14
+ def thread_safe_list():
15
+ """
16
+ Create a thread-safe list for collecting results.
17
+
18
+ Returns:
19
+ Thread-safe list implementation.
20
+ """
21
+ class ThreadSafeList:
22
+ def __init__(self):
23
+ self._list = []
24
+ self._lock = threading.Lock()
25
+
26
+ def append(self, item: Any):
27
+ """Thread-safe append."""
28
+ with self._lock:
29
+ self._list.append(item)
30
+
31
+ def extend(self, items):
32
+ """Thread-safe extend."""
33
+ with self._lock:
34
+ self._list.extend(items)
35
+
36
+ def get_all(self) -> list:
37
+ """Get copy of all items."""
38
+ with self._lock:
39
+ return self._list.copy()
40
+
41
+ def clear(self):
42
+ """Clear the list."""
43
+ with self._lock:
44
+ self._list.clear()
45
+
46
+ def __len__(self) -> int:
47
+ with self._lock:
48
+ return len(self._list)
49
+
50
+ def __getitem__(self, index):
51
+ with self._lock:
52
+ return self._list[index]
53
+
54
+ return ThreadSafeList()
55
+
56
+
57
+ @pytest.fixture
58
+ def thread_safe_counter():
59
+ """
60
+ Create a thread-safe counter.
61
+
62
+ Returns:
63
+ Thread-safe counter implementation.
64
+ """
65
+ class ThreadSafeCounter:
66
+ def __init__(self, initial: int = 0):
67
+ self._value = initial
68
+ self._lock = threading.Lock()
69
+
70
+ def increment(self, amount: int = 1) -> int:
71
+ """Thread-safe increment."""
72
+ with self._lock:
73
+ self._value += amount
74
+ return self._value
75
+
76
+ def decrement(self, amount: int = 1) -> int:
77
+ """Thread-safe decrement."""
78
+ with self._lock:
79
+ self._value -= amount
80
+ return self._value
81
+
82
+ @property
83
+ def value(self) -> int:
84
+ """Get current value."""
85
+ with self._lock:
86
+ return self._value
87
+
88
+ def reset(self, value: int = 0):
89
+ """Reset counter."""
90
+ with self._lock:
91
+ self._value = value
92
+
93
+ return ThreadSafeCounter()
94
+
95
+
96
+ __all__ = [
97
+ "thread_safe_list",
98
+ "thread_safe_counter",
99
+ ]
@@ -0,0 +1,263 @@
1
+ """
2
+ Thread execution and testing helper fixtures.
3
+
4
+ Advanced fixtures for concurrent execution, synchronization testing, deadlock detection,
5
+ and exception handling in threaded code.
6
+ """
7
+
8
+ import threading
9
+ import time
10
+ from typing import Any, Callable, Optional
11
+ from concurrent.futures import ThreadPoolExecutor
12
+
13
+ import pytest
14
+
15
+
16
+ @pytest.fixture
17
+ def concurrent_executor():
18
+ """
19
+ Helper for executing functions concurrently in tests.
20
+
21
+ Returns:
22
+ Concurrent execution helper.
23
+ """
24
+ class ConcurrentExecutor:
25
+ def __init__(self):
26
+ self.results = []
27
+ self.exceptions = []
28
+
29
+ def run_concurrent(self, func: Callable, args_list: list[tuple], max_workers: int = 4) -> list[Any]:
30
+ """
31
+ Run function concurrently with different arguments.
32
+
33
+ Args:
34
+ func: Function to execute
35
+ args_list: List of argument tuples
36
+ max_workers: Maximum concurrent workers
37
+
38
+ Returns:
39
+ List of results in order
40
+ """
41
+ with ThreadPoolExecutor(max_workers=max_workers) as executor:
42
+ futures = []
43
+ for args in args_list:
44
+ if isinstance(args, tuple):
45
+ future = executor.submit(func, *args)
46
+ else:
47
+ future = executor.submit(func, args)
48
+ futures.append(future)
49
+
50
+ results = []
51
+ for future in futures:
52
+ try:
53
+ result = future.result(timeout=10)
54
+ results.append(result)
55
+ self.results.append(result)
56
+ except Exception as e:
57
+ self.exceptions.append(e)
58
+ results.append(None)
59
+
60
+ return results
61
+
62
+ def run_parallel(self, funcs: list[Callable], timeout: float = 10) -> list[Any]:
63
+ """
64
+ Run different functions in parallel.
65
+
66
+ Args:
67
+ funcs: List of functions to execute
68
+ timeout: Timeout for each function
69
+
70
+ Returns:
71
+ List of results
72
+ """
73
+ with ThreadPoolExecutor(max_workers=len(funcs)) as executor:
74
+ futures = [executor.submit(func) for func in funcs]
75
+ results = []
76
+
77
+ for future in futures:
78
+ try:
79
+ result = future.result(timeout=timeout)
80
+ results.append(result)
81
+ except Exception as e:
82
+ self.exceptions.append(e)
83
+ results.append(None)
84
+
85
+ return results
86
+
87
+ return ConcurrentExecutor()
88
+
89
+
90
+ @pytest.fixture
91
+ def thread_synchronizer():
92
+ """
93
+ Helper for synchronizing test threads.
94
+
95
+ Returns:
96
+ Thread synchronization helper.
97
+ """
98
+ class ThreadSynchronizer:
99
+ def __init__(self):
100
+ self.checkpoints = {}
101
+
102
+ def checkpoint(self, name: str, thread_id: Optional[int] = None):
103
+ """
104
+ Record that a thread reached a checkpoint.
105
+
106
+ Args:
107
+ name: Checkpoint name
108
+ thread_id: Optional thread ID (uses current if None)
109
+ """
110
+ thread_id = thread_id or threading.get_ident()
111
+ if name not in self.checkpoints:
112
+ self.checkpoints[name] = []
113
+ self.checkpoints[name].append((thread_id, time.time()))
114
+
115
+ def wait_for_checkpoint(self, name: str, count: int, timeout: float = 5.0) -> bool:
116
+ """
117
+ Wait for N threads to reach a checkpoint.
118
+
119
+ Args:
120
+ name: Checkpoint name
121
+ count: Number of threads to wait for
122
+ timeout: Maximum wait time
123
+
124
+ Returns:
125
+ True if checkpoint reached, False if timeout
126
+ """
127
+ start = time.time()
128
+ while time.time() - start < timeout:
129
+ if name in self.checkpoints and len(self.checkpoints[name]) >= count:
130
+ return True
131
+ time.sleep(0.01)
132
+ return False
133
+
134
+ def get_order(self, checkpoint: str) -> list[int]:
135
+ """
136
+ Get order in which threads reached checkpoint.
137
+
138
+ Args:
139
+ checkpoint: Checkpoint name
140
+
141
+ Returns:
142
+ List of thread IDs in order
143
+ """
144
+ if checkpoint not in self.checkpoints:
145
+ return []
146
+ return [tid for tid, _ in sorted(self.checkpoints[checkpoint], key=lambda x: x[1])]
147
+
148
+ def clear(self):
149
+ """Clear all checkpoints."""
150
+ self.checkpoints.clear()
151
+
152
+ return ThreadSynchronizer()
153
+
154
+
155
+ @pytest.fixture
156
+ def deadlock_detector():
157
+ """
158
+ Helper for detecting potential deadlocks in tests.
159
+
160
+ Returns:
161
+ Deadlock detection helper.
162
+ """
163
+ class DeadlockDetector:
164
+ def __init__(self):
165
+ self.locks_held = {} # thread_id -> set of locks
166
+ self.lock = threading.Lock()
167
+
168
+ def acquire(self, lock_name: str, thread_id: Optional[int] = None):
169
+ """Record lock acquisition."""
170
+ thread_id = thread_id or threading.get_ident()
171
+ with self.lock:
172
+ if thread_id not in self.locks_held:
173
+ self.locks_held[thread_id] = set()
174
+ self.locks_held[thread_id].add(lock_name)
175
+
176
+ def release(self, lock_name: str, thread_id: Optional[int] = None):
177
+ """Record lock release."""
178
+ thread_id = thread_id or threading.get_ident()
179
+ with self.lock:
180
+ if thread_id in self.locks_held:
181
+ self.locks_held[thread_id].discard(lock_name)
182
+
183
+ def check_circular_wait(self) -> bool:
184
+ """
185
+ Check for potential circular wait conditions.
186
+
187
+ Returns:
188
+ True if potential deadlock detected
189
+ """
190
+ # Simplified check - in practice would need wait-for graph
191
+ with self.lock:
192
+ # Check if multiple threads hold multiple locks
193
+ multi_lock_threads = [
194
+ tid for tid, locks in self.locks_held.items()
195
+ if len(locks) > 1
196
+ ]
197
+ return len(multi_lock_threads) > 1
198
+
199
+ def get_held_locks(self) -> dict[int, set[str]]:
200
+ """Get current lock holdings."""
201
+ with self.lock:
202
+ return self.locks_held.copy()
203
+
204
+ return DeadlockDetector()
205
+
206
+
207
+ @pytest.fixture
208
+ def thread_exception_handler():
209
+ """
210
+ Capture exceptions from threads for testing.
211
+
212
+ Returns:
213
+ Exception handler for threads.
214
+ """
215
+ class ThreadExceptionHandler:
216
+ def __init__(self):
217
+ self.exceptions = []
218
+ self.lock = threading.Lock()
219
+
220
+ def handle(self, func: Callable) -> Callable:
221
+ """
222
+ Wrap function to capture exceptions.
223
+
224
+ Args:
225
+ func: Function to wrap
226
+
227
+ Returns:
228
+ Wrapped function
229
+ """
230
+ def wrapper(*args, **kwargs):
231
+ try:
232
+ return func(*args, **kwargs)
233
+ except Exception as e:
234
+ with self.lock:
235
+ self.exceptions.append({
236
+ 'thread': threading.current_thread().name,
237
+ 'exception': e,
238
+ 'time': time.time()
239
+ })
240
+ raise
241
+
242
+ return wrapper
243
+
244
+ def get_exceptions(self) -> list[dict]:
245
+ """Get all captured exceptions."""
246
+ with self.lock:
247
+ return self.exceptions.copy()
248
+
249
+ def assert_no_exceptions(self):
250
+ """Assert no exceptions were raised."""
251
+ with self.lock:
252
+ if self.exceptions:
253
+ raise AssertionError(f"Thread exceptions occurred: {self.exceptions}")
254
+
255
+ return ThreadExceptionHandler()
256
+
257
+
258
+ __all__ = [
259
+ "concurrent_executor",
260
+ "thread_synchronizer",
261
+ "deadlock_detector",
262
+ "thread_exception_handler",
263
+ ]
@@ -0,0 +1,54 @@
1
+ """
2
+ Threading Test Fixtures and Utilities.
3
+
4
+ Core threading fixtures with re-exports from specialized modules.
5
+ Fixtures for testing multi-threaded code, thread synchronization,
6
+ and concurrent operations across the provide-io ecosystem.
7
+ """
8
+
9
+ # Re-export all fixtures from specialized modules
10
+ from provide.foundation.testing.threading.basic_fixtures import (
11
+ test_thread,
12
+ thread_pool,
13
+ mock_thread,
14
+ thread_local_storage,
15
+ )
16
+
17
+ from provide.foundation.testing.threading.sync_fixtures import (
18
+ thread_barrier,
19
+ thread_event,
20
+ thread_condition,
21
+ )
22
+
23
+ from provide.foundation.testing.threading.data_fixtures import (
24
+ thread_safe_list,
25
+ thread_safe_counter,
26
+ )
27
+
28
+ from provide.foundation.testing.threading.execution_fixtures import (
29
+ concurrent_executor,
30
+ thread_synchronizer,
31
+ deadlock_detector,
32
+ thread_exception_handler,
33
+ )
34
+
35
+
36
+ __all__ = [
37
+ # Basic threading fixtures
38
+ "test_thread",
39
+ "thread_pool",
40
+ "mock_thread",
41
+ "thread_local_storage",
42
+ # Synchronization fixtures
43
+ "thread_barrier",
44
+ "thread_event",
45
+ "thread_condition",
46
+ # Thread-safe data structures
47
+ "thread_safe_list",
48
+ "thread_safe_counter",
49
+ # Execution and testing helpers
50
+ "concurrent_executor",
51
+ "thread_synchronizer",
52
+ "deadlock_detector",
53
+ "thread_exception_handler",
54
+ ]
@@ -0,0 +1,97 @@
1
+ """
2
+ Thread synchronization test fixtures.
3
+
4
+ Fixtures for thread barriers, events, conditions, and other synchronization primitives.
5
+ """
6
+
7
+ import threading
8
+
9
+ import pytest
10
+
11
+
12
+ @pytest.fixture
13
+ def thread_barrier():
14
+ """
15
+ Create a barrier for thread synchronization.
16
+
17
+ Returns:
18
+ Function to create barriers for N threads.
19
+ """
20
+ barriers = []
21
+
22
+ def _create_barrier(n_threads: int, timeout: float | None = None) -> threading.Barrier:
23
+ """
24
+ Create a barrier for synchronizing threads.
25
+
26
+ Args:
27
+ n_threads: Number of threads to synchronize
28
+ timeout: Optional timeout for barrier
29
+
30
+ Returns:
31
+ Barrier instance
32
+ """
33
+ barrier = threading.Barrier(n_threads, timeout=timeout)
34
+ barriers.append(barrier)
35
+ return barrier
36
+
37
+ yield _create_barrier
38
+
39
+ # Cleanup: abort all barriers
40
+ for barrier in barriers:
41
+ try:
42
+ barrier.abort()
43
+ except threading.BrokenBarrierError:
44
+ pass
45
+
46
+
47
+ @pytest.fixture
48
+ def thread_event():
49
+ """
50
+ Create thread events for signaling.
51
+
52
+ Returns:
53
+ Function to create thread events.
54
+ """
55
+ events = []
56
+
57
+ def _create_event() -> threading.Event:
58
+ """Create a thread event."""
59
+ event = threading.Event()
60
+ events.append(event)
61
+ return event
62
+
63
+ yield _create_event
64
+
65
+ # Cleanup: set all events to release waiting threads
66
+ for event in events:
67
+ event.set()
68
+
69
+
70
+ @pytest.fixture
71
+ def thread_condition():
72
+ """
73
+ Create condition variables for thread coordination.
74
+
75
+ Returns:
76
+ Function to create condition variables.
77
+ """
78
+ def _create_condition(lock: Optional[threading.Lock] = None) -> threading.Condition:
79
+ """
80
+ Create a condition variable.
81
+
82
+ Args:
83
+ lock: Optional lock to use (creates new if None)
84
+
85
+ Returns:
86
+ Condition variable
87
+ """
88
+ return threading.Condition(lock)
89
+
90
+ return _create_condition
91
+
92
+
93
+ __all__ = [
94
+ "thread_barrier",
95
+ "thread_event",
96
+ "thread_condition",
97
+ ]
@@ -0,0 +1,32 @@
1
+ """
2
+ Time testing utilities for the provide-io ecosystem.
3
+
4
+ Fixtures and utilities for mocking time, freezing time, and testing
5
+ time-dependent code across any project that depends on provide.foundation.
6
+ """
7
+
8
+ from provide.foundation.testing.time.fixtures import (
9
+ freeze_time,
10
+ mock_sleep,
11
+ mock_sleep_with_callback,
12
+ time_machine,
13
+ timer,
14
+ mock_datetime,
15
+ time_travel,
16
+ rate_limiter_mock,
17
+ benchmark_timer,
18
+ advance_time,
19
+ )
20
+
21
+ __all__ = [
22
+ "freeze_time",
23
+ "mock_sleep",
24
+ "mock_sleep_with_callback",
25
+ "time_machine",
26
+ "timer",
27
+ "mock_datetime",
28
+ "time_travel",
29
+ "rate_limiter_mock",
30
+ "benchmark_timer",
31
+ "advance_time",
32
+ ]