Skip to main content

formulon

PyPI npm License Python Docs

Recalculate Excel workbooks and formulas from Python, with results checked against real Excel 365. No Excel install, no Windows, no COM automation: the wheel is pure Python around the engine compiled to WebAssembly, so one py3-none-any wheel runs anywhere wasmtime does.

Known differences from Excel are listed case by case in tests/divergence.yaml, each with a reason and the Excel build it was last verified on.

📖 Documentation  ·  Python guide  ·  API  ·  Batch recalculation

What's inside

  • Formula engine — 526 Excel function names, 511 implemented locally; dynamic arrays, LET / LAMBDA, and REGEX*. Coverage
  • Workbook I/O — read, recalculate and write .xlsx and .xlsb, including styles, conditional formatting, tables, pivot tables and print layout. File formats
  • Workbook editing — cells, sheets, rows and columns, styles, merges, comments, validations, pivot tables, print settings and furigana, through a typed Workbook API. API
  • Locale profiles — 28 Excel behavior profiles across fourteen locales on Mac and Windows hosts. Locale profiles
  • Excel oracle — formula results are compared bit for bit against goldens captured from Mac Excel 365 in fourteen locales. Oracle testing

Installation

pip install formulon   # Python 3.9+

wasmtime is the only runtime dependency; pip picks its platform build. Recalculation is serial in this package, with results identical to the threaded surfaces.

Quick start

import formulon

print(formulon.eval_formula("=SUM(1,2,3)").to_python())  # 6.0

v = formulon.eval_formula("=1/0")
print(v.kind.name, v.error_code)  # ERROR 1

Excel errors come back as values; FormulonError is raised only for host-side failures. See Errors.

Recalculate a workbook

from formulon import Workbook

with open("input.xlsx", "rb") as f:
    data = f.read()

with Workbook.load(data) as wb:
    wb.set_number(0, 0, 0, 42.0)  # Sheet1!A1
    wb.set_formula(0, 1, 0, "=A1*2")  # Sheet1!A2
    wb.recalc()
    print(wb.get_value(0, 1, 0).to_python())  # 84.0

    with open("output.xlsx", "wb") as f:
        f.write(wb.save())

Switching locale profiles

New workbooks use win-365-en_US. Formulas are always written with English function names and the stored separators; the profile decides how text is parsed and how results are rendered. Switch it per workbook and recalculate:

with formulon.Workbook.create_default() as wb:
    wb.set_formula(0, 0, 0, '=LENB("日本")')
    wb.set_formula(0, 1, 0, '=VALUE("1,5")')
    wb.set_formula(0, 2, 0, "=ISEVEN(2)")

    for profile in ("mac-365-en_US", "mac-365-ja_JP", "mac-365-de_DE"):
        wb.set_excel_profile_id(profile)
        wb.recalc()
        print(profile, [wb.get_display_text(0, row, 0)[0] for row in range(3)])
# mac-365-en_US ['2', '#VALUE!', 'TRUE']
# mac-365-ja_JP ['4', '#VALUE!', 'TRUE']
# mac-365-de_DE ['2', '1,5', 'WAHR']

The ids are {mac,win}-365-{ja_JP,en_US,de_DE,fr_FR,zh_CN,ko_KR,th_TH,es_ES,es_MX,pt_BR,ru_RU,zh_TW,it_IT,nl_NL}. Every mac-* profile and win-365-ja_JP is measured against Excel; the other win-* profiles are estimated from the Mac measurements. On a mac-* profile, text comparison, sorting, lookups and grouping follow that locale's measured Mac Excel collation; win-* profiles add the Windows word-sort rules measured on Windows Excel 365 ja-JP to that locale's collation. The profile is not saved into the file, so store the id your application targets and apply it again after loading.

For a new workbook that matches what Excel creates in a locale, use Workbook.create_for_profile(id) instead of create_default: it selects the profile and also sets the body and phonetic fonts, the localized Normal style and first sheet names, and the page margins Excel uses there.

Non-goals

VBA execution, legacy .xls, chart rendering, Power Query / DAX, pivot cache refresh from source data, live external connections, and a spreadsheet UI are permanently out of scope. See Non-goals.

License

Apache License 2.0. See also NOTICE.

Metadata

Release files for formulon 0.15.2

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

Built distribution (wheel)

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

Release files / formulon-0.15.2-py3-none-any.whl

Download URL formulon-0.15.2-py3-none-any.whl
Size 1.4 MB
Tags Python 3
SHA-256 checksum
How to use checksums
06e72dfe6e4b08ab379719baa0314340566b7f47845516c96645e654e68f0d0c
BLAKE2b-256 checksum
How to use checksums
d01a423282439974ef7e169aef44c595370651dc7212021d3023e14b40c7790b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 Oct 13, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.15.2 This release

1 release file

0.15.1

1 release file

0.15.0

1 release file

0.14.0

1 release file

0.13.0

1 release file

0.12.0

1 release file

0.11.1

1 release file

0.11.0

1 release file

0.10.0

1 release file

0.9.7

1 release file

0.9.6

1 release file

0.9.5

1 release file

0.9.4

1 release file

0.9.3

1 release file

0.9.2

1 release file

0.9.1

1 release file

0.9.0

1 release file

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