Python bindings for io_uring with dynamic buffer size adjustment
Project description
pyuring
pyuring is a Python library for performing file I/O using the Linux io_uring kernel interface.
io_uring submits I/O operations to the kernel through a shared-memory ring buffer instead of issuing individual system calls per operation. This reduces per-operation syscall overhead, which is especially noticeable in workloads with many small or concurrent I/O operations.
pyuring exposes io_uring to Python through a C shared library (liburingwrap.so, built on top of liburing) and ctypes bindings. You do not need to understand the ring buffer mechanics to use the high-level API — but if you want direct control over submission and completion queues, that is available too.
Requires: Linux kernel 5.15+, Python 3.8+
Install
pip install pyuring
On glibc x86_64 Linux, pip installs a manylinux wheel that includes a pre-built liburingwrap.so — no separate liburing package is needed. For other platforms or source builds, see docs/INSTALLATION.md.
What pyuring provides
High-level file I/O helpers
The simplest way to use pyuring. copy, write, and write_many handle queue depth tuning, buffer management, and the io_uring pipeline internally.
import pyuring as iou
# Copy a file
iou.copy("/tmp/src.dat", "/tmp/dst.dat")
# Write a new file (100 MiB of data)
iou.write("/tmp/new.dat", total_mb=100)
# Write multiple files into a directory
iou.write_many("/tmp/out", nfiles=10, mb_per_file=100)
The mode parameter controls how queue depth and buffer size are tuned:
| mode | Behavior |
|---|---|
"auto" (default) |
Starts with the default block size and increases it as the operation progresses. Uses the dynamic buffer C path. |
"safe" |
Conservative settings: queue depth capped at 16 (copy) or 128 (write), block size capped at 1 MiB (copy) or 4 KiB (write). |
"fast" |
Aggressive settings: queue depth at least 64 (copy) or 256 (write), block size at least 1 MiB (copy) or 64 KiB (write). |
You can track progress or cancel an operation cooperatively using progress_cb:
def on_progress(done_bytes, total_bytes):
print(f"{done_bytes} / {total_bytes} bytes")
return False # return True to cancel (raises UringError with errno.ECANCELED)
iou.copy("/tmp/src.dat", "/tmp/dst.dat", progress_cb=on_progress)
UringCtx — direct ring control
UringCtx wraps a single io_uring instance. Use it when you need to submit and receive completions manually, register fixed file descriptors or buffers, or configure the ring with specific setup flags.
import os
import pyuring as iou
with iou.UringCtx(entries=64) as ctx:
fd = os.open("/tmp/data.bin", os.O_RDONLY)
# Synchronous read (submits one SQE and waits for its CQE internally)
data = ctx.read(fd, length=4096, offset=0)
# Asynchronous: submit a read, then wait for its completion separately
buf = bytearray(4096)
ctx.read_async(fd, buf, offset=0, user_data=42)
ctx.submit()
user_data, result = ctx.wait_completion()
# result is the number of bytes read, or a negative errno on error
You can pass IORING_SETUP_* flags to tune the ring at creation time:
ctx = iou.UringCtx(
entries=128,
setup_flags=iou.IORING_SETUP_SINGLE_ISSUER | iou.IORING_SETUP_COOP_TASKRUN,
)
UringAsync — asyncio integration
UringAsync integrates UringCtx with an asyncio event loop. It registers the ring's completion queue file descriptor (ring_fd) with the loop's reader, so await ua.wait_completion() returns as soon as a CQE is available — without blocking the event loop thread.
import asyncio
import pyuring as iou
from pyuring import UringAsync
async def main():
with iou.UringCtx(entries=64) as ctx:
async with UringAsync(ctx) as ua:
fd = os.open("/tmp/data.bin", os.O_RDONLY)
buf = bytearray(4096)
ctx.read_async(fd, buf, user_data=1)
ctx.submit()
user_data, result = await ua.wait_completion()
asyncio.run(main())
BufferPool — native buffer management
BufferPool allocates and manages a set of fixed-size buffers in native memory. Use it with read_async / write_async when you want to avoid Python object allocation per I/O operation.
with iou.BufferPool.create(initial_count=8, initial_size=4096) as pool:
ptr, size = pool.get_ptr(0) # raw pointer to buffer slot 0
ctx.read_async(fd, (ptr, size), user_data=0)
ctx.submit()
ctx.wait_completion()
data = pool.get(0) # read the result as bytes
Kernel capability probe
Before using a specific io_uring opcode, you can check at runtime whether the running kernel supports it. This is useful because opcode availability depends on the kernel version.
from pyuring import opcode_supported, require_opcode_supported, IORING_OP_SPLICE
# Returns True/False
if iou.opcode_supported(iou.IORING_OP_SPLICE):
...
# Raises UringError(errno.EOPNOTSUPP) if not supported
require_opcode_supported(iou.IORING_OP_SPLICE, "my_splice_op")
Error handling
All errors from the native layer raise UringError, which is a subclass of OSError. It carries three fields:
| Field | Content |
|---|---|
errno |
The kernel errno value (same meaning as in os / OSError). |
operation |
The name of the C wrapper function that failed (e.g. "uring_copy_path"). |
detail |
An optional string with additional context, such as search paths when liburingwrap.so cannot be found. |
import errno
from pyuring import UringError
try:
iou.copy("/tmp/src.dat", "/tmp/dst.dat")
except UringError as e:
if e.errno == errno.ENOENT:
print("source file not found")
elif e.errno == errno.ECANCELED:
print("cancelled by progress callback")
print(f"failed in: {e.operation}")
Further reading
| Document | Contents |
|---|---|
| docs/USAGE.md | Full API reference for all classes and functions |
| docs/INSTALLATION.md | Build from source, liburing options, platform notes |
| docs/BENCHMARKS.md | How to run the included benchmarks |
| docs/TESTING.md | How to run the test suite |
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pyuring-0.3.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl.
File metadata
- Download URL: pyuring-0.3.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl
- Upload date:
- Size: 201.9 kB
- Tags: PyPy, manylinux: glibc 2.17+ x86-64, manylinux: glibc 2.28+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.8.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
988055e199ecdd46387e0b0ebf4a059346768641d7480e26e4c1882f4b8487f1
|
|
| MD5 |
59b135fff7a2e65cb248d8dd4880e311
|
|
| BLAKE2b-256 |
a27af27fba76e7d8eaf6e0427a1bfc293d25429e8e81fd5107168907d88c8754
|
File details
Details for the file pyuring-0.3.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl.
File metadata
- Download URL: pyuring-0.3.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl
- Upload date:
- Size: 201.9 kB
- Tags: PyPy, manylinux: glibc 2.17+ x86-64, manylinux: glibc 2.28+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.8.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
56c78f2c3a96c3ac1b85a50d640e294abb9c4a48444560654e56ceff256d8305
|
|
| MD5 |
08866416eb5efbeb402a319517006213
|
|
| BLAKE2b-256 |
ea52d3e2b035ed71ffe77193dd3720fe5c4d560c4caea5b7c6828c3d9692770c
|
File details
Details for the file pyuring-0.3.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl.
File metadata
- Download URL: pyuring-0.3.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl
- Upload date:
- Size: 201.9 kB
- Tags: PyPy, manylinux: glibc 2.17+ x86-64, manylinux: glibc 2.28+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.8.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9cd2bc8761aa23bfcda8f915bdc1b8cdc36a0a897a5f661caef0063e840f1245
|
|
| MD5 |
674cf0f36312cf8ab3afb9ceed558568
|
|
| BLAKE2b-256 |
d64ca142ea438e8062a92cf08b545549fd55fb22f9cdf5856a0ea9f4bd67991d
|
File details
Details for the file pyuring-0.3.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl.
File metadata
- Download URL: pyuring-0.3.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl
- Upload date:
- Size: 201.6 kB
- Tags: PyPy, manylinux: glibc 2.17+ x86-64, manylinux: glibc 2.28+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.8.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
286c3d93428d72276b2e2508968b1468e1f5ba2e2254add2b5ec794d4097532b
|
|
| MD5 |
0bd477da1541d2f6225f104a3da84519
|
|
| BLAKE2b-256 |
91114b896cb64b8357ba535cb85c302690ce15988b564ef775fcbcfa3cf30fdd
|
File details
Details for the file pyuring-0.3.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl.
File metadata
- Download URL: pyuring-0.3.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl
- Upload date:
- Size: 201.9 kB
- Tags: CPython 3.13, manylinux: glibc 2.17+ x86-64, manylinux: glibc 2.28+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.8.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b8e691c03c9d6a8ebe29283179f85d4e61347e73dbc6b1f00060e9e5f2acf88d
|
|
| MD5 |
b22c3fb5eb6f29ba82ddd0e3b0ca58f3
|
|
| BLAKE2b-256 |
2d2e830626e08b30f264ea328efc5633aed1451f36679f25f2605d264a2bc531
|
File details
Details for the file pyuring-0.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl.
File metadata
- Download URL: pyuring-0.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl
- Upload date:
- Size: 201.9 kB
- Tags: CPython 3.12, manylinux: glibc 2.17+ x86-64, manylinux: glibc 2.28+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.8.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0cebc3801b02f3d5e3925b6c818d61fcca368223ea5ccbbb28e6e029598af7e9
|
|
| MD5 |
049698acccf81c9e8f406ab432b2fc45
|
|
| BLAKE2b-256 |
3458862fd16d621982af5c8bfd86c4dab8eca1d347c4e4a7738ba269579e1c0a
|
File details
Details for the file pyuring-0.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl.
File metadata
- Download URL: pyuring-0.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl
- Upload date:
- Size: 201.9 kB
- Tags: CPython 3.11, manylinux: glibc 2.17+ x86-64, manylinux: glibc 2.28+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.8.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5b0c95543ffc510d95b5b91b8ced1259f353b581c72247ec5a3cce7281db190b
|
|
| MD5 |
fd77096c323fcbc26fa3ced039fca1c1
|
|
| BLAKE2b-256 |
4a982c7c449cb4164c7216397b5d84e183959432db77a3f160f18912b765fd29
|
File details
Details for the file pyuring-0.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl.
File metadata
- Download URL: pyuring-0.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl
- Upload date:
- Size: 201.9 kB
- Tags: CPython 3.10, manylinux: glibc 2.17+ x86-64, manylinux: glibc 2.28+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.8.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7843e05279433cc603f4b267339294aed97ded1fc08a0ee92b416731ee3e422d
|
|
| MD5 |
f33294cfa48e1fb63e31d7a5cc504eea
|
|
| BLAKE2b-256 |
1d7cde16dae8003be12c56aeeabcdee9c39db4c47721b3fcd6f0cafbe97b4a76
|
File details
Details for the file pyuring-0.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl.
File metadata
- Download URL: pyuring-0.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl
- Upload date:
- Size: 201.9 kB
- Tags: CPython 3.9, manylinux: glibc 2.17+ x86-64, manylinux: glibc 2.28+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.8.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7406387d389ae4691110c05cf6ffd40626450fb8cb01b60867804842232bde77
|
|
| MD5 |
a22d9f027e127b47f9d0b07c5c6dd673
|
|
| BLAKE2b-256 |
7bb2a8a0927deae5cbae0a6038e37602b3afc62fa4c4d0d91ac0f421e9d5dcc5
|
File details
Details for the file pyuring-0.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl.
File metadata
- Download URL: pyuring-0.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl
- Upload date:
- Size: 201.4 kB
- Tags: CPython 3.8, manylinux: glibc 2.17+ x86-64, manylinux: glibc 2.28+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.8.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8cc4066b419822ab7f2fab91074b6fbe7420465ad46e196188da69afc1b2af1a
|
|
| MD5 |
e3346fc66ef320b745c42052dfff25ce
|
|
| BLAKE2b-256 |
8e7cac1e24288a058e60b2394dcf1bcd0dd3a07b4f5f4b5701d25cca72e22765
|