provide-foundation 0.0.0.dev1__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.
Files changed (163) hide show
  1. provide/foundation/__init__.py +36 -10
  2. provide/foundation/archive/__init__.py +1 -1
  3. provide/foundation/archive/base.py +15 -14
  4. provide/foundation/archive/bzip2.py +40 -40
  5. provide/foundation/archive/gzip.py +42 -42
  6. provide/foundation/archive/operations.py +93 -96
  7. provide/foundation/archive/tar.py +33 -31
  8. provide/foundation/archive/zip.py +52 -50
  9. provide/foundation/asynctools/__init__.py +20 -0
  10. provide/foundation/asynctools/core.py +126 -0
  11. provide/foundation/cli/__init__.py +2 -2
  12. provide/foundation/cli/commands/deps.py +15 -9
  13. provide/foundation/cli/commands/logs/__init__.py +3 -3
  14. provide/foundation/cli/commands/logs/generate.py +2 -2
  15. provide/foundation/cli/commands/logs/query.py +4 -4
  16. provide/foundation/cli/commands/logs/send.py +3 -3
  17. provide/foundation/cli/commands/logs/tail.py +3 -3
  18. provide/foundation/cli/decorators.py +11 -11
  19. provide/foundation/cli/main.py +1 -1
  20. provide/foundation/cli/testing.py +2 -40
  21. provide/foundation/cli/utils.py +21 -18
  22. provide/foundation/config/__init__.py +35 -2
  23. provide/foundation/config/base.py +2 -2
  24. provide/foundation/config/converters.py +477 -0
  25. provide/foundation/config/defaults.py +67 -0
  26. provide/foundation/config/env.py +6 -20
  27. provide/foundation/config/loader.py +10 -4
  28. provide/foundation/config/sync.py +8 -6
  29. provide/foundation/config/types.py +5 -5
  30. provide/foundation/config/validators.py +4 -4
  31. provide/foundation/console/input.py +5 -5
  32. provide/foundation/console/output.py +36 -14
  33. provide/foundation/context/__init__.py +8 -4
  34. provide/foundation/context/core.py +88 -110
  35. provide/foundation/crypto/certificates/__init__.py +9 -5
  36. provide/foundation/crypto/certificates/base.py +2 -2
  37. provide/foundation/crypto/certificates/certificate.py +48 -19
  38. provide/foundation/crypto/certificates/factory.py +26 -18
  39. provide/foundation/crypto/certificates/generator.py +24 -23
  40. provide/foundation/crypto/certificates/loader.py +24 -16
  41. provide/foundation/crypto/certificates/operations.py +17 -10
  42. provide/foundation/crypto/certificates/trust.py +21 -21
  43. provide/foundation/env/__init__.py +28 -0
  44. provide/foundation/env/core.py +218 -0
  45. provide/foundation/errors/__init__.py +3 -3
  46. provide/foundation/errors/decorators.py +0 -234
  47. provide/foundation/errors/types.py +0 -98
  48. provide/foundation/eventsets/display.py +13 -14
  49. provide/foundation/eventsets/registry.py +61 -31
  50. provide/foundation/eventsets/resolver.py +50 -46
  51. provide/foundation/eventsets/sets/das.py +8 -8
  52. provide/foundation/eventsets/sets/database.py +14 -14
  53. provide/foundation/eventsets/sets/http.py +21 -21
  54. provide/foundation/eventsets/sets/llm.py +16 -16
  55. provide/foundation/eventsets/sets/task_queue.py +13 -13
  56. provide/foundation/eventsets/types.py +7 -7
  57. provide/foundation/file/directory.py +14 -23
  58. provide/foundation/file/lock.py +4 -3
  59. provide/foundation/hub/components.py +75 -389
  60. provide/foundation/hub/config.py +157 -0
  61. provide/foundation/hub/discovery.py +63 -0
  62. provide/foundation/hub/handlers.py +89 -0
  63. provide/foundation/hub/lifecycle.py +195 -0
  64. provide/foundation/hub/manager.py +7 -4
  65. provide/foundation/hub/processors.py +49 -0
  66. provide/foundation/integrations/__init__.py +11 -0
  67. provide/foundation/{observability → integrations}/openobserve/__init__.py +10 -7
  68. provide/foundation/{observability → integrations}/openobserve/auth.py +1 -1
  69. provide/foundation/{observability → integrations}/openobserve/client.py +14 -14
  70. provide/foundation/{observability → integrations}/openobserve/commands.py +12 -12
  71. provide/foundation/integrations/openobserve/config.py +37 -0
  72. provide/foundation/{observability → integrations}/openobserve/formatters.py +1 -1
  73. provide/foundation/{observability → integrations}/openobserve/otlp.py +2 -2
  74. provide/foundation/{observability → integrations}/openobserve/search.py +2 -3
  75. provide/foundation/{observability → integrations}/openobserve/streaming.py +5 -5
  76. provide/foundation/logger/__init__.py +0 -1
  77. provide/foundation/logger/config/base.py +1 -1
  78. provide/foundation/logger/config/logging.py +69 -299
  79. provide/foundation/logger/config/telemetry.py +39 -121
  80. provide/foundation/logger/factories.py +2 -2
  81. provide/foundation/logger/processors/main.py +12 -10
  82. provide/foundation/logger/ratelimit/limiters.py +4 -4
  83. provide/foundation/logger/ratelimit/processor.py +1 -1
  84. provide/foundation/logger/setup/coordinator.py +39 -25
  85. provide/foundation/logger/setup/processors.py +3 -3
  86. provide/foundation/logger/setup/testing.py +14 -0
  87. provide/foundation/logger/trace.py +5 -5
  88. provide/foundation/metrics/__init__.py +1 -1
  89. provide/foundation/metrics/otel.py +3 -1
  90. provide/foundation/observability/__init__.py +3 -3
  91. provide/foundation/process/__init__.py +9 -0
  92. provide/foundation/process/exit.py +48 -0
  93. provide/foundation/process/lifecycle.py +69 -46
  94. provide/foundation/resilience/__init__.py +36 -0
  95. provide/foundation/resilience/circuit.py +166 -0
  96. provide/foundation/resilience/decorators.py +236 -0
  97. provide/foundation/resilience/fallback.py +208 -0
  98. provide/foundation/resilience/retry.py +327 -0
  99. provide/foundation/serialization/__init__.py +16 -0
  100. provide/foundation/serialization/core.py +70 -0
  101. provide/foundation/streams/config.py +78 -0
  102. provide/foundation/streams/console.py +4 -5
  103. provide/foundation/streams/core.py +5 -2
  104. provide/foundation/streams/file.py +12 -2
  105. provide/foundation/testing/__init__.py +29 -9
  106. provide/foundation/testing/archive/__init__.py +7 -7
  107. provide/foundation/testing/archive/fixtures.py +58 -54
  108. provide/foundation/testing/cli.py +30 -20
  109. provide/foundation/testing/common/__init__.py +13 -15
  110. provide/foundation/testing/common/fixtures.py +27 -57
  111. provide/foundation/testing/file/__init__.py +15 -15
  112. provide/foundation/testing/file/content_fixtures.py +289 -0
  113. provide/foundation/testing/file/directory_fixtures.py +107 -0
  114. provide/foundation/testing/file/fixtures.py +42 -516
  115. provide/foundation/testing/file/special_fixtures.py +145 -0
  116. provide/foundation/testing/logger.py +89 -8
  117. provide/foundation/testing/mocking/__init__.py +21 -21
  118. provide/foundation/testing/mocking/fixtures.py +80 -67
  119. provide/foundation/testing/process/__init__.py +23 -23
  120. provide/foundation/testing/process/async_fixtures.py +414 -0
  121. provide/foundation/testing/process/fixtures.py +48 -571
  122. provide/foundation/testing/process/subprocess_fixtures.py +210 -0
  123. provide/foundation/testing/threading/__init__.py +17 -17
  124. provide/foundation/testing/threading/basic_fixtures.py +105 -0
  125. provide/foundation/testing/threading/data_fixtures.py +101 -0
  126. provide/foundation/testing/threading/execution_fixtures.py +278 -0
  127. provide/foundation/testing/threading/fixtures.py +32 -502
  128. provide/foundation/testing/threading/sync_fixtures.py +100 -0
  129. provide/foundation/testing/time/__init__.py +11 -11
  130. provide/foundation/testing/time/fixtures.py +95 -83
  131. provide/foundation/testing/transport/__init__.py +9 -9
  132. provide/foundation/testing/transport/fixtures.py +54 -54
  133. provide/foundation/time/__init__.py +18 -0
  134. provide/foundation/time/core.py +63 -0
  135. provide/foundation/tools/__init__.py +2 -2
  136. provide/foundation/tools/base.py +68 -67
  137. provide/foundation/tools/cache.py +69 -74
  138. provide/foundation/tools/downloader.py +68 -62
  139. provide/foundation/tools/installer.py +51 -57
  140. provide/foundation/tools/registry.py +38 -45
  141. provide/foundation/tools/resolver.py +70 -68
  142. provide/foundation/tools/verifier.py +39 -50
  143. provide/foundation/tracer/spans.py +2 -14
  144. provide/foundation/transport/__init__.py +26 -33
  145. provide/foundation/transport/base.py +32 -30
  146. provide/foundation/transport/client.py +44 -49
  147. provide/foundation/transport/config.py +36 -107
  148. provide/foundation/transport/errors.py +13 -27
  149. provide/foundation/transport/http.py +69 -55
  150. provide/foundation/transport/middleware.py +113 -114
  151. provide/foundation/transport/registry.py +29 -27
  152. provide/foundation/transport/types.py +6 -6
  153. provide/foundation/utils/deps.py +17 -14
  154. provide/foundation/utils/parsing.py +49 -4
  155. {provide_foundation-0.0.0.dev1.dist-info → provide_foundation-0.0.0.dev3.dist-info}/METADATA +2 -2
  156. provide_foundation-0.0.0.dev3.dist-info/RECORD +233 -0
  157. provide_foundation-0.0.0.dev1.dist-info/RECORD +0 -200
  158. /provide/foundation/{observability → integrations}/openobserve/exceptions.py +0 -0
  159. /provide/foundation/{observability → integrations}/openobserve/models.py +0 -0
  160. {provide_foundation-0.0.0.dev1.dist-info → provide_foundation-0.0.0.dev3.dist-info}/WHEEL +0 -0
  161. {provide_foundation-0.0.0.dev1.dist-info → provide_foundation-0.0.0.dev3.dist-info}/entry_points.txt +0 -0
  162. {provide_foundation-0.0.0.dev1.dist-info → provide_foundation-0.0.0.dev3.dist-info}/licenses/LICENSE +0 -0
  163. {provide_foundation-0.0.0.dev1.dist-info → provide_foundation-0.0.0.dev3.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,278 @@
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
+ from concurrent.futures import ThreadPoolExecutor
9
+ import threading
10
+ import time
11
+ from typing import Any, Callable, Optional
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
+
25
+ class ConcurrentExecutor:
26
+ def __init__(self):
27
+ self.results = []
28
+ self.exceptions = []
29
+
30
+ def run_concurrent(
31
+ self, func: Callable, args_list: list[tuple], max_workers: int = 4
32
+ ) -> list[Any]:
33
+ """
34
+ Run function concurrently with different arguments.
35
+
36
+ Args:
37
+ func: Function to execute
38
+ args_list: List of argument tuples
39
+ max_workers: Maximum concurrent workers
40
+
41
+ Returns:
42
+ List of results in order
43
+ """
44
+ with ThreadPoolExecutor(max_workers=max_workers) as executor:
45
+ futures = []
46
+ for args in args_list:
47
+ if isinstance(args, tuple):
48
+ future = executor.submit(func, *args)
49
+ else:
50
+ future = executor.submit(func, args)
51
+ futures.append(future)
52
+
53
+ results = []
54
+ for future in futures:
55
+ try:
56
+ result = future.result(timeout=10)
57
+ results.append(result)
58
+ self.results.append(result)
59
+ except Exception as e:
60
+ self.exceptions.append(e)
61
+ results.append(None)
62
+
63
+ return results
64
+
65
+ def run_parallel(self, funcs: list[Callable], timeout: float = 10) -> list[Any]:
66
+ """
67
+ Run different functions in parallel.
68
+
69
+ Args:
70
+ funcs: List of functions to execute
71
+ timeout: Timeout for each function
72
+
73
+ Returns:
74
+ List of results
75
+ """
76
+ with ThreadPoolExecutor(max_workers=len(funcs)) as executor:
77
+ futures = [executor.submit(func) for func in funcs]
78
+ results = []
79
+
80
+ for future in futures:
81
+ try:
82
+ result = future.result(timeout=timeout)
83
+ results.append(result)
84
+ except Exception as e:
85
+ self.exceptions.append(e)
86
+ results.append(None)
87
+
88
+ return results
89
+
90
+ return ConcurrentExecutor()
91
+
92
+
93
+ @pytest.fixture
94
+ def thread_synchronizer():
95
+ """
96
+ Helper for synchronizing test threads.
97
+
98
+ Returns:
99
+ Thread synchronization helper.
100
+ """
101
+
102
+ class ThreadSynchronizer:
103
+ def __init__(self):
104
+ self.checkpoints = {}
105
+
106
+ def checkpoint(self, name: str, thread_id: Optional[int] = None):
107
+ """
108
+ Record that a thread reached a checkpoint.
109
+
110
+ Args:
111
+ name: Checkpoint name
112
+ thread_id: Optional thread ID (uses current if None)
113
+ """
114
+ thread_id = thread_id or threading.get_ident()
115
+ if name not in self.checkpoints:
116
+ self.checkpoints[name] = []
117
+ self.checkpoints[name].append((thread_id, time.time()))
118
+
119
+ def wait_for_checkpoint(
120
+ self, name: str, count: int, timeout: float = 5.0
121
+ ) -> bool:
122
+ """
123
+ Wait for N threads to reach a checkpoint.
124
+
125
+ Args:
126
+ name: Checkpoint name
127
+ count: Number of threads to wait for
128
+ timeout: Maximum wait time
129
+
130
+ Returns:
131
+ True if checkpoint reached, False if timeout
132
+ """
133
+ start = time.time()
134
+ while time.time() - start < timeout:
135
+ if name in self.checkpoints and len(self.checkpoints[name]) >= count:
136
+ return True
137
+ time.sleep(0.01)
138
+ return False
139
+
140
+ def get_order(self, checkpoint: str) -> list[int]:
141
+ """
142
+ Get order in which threads reached checkpoint.
143
+
144
+ Args:
145
+ checkpoint: Checkpoint name
146
+
147
+ Returns:
148
+ List of thread IDs in order
149
+ """
150
+ if checkpoint not in self.checkpoints:
151
+ return []
152
+ return [
153
+ tid
154
+ for tid, _ in sorted(self.checkpoints[checkpoint], key=lambda x: x[1])
155
+ ]
156
+
157
+ def clear(self):
158
+ """Clear all checkpoints."""
159
+ self.checkpoints.clear()
160
+
161
+ return ThreadSynchronizer()
162
+
163
+
164
+ @pytest.fixture
165
+ def deadlock_detector():
166
+ """
167
+ Helper for detecting potential deadlocks in tests.
168
+
169
+ Returns:
170
+ Deadlock detection helper.
171
+ """
172
+
173
+ class DeadlockDetector:
174
+ def __init__(self):
175
+ self.locks_held = {} # thread_id -> set of locks
176
+ self.lock = threading.Lock()
177
+
178
+ def acquire(self, lock_name: str, thread_id: Optional[int] = None):
179
+ """Record lock acquisition."""
180
+ thread_id = thread_id or threading.get_ident()
181
+ with self.lock:
182
+ if thread_id not in self.locks_held:
183
+ self.locks_held[thread_id] = set()
184
+ self.locks_held[thread_id].add(lock_name)
185
+
186
+ def release(self, lock_name: str, thread_id: Optional[int] = None):
187
+ """Record lock release."""
188
+ thread_id = thread_id or threading.get_ident()
189
+ with self.lock:
190
+ if thread_id in self.locks_held:
191
+ self.locks_held[thread_id].discard(lock_name)
192
+
193
+ def check_circular_wait(self) -> bool:
194
+ """
195
+ Check for potential circular wait conditions.
196
+
197
+ Returns:
198
+ True if potential deadlock detected
199
+ """
200
+ # Simplified check - in practice would need wait-for graph
201
+ with self.lock:
202
+ # Check if multiple threads hold multiple locks
203
+ multi_lock_threads = [
204
+ tid for tid, locks in self.locks_held.items() if len(locks) > 1
205
+ ]
206
+ return len(multi_lock_threads) > 1
207
+
208
+ def get_held_locks(self) -> dict[int, set[str]]:
209
+ """Get current lock holdings."""
210
+ with self.lock:
211
+ return self.locks_held.copy()
212
+
213
+ return DeadlockDetector()
214
+
215
+
216
+ @pytest.fixture
217
+ def thread_exception_handler():
218
+ """
219
+ Capture exceptions from threads for testing.
220
+
221
+ Returns:
222
+ Exception handler for threads.
223
+ """
224
+
225
+ class ThreadExceptionHandler:
226
+ def __init__(self):
227
+ self.exceptions = []
228
+ self.lock = threading.Lock()
229
+
230
+ def handle(self, func: Callable) -> Callable:
231
+ """
232
+ Wrap function to capture exceptions.
233
+
234
+ Args:
235
+ func: Function to wrap
236
+
237
+ Returns:
238
+ Wrapped function
239
+ """
240
+
241
+ def wrapper(*args, **kwargs):
242
+ try:
243
+ return func(*args, **kwargs)
244
+ except Exception as e:
245
+ with self.lock:
246
+ self.exceptions.append(
247
+ {
248
+ "thread": threading.current_thread().name,
249
+ "exception": e,
250
+ "time": time.time(),
251
+ }
252
+ )
253
+ raise
254
+
255
+ return wrapper
256
+
257
+ def get_exceptions(self) -> list[dict]:
258
+ """Get all captured exceptions."""
259
+ with self.lock:
260
+ return self.exceptions.copy()
261
+
262
+ def assert_no_exceptions(self):
263
+ """Assert no exceptions were raised."""
264
+ with self.lock:
265
+ if self.exceptions:
266
+ raise AssertionError(
267
+ f"Thread exceptions occurred: {self.exceptions}"
268
+ )
269
+
270
+ return ThreadExceptionHandler()
271
+
272
+
273
+ __all__ = [
274
+ "concurrent_executor",
275
+ "deadlock_detector",
276
+ "thread_exception_handler",
277
+ "thread_synchronizer",
278
+ ]