Objective, reproducible spreadsheet-library benchmarks with a Python-first decision surface.
Most Excel library comparisons focus on speed. ExcelBench focuses on the question developers actually have:
Can this library handle my real spreadsheet without breaking the parts I care about?
ExcelBench models 19 XLSX features across 12+ Python adapters. In the fresh wheel-backed WolfXL 2.0 release snapshot, 18 are scoreable across libraries (pivot tables remain N/A on macOS fixtures).
Python release snapshot: 2026-04-29 UTC | wheel-backed WolfXL 2.0 rerun | Fidelity | Perf | Dashboard
In that snapshot, WolfXL reaches
18/18green features with100%pass rate.Cross-language context snapshot: Apache POI
18/18| Excelize18/18Pivot capability lane: separate artifact because the shipped macOS pivot fixture is not scoreable, while
excelizecan still emit pivot-bearing workbooks.Historical public baseline: 2026-02-17 | Excel 16.105.3 | macOS (Apple Silicon) | Full results
Newer performance snapshot: 2026-04-20 | Perf results
Read Public Reporting Status before quoting numbers across snapshots.
The current story: ExcelBench now has three useful lanes. The Python release lane answers the migration question. The cross-language lane answers the ecosystem-positioning question. The pivot capability lane captures pivot evidence separately when the scored fixture is not valid on this platform. Keep every claim tied to the exact dated artifact you are citing.
ExcelBench intentionally keeps the main public comparison Python-first. That is the decision surface most users care about: openpyxl, xlsxwriter, python-calamine, pandas, and adjacent Python options.
Cross-language libraries matter too, but for a different reason: they show how strong WolfXL looks next to mature spreadsheet tooling outside Python. The current checked-in cross-language lane includes:
Apache POIExcelize
Pivot tables sit in a separate capability lane. On macOS, the shipped pivot fixture does not currently contain scoreable pivot OOXML, so the pivot story is tracked as a dedicated artifact instead of being mixed into the scored lane.
See cross-language comparison strategy.
-
Python replacement lane Use this when the question is: what should a Python team use instead of
openpyxl? -
Cross-language context lane Use this when the question is: how does WolfXL compare to serious spreadsheet tooling in Java and Go?
-
Pivot capability lane Use this when the question is: can the cross-language helpers detect or emit pivot-bearing workbooks even when the main scored fixture is not valid on macOS?
| Library | Caps | Fidelity | Read Speed | Write Speed | Modify |
|---|---|---|---|---|---|
| wolfxl | R+W | 18/18 in 2026-04-29 release snapshot | workload-specific | workload-specific | Patch |
| openpyxl | R+W | 18/18 in 2026-04-29 release snapshot | 1x (baseline per workload) | 1x (baseline per workload) | Rewrite |
| xlsxwriter | W | 15/18 in 2026-04-29 release snapshot | -- | ~1x | No |
| xlsxwriter-constmem | W | 12/18 in 2026-04-29 release snapshot | -- | ~2x | No |
| python-calamine | R | 1/18 in 2026-04-29 release snapshot | ~1.3x | -- | No |
| pandas | R+W | 3/18 in 2026-04-29 release snapshot | <1x | <1x | Rebuild |
| polars | R | 0/18 in 2026-04-29 release snapshot | ~1x | -- | No |
Speed numbers are snapshot-specific. Always cite the artifact date, workload, and profile. See performance results, METHODOLOGY.md, and Public Reporting Status.
- High-fidelity libraries are rare: in the fresh wheel-backed release snapshot, only openpyxl and WolfXL reach 18/18 green features
- Patch modify is structurally different: WolfXL's
load_workbook(path, modify=True)uses surgical ZIP patching rather than a full workbook rewrite - The abstraction tax is real: pandas wraps openpyxl but drops from 16 to 3 green features due to DataFrame coercion (errors become NaN)
- Speed vs fidelity tradeoff is measurable: use the perf snapshot together with the fidelity matrix rather than quoting one without the other
- Optimization modes have clear costs: openpyxl-readonly loses 13 green features for streaming speed
- Cross-language context is now strong too: both
Apache POIandExcelizeland at18/18in the current scored write lane
See the release snapshot dashboard for the fresh wheel-backed combined view, or the historical dashboard for the older public baseline.
| Score | Meaning |
|---|---|
| π’ 3 | Complete -- full fidelity, indistinguishable from Excel |
| π‘ 2 | Functional -- works for common cases, some edge-case failures |
| π 1 | Minimal -- basic recognition but significant limitations |
| π΄ 0 | Unsupported -- errors, corruption, or complete data loss |
| Library | Version | Lang | Caps | Green Features |
|---|---|---|---|---|
| openpyxl | 3.1.5 | Python | R+W | 18/18 |
| XlsxWriter | 3.2.9 | Python | W | 15/18 |
| xlsxwriter-constmem | 3.2.9 | Python | W | 12/18 |
| openpyxl-readonly | 3.1.5 | Python | R | 3/18 |
| pandas | 3.0.0 | Python | R+W | 3/18 |
| pyexcel | 0.7.4 | Python | R+W | 3/18 |
| tablib | 3.9.0 | Python | R+W | 3/18 |
| pylightxl | 1.61 | Python | R+W | 2/18 |
| python-calamine | 0.6.1 | Rust | R | 1/18 |
| polars | 1.38.1 | Rust | R | 0/18 |
| xlwt | 1.3.0 | Python | W | 4/18 |
| xlrd | 2.0.2 | Python | R | .xls only |
| Library | Green Features | Notes |
|---|---|---|
| xlrd | 4/4 | Full .xls read fidelity |
| python-calamine | 2/4 | Cross-format reader |
Five additional adapters via Rust/PyO3 extension modules:
| Library | Caps | Source | Notes |
|---|---|---|---|
| WolfXL (calamine-styled) | R | PyPI | Full-fidelity Rust reader with style extraction |
| WolfXL (rust_xlsxwriter) | W | PyPI | Full-fidelity Rust writer |
| calamine (basic) | R | Local | Direct calamine bindings (data only, no styles) |
| rust_xlsxwriter (direct) | W | Local | Direct rust_xlsxwriter bindings |
| umya-spreadsheet | R+W | Local | Rust read + write |
# WolfXL adapters (from PyPI β no Rust toolchain needed)
uv sync --extra rust
# Local-only adapters (requires Rust toolchain + maturin)
uv run maturin develop --manifest-path rust/excelbench_rust/Cargo.toml \
--features calamine,rust_xlsxwriter,umya
uv syncmay uninstall locally-built extensions; rerunmaturin developafter.
ExcelBench now ships a separate cross-language context snapshot for mature non-Python spreadsheet libraries:
Apache POI(Java)Excelize(Go)
These are not framed as Python drop-in replacements. They answer a different question: how strong is WolfXL relative to serious spreadsheet tooling outside Python?
Current checked-in cross-language snapshot:
results-cross-language/README.mdresults-cross-language/CONTEXT.mdresults-cross-language-pivots/README.mddocs/cross-language-context.md
Current takeaways from that snapshot:
apache-poi:18/18green features in the scored write surfaces of this laneexcelize:18/18green features in the scored write surfaces of this lanepivot_tables: tracked in a separate capability artifact because the shipped macOS fixture does not contain scoreable pivot OOXML, whileexcelizecan still emit pivot-bearing workbooks
The concrete rollout plan for the first two candidates is here:
Run the dedicated cross-language context snapshot with:
uv run excelbench cross-language-context --tests fixtures/excel --output results-cross-languageRun the dedicated pivot capability artifact with:
uv run excelbench cross-language-pivot-context --fixture fixtures/excel/tier2/15_pivot_tables.xlsx --output results-cross-language-pivots- Generate reference files -- xlwings drives real Excel to produce canonical
.xlsx/.xlstest files with known features. - Read tests -- each library reads the Excel-generated file; extracted values are compared to the expected manifest.
- Write tests -- each library writes a new file from the same spec; the output is verified by a trusted oracle (Excel via xlwings, or openpyxl in CI).
- Score -- pass rates map to the 0-3 fidelity scale per feature.
Full methodology: METHODOLOGY.md
- Treat each
results/directory as a dated snapshot. - Do not merge February fidelity claims and April perf claims into one undated headline.
- Cite the artifact date and workload whenever quoting a speedup number.
- Keep WolfXL-specific release claims aligned with the WolfXL repo's evidence page.
WolfXL documentation lives in the wolfxl repository.
# Install
uv sync
# Run the benchmark against pre-built fixtures (no Excel required)
uv run excelbench benchmark --tests fixtures/excel --output results
# Generate the heatmap
uv run excelbench heatmap
# Generate the combined fidelity + performance dashboard
uv run excelbench dashboard
# View results
open results/xlsx/README.md # macOS; use xdg-open on LinuxTo regenerate canonical fixtures from scratch (requires Excel installed):
uv run excelbench generate --output fixtures/excel| Tier | Features | Count |
|---|---|---|
| Tier 0 -- Core | Cell values, formulas, multiple sheets | 3 |
| Tier 1 -- Formatting | Text formatting, background colors, number formats, alignment, borders, dimensions | 6 |
| Tier 2 -- Advanced | Merged cells, conditional formatting, data validation, hyperlinks, images, comments, freeze panes, pivot tables | 8 |
| Tier 3 -- Workbook metadata | Named ranges, tables | 2 |
Pivot tables are tested but score N/A across all adapters in the current macOS run. Library green-feature scores therefore use an /18 denominator in the fresh release snapshot.
Charts, print settings, protection.
- XLSX results -- per-library, per-test-case breakdowns with tier list
- Release snapshot results -- fresh wheel-backed WolfXL 2.0 rerun
- XLS results -- legacy format results
- Performance results -- throughput benchmarks (cells/s)
- Release snapshot perf -- matching wheel-backed perf snapshot
- Dashboard -- combined fidelity + performance comparison
- Release snapshot dashboard -- combined view for the fresh rerun
- Heatmap (PNG) | SVG -- visual score matrix
v0.1.0 -- actively maintained benchmarking harness with dated fidelity and performance snapshots, reproducible methodology, and multi-adapter coverage across Python and Rust-backed spreadsheet libraries.
See CONTRIBUTING.md for setup instructions, how to add features, and how to add library adapters.
MIT
