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,7 +5,6 @@ Provides fixtures for mocking and testing subprocess operations,
|
|
5
5
|
stream handling, and process communication.
|
6
6
|
"""
|
7
7
|
|
8
|
-
import asyncio
|
9
8
|
from unittest.mock import AsyncMock, Mock
|
10
9
|
|
11
10
|
import pytest
|
@@ -15,7 +14,7 @@ import pytest
|
|
15
14
|
def mock_async_process() -> AsyncMock:
|
16
15
|
"""
|
17
16
|
Mock async subprocess for testing.
|
18
|
-
|
17
|
+
|
19
18
|
Returns:
|
20
19
|
AsyncMock configured as a subprocess with common attributes.
|
21
20
|
"""
|
@@ -29,7 +28,7 @@ def mock_async_process() -> AsyncMock:
|
|
29
28
|
mock_process.wait = AsyncMock(return_value=0)
|
30
29
|
mock_process.kill = Mock()
|
31
30
|
mock_process.terminate = Mock()
|
32
|
-
|
31
|
+
|
33
32
|
return mock_process
|
34
33
|
|
35
34
|
|
@@ -37,21 +36,21 @@ def mock_async_process() -> AsyncMock:
|
|
37
36
|
async def async_stream_reader() -> AsyncMock:
|
38
37
|
"""
|
39
38
|
Mock async stream reader for subprocess stdout/stderr.
|
40
|
-
|
39
|
+
|
41
40
|
Returns:
|
42
41
|
AsyncMock configured as a stream reader.
|
43
42
|
"""
|
44
43
|
reader = AsyncMock()
|
45
|
-
|
44
|
+
|
46
45
|
# Simulate reading lines
|
47
46
|
async def readline_side_effect():
|
48
47
|
for line in [b"line1\n", b"line2\n", b""]:
|
49
48
|
yield line
|
50
|
-
|
49
|
+
|
51
50
|
reader.readline = AsyncMock(side_effect=readline_side_effect().__anext__)
|
52
51
|
reader.read = AsyncMock(return_value=b"full content")
|
53
52
|
reader.at_eof = Mock(side_effect=[False, False, True])
|
54
|
-
|
53
|
+
|
55
54
|
return reader
|
56
55
|
|
57
56
|
|
@@ -59,25 +58,23 @@ async def async_stream_reader() -> AsyncMock:
|
|
59
58
|
def async_subprocess():
|
60
59
|
"""
|
61
60
|
Create mock async subprocess for testing.
|
62
|
-
|
61
|
+
|
63
62
|
Returns:
|
64
63
|
Function that creates mock subprocess with configurable behavior.
|
65
64
|
"""
|
65
|
+
|
66
66
|
def _create_subprocess(
|
67
|
-
returncode: int = 0,
|
68
|
-
stdout: bytes = b"",
|
69
|
-
stderr: bytes = b"",
|
70
|
-
pid: int = 12345
|
67
|
+
returncode: int = 0, stdout: bytes = b"", stderr: bytes = b"", pid: int = 12345
|
71
68
|
) -> AsyncMock:
|
72
69
|
"""
|
73
70
|
Create a mock async subprocess.
|
74
|
-
|
71
|
+
|
75
72
|
Args:
|
76
73
|
returncode: Process return code
|
77
74
|
stdout: Process stdout output
|
78
75
|
stderr: Process stderr output
|
79
76
|
pid: Process ID
|
80
|
-
|
77
|
+
|
81
78
|
Returns:
|
82
79
|
AsyncMock configured as subprocess
|
83
80
|
"""
|
@@ -89,25 +86,25 @@ def async_subprocess():
|
|
89
86
|
process.kill = Mock()
|
90
87
|
process.terminate = Mock()
|
91
88
|
process.send_signal = Mock()
|
92
|
-
|
89
|
+
|
93
90
|
# Add stdout/stderr as async stream readers
|
94
91
|
process.stdout = AsyncMock()
|
95
92
|
process.stdout.read = AsyncMock(return_value=stdout)
|
96
93
|
process.stdout.readline = AsyncMock(side_effect=[stdout, b""])
|
97
94
|
process.stdout.at_eof = Mock(side_effect=[False, True])
|
98
|
-
|
95
|
+
|
99
96
|
process.stderr = AsyncMock()
|
100
97
|
process.stderr.read = AsyncMock(return_value=stderr)
|
101
98
|
process.stderr.readline = AsyncMock(side_effect=[stderr, b""])
|
102
99
|
process.stderr.at_eof = Mock(side_effect=[False, True])
|
103
|
-
|
100
|
+
|
104
101
|
process.stdin = AsyncMock()
|
105
102
|
process.stdin.write = AsyncMock()
|
106
103
|
process.stdin.drain = AsyncMock()
|
107
104
|
process.stdin.close = Mock()
|
108
|
-
|
105
|
+
|
109
106
|
return process
|
110
|
-
|
107
|
+
|
111
108
|
return _create_subprocess
|
112
109
|
|
113
110
|
|
@@ -115,48 +112,49 @@ def async_subprocess():
|
|
115
112
|
def async_mock_server():
|
116
113
|
"""
|
117
114
|
Create a mock async server for testing.
|
118
|
-
|
115
|
+
|
119
116
|
Returns:
|
120
117
|
Mock server with async methods.
|
121
118
|
"""
|
119
|
+
|
122
120
|
class AsyncMockServer:
|
123
121
|
def __init__(self):
|
124
122
|
self.started = False
|
125
123
|
self.connections = []
|
126
124
|
self.requests = []
|
127
|
-
|
125
|
+
|
128
126
|
async def start(self, host: str = "localhost", port: int = 8080):
|
129
127
|
"""Start the mock server."""
|
130
128
|
self.started = True
|
131
129
|
self.host = host
|
132
130
|
self.port = port
|
133
|
-
|
131
|
+
|
134
132
|
async def stop(self):
|
135
133
|
"""Stop the mock server."""
|
136
134
|
self.started = False
|
137
135
|
for conn in self.connections:
|
138
136
|
await conn.close()
|
139
|
-
|
137
|
+
|
140
138
|
async def handle_connection(self, reader, writer):
|
141
139
|
"""Mock connection handler."""
|
142
140
|
conn = {"reader": reader, "writer": writer}
|
143
141
|
self.connections.append(conn)
|
144
|
-
|
142
|
+
|
145
143
|
# Mock reading request
|
146
144
|
data = await reader.read(1024)
|
147
145
|
self.requests.append(data)
|
148
|
-
|
146
|
+
|
149
147
|
# Mock sending response
|
150
148
|
writer.write(b"HTTP/1.1 200 OK\r\n\r\nOK")
|
151
149
|
await writer.drain()
|
152
|
-
|
150
|
+
|
153
151
|
writer.close()
|
154
152
|
await writer.wait_closed()
|
155
|
-
|
153
|
+
|
156
154
|
def get_url(self) -> str:
|
157
155
|
"""Get server URL."""
|
158
156
|
return f"http://{self.host}:{self.port}"
|
159
|
-
|
157
|
+
|
160
158
|
return AsyncMockServer()
|
161
159
|
|
162
160
|
|
@@ -164,46 +162,49 @@ def async_mock_server():
|
|
164
162
|
def async_test_client():
|
165
163
|
"""
|
166
164
|
Create an async HTTP test client.
|
167
|
-
|
165
|
+
|
168
166
|
Returns:
|
169
167
|
Mock async HTTP client for testing.
|
170
168
|
"""
|
169
|
+
|
171
170
|
class AsyncTestClient:
|
172
171
|
def __init__(self):
|
173
172
|
self.responses = {}
|
174
173
|
self.requests = []
|
175
|
-
|
174
|
+
|
176
175
|
def set_response(self, url: str, response: dict):
|
177
176
|
"""Set a mock response for a URL."""
|
178
177
|
self.responses[url] = response
|
179
|
-
|
178
|
+
|
180
179
|
async def get(self, url: str, **kwargs) -> dict:
|
181
180
|
"""Mock GET request."""
|
182
181
|
self.requests.append({"method": "GET", "url": url, "kwargs": kwargs})
|
183
182
|
return self.responses.get(url, {"status": 404, "body": "Not Found"})
|
184
|
-
|
183
|
+
|
185
184
|
async def post(self, url: str, data=None, **kwargs) -> dict:
|
186
185
|
"""Mock POST request."""
|
187
|
-
self.requests.append(
|
186
|
+
self.requests.append(
|
187
|
+
{"method": "POST", "url": url, "data": data, "kwargs": kwargs}
|
188
|
+
)
|
188
189
|
return self.responses.get(url, {"status": 200, "body": "OK"})
|
189
|
-
|
190
|
+
|
190
191
|
async def close(self):
|
191
192
|
"""Close the client."""
|
192
193
|
pass
|
193
|
-
|
194
|
+
|
194
195
|
async def __aenter__(self):
|
195
196
|
return self
|
196
|
-
|
197
|
+
|
197
198
|
async def __aexit__(self, *args):
|
198
199
|
await self.close()
|
199
|
-
|
200
|
+
|
200
201
|
return AsyncTestClient()
|
201
202
|
|
202
203
|
|
203
204
|
__all__ = [
|
204
|
-
"
|
205
|
+
"async_mock_server",
|
205
206
|
"async_stream_reader",
|
206
207
|
"async_subprocess",
|
207
|
-
"async_mock_server",
|
208
208
|
"async_test_client",
|
209
|
-
|
209
|
+
"mock_async_process",
|
210
|
+
]
|
@@ -6,33 +6,33 @@ and concurrent operations across any project that depends on provide.foundation.
|
|
6
6
|
"""
|
7
7
|
|
8
8
|
from provide.foundation.testing.threading.fixtures import (
|
9
|
+
concurrent_executor,
|
10
|
+
deadlock_detector,
|
11
|
+
mock_thread,
|
9
12
|
test_thread,
|
10
|
-
thread_pool,
|
11
13
|
thread_barrier,
|
12
|
-
thread_safe_list,
|
13
|
-
thread_safe_counter,
|
14
|
-
thread_event,
|
15
14
|
thread_condition,
|
16
|
-
|
15
|
+
thread_event,
|
16
|
+
thread_exception_handler,
|
17
17
|
thread_local_storage,
|
18
|
-
|
18
|
+
thread_pool,
|
19
|
+
thread_safe_counter,
|
20
|
+
thread_safe_list,
|
19
21
|
thread_synchronizer,
|
20
|
-
deadlock_detector,
|
21
|
-
thread_exception_handler,
|
22
22
|
)
|
23
23
|
|
24
24
|
__all__ = [
|
25
|
+
"concurrent_executor",
|
26
|
+
"deadlock_detector",
|
27
|
+
"mock_thread",
|
25
28
|
"test_thread",
|
26
|
-
"thread_pool",
|
27
29
|
"thread_barrier",
|
28
|
-
"thread_safe_list",
|
29
|
-
"thread_safe_counter",
|
30
|
-
"thread_event",
|
31
30
|
"thread_condition",
|
32
|
-
"
|
31
|
+
"thread_event",
|
32
|
+
"thread_exception_handler",
|
33
33
|
"thread_local_storage",
|
34
|
-
"
|
34
|
+
"thread_pool",
|
35
|
+
"thread_safe_counter",
|
36
|
+
"thread_safe_list",
|
35
37
|
"thread_synchronizer",
|
36
|
-
|
37
|
-
"thread_exception_handler",
|
38
|
-
]
|
38
|
+
]
|
@@ -4,9 +4,9 @@ Basic threading test fixtures.
|
|
4
4
|
Core fixtures for creating threads, thread pools, mocks, and thread-local storage.
|
5
5
|
"""
|
6
6
|
|
7
|
-
import threading
|
8
7
|
from concurrent.futures import ThreadPoolExecutor
|
9
|
-
|
8
|
+
import threading
|
9
|
+
from typing import Callable
|
10
10
|
from unittest.mock import Mock
|
11
11
|
|
12
12
|
import pytest
|
@@ -16,33 +16,37 @@ import pytest
|
|
16
16
|
def test_thread():
|
17
17
|
"""
|
18
18
|
Create a test thread with automatic cleanup.
|
19
|
-
|
19
|
+
|
20
20
|
Returns:
|
21
21
|
Function to create and manage test threads.
|
22
22
|
"""
|
23
23
|
threads = []
|
24
|
-
|
25
|
-
def _create_thread(
|
24
|
+
|
25
|
+
def _create_thread(
|
26
|
+
target: Callable, args: tuple = (), kwargs: dict = None, daemon: bool = True
|
27
|
+
) -> threading.Thread:
|
26
28
|
"""
|
27
29
|
Create a test thread.
|
28
|
-
|
30
|
+
|
29
31
|
Args:
|
30
32
|
target: Function to run in thread
|
31
33
|
args: Positional arguments for target
|
32
34
|
kwargs: Keyword arguments for target
|
33
35
|
daemon: Whether thread should be daemon
|
34
|
-
|
36
|
+
|
35
37
|
Returns:
|
36
38
|
Started thread instance
|
37
39
|
"""
|
38
40
|
kwargs = kwargs or {}
|
39
|
-
thread = threading.Thread(
|
41
|
+
thread = threading.Thread(
|
42
|
+
target=target, args=args, kwargs=kwargs, daemon=daemon
|
43
|
+
)
|
40
44
|
threads.append(thread)
|
41
45
|
thread.start()
|
42
46
|
return thread
|
43
|
-
|
47
|
+
|
44
48
|
yield _create_thread
|
45
|
-
|
49
|
+
|
46
50
|
# Cleanup: wait for all threads to complete
|
47
51
|
for thread in threads:
|
48
52
|
if thread.is_alive():
|
@@ -53,7 +57,7 @@ def test_thread():
|
|
53
57
|
def thread_pool():
|
54
58
|
"""
|
55
59
|
Create a thread pool executor for testing.
|
56
|
-
|
60
|
+
|
57
61
|
Returns:
|
58
62
|
ThreadPoolExecutor instance with automatic cleanup.
|
59
63
|
"""
|
@@ -66,7 +70,7 @@ def thread_pool():
|
|
66
70
|
def mock_thread():
|
67
71
|
"""
|
68
72
|
Create a mock thread for testing without actual threading.
|
69
|
-
|
73
|
+
|
70
74
|
Returns:
|
71
75
|
Mock thread object.
|
72
76
|
"""
|
@@ -78,7 +82,7 @@ def mock_thread():
|
|
78
82
|
mock.start = Mock()
|
79
83
|
mock.join = Mock()
|
80
84
|
mock.run = Mock()
|
81
|
-
|
85
|
+
|
82
86
|
return mock
|
83
87
|
|
84
88
|
|
@@ -86,7 +90,7 @@ def mock_thread():
|
|
86
90
|
def thread_local_storage():
|
87
91
|
"""
|
88
92
|
Create thread-local storage for testing.
|
89
|
-
|
93
|
+
|
90
94
|
Returns:
|
91
95
|
Thread-local storage object.
|
92
96
|
"""
|
@@ -94,8 +98,8 @@ def thread_local_storage():
|
|
94
98
|
|
95
99
|
|
96
100
|
__all__ = [
|
97
|
-
"test_thread",
|
98
|
-
"thread_pool",
|
99
101
|
"mock_thread",
|
102
|
+
"test_thread",
|
100
103
|
"thread_local_storage",
|
101
|
-
|
104
|
+
"thread_pool",
|
105
|
+
]
|
@@ -14,43 +14,44 @@ import pytest
|
|
14
14
|
def thread_safe_list():
|
15
15
|
"""
|
16
16
|
Create a thread-safe list for collecting results.
|
17
|
-
|
17
|
+
|
18
18
|
Returns:
|
19
19
|
Thread-safe list implementation.
|
20
20
|
"""
|
21
|
+
|
21
22
|
class ThreadSafeList:
|
22
23
|
def __init__(self):
|
23
24
|
self._list = []
|
24
25
|
self._lock = threading.Lock()
|
25
|
-
|
26
|
+
|
26
27
|
def append(self, item: Any):
|
27
28
|
"""Thread-safe append."""
|
28
29
|
with self._lock:
|
29
30
|
self._list.append(item)
|
30
|
-
|
31
|
+
|
31
32
|
def extend(self, items):
|
32
33
|
"""Thread-safe extend."""
|
33
34
|
with self._lock:
|
34
35
|
self._list.extend(items)
|
35
|
-
|
36
|
+
|
36
37
|
def get_all(self) -> list:
|
37
38
|
"""Get copy of all items."""
|
38
39
|
with self._lock:
|
39
40
|
return self._list.copy()
|
40
|
-
|
41
|
+
|
41
42
|
def clear(self):
|
42
43
|
"""Clear the list."""
|
43
44
|
with self._lock:
|
44
45
|
self._list.clear()
|
45
|
-
|
46
|
+
|
46
47
|
def __len__(self) -> int:
|
47
48
|
with self._lock:
|
48
49
|
return len(self._list)
|
49
|
-
|
50
|
+
|
50
51
|
def __getitem__(self, index):
|
51
52
|
with self._lock:
|
52
53
|
return self._list[index]
|
53
|
-
|
54
|
+
|
54
55
|
return ThreadSafeList()
|
55
56
|
|
56
57
|
|
@@ -58,42 +59,43 @@ def thread_safe_list():
|
|
58
59
|
def thread_safe_counter():
|
59
60
|
"""
|
60
61
|
Create a thread-safe counter.
|
61
|
-
|
62
|
+
|
62
63
|
Returns:
|
63
64
|
Thread-safe counter implementation.
|
64
65
|
"""
|
66
|
+
|
65
67
|
class ThreadSafeCounter:
|
66
68
|
def __init__(self, initial: int = 0):
|
67
69
|
self._value = initial
|
68
70
|
self._lock = threading.Lock()
|
69
|
-
|
71
|
+
|
70
72
|
def increment(self, amount: int = 1) -> int:
|
71
73
|
"""Thread-safe increment."""
|
72
74
|
with self._lock:
|
73
75
|
self._value += amount
|
74
76
|
return self._value
|
75
|
-
|
77
|
+
|
76
78
|
def decrement(self, amount: int = 1) -> int:
|
77
79
|
"""Thread-safe decrement."""
|
78
80
|
with self._lock:
|
79
81
|
self._value -= amount
|
80
82
|
return self._value
|
81
|
-
|
83
|
+
|
82
84
|
@property
|
83
85
|
def value(self) -> int:
|
84
86
|
"""Get current value."""
|
85
87
|
with self._lock:
|
86
88
|
return self._value
|
87
|
-
|
89
|
+
|
88
90
|
def reset(self, value: int = 0):
|
89
91
|
"""Reset counter."""
|
90
92
|
with self._lock:
|
91
93
|
self._value = value
|
92
|
-
|
94
|
+
|
93
95
|
return ThreadSafeCounter()
|
94
96
|
|
95
97
|
|
96
98
|
__all__ = [
|
97
|
-
"thread_safe_list",
|
98
99
|
"thread_safe_counter",
|
99
|
-
|
100
|
+
"thread_safe_list",
|
101
|
+
]
|