Skip to main content

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: call write_row([...]) repeatedly; uses inline strings so memory stays bounded (no giant SST while writing). Supports with / 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 a list of cell values). For typical workbooks whose cells are wrapped in <row> (Excel, XlsxWriter, OpenPyxl), Rust does not build a full rows × cols grid in memory; peak RSS stays much lower than read_xlsx. Sheets that need a legacy sparse layout (cells not under <row>) fall back internally to buffering like read_xlsx.
  • Read path: one ZIP archive is opened during load() / parse_workbook and reused for every sheet read; worksheet XML is parsed from the zip entry stream (no full-sheet String). Shared string table entries use Arc<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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

veloxlsx-0.1.0.tar.gz (27.9 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

veloxlsx-0.1.0-cp310-abi3-win_amd64.whl (431.6 kB view details)

Uploaded CPython 3.10+Windows x86-64

veloxlsx-0.1.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (596.1 kB view details)

Uploaded CPython 3.10+manylinux: glibc 2.17+ x86-64

veloxlsx-0.1.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (591.4 kB view details)

Uploaded CPython 3.10+manylinux: glibc 2.17+ ARM64

veloxlsx-0.1.0-cp310-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl (1.1 MB view details)

Uploaded CPython 3.10+macOS 10.12+ universal2 (ARM64, x86-64)macOS 10.12+ x86-64macOS 11.0+ ARM64

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

Hashes for veloxlsx-0.1.0.tar.gz
Algorithm Hash digest
SHA256 e834e49069eba509a2f099f10f4fe95a7193cb1206365a895892d775e62b1af9
MD5 ee05bb4faf4f72d7023090dde17dce89
BLAKE2b-256 9b79ed4fa0c5f749de43f21f9846122ed7f10f402070924f53719f5f52b18ecb

See more details on using hashes here.

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

Hashes for veloxlsx-0.1.0-cp310-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 c14ffe17c36fc3bf0bc193c7968f932652d867d606dd1c1f561a14c3264b257d
MD5 3bb4bde206b3bc1003b8adc23035e697
BLAKE2b-256 5766c64cf780cdc3a61cd23c94a3802838273ab3b0796458b5c6dc1bb0af8124

See more details on using hashes here.

File details

Details for the file veloxlsx-0.1.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for veloxlsx-0.1.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 2d7726b849ae4b99e3975f114fb9276d09e5ef371f39ef417f79f8ba4e74826b
MD5 0fbfa41375a43b0b56cf0d1334d398ca
BLAKE2b-256 af9ec7f1788c2d071870237c54b998971fc6c7fc93d9382b3bbe4581cc2148b6

See more details on using hashes here.

File details

Details for the file veloxlsx-0.1.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for veloxlsx-0.1.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 7c8d90e54ee97acbcc7611e2d6b3e4321b1601460f0e32c4dad951fe46926321
MD5 072f07d45e5134a302cdf3301af7fa42
BLAKE2b-256 60ebc0b0431a2f25b10f7c7e731e51999699c2aaf5f97392c727acc30742c067

See more details on using hashes here.

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

File hashes

Hashes for veloxlsx-0.1.0-cp310-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl
Algorithm Hash digest
SHA256 460aa70991ff20733cde68b5c99192669a2e6a17d0677e47ce0460d939db1449
MD5 f88972738708a72a62daa86c84a4e679
BLAKE2b-256 b2d33e0b48a1a51962d6be26d43f7216b5d35e5d122e01e6a3387095f9cfc7d1

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page