Python-first XLSX reader with a Rust core
Project description
veloxlsx
Python bindings over a Rust core for reading .xlsx (Office Open XML) workbooks. The goal is read speed and a small, typed surface area while the format support grows.
Install: pip install veloxlsx, then import veloxlsx.
Status (Phase 1)
- Reads workbook structure, shared strings, and worksheet cell grids.
- Cell kinds: numbers, booleans, shared strings, inline strings, basic error markers, plain text fallbacks.
- Dates are not interpreted from number formats yet; numeric date serials may appear as floats (same caveat as many minimal readers).
- Styles (fonts, fills, borders) are not applied to values.
Phase 2 — write + faster read
veloxlsx.write_xlsx(path, rows, sheet=...)— single-sheet writer with shared-string deduplication (memory scales with unique strings, not cell count).veloxlsx.StreamWriter(path, sheet_name=...)— streaming writer: callwrite_row([...])repeatedly; uses inline strings so memory stays bounded (no giant SST while writing). Supportswith/close().veloxlsx.iter_rows(path, sheet=...),Workbook.iter_rows(...),Sheet.iter_rows()— streaming read on the Python side: yields one row at a time (each row is alistof cell values). For typical workbooks whose cells are wrapped in<row>(Excel, XlsxWriter, OpenPyxl), Rust does not build a fullrows × colsgrid in memory; peak RSS stays much lower thanread_xlsx. Sheets that need a legacy sparse layout (cells not under<row>) fall back internally to buffering likeread_xlsx.- Read path: one ZIP archive is opened during
load()/parse_workbookand reused for every sheet read; worksheet XML is parsed from the zip entry stream (no full-sheetString). Shared string table entries useArc<str>so repeated values clone a pointer, not the text.
Benchmarks (large files vs other libraries)
The default unit run (pytest) only hits tests/. For a large grid comparison against openpyxl, python-calamine (Rust calamine), and pandas (read_excel with calamine vs openpyxl engines), use the separate suite under benchmarks/:
maturin develop --release
pip install -e ".[dev]" # includes xlsxwriter, pandas, python-calamine, pytest-benchmark
pytest benchmarks/
Grid size (defaults 4000 × 120 cells ≈ 480k values):
VELOXLSX_BENCH_ROWS=10000 VELOXLSX_BENCH_COLS=200 pytest benchmarks/
The workbook is generated with xlsxwriter (fast streaming write) so you are mostly measuring read performance, not fixture build time after the first module-scoped write.
Cross-library timing & memory (same fixture)
benchmarks/memory_timing.py runs one scenario per subprocess and prints wall time (time.perf_counter) and peak RSS (resource.getrusage(RUSAGE_SELF).ru_maxrss, converted to MiB; Linux reports KiB, macOS bytes). Optional libraries are skipped if not installed (pip install -e ".[dev]").
maturin develop --release
pip install -e ".[dev]"
python benchmarks/memory_timing.py
# optional: VELOXLSX_BENCH_ROWS=10000 VELOXLSX_BENCH_COLS=200 python benchmarks/memory_timing.py
Sample read comparison — same workbook (4000 × 120 numeric grid, ~480k cells); macOS arm64, Python 3.13, release veloxlsx, April 2026. Numbers are indicative (OS/CPU/RAM/Python build change them).
| API / library | Time (ms) | Peak RSS (MiB) |
|---|---|---|
veloxlsx read_xlsx (nested lists) |
236.3 | 114.7 |
veloxlsx iter_rows (streaming; one row at a time) |
258.8 | 36.0 |
veloxlsx load + read_sheet(0) |
241.0 | 114.6 |
openpyxl read-only iter_rows |
603.4 | 38.9 |
python-calamine to_python() |
196.0 | 68.9 |
pandas read_excel (engine="calamine") |
228.2 | 141.4 |
pandas read_excel (engine="openpyxl") |
812.6 | 101.5 |
Sample write comparison — generating a new file of the same shape (numeric grid):
| API / library | Time (ms) | Peak RSS (MiB) |
|---|---|---|
veloxlsx StreamWriter (row stream) |
298.3 | 15.6 |
veloxlsx write_xlsx (grid in Python) |
273.0 | 70.7 |
XlsxWriter constant_memory |
829.9 | 24.3 |
How to interpret: higher peak RSS usually means the API materialized a large object graph in Python (e.g. read_xlsx building a nested list for every cell). iter_rows avoids holding the whole sheet in Python at once and, for row-based XML, avoids a full Rust grid—here RSS is in the same ballpark as openpyxl read-only with much lower wall time. Legacy sheets may still buffer like read_xlsx. Re-run memory_timing.py on your machine before choosing.
For pytest micro-benchmarks (not RSS), see pytest benchmarks/.
| Library | Read | Write | Excel feature surface |
|---|---|---|---|
| veloxlsx | Yes (read_xlsx, iter_rows) |
Yes (write_xlsx, StreamWriter) |
Values / basic cell types only (see Status above). |
| python-calamine | Yes | No | Read-focused; Rust calamine. |
| openpyxl | Yes | Yes | Broad OOXML (styles, charts, …). |
| pandas | Yes (read_excel) |
Yes (to_excel, engine-dependent) |
DataFrame-centric; uses engines above. |
| XlsxWriter | No | Yes | Write-only; rich writing features. |
Install (from source)
Requires Rust, Python 3.10+, and maturin.
python -m venv .venv
source .venv/bin/activate
pip install maturin
maturin develop --extras dev
Typing (Pyright, mypy, …)
The wheel / editable install is PEP 561–aware (py.typed plus python/veloxlsx/__init__.pyi). The native module is veloxlsx._native; import the public API from veloxlsx. Runtime aliases CellValue, Row, and Grid match the stubs:
from veloxlsx import CellValue, Grid, Row, read_xlsx
def f(rows: Grid) -> list[Row]:
return [list(r) for r in rows]
Usage
import veloxlsx
grid = veloxlsx.read_xlsx("book.xlsx") # first sheet
grid = veloxlsx.read_xlsx("book.xlsx", "Sheet2")
grid = veloxlsx.read_xlsx("book.xlsx", 0)
wb = veloxlsx.load("book.xlsx")
assert wb.sheet_names[0] == "Sheet1"
same = wb.read_sheet(0)
sheet = wb["Sheet1"]
rows = sheet.to_list()
for row in wb.iter_rows("Sheet1"):
pass # each row: list of None / bool / int / float / str
veloxlsx.write_xlsx("out.xlsx", [["a", 1], ["b", 2]], sheet="Data")
with veloxlsx.StreamWriter("big.xlsx", sheet_name="Sheet1") as w:
for i in range(1_000_000):
w.write_row([i, f"row {i}"])
for row in veloxlsx.iter_rows("book.xlsx", "Data"):
pass
License
Licensed under either of Apache-2.0 or MIT at your option.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
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 veloxlsx-0.1.0.tar.gz.
File metadata
- Download URL: veloxlsx-0.1.0.tar.gz
- Upload date:
- Size: 27.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e834e49069eba509a2f099f10f4fe95a7193cb1206365a895892d775e62b1af9
|
|
| MD5 |
ee05bb4faf4f72d7023090dde17dce89
|
|
| BLAKE2b-256 |
9b79ed4fa0c5f749de43f21f9846122ed7f10f402070924f53719f5f52b18ecb
|
File details
Details for the file veloxlsx-0.1.0-cp310-abi3-win_amd64.whl.
File metadata
- Download URL: veloxlsx-0.1.0-cp310-abi3-win_amd64.whl
- Upload date:
- Size: 431.6 kB
- Tags: CPython 3.10+, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c14ffe17c36fc3bf0bc193c7968f932652d867d606dd1c1f561a14c3264b257d
|
|
| MD5 |
3bb4bde206b3bc1003b8adc23035e697
|
|
| BLAKE2b-256 |
5766c64cf780cdc3a61cd23c94a3802838273ab3b0796458b5c6dc1bb0af8124
|
File details
Details for the file veloxlsx-0.1.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: veloxlsx-0.1.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 596.1 kB
- Tags: CPython 3.10+, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2d7726b849ae4b99e3975f114fb9276d09e5ef371f39ef417f79f8ba4e74826b
|
|
| MD5 |
0fbfa41375a43b0b56cf0d1334d398ca
|
|
| BLAKE2b-256 |
af9ec7f1788c2d071870237c54b998971fc6c7fc93d9382b3bbe4581cc2148b6
|
File details
Details for the file veloxlsx-0.1.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.
File metadata
- Download URL: veloxlsx-0.1.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
- Upload date:
- Size: 591.4 kB
- Tags: CPython 3.10+, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7c8d90e54ee97acbcc7611e2d6b3e4321b1601460f0e32c4dad951fe46926321
|
|
| MD5 |
072f07d45e5134a302cdf3301af7fa42
|
|
| BLAKE2b-256 |
60ebc0b0431a2f25b10f7c7e731e51999699c2aaf5f97392c727acc30742c067
|
File details
Details for the file veloxlsx-0.1.0-cp310-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl.
File metadata
- Download URL: veloxlsx-0.1.0-cp310-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl
- Upload date:
- Size: 1.1 MB
- Tags: CPython 3.10+, macOS 10.12+ universal2 (ARM64, x86-64), macOS 10.12+ x86-64, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
460aa70991ff20733cde68b5c99192669a2e6a17d0677e47ce0460d939db1449
|
|
| MD5 |
f88972738708a72a62daa86c84a4e679
|
|
| BLAKE2b-256 |
b2d33e0b48a1a51962d6be26d43f7216b5d35e5d122e01e6a3387095f9cfc7d1
|