Skip to main content

xlrecalc

xlrecalc recalculates Excel workbooks in pure Python. It evaluates a workbook's formulas with the results Excel computes and writes them back into the file as the cached values Excel stores, so that openpyxl's data-only mode, pandas and other readers see values where a workbook written by a program has only formulas. Results are tested against values captured from Excel 16 for Mac.

Documentation: https://xlrecalc.readthedocs.io.

pip install xlrecalc

Python 3.11 or later. The one dependency is xlformat, which applies Excel's number formats for TEXT.

Recalculating a file

openpyxl writes formulas without their values, so a reader of the file finds nothing in those cells. recalculate computes them and writes the values into the file:

>>> import pathlib, tempfile, openpyxl, xlrecalc
>>> path = pathlib.Path(tempfile.mkdtemp()) / "model.xlsx"
>>> wb = openpyxl.Workbook()
>>> ws = wb.active
>>> ws.append(["Units", "Price", "Revenue"])
>>> ws.append([120, 9.5, "=A2*B2"])
>>> ws.append([80, 12.25, "=A3*B3"])
>>> ws["C4"] = "=SUM(C2:C3)"
>>> wb.save(path)
>>> print(openpyxl.load_workbook(path, data_only=True).active["C4"].value)
None
>>> report = xlrecalc.recalculate(path)  # in place; or recalculate(source, destination)
>>> openpyxl.load_workbook(path, data_only=True).active["C4"].value
2120
>>> report.uncomputed  # cells it could not compute, left as they were
set()

Only the cached values change: every other part of the file is copied as it was, byte for byte. By default the file also asks Excel to recalculate when it opens it, so a value xlrecalc got wrong never persists in what Excel shows (full_calc_on_load=False leaves the file's setting alone).

Working with a workbook

load reads a workbook into memory. Reading a value computes what it needs; changing a cell makes its dependents stale; save writes the changed cells and the new values.

>>> book = xlrecalc.load(path)
>>> book.value("Sheet!C4")
2120.0
>>> book.set("B2", 10)  # a constant
>>> book.value("C4")
2180.0
>>> book.set_formula("D4", '=TEXT(C4,"#,##0.00")')
>>> book.value("D4")
'2,180.00'
>>> book.values("C2:C4")
[[1200.0], [980.0], [2180.0]]
>>> book.save(path.with_name("scenario.xlsx"))

set always stores a constant, unlike openpyxl, where assigning "=A1" makes a formula: book.set("A2", "=A1") stores the text =A1. Use set_formula for formulas. Numbers come back as floats, as Excel holds them; errors as xlrecalc.ErrorValue, which is not a string, so the error #N/A and the text "#N/A" stay apart.

What it computes, and what not yet

  • Functions: 156 of Excel's functions (8 of them partly), the most used ones first: math, statistics, logic, text, dates, lookup (VLOOKUP, INDEX, MATCH, OFFSET, INDIRECT...), the financial and bond functions, the database functions. The coverage matrix lists every Excel function, whether it is computed, and the captured evidence for it.
  • Evidence: 12,731 formulas computed by Excel and compared with xlrecalc's results: 12,608 match, bit for bit or within a small tolerance declared per function (a few units in the last place, or a relative 1E-9 for the iterative functions), 121 known deviations, each listed with its reason in QUIRKS.md, and 2 not evaluated (they call XLOOKUP, not implemented yet). The largest group of deviations is the iterative functions: from some starting guesses Excel's IRR and RATE reach another root than xlrecalc, or a rate where xlrecalc gives #NUM!, and XIRR stops about 1E-8 from the root; 73 of the 271 captured rows of IRR, XIRR and RATE differ that way.
  • Excel's behavior: coercion between kinds, error values, the 15-digit rules, the 1900 leap-year bug and the 1904 date system, arrays, dynamic arrays and spill, implicit intersection, circular references (left uncalculated, as Excel does with iteration off). Four quirks can be turned off (Quirks).
  • Not yet: iterative calculation of circular references; the array-making functions (SEQUENCE, FILTER, SORT, UNIQUE, LAMBDA and its helpers) and XLOOKUP; structured (table) references and 3-D references; CELL's formatting kinds; computed criteria in the database functions; LINEST with several regressors; inserting or deleting rows and columns. A formula xlrecalc cannot compute keeps the value the file holds, and the report lists it.

Speed and memory

On a workbook of 1,000,000 rows and 3,000,003 formulas written by openpyxl (so no formula has a cached value), recalculate reads the file, computes every formula and writes the values back in 50.6 s, with a peak memory of 1,163 MB. Changing the first cell of a dependency chain a million cells long and computing again takes 5.1 s. Measured on an Apple M4 Pro with 24 GB, CPython 3.11.18. Formulas of the same relative shape share one compiled function, and dependents come from their geometry rather than per-cell links, so most of the memory holds the cells' values.

To reproduce, in a clone of the repository:

cd bench && uv run python gen.py 1000000 && cd ..   # the workbook (openpyxl)
uv run python bench/recalc_bench.py 1000000         # read, compute, write back
uv run python bench/engine_bench.py 1000000 --xlsx  # compute, then change A1

Part of sheetmill

xlrecalc is part of the sheetmill project, with xlformat, which applies Excel number formats, and sheetpeek, which shows workbooks as Excel does.

Development

uv sync --group docs then uv run pytest; CONTRIBUTING.md has the pip route, the full set of checks and the commit conventions. ARCHITECTURE.md describes the design and the measurements behind it, CAPTURING.md how results are captured from Excel, bench/ reruns the measurements.

Most of the code is written with Claude Code, reviewed before each commit and tested against results captured from Excel; see CONTRIBUTING.md.

License

MIT.

Metadata

Release files for xlrecalc 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for xlrecalc 0.1.0
File Size Uploaded Provenance Actions
xlrecalc-0.1.0.tar.gz 417.3 kB With provenance Details for xlrecalc-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for xlrecalc 0.1.0
File Interpreter ABI Platform Actions
xlrecalc-0.1.0-py3-none-any.whl Python 3 none any Details for xlrecalc-0.1.0-py3-none-any.whl

Total release size: 553.5 kB

Release files / xlrecalc-0.1.0.tar.gz

Download URL xlrecalc-0.1.0.tar.gz
Size 417.3 kB
Tags Source
SHA-256 checksum
How to use checksums
304a90cd8e5b0e7707ddfeb1e6d2a19a842fb380b60b74b61d15c65b50c1a014
BLAKE2b-256 checksum
How to use checksums
e6c9de03790973fdc1af4329aa4c41ef1b71b7b8a2b247a05c2b2daf0196c90f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 3, 2026.

Transparency log

Release files / xlrecalc-0.1.0-py3-none-any.whl

Download URL xlrecalc-0.1.0-py3-none-any.whl
Size 136.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
81a8b7398ca92c2848bc94cfccbb4187af17a04723a31d954680a1de03687980
BLAKE2b-256 checksum
How to use checksums
e8f46f629e01eca2033bb7d72a372c3e1b0df0b8ddeb553f0836e667a2846cb2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 3, 2026.

Transparency log

Security for xlrecalc 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for xlrecalc-0.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 3, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page