pyomq 0.2.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.
- pyomq-0.2.0/Cargo.toml +45 -0
- pyomq-0.2.0/PKG-INFO +136 -0
- pyomq-0.2.0/README.md +105 -0
- pyomq-0.2.0/bindings/pyomq/.gitignore +1 -0
- pyomq-0.2.0/bindings/pyomq/CHANGELOG.md +15 -0
- pyomq-0.2.0/bindings/pyomq/Cargo.lock +1913 -0
- pyomq-0.2.0/bindings/pyomq/Cargo.toml +39 -0
- pyomq-0.2.0/bindings/pyomq/README.md +105 -0
- pyomq-0.2.0/bindings/pyomq/scripts/update_perf.py +296 -0
- pyomq-0.2.0/bindings/pyomq/src/constants.rs +131 -0
- pyomq-0.2.0/bindings/pyomq/src/context.rs +117 -0
- pyomq-0.2.0/bindings/pyomq/src/conversions.rs +73 -0
- pyomq-0.2.0/bindings/pyomq/src/dispatch.rs +51 -0
- pyomq-0.2.0/bindings/pyomq/src/error.rs +69 -0
- pyomq-0.2.0/bindings/pyomq/src/lib.rs +93 -0
- pyomq-0.2.0/bindings/pyomq/src/options.rs +373 -0
- pyomq-0.2.0/bindings/pyomq/src/runtime.rs +402 -0
- pyomq-0.2.0/bindings/pyomq/src/socket.rs +556 -0
- pyomq-0.2.0/bindings/pyomq/src/socket_async.rs +300 -0
- pyomq-0.2.0/bindings/pyomq/tests/conftest.py +49 -0
- pyomq-0.2.0/bindings/pyomq/tests/test_async.py +114 -0
- pyomq-0.2.0/bindings/pyomq/tests/test_async_compat.py +83 -0
- pyomq-0.2.0/bindings/pyomq/tests/test_async_interop.py +88 -0
- pyomq-0.2.0/bindings/pyomq/tests/test_basic.py +88 -0
- pyomq-0.2.0/bindings/pyomq/tests/test_compat.py +427 -0
- pyomq-0.2.0/bindings/pyomq/tests/test_exceptions.py +149 -0
- pyomq-0.2.0/bindings/pyomq/tests/test_interop.py +257 -0
- pyomq-0.2.0/bindings/pyomq/tests/test_options.py +145 -0
- pyomq-0.2.0/bindings/pyomq/tests/test_perf.py +124 -0
- pyomq-0.2.0/bindings/pyomq/tests/test_poller.py +177 -0
- pyomq-0.2.0/bindings/pyomq/tests/test_pubsub.py +50 -0
- pyomq-0.2.0/bindings/pyomq/tests/test_reqrep.py +42 -0
- pyomq-0.2.0/bindings/pyomq/tests/test_socket_types.py +262 -0
- pyomq-0.2.0/blume/Cargo.toml +24 -0
- pyomq-0.2.0/blume/README.md +48 -0
- pyomq-0.2.0/blume/benches/throughput.rs +277 -0
- pyomq-0.2.0/blume/src/error.rs +72 -0
- pyomq-0.2.0/blume/src/lib.rs +9 -0
- pyomq-0.2.0/blume/src/receiver.rs +113 -0
- pyomq-0.2.0/blume/src/sender.rs +60 -0
- pyomq-0.2.0/blume/src/shared.rs +145 -0
- pyomq-0.2.0/blume/tests/basic.rs +84 -0
- pyomq-0.2.0/blume/tests/batch.rs +80 -0
- pyomq-0.2.0/blume/tests/bounded.rs +60 -0
- pyomq-0.2.0/blume/tests/disconnect.rs +59 -0
- pyomq-0.2.0/blume/tests/mpsc.rs +125 -0
- pyomq-0.2.0/omq-compio/CHANGELOG.md +201 -0
- pyomq-0.2.0/omq-compio/Cargo.toml +82 -0
- pyomq-0.2.0/omq-compio/benches/common/mod.rs +349 -0
- pyomq-0.2.0/omq-compio/benches/compression.rs +351 -0
- pyomq-0.2.0/omq-compio/benches/latency.rs +155 -0
- pyomq-0.2.0/omq-compio/benches/multithread_push_pull.rs +161 -0
- pyomq-0.2.0/omq-compio/benches/pair.rs +165 -0
- pyomq-0.2.0/omq-compio/benches/pub_sub.rs +220 -0
- pyomq-0.2.0/omq-compio/benches/push_pull.rs +302 -0
- pyomq-0.2.0/omq-compio/benches/req_rep.rs +79 -0
- pyomq-0.2.0/omq-compio/benches/router_dealer.rs +191 -0
- pyomq-0.2.0/omq-compio/examples/profile_tcp.rs +90 -0
- pyomq-0.2.0/omq-compio/src/bin/bench_peer.rs +114 -0
- pyomq-0.2.0/omq-compio/src/lib.rs +47 -0
- pyomq-0.2.0/omq-compio/src/monitor.rs +114 -0
- pyomq-0.2.0/omq-compio/src/runtime.rs +105 -0
- pyomq-0.2.0/omq-compio/src/socket/dial.rs +422 -0
- pyomq-0.2.0/omq-compio/src/socket/handle.rs +1472 -0
- pyomq-0.2.0/omq-compio/src/socket/inner.rs +1164 -0
- pyomq-0.2.0/omq-compio/src/socket/install.rs +358 -0
- pyomq-0.2.0/omq-compio/src/socket/mod.rs +86 -0
- pyomq-0.2.0/omq-compio/src/socket/send.rs +830 -0
- pyomq-0.2.0/omq-compio/src/transport/driver.rs +992 -0
- pyomq-0.2.0/omq-compio/src/transport/inproc.rs +218 -0
- pyomq-0.2.0/omq-compio/src/transport/ipc.rs +104 -0
- pyomq-0.2.0/omq-compio/src/transport/mod.rs +9 -0
- pyomq-0.2.0/omq-compio/src/transport/peer_io.rs +313 -0
- pyomq-0.2.0/omq-compio/src/transport/tcp.rs +57 -0
- pyomq-0.2.0/omq-compio/src/transport/udp.rs +115 -0
- pyomq-0.2.0/omq-compio/tests/blake3zmq.rs +142 -0
- pyomq-0.2.0/omq-compio/tests/broker.rs +202 -0
- pyomq-0.2.0/omq-compio/tests/conflate.rs +123 -0
- pyomq-0.2.0/omq-compio/tests/connection_errors.rs +120 -0
- pyomq-0.2.0/omq-compio/tests/coverage_matrix.rs +355 -0
- pyomq-0.2.0/omq-compio/tests/curve.rs +192 -0
- pyomq-0.2.0/omq-compio/tests/double_close.rs +87 -0
- pyomq-0.2.0/omq-compio/tests/draft_types.rs +167 -0
- pyomq-0.2.0/omq-compio/tests/fuzz_parsers.rs +469 -0
- pyomq-0.2.0/omq-compio/tests/fuzz_socket_actions.rs +227 -0
- pyomq-0.2.0/omq-compio/tests/handshake_timeout.rs +73 -0
- pyomq-0.2.0/omq-compio/tests/heartbeat.rs +152 -0
- pyomq-0.2.0/omq-compio/tests/inproc_subside.rs +108 -0
- pyomq-0.2.0/omq-compio/tests/interop_pyzmq_curve.rs +336 -0
- pyomq-0.2.0/omq-compio/tests/interop_ruby.rs +461 -0
- pyomq-0.2.0/omq-compio/tests/ipc_basic.rs +85 -0
- pyomq-0.2.0/omq-compio/tests/ipv6.rs +128 -0
- pyomq-0.2.0/omq-compio/tests/large_messages.rs +260 -0
- pyomq-0.2.0/omq-compio/tests/linger.rs +182 -0
- pyomq-0.2.0/omq-compio/tests/lz4_tcp.rs +88 -0
- pyomq-0.2.0/omq-compio/tests/mixed_transports.rs +142 -0
- pyomq-0.2.0/omq-compio/tests/monitor.rs +84 -0
- pyomq-0.2.0/omq-compio/tests/multi_peer.rs +142 -0
- pyomq-0.2.0/omq-compio/tests/options_polish.rs +283 -0
- pyomq-0.2.0/omq-compio/tests/priority.rs +223 -0
- pyomq-0.2.0/omq-compio/tests/pub_sub.rs +175 -0
- pyomq-0.2.0/omq-compio/tests/push_pull.rs +284 -0
- pyomq-0.2.0/omq-compio/tests/radio_dish.rs +128 -0
- pyomq-0.2.0/omq-compio/tests/reconnect.rs +225 -0
- pyomq-0.2.0/omq-compio/tests/reconnect_all_types.rs +203 -0
- pyomq-0.2.0/omq-compio/tests/recv_direct.rs +181 -0
- pyomq-0.2.0/omq-compio/tests/req_rep.rs +300 -0
- pyomq-0.2.0/omq-compio/tests/router_dealer.rs +151 -0
- pyomq-0.2.0/omq-compio/tests/tcp_basic.rs +84 -0
- pyomq-0.2.0/omq-compio/tests/udp.rs +137 -0
- pyomq-0.2.0/omq-compio/tests/unbind_disconnect.rs +75 -0
- pyomq-0.2.0/omq-compio/tests/xpub_xsub.rs +258 -0
- pyomq-0.2.0/omq-compio/tests/zstd_tcp.rs +239 -0
- pyomq-0.2.0/omq-proto/CHANGELOG.md +103 -0
- pyomq-0.2.0/omq-proto/Cargo.toml +57 -0
- pyomq-0.2.0/omq-proto/benches/mechanism_frame.rs +151 -0
- pyomq-0.2.0/omq-proto/src/backoff.rs +92 -0
- pyomq-0.2.0/omq-proto/src/connect_opts.rs +59 -0
- pyomq-0.2.0/omq-proto/src/endpoint.rs +337 -0
- pyomq-0.2.0/omq-proto/src/error.rs +48 -0
- pyomq-0.2.0/omq-proto/src/lib.rs +38 -0
- pyomq-0.2.0/omq-proto/src/message.rs +1045 -0
- pyomq-0.2.0/omq-proto/src/monitor.rs +157 -0
- pyomq-0.2.0/omq-proto/src/options.rs +749 -0
- pyomq-0.2.0/omq-proto/src/proto/chunked_buf.rs +381 -0
- pyomq-0.2.0/omq-proto/src/proto/command.rs +479 -0
- pyomq-0.2.0/omq-proto/src/proto/connection.rs +1105 -0
- pyomq-0.2.0/omq-proto/src/proto/frame.rs +504 -0
- pyomq-0.2.0/omq-proto/src/proto/greeting.rs +327 -0
- pyomq-0.2.0/omq-proto/src/proto/mechanism/blake3zmq/cookie.rs +175 -0
- pyomq-0.2.0/omq-proto/src/proto/mechanism/blake3zmq/crypto.rs +216 -0
- pyomq-0.2.0/omq-proto/src/proto/mechanism/blake3zmq/handshake.rs +881 -0
- pyomq-0.2.0/omq-proto/src/proto/mechanism/blake3zmq/mod.rs +357 -0
- pyomq-0.2.0/omq-proto/src/proto/mechanism/blake3zmq/transform.rs +195 -0
- pyomq-0.2.0/omq-proto/src/proto/mechanism/blake3zmq/wire.rs +105 -0
- pyomq-0.2.0/omq-proto/src/proto/mechanism/curve.rs +808 -0
- pyomq-0.2.0/omq-proto/src/proto/mechanism/curve_keys.rs +183 -0
- pyomq-0.2.0/omq-proto/src/proto/mechanism/mod.rs +414 -0
- pyomq-0.2.0/omq-proto/src/proto/mod.rs +237 -0
- pyomq-0.2.0/omq-proto/src/proto/transform/common.rs +85 -0
- pyomq-0.2.0/omq-proto/src/proto/transform/lz4.rs +618 -0
- pyomq-0.2.0/omq-proto/src/proto/transform/mod.rs +164 -0
- pyomq-0.2.0/omq-proto/src/proto/transform/zstd.rs +695 -0
- pyomq-0.2.0/omq-proto/src/proto/z85.rs +177 -0
- pyomq-0.2.0/omq-proto/src/subscription.rs +141 -0
- pyomq-0.2.0/omq-proto/src/type_state.rs +246 -0
- pyomq-0.2.0/omq-proto/tests/connection.rs +551 -0
- pyomq-0.2.0/omq-proto/tests/endpoint.rs +220 -0
- pyomq-0.2.0/pyproject.toml +59 -0
- pyomq-0.2.0/python/pyomq/__init__.py +453 -0
- pyomq-0.2.0/python/pyomq/asyncio.py +206 -0
- pyomq-0.2.0/python/pyomq/error.py +47 -0
pyomq-0.2.0/Cargo.toml
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
[workspace]
|
|
2
|
+
members = [
|
|
3
|
+
"blume",
|
|
4
|
+
"omq",
|
|
5
|
+
"omq-compio",
|
|
6
|
+
"omq-proto",
|
|
7
|
+
"omq-tokio",
|
|
8
|
+
]
|
|
9
|
+
default-members = ["blume", "omq", "omq-compio", "omq-proto", "omq-tokio"]
|
|
10
|
+
# Bindings live in their own subtree. Each is its own build root - Python's
|
|
11
|
+
# maturin / Ruby's rake-compiler / etc. drive them - and they would otherwise
|
|
12
|
+
# pull foreign-language toolchains into `cargo build --workspace`.
|
|
13
|
+
exclude = ["bindings"]
|
|
14
|
+
resolver = "2"
|
|
15
|
+
|
|
16
|
+
[workspace.package]
|
|
17
|
+
edition = "2024"
|
|
18
|
+
rust-version = "1.93"
|
|
19
|
+
license = "ISC"
|
|
20
|
+
authors = ["Patrik Wenger <paddor@gmail.com>"]
|
|
21
|
+
repository = "https://github.com/paddor/omq.rs"
|
|
22
|
+
description = "Pure Rust OMQ/ZeroMQ: wire-compatible, feature-complete, high-performance."
|
|
23
|
+
|
|
24
|
+
[workspace.lints.rust]
|
|
25
|
+
missing_debug_implementations = "deny"
|
|
26
|
+
unsafe_op_in_unsafe_fn = "deny"
|
|
27
|
+
rust_2018_idioms = { level = "warn", priority = -1 }
|
|
28
|
+
unreachable_pub = "warn"
|
|
29
|
+
|
|
30
|
+
[workspace.lints.clippy]
|
|
31
|
+
all = { level = "warn", priority = -1 }
|
|
32
|
+
pedantic = { level = "warn", priority = -1 }
|
|
33
|
+
module_name_repetitions = "allow"
|
|
34
|
+
missing_errors_doc = "allow"
|
|
35
|
+
missing_panics_doc = "allow"
|
|
36
|
+
must_use_candidate = "allow"
|
|
37
|
+
cast_possible_truncation = "allow"
|
|
38
|
+
cast_sign_loss = "allow"
|
|
39
|
+
cast_precision_loss = "allow"
|
|
40
|
+
|
|
41
|
+
[profile.bench]
|
|
42
|
+
debug = "line-tables-only"
|
|
43
|
+
|
|
44
|
+
[profile.release]
|
|
45
|
+
debug = "line-tables-only"
|
pyomq-0.2.0/PKG-INFO
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pyomq
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Classifier: Development Status :: 3 - Alpha
|
|
5
|
+
Classifier: License :: OSI Approved :: ISC License (ISCL)
|
|
6
|
+
Classifier: Programming Language :: Python :: 3
|
|
7
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
8
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
12
|
+
Classifier: Programming Language :: Rust
|
|
13
|
+
Classifier: Topic :: System :: Networking
|
|
14
|
+
Requires-Dist: pytest>=7 ; extra == 'test'
|
|
15
|
+
Requires-Dist: pytest-asyncio>=0.21 ; extra == 'test'
|
|
16
|
+
Requires-Dist: pyzmq>=25 ; extra == 'test'
|
|
17
|
+
Provides-Extra: all
|
|
18
|
+
Provides-Extra: blake3zmq
|
|
19
|
+
Provides-Extra: curve
|
|
20
|
+
Provides-Extra: lz4
|
|
21
|
+
Provides-Extra: test
|
|
22
|
+
Provides-Extra: zstd
|
|
23
|
+
Summary: Python binding for omq.rs (Rust libzmq port). Drop-in pyzmq replacement on the common path.
|
|
24
|
+
Keywords: zeromq,omq,messaging,pyzmq,zmq
|
|
25
|
+
Author-email: Patrik Wenger <paddor@gmail.com>
|
|
26
|
+
License: ISC
|
|
27
|
+
Requires-Python: >=3.9
|
|
28
|
+
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
29
|
+
Project-URL: Repository, https://github.com/paddor/omq.rs
|
|
30
|
+
|
|
31
|
+
# pyomq
|
|
32
|
+
|
|
33
|
+
Python binding for [omq.rs](https://github.com/paddor/omq.rs), a Rust libzmq
|
|
34
|
+
port. Drop-in pyzmq replacement on the common path.
|
|
35
|
+
|
|
36
|
+
## Install
|
|
37
|
+
|
|
38
|
+
```sh
|
|
39
|
+
uv pip install pyomq
|
|
40
|
+
# Optional extras (built into the wheel via cargo features):
|
|
41
|
+
uv pip install 'pyomq[curve]'
|
|
42
|
+
uv pip install 'pyomq[blake3zmq,lz4,zstd]'
|
|
43
|
+
uv pip install 'pyomq[test]' # adds pytest, pyzmq for the interop suite
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Usage
|
|
47
|
+
|
|
48
|
+
```python
|
|
49
|
+
import pyomq as zmq # drop-in for `import zmq` from pyzmq
|
|
50
|
+
|
|
51
|
+
ctx = zmq.Context()
|
|
52
|
+
push = ctx.socket(zmq.PUSH)
|
|
53
|
+
push.connect("tcp://127.0.0.1:5555")
|
|
54
|
+
push.send(b"hello")
|
|
55
|
+
push.close()
|
|
56
|
+
ctx.term()
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
For asynchronous code:
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
import pyomq.asyncio as zmq_async
|
|
63
|
+
|
|
64
|
+
ctx = zmq_async.Context()
|
|
65
|
+
sock = ctx.socket(pyomq.PUSH)
|
|
66
|
+
await sock.connect("tcp://127.0.0.1:5555")
|
|
67
|
+
await sock.send(b"hello")
|
|
68
|
+
await sock.close()
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Status
|
|
72
|
+
|
|
73
|
+
Sync and `asyncio` APIs both ship in this release. All 19 ZMTP socket types are wired:
|
|
74
|
+
|
|
75
|
+
- **Standard (RFC 28 + 47)**: PAIR, PUB, SUB, REQ, REP, DEALER, ROUTER, PULL, PUSH, XPUB, XSUB.
|
|
76
|
+
- **Draft**: SERVER, CLIENT (RFC 41), RADIO, DISH (RFC 48), GATHER, SCATTER (RFC 49), PEER, CHANNEL (RFC 51).
|
|
77
|
+
|
|
78
|
+
Transports: `tcp://`, `ipc://`, `inproc://`, and `udp://` (RADIO/DISH only).
|
|
79
|
+
Optional features built into the wheel: `curve`, `blake3zmq`, `lz4`, `zstd`.
|
|
80
|
+
|
|
81
|
+
DISH groups: use `socket.join(b"group")` / `socket.leave(b"group")` to manage
|
|
82
|
+
subscriptions; messages are sent as multipart `[group, body]`.
|
|
83
|
+
|
|
84
|
+
## Backend
|
|
85
|
+
|
|
86
|
+
pyomq is built on `omq-compio` (single-threaded io_uring on Linux). The runtime
|
|
87
|
+
runs on a dedicated background thread; every Python call releases the GIL
|
|
88
|
+
across the runtime trip. This is the only backend pyomq supports — the
|
|
89
|
+
`omq-tokio` backend exists in the upstream Rust workspace for callers that need
|
|
90
|
+
a multi-thread tokio integration, but pyomq's per-call overhead is shaped
|
|
91
|
+
around compio's single-thread invariant.
|
|
92
|
+
|
|
93
|
+
## Performance
|
|
94
|
+
|
|
95
|
+
Loopback PUSH/PULL throughput vs pyzmq, on a Linux 6.12 (Debian 13) VM on an
|
|
96
|
+
Intel Mac Mini 2018 (i7-8700B, 3.2 GHz), Rust 1.95.0, default features:
|
|
97
|
+
|
|
98
|
+
<!-- PERF:START -->
|
|
99
|
+
| Size | inproc pyomq | inproc pyzmq | ratio | tcp pyomq | tcp pyzmq | ratio |
|
|
100
|
+
|---------|-------------:|-------------:|----------:|----------:|----------:|----------:|
|
|
101
|
+
| 8 B | 1.30 M/s | 627 k/s | **2.08×** | 1.36 M/s | 565 k/s | **2.41×** |
|
|
102
|
+
| 32 B | 1.29 M/s | 620 k/s | **2.08×** | 1.36 M/s | 576 k/s | **2.37×** |
|
|
103
|
+
| 128 B | 1.31 M/s | 516 k/s | **2.54×** | 1.29 M/s | 496 k/s | **2.61×** |
|
|
104
|
+
| 512 B | 1.29 M/s | 480 k/s | **2.69×** | 1.21 M/s | 461 k/s | **2.62×** |
|
|
105
|
+
| 2 KiB | 1.17 M/s | 461 k/s | **2.54×** | 908 k/s | 342 k/s | **2.65×** |
|
|
106
|
+
| 8 KiB | 1.04 M/s | 368 k/s | **2.83×** | 349 k/s | 102 k/s | **3.41×** |
|
|
107
|
+
| 32 KiB | 622 k/s | 196 k/s | **3.17×** | 116 k/s | 46 k/s | **2.50×** |
|
|
108
|
+
| 128 KiB | 203 k/s | 70 k/s | **2.91×** | 32 k/s | 24 k/s | **1.32×** |
|
|
109
|
+
<!-- PERF:END -->
|
|
110
|
+
|
|
111
|
+
### `zmq.proxy()` forwarding (128 B, TCP)
|
|
112
|
+
|
|
113
|
+
<!-- PROXY_PERF:START -->
|
|
114
|
+
| | pyomq | pyzmq | ratio |
|
|
115
|
+
|--------------------|----------:|----------:|----------:|
|
|
116
|
+
| PUSH/PULL msg/s | 963 k/s | 520 k/s | **1.85×** |
|
|
117
|
+
| REQ/REP rt/s | 8,764/s | 6,521/s | **1.34×** |
|
|
118
|
+
<!-- PROXY_PERF:END -->
|
|
119
|
+
|
|
120
|
+
pyomq's `proxy()` runs as a native Rust async loop on the compio thread — no
|
|
121
|
+
Python per-message overhead. pyzmq's `zmq.proxy()` calls libzmq's C-level
|
|
122
|
+
`zmq_proxy`. PUSH/PULL forwarding is throughput-bound and pyomq is ~1.9× faster.
|
|
123
|
+
REQ/REP is latency-bound (4 TCP hops per round-trip) so both are similar.
|
|
124
|
+
|
|
125
|
+
Run `scripts/update_perf.py` (after `maturin develop --release`) to re-measure and update the tables above.
|
|
126
|
+
|
|
127
|
+
## Develop
|
|
128
|
+
|
|
129
|
+
```sh
|
|
130
|
+
cd bindings/pyomq
|
|
131
|
+
uv venv && source .venv/bin/activate
|
|
132
|
+
uv pip install maturin pytest pyzmq
|
|
133
|
+
maturin develop --release
|
|
134
|
+
pytest -v
|
|
135
|
+
```
|
|
136
|
+
|
pyomq-0.2.0/README.md
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# pyomq
|
|
2
|
+
|
|
3
|
+
Python binding for [omq.rs](https://github.com/paddor/omq.rs), a Rust libzmq
|
|
4
|
+
port. Drop-in pyzmq replacement on the common path.
|
|
5
|
+
|
|
6
|
+
## Install
|
|
7
|
+
|
|
8
|
+
```sh
|
|
9
|
+
uv pip install pyomq
|
|
10
|
+
# Optional extras (built into the wheel via cargo features):
|
|
11
|
+
uv pip install 'pyomq[curve]'
|
|
12
|
+
uv pip install 'pyomq[blake3zmq,lz4,zstd]'
|
|
13
|
+
uv pip install 'pyomq[test]' # adds pytest, pyzmq for the interop suite
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Usage
|
|
17
|
+
|
|
18
|
+
```python
|
|
19
|
+
import pyomq as zmq # drop-in for `import zmq` from pyzmq
|
|
20
|
+
|
|
21
|
+
ctx = zmq.Context()
|
|
22
|
+
push = ctx.socket(zmq.PUSH)
|
|
23
|
+
push.connect("tcp://127.0.0.1:5555")
|
|
24
|
+
push.send(b"hello")
|
|
25
|
+
push.close()
|
|
26
|
+
ctx.term()
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
For asynchronous code:
|
|
30
|
+
|
|
31
|
+
```python
|
|
32
|
+
import pyomq.asyncio as zmq_async
|
|
33
|
+
|
|
34
|
+
ctx = zmq_async.Context()
|
|
35
|
+
sock = ctx.socket(pyomq.PUSH)
|
|
36
|
+
await sock.connect("tcp://127.0.0.1:5555")
|
|
37
|
+
await sock.send(b"hello")
|
|
38
|
+
await sock.close()
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Status
|
|
42
|
+
|
|
43
|
+
Sync and `asyncio` APIs both ship in this release. All 19 ZMTP socket types are wired:
|
|
44
|
+
|
|
45
|
+
- **Standard (RFC 28 + 47)**: PAIR, PUB, SUB, REQ, REP, DEALER, ROUTER, PULL, PUSH, XPUB, XSUB.
|
|
46
|
+
- **Draft**: SERVER, CLIENT (RFC 41), RADIO, DISH (RFC 48), GATHER, SCATTER (RFC 49), PEER, CHANNEL (RFC 51).
|
|
47
|
+
|
|
48
|
+
Transports: `tcp://`, `ipc://`, `inproc://`, and `udp://` (RADIO/DISH only).
|
|
49
|
+
Optional features built into the wheel: `curve`, `blake3zmq`, `lz4`, `zstd`.
|
|
50
|
+
|
|
51
|
+
DISH groups: use `socket.join(b"group")` / `socket.leave(b"group")` to manage
|
|
52
|
+
subscriptions; messages are sent as multipart `[group, body]`.
|
|
53
|
+
|
|
54
|
+
## Backend
|
|
55
|
+
|
|
56
|
+
pyomq is built on `omq-compio` (single-threaded io_uring on Linux). The runtime
|
|
57
|
+
runs on a dedicated background thread; every Python call releases the GIL
|
|
58
|
+
across the runtime trip. This is the only backend pyomq supports — the
|
|
59
|
+
`omq-tokio` backend exists in the upstream Rust workspace for callers that need
|
|
60
|
+
a multi-thread tokio integration, but pyomq's per-call overhead is shaped
|
|
61
|
+
around compio's single-thread invariant.
|
|
62
|
+
|
|
63
|
+
## Performance
|
|
64
|
+
|
|
65
|
+
Loopback PUSH/PULL throughput vs pyzmq, on a Linux 6.12 (Debian 13) VM on an
|
|
66
|
+
Intel Mac Mini 2018 (i7-8700B, 3.2 GHz), Rust 1.95.0, default features:
|
|
67
|
+
|
|
68
|
+
<!-- PERF:START -->
|
|
69
|
+
| Size | inproc pyomq | inproc pyzmq | ratio | tcp pyomq | tcp pyzmq | ratio |
|
|
70
|
+
|---------|-------------:|-------------:|----------:|----------:|----------:|----------:|
|
|
71
|
+
| 8 B | 1.30 M/s | 627 k/s | **2.08×** | 1.36 M/s | 565 k/s | **2.41×** |
|
|
72
|
+
| 32 B | 1.29 M/s | 620 k/s | **2.08×** | 1.36 M/s | 576 k/s | **2.37×** |
|
|
73
|
+
| 128 B | 1.31 M/s | 516 k/s | **2.54×** | 1.29 M/s | 496 k/s | **2.61×** |
|
|
74
|
+
| 512 B | 1.29 M/s | 480 k/s | **2.69×** | 1.21 M/s | 461 k/s | **2.62×** |
|
|
75
|
+
| 2 KiB | 1.17 M/s | 461 k/s | **2.54×** | 908 k/s | 342 k/s | **2.65×** |
|
|
76
|
+
| 8 KiB | 1.04 M/s | 368 k/s | **2.83×** | 349 k/s | 102 k/s | **3.41×** |
|
|
77
|
+
| 32 KiB | 622 k/s | 196 k/s | **3.17×** | 116 k/s | 46 k/s | **2.50×** |
|
|
78
|
+
| 128 KiB | 203 k/s | 70 k/s | **2.91×** | 32 k/s | 24 k/s | **1.32×** |
|
|
79
|
+
<!-- PERF:END -->
|
|
80
|
+
|
|
81
|
+
### `zmq.proxy()` forwarding (128 B, TCP)
|
|
82
|
+
|
|
83
|
+
<!-- PROXY_PERF:START -->
|
|
84
|
+
| | pyomq | pyzmq | ratio |
|
|
85
|
+
|--------------------|----------:|----------:|----------:|
|
|
86
|
+
| PUSH/PULL msg/s | 963 k/s | 520 k/s | **1.85×** |
|
|
87
|
+
| REQ/REP rt/s | 8,764/s | 6,521/s | **1.34×** |
|
|
88
|
+
<!-- PROXY_PERF:END -->
|
|
89
|
+
|
|
90
|
+
pyomq's `proxy()` runs as a native Rust async loop on the compio thread — no
|
|
91
|
+
Python per-message overhead. pyzmq's `zmq.proxy()` calls libzmq's C-level
|
|
92
|
+
`zmq_proxy`. PUSH/PULL forwarding is throughput-bound and pyomq is ~1.9× faster.
|
|
93
|
+
REQ/REP is latency-bound (4 TCP hops per round-trip) so both are similar.
|
|
94
|
+
|
|
95
|
+
Run `scripts/update_perf.py` (after `maturin develop --release`) to re-measure and update the tables above.
|
|
96
|
+
|
|
97
|
+
## Develop
|
|
98
|
+
|
|
99
|
+
```sh
|
|
100
|
+
cd bindings/pyomq
|
|
101
|
+
uv venv && source .venv/bin/activate
|
|
102
|
+
uv pip install maturin pytest pyzmq
|
|
103
|
+
maturin develop --release
|
|
104
|
+
pytest -v
|
|
105
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/CLA*
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.2.0](https://github.com/paddor/omq.rs/releases/tag/pyomq-v0.2.0) - 2026-05-04
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- First PyPI release. Python binding for omq-compio (compio/io_uring backend).
|
|
15
|
+
Linux x86_64 and aarch64 wheels; stable ABI covers Python 3.9+.
|