global-buffer 1.0.0__tar.gz

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 (35) hide show
  1. global_buffer-1.0.0/LICENSE +21 -0
  2. global_buffer-1.0.0/MANIFEST.in +4 -0
  3. global_buffer-1.0.0/PKG-INFO +211 -0
  4. global_buffer-1.0.0/README.md +177 -0
  5. global_buffer-1.0.0/pyproject.toml +57 -0
  6. global_buffer-1.0.0/setup.cfg +4 -0
  7. global_buffer-1.0.0/setup.py +19 -0
  8. global_buffer-1.0.0/src/global_buffer/__init__.py +46 -0
  9. global_buffer-1.0.0/src/global_buffer/_core.c +12665 -0
  10. global_buffer-1.0.0/src/global_buffer/_core.pyx +286 -0
  11. global_buffer-1.0.0/src/global_buffer/_version.py +1 -0
  12. global_buffer-1.0.0/src/global_buffer/buffer.py +181 -0
  13. global_buffer-1.0.0/src/global_buffer/codec.py +32 -0
  14. global_buffer-1.0.0/src/global_buffer/consumer.py +44 -0
  15. global_buffer-1.0.0/src/global_buffer/exceptions.py +23 -0
  16. global_buffer-1.0.0/src/global_buffer/gb_atomics.h +22 -0
  17. global_buffer-1.0.0/src/global_buffer/layout.py +142 -0
  18. global_buffer-1.0.0/src/global_buffer/notifier.py +55 -0
  19. global_buffer-1.0.0/src/global_buffer/reader.py +184 -0
  20. global_buffer-1.0.0/src/global_buffer/spec.py +67 -0
  21. global_buffer-1.0.0/src/global_buffer.egg-info/PKG-INFO +211 -0
  22. global_buffer-1.0.0/src/global_buffer.egg-info/SOURCES.txt +35 -0
  23. global_buffer-1.0.0/src/global_buffer.egg-info/dependency_links.txt +1 -0
  24. global_buffer-1.0.0/src/global_buffer.egg-info/requires.txt +7 -0
  25. global_buffer-1.0.0/src/global_buffer.egg-info/top_level.txt +1 -0
  26. global_buffer-1.0.0/tests/test_buffer_reader.py +171 -0
  27. global_buffer-1.0.0/tests/test_codec.py +28 -0
  28. global_buffer-1.0.0/tests/test_consumer.py +41 -0
  29. global_buffer-1.0.0/tests/test_core_ring.py +90 -0
  30. global_buffer-1.0.0/tests/test_crossproc.py +103 -0
  31. global_buffer-1.0.0/tests/test_extra.py +209 -0
  32. global_buffer-1.0.0/tests/test_layout.py +54 -0
  33. global_buffer-1.0.0/tests/test_notifier.py +49 -0
  34. global_buffer-1.0.0/tests/test_public_api.py +26 -0
  35. global_buffer-1.0.0/tests/test_spec.py +40 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Izzet Sezer
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,4 @@
1
+ include src/global_buffer/_core.pyx
2
+ include src/global_buffer/_core.c
3
+ include src/global_buffer/gb_atomics.h
4
+ include LICENSE README.md
@@ -0,0 +1,211 @@
1
+ Metadata-Version: 2.4
2
+ Name: global_buffer
3
+ Version: 1.0.0
4
+ Summary: Cross-platform cross-process shared-memory ring buffer: zero-copy numpy arrays + pydantic messages, 0-CPU blocking callbacks.
5
+ Author: Izzet Sezer
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/sezer-muhammed/GlobalBuffer
8
+ Project-URL: Repository, https://github.com/sezer-muhammed/GlobalBuffer
9
+ Project-URL: Documentation, https://github.com/sezer-muhammed/GlobalBuffer/tree/main/docs
10
+ Project-URL: Changelog, https://github.com/sezer-muhammed/GlobalBuffer/blob/main/CHANGELOG.md
11
+ Project-URL: Bug Tracker, https://github.com/sezer-muhammed/GlobalBuffer/issues
12
+ Keywords: shared-memory,ipc,ring-buffer,numpy,pydantic,zero-copy
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.9
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Operating System :: OS Independent
20
+ Classifier: Topic :: System :: Hardware
21
+ Classifier: Topic :: System :: Networking
22
+ Classifier: Intended Audience :: Developers
23
+ Classifier: Intended Audience :: Science/Research
24
+ Requires-Python: >=3.9
25
+ Description-Content-Type: text/markdown
26
+ License-File: LICENSE
27
+ Requires-Dist: numpy>=1.23
28
+ Requires-Dist: msgspec>=0.18
29
+ Requires-Dist: pydantic>=2
30
+ Provides-Extra: dev
31
+ Requires-Dist: pytest>=7; extra == "dev"
32
+ Requires-Dist: Cython>=3.0; extra == "dev"
33
+ Dynamic: license-file
34
+
35
+ # GlobalBuffer
36
+
37
+ Cross-platform, cross-process **named shared-memory buffer** for Python.
38
+
39
+ `import global_buffer as gb`
40
+
41
+ A writer publishes samples by name; any process on the same host attaches by name
42
+ and reads — either the newest sample or every sample in order, by blocking call or
43
+ background callback. Built for streams that mix **high frequency** (e.g. 200 Hz
44
+ numeric arrays) and **low frequency** (e.g. 1 Hz structured status messages)
45
+ without burning CPU on either end.
46
+
47
+ It fills the gap between `multiprocessing.shared_memory` (too low-level),
48
+ `UltraDict` (dated, pickle-based), and iceoryx2/eCAL (heavy native installs):
49
+ a pip-installable, pydantic-native, callback-driven buffer with a clean API and a
50
+ lock-free Cython hot path.
51
+
52
+ ## Status
53
+
54
+ **v1.0.0.** Core is stable and covered by 70 tests (including a cross-process
55
+ no-torn-reads stress test), verified on macOS / CPython 3.14. Linux, Windows and
56
+ aarch64 (Jetson) are supported and wheels are configured, with broad CI
57
+ verification on those platforms in progress. See [`CHANGELOG.md`](CHANGELOG.md)
58
+ for known limitations.
59
+
60
+ ## Features
61
+
62
+ - **Two stream kinds, one API**
63
+ - **Array streams** — fixed dtype + shape numpy data, written and read **zero-copy**.
64
+ - **Message streams** — `pydantic` models on the public API, `msgspec` (msgpack) on the wire (~10× faster than pickle).
65
+ - **Last-value or in-order reads** — `latest()` jumps to the newest sample;
66
+ `next()` consumes every sample in order and reports `overruns` if a reader falls behind.
67
+ - **Lock-free, tear-free** — single-writer / multi-reader ring with a spare slot
68
+ (`capacity + 1`) plus a per-slot seqlock implemented with C11 atomics. No torn reads even at high rate.
69
+ - **Near-0-CPU wakeups** — readers block on an adaptive poll of the shared commit
70
+ counter; idle readers cost roughly one atomic load every couple of milliseconds.
71
+ - **Cross-platform** — Linux, macOS, Windows; ships as compiled wheels.
72
+
73
+ ## Install
74
+
75
+ ```bash
76
+ pip install global_buffer
77
+ ```
78
+
79
+ Wheels are published for CPython 3.9–3.13 on manylinux x86_64 / aarch64,
80
+ macOS (x86_64 + arm64) and Windows amd64. A source build needs a C11 compiler.
81
+
82
+ ## Quickstart
83
+
84
+ ### Array stream (200 Hz, zero-copy)
85
+
86
+ ```python
87
+ import global_buffer as gb
88
+ import numpy as np
89
+
90
+ # writer / owner
91
+ csi = gb.create(name="csi", schema=gb.ArraySpec(dtype="complex64", shape=(64, 4)),
92
+ capacity=8)
93
+
94
+ with csi.reserve() as slot: # slot is an ndarray view directly into shm
95
+ slot[:] = frame # fill in place — no copy
96
+ # or: csi.write(frame) # single-memcpy convenience form
97
+
98
+ # reader (any other process)
99
+ r = gb.attach("csi") # schema discovered from the segment
100
+ frame = r.latest() # newest committed sample
101
+ r.on_data(lambda sample, seq: process(sample), mode="latest") # bg thread
102
+ ```
103
+
104
+ ### Message stream (1 Hz, pydantic)
105
+
106
+ ```python
107
+ import pydantic, global_buffer as gb
108
+
109
+ class Status(pydantic.BaseModel):
110
+ gain: float
111
+ cam_on: bool
112
+
113
+ status = gb.create(name="status", schema=Status, capacity=4, max_bytes=512)
114
+ status.write(Status(gain=1.2, cam_on=True))
115
+
116
+ rs = gb.attach("status", model=Status) # schema mismatch -> raises on attach
117
+ msg = rs.next(timeout=1.0) # -> validated Status instance
118
+ ```
119
+
120
+ ### OO consumer
121
+
122
+ ```python
123
+ class CsiConsumer(gb.Consumer):
124
+ def callback(self): # framework sets self.data / self.seq
125
+ self.processed = heavy_process(self.data)
126
+
127
+ ob = CsiConsumer.attach("csi", mode="latest")
128
+ ob.start()
129
+ ...
130
+ ob.stop()
131
+ ```
132
+
133
+ ## Semantics
134
+
135
+ - `capacity` is the number of logical slots; the core allocates `capacity + 1` so
136
+ the writer never overwrites the slot a reader could currently be reading.
137
+ - A reader created with `attach()` starts at the newest sample present at attach time.
138
+ - `latest()` returns `None` on an empty buffer. `next(timeout=...)` raises
139
+ `gb.Empty` on timeout; without a timeout it blocks.
140
+ - `next()` accumulates `reader.overruns` when the writer laps the reader by more
141
+ than `capacity` samples (the reader then jumps to the oldest still-available sample).
142
+ - `reader.writer_alive` reflects a heartbeat the writer stamps on every write
143
+ (a writer silent for >2 s reads as not alive).
144
+
145
+ ## Lifecycle
146
+
147
+ ```python
148
+ buf.close() # detach this handle (segment stays alive)
149
+ buf.unlink() # owner removes the segment
150
+ gb.unlink(name) # remove a segment by name (e.g. clean up after a crash)
151
+ ```
152
+
153
+ GlobalBuffer manages segment lifetime explicitly (it opts out of the
154
+ multiprocessing `resource_tracker` where supported, Python 3.13+), so a reader
155
+ exiting never unlinks the owner's segment.
156
+
157
+ ## Platform support
158
+
159
+ | OS | Segment | Notification |
160
+ |---|---|---|
161
+ | Linux | `multiprocessing.shared_memory` (POSIX shm) | adaptive poll on commit counter |
162
+ | macOS | `multiprocessing.shared_memory` (POSIX shm) | adaptive poll on commit counter |
163
+ | Windows | `multiprocessing.shared_memory` (mem-mapped) | adaptive poll on commit counter |
164
+
165
+ > **Verification status.** Behaviour is verified on macOS today; the Linux/Windows
166
+ > CI matrix and aarch64 wheels are configured and will be exercised before those
167
+ > platforms are declared production-verified.
168
+ >
169
+ > **Note on notifications.** The current release uses adaptive polling of the
170
+ > shared commit counter for wakeups — fully portable, reliable on all three OSes,
171
+ > and near-0 CPU when idle (the poll interval backs off to ~2 ms). A true 0-CPU
172
+ > kernel-blocking backend (Linux `eventfd` / process-shared pthread condvar,
173
+ > Windows named semaphore) fits behind the same interface and is planned once it
174
+ > can be verified per-OS in CI. POSIX named semaphores were evaluated and dropped:
175
+ > they behave unreliably on macOS.
176
+
177
+ ## Build from source
178
+
179
+ ```bash
180
+ python -m pip install -U pip setuptools wheel Cython numpy msgspec pydantic
181
+ python setup.py build_ext --inplace
182
+ PYTHONPATH=src python -c "import global_buffer as gb; print(gb.__version__)"
183
+ ```
184
+
185
+ ## Run the tests
186
+
187
+ ```bash
188
+ PYTHONPATH=src python -m pytest tests -v # full suite
189
+ PYTHONPATH=src python -m pytest tests -m "not crossproc_slow" # skip the long stress test
190
+ ```
191
+
192
+ Or in Docker:
193
+
194
+ ```bash
195
+ docker build -t globalbuffer . && docker run --rm globalbuffer
196
+ docker compose up # two-process writer/reader demo
197
+ ```
198
+
199
+ ## Jetson / aarch64
200
+
201
+ Wheels are built for `manylinux aarch64`. Atomics and process spawn behaviour can
202
+ differ from x86; run the suite on the target device once as a smoke test.
203
+
204
+ ## Design
205
+
206
+ Full documentation is in [`docs/`](docs/index.md); design rationale and the
207
+ on-disk segment layout are in [`docs/design.md`](docs/design.md).
208
+
209
+ ## License
210
+
211
+ MIT © 2026 Izzet Sezer
@@ -0,0 +1,177 @@
1
+ # GlobalBuffer
2
+
3
+ Cross-platform, cross-process **named shared-memory buffer** for Python.
4
+
5
+ `import global_buffer as gb`
6
+
7
+ A writer publishes samples by name; any process on the same host attaches by name
8
+ and reads — either the newest sample or every sample in order, by blocking call or
9
+ background callback. Built for streams that mix **high frequency** (e.g. 200 Hz
10
+ numeric arrays) and **low frequency** (e.g. 1 Hz structured status messages)
11
+ without burning CPU on either end.
12
+
13
+ It fills the gap between `multiprocessing.shared_memory` (too low-level),
14
+ `UltraDict` (dated, pickle-based), and iceoryx2/eCAL (heavy native installs):
15
+ a pip-installable, pydantic-native, callback-driven buffer with a clean API and a
16
+ lock-free Cython hot path.
17
+
18
+ ## Status
19
+
20
+ **v1.0.0.** Core is stable and covered by 70 tests (including a cross-process
21
+ no-torn-reads stress test), verified on macOS / CPython 3.14. Linux, Windows and
22
+ aarch64 (Jetson) are supported and wheels are configured, with broad CI
23
+ verification on those platforms in progress. See [`CHANGELOG.md`](CHANGELOG.md)
24
+ for known limitations.
25
+
26
+ ## Features
27
+
28
+ - **Two stream kinds, one API**
29
+ - **Array streams** — fixed dtype + shape numpy data, written and read **zero-copy**.
30
+ - **Message streams** — `pydantic` models on the public API, `msgspec` (msgpack) on the wire (~10× faster than pickle).
31
+ - **Last-value or in-order reads** — `latest()` jumps to the newest sample;
32
+ `next()` consumes every sample in order and reports `overruns` if a reader falls behind.
33
+ - **Lock-free, tear-free** — single-writer / multi-reader ring with a spare slot
34
+ (`capacity + 1`) plus a per-slot seqlock implemented with C11 atomics. No torn reads even at high rate.
35
+ - **Near-0-CPU wakeups** — readers block on an adaptive poll of the shared commit
36
+ counter; idle readers cost roughly one atomic load every couple of milliseconds.
37
+ - **Cross-platform** — Linux, macOS, Windows; ships as compiled wheels.
38
+
39
+ ## Install
40
+
41
+ ```bash
42
+ pip install global_buffer
43
+ ```
44
+
45
+ Wheels are published for CPython 3.9–3.13 on manylinux x86_64 / aarch64,
46
+ macOS (x86_64 + arm64) and Windows amd64. A source build needs a C11 compiler.
47
+
48
+ ## Quickstart
49
+
50
+ ### Array stream (200 Hz, zero-copy)
51
+
52
+ ```python
53
+ import global_buffer as gb
54
+ import numpy as np
55
+
56
+ # writer / owner
57
+ csi = gb.create(name="csi", schema=gb.ArraySpec(dtype="complex64", shape=(64, 4)),
58
+ capacity=8)
59
+
60
+ with csi.reserve() as slot: # slot is an ndarray view directly into shm
61
+ slot[:] = frame # fill in place — no copy
62
+ # or: csi.write(frame) # single-memcpy convenience form
63
+
64
+ # reader (any other process)
65
+ r = gb.attach("csi") # schema discovered from the segment
66
+ frame = r.latest() # newest committed sample
67
+ r.on_data(lambda sample, seq: process(sample), mode="latest") # bg thread
68
+ ```
69
+
70
+ ### Message stream (1 Hz, pydantic)
71
+
72
+ ```python
73
+ import pydantic, global_buffer as gb
74
+
75
+ class Status(pydantic.BaseModel):
76
+ gain: float
77
+ cam_on: bool
78
+
79
+ status = gb.create(name="status", schema=Status, capacity=4, max_bytes=512)
80
+ status.write(Status(gain=1.2, cam_on=True))
81
+
82
+ rs = gb.attach("status", model=Status) # schema mismatch -> raises on attach
83
+ msg = rs.next(timeout=1.0) # -> validated Status instance
84
+ ```
85
+
86
+ ### OO consumer
87
+
88
+ ```python
89
+ class CsiConsumer(gb.Consumer):
90
+ def callback(self): # framework sets self.data / self.seq
91
+ self.processed = heavy_process(self.data)
92
+
93
+ ob = CsiConsumer.attach("csi", mode="latest")
94
+ ob.start()
95
+ ...
96
+ ob.stop()
97
+ ```
98
+
99
+ ## Semantics
100
+
101
+ - `capacity` is the number of logical slots; the core allocates `capacity + 1` so
102
+ the writer never overwrites the slot a reader could currently be reading.
103
+ - A reader created with `attach()` starts at the newest sample present at attach time.
104
+ - `latest()` returns `None` on an empty buffer. `next(timeout=...)` raises
105
+ `gb.Empty` on timeout; without a timeout it blocks.
106
+ - `next()` accumulates `reader.overruns` when the writer laps the reader by more
107
+ than `capacity` samples (the reader then jumps to the oldest still-available sample).
108
+ - `reader.writer_alive` reflects a heartbeat the writer stamps on every write
109
+ (a writer silent for >2 s reads as not alive).
110
+
111
+ ## Lifecycle
112
+
113
+ ```python
114
+ buf.close() # detach this handle (segment stays alive)
115
+ buf.unlink() # owner removes the segment
116
+ gb.unlink(name) # remove a segment by name (e.g. clean up after a crash)
117
+ ```
118
+
119
+ GlobalBuffer manages segment lifetime explicitly (it opts out of the
120
+ multiprocessing `resource_tracker` where supported, Python 3.13+), so a reader
121
+ exiting never unlinks the owner's segment.
122
+
123
+ ## Platform support
124
+
125
+ | OS | Segment | Notification |
126
+ |---|---|---|
127
+ | Linux | `multiprocessing.shared_memory` (POSIX shm) | adaptive poll on commit counter |
128
+ | macOS | `multiprocessing.shared_memory` (POSIX shm) | adaptive poll on commit counter |
129
+ | Windows | `multiprocessing.shared_memory` (mem-mapped) | adaptive poll on commit counter |
130
+
131
+ > **Verification status.** Behaviour is verified on macOS today; the Linux/Windows
132
+ > CI matrix and aarch64 wheels are configured and will be exercised before those
133
+ > platforms are declared production-verified.
134
+ >
135
+ > **Note on notifications.** The current release uses adaptive polling of the
136
+ > shared commit counter for wakeups — fully portable, reliable on all three OSes,
137
+ > and near-0 CPU when idle (the poll interval backs off to ~2 ms). A true 0-CPU
138
+ > kernel-blocking backend (Linux `eventfd` / process-shared pthread condvar,
139
+ > Windows named semaphore) fits behind the same interface and is planned once it
140
+ > can be verified per-OS in CI. POSIX named semaphores were evaluated and dropped:
141
+ > they behave unreliably on macOS.
142
+
143
+ ## Build from source
144
+
145
+ ```bash
146
+ python -m pip install -U pip setuptools wheel Cython numpy msgspec pydantic
147
+ python setup.py build_ext --inplace
148
+ PYTHONPATH=src python -c "import global_buffer as gb; print(gb.__version__)"
149
+ ```
150
+
151
+ ## Run the tests
152
+
153
+ ```bash
154
+ PYTHONPATH=src python -m pytest tests -v # full suite
155
+ PYTHONPATH=src python -m pytest tests -m "not crossproc_slow" # skip the long stress test
156
+ ```
157
+
158
+ Or in Docker:
159
+
160
+ ```bash
161
+ docker build -t globalbuffer . && docker run --rm globalbuffer
162
+ docker compose up # two-process writer/reader demo
163
+ ```
164
+
165
+ ## Jetson / aarch64
166
+
167
+ Wheels are built for `manylinux aarch64`. Atomics and process spawn behaviour can
168
+ differ from x86; run the suite on the target device once as a smoke test.
169
+
170
+ ## Design
171
+
172
+ Full documentation is in [`docs/`](docs/index.md); design rationale and the
173
+ on-disk segment layout are in [`docs/design.md`](docs/design.md).
174
+
175
+ ## License
176
+
177
+ MIT © 2026 Izzet Sezer
@@ -0,0 +1,57 @@
1
+ [build-system]
2
+ requires = ["setuptools>=64", "wheel", "Cython>=3.0", "numpy>=1.23"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "global_buffer"
7
+ dynamic = ["version"]
8
+ description = "Cross-platform cross-process shared-memory ring buffer: zero-copy numpy arrays + pydantic messages, 0-CPU blocking callbacks."
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ requires-python = ">=3.9"
12
+ authors = [{ name = "Izzet Sezer" }]
13
+ keywords = ["shared-memory", "ipc", "ring-buffer", "numpy", "pydantic", "zero-copy"]
14
+ classifiers = [
15
+ "Programming Language :: Python :: 3",
16
+ "Programming Language :: Python :: 3.9",
17
+ "Programming Language :: Python :: 3.10",
18
+ "Programming Language :: Python :: 3.11",
19
+ "Programming Language :: Python :: 3.12",
20
+ "Programming Language :: Python :: 3.13",
21
+ "Operating System :: OS Independent",
22
+ "Topic :: System :: Hardware",
23
+ "Topic :: System :: Networking",
24
+ "Intended Audience :: Developers",
25
+ "Intended Audience :: Science/Research",
26
+ ]
27
+ dependencies = ["numpy>=1.23", "msgspec>=0.18", "pydantic>=2"]
28
+
29
+ [project.urls]
30
+ Homepage = "https://github.com/sezer-muhammed/GlobalBuffer"
31
+ Repository = "https://github.com/sezer-muhammed/GlobalBuffer"
32
+ Documentation = "https://github.com/sezer-muhammed/GlobalBuffer/tree/main/docs"
33
+ Changelog = "https://github.com/sezer-muhammed/GlobalBuffer/blob/main/CHANGELOG.md"
34
+ "Bug Tracker" = "https://github.com/sezer-muhammed/GlobalBuffer/issues"
35
+
36
+ [project.optional-dependencies]
37
+ dev = ["pytest>=7", "Cython>=3.0"]
38
+
39
+ [tool.setuptools]
40
+ package-dir = { "" = "src" }
41
+ packages = ["global_buffer"]
42
+
43
+ [tool.setuptools.dynamic]
44
+ version = { attr = "global_buffer._version.__version__" }
45
+
46
+ [tool.cibuildwheel]
47
+ build = "cp39-* cp310-* cp311-* cp312-* cp313-*"
48
+ skip = "*-musllinux_i686 *_i686 pp*"
49
+ test-requires = ["pytest", "numpy", "msgspec", "pydantic"]
50
+ test-command = "pytest {project}/tests -m 'not crossproc_slow'"
51
+ archs = ["auto64"]
52
+
53
+ [tool.cibuildwheel.linux]
54
+ archs = ["x86_64", "aarch64"]
55
+
56
+ [tool.pytest.ini_options]
57
+ markers = ["crossproc_slow: long cross-process stress tests"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,19 @@
1
+ import sys
2
+
3
+ import numpy
4
+ from setuptools import Extension, setup
5
+ from Cython.Build import cythonize
6
+
7
+ if sys.platform == "win32":
8
+ extra = ["/std:c11", "/O2"]
9
+ else:
10
+ extra = ["-std=c11", "-O3"]
11
+
12
+ ext = Extension(
13
+ "global_buffer._core",
14
+ sources=["src/global_buffer/_core.pyx"],
15
+ include_dirs=[numpy.get_include(), "src/global_buffer"],
16
+ extra_compile_args=extra,
17
+ )
18
+
19
+ setup(ext_modules=cythonize([ext], language_level=3))
@@ -0,0 +1,46 @@
1
+ """GlobalBuffer: cross-platform, cross-process shared-memory ring buffer.
2
+
3
+ Zero-copy numpy array streams and pydantic message streams, last-value or
4
+ in-order reads, and background callbacks. See the README for the full API.
5
+ """
6
+ from ._version import __version__
7
+ from .buffer import GlobalBuffer, open_shm, shm_name
8
+ from .consumer import Consumer
9
+ from .exceptions import (BufferClosed, BufferExists, BufferNotFound, Empty,
10
+ GlobalBufferError, SchemaMismatch)
11
+ from .reader import Reader
12
+ from .spec import ArraySpec
13
+
14
+
15
+ def create(name, schema, capacity, max_bytes=None):
16
+ """Create and own a named buffer (writer). ``schema`` is an
17
+ :class:`ArraySpec` or a ``pydantic.BaseModel`` subclass."""
18
+ return GlobalBuffer(name, schema, capacity, max_bytes=max_bytes)
19
+
20
+
21
+ def attach(name, model=None, poll_min=None, poll_max=None):
22
+ """Attach to an existing named buffer (reader). For message buffers, pass
23
+ ``model=`` to get validated instances and a schema-compatibility check.
24
+
25
+ ``poll_max`` raises the wakeup poll-backoff cap (seconds); a larger value
26
+ lowers idle CPU when running many readers, at the cost of up to that much
27
+ extra wake latency (default ~2 ms). ``poll_min`` sets the busy floor."""
28
+ return Reader(name, model=model, poll_min=poll_min, poll_max=poll_max)
29
+
30
+
31
+ def unlink(name):
32
+ """Remove a named segment by name (e.g. to clean up after a crash)."""
33
+ try:
34
+ shm = open_shm(shm_name(name))
35
+ except FileNotFoundError:
36
+ return
37
+ shm.close()
38
+ shm.unlink()
39
+
40
+
41
+ __all__ = [
42
+ "__version__", "ArraySpec", "GlobalBuffer", "Reader", "Consumer",
43
+ "create", "attach", "unlink",
44
+ "GlobalBufferError", "Empty", "SchemaMismatch", "BufferClosed",
45
+ "BufferExists", "BufferNotFound",
46
+ ]