The original motivation was server-side formula evaluation in Python. openpyxl reads and writes xlsx well but evaluates nothing - formula cells return None unless Excel cached values on last save. xlcalc actually evaluates but covers around 50 functions. If you needed XLOOKUP, SUMIFS with multiple criteria, IRR, XIRR, or dynamic arrays like FILTER and UNIQUE, you were either installing Excel on a Linux box or accepting the gaps.
There's a one-liner for the common case:
import formualizer as fz
fz.recalculate_file("model.xlsx", output="recalculated.xlsx")
Or drive it programmatically — load a workbook, change inputs, evaluate: wb = fz.load_workbook("model.xlsx")
wb.set_value("Assumptions", 3, 2, 0.08)
wb.evaluate_all()
print(wb.evaluate_cell("Summary", 5, 3)) # =IRR(...)
You can also register Python callbacks as first-class formula functions that participate in the dependency graph.The Rust and WASM targets are also fully supported - the engine is the core with Python, WASM, and a stable CFFI as targets.
Formal benchmarks are in progress!
ManfredMacx•1h ago
Arrow-backed storage: cell data lives in Apache Arrow arrays, organized as stripes (blocks of rows x columns). Range operations like SUMIFS, VLOOKUP, and XLOOKUP receive typed numeric slices (&[f64]) directly rather than iterating cell-by-cell. This is what makes criteria aggregates over large ranges fast rather than a loop over boxed values.
Incremental dependency graph: every formula registers its precedents at parse time. On edit, we propagate a dirty set via reverse edges and only re-evaluate the affected subgraph. For a model with many formulas, a single-cell edit typically touches a small fraction of them. Formal benchmarks are in progress across linear chains, fan-out/fan-in, SUMIFS-heavy, and spill-heavy workload shapes.