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 compare text case-insensitively by bytes, because Windows ordering is not measured. The profile is not saved into the file, so store the id your application targets and apply it again after loading.

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.14.0

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.14.0
File Interpreter ABI Platform
formulon-0.14.0-py3-none-any.whl Python 3 none any Details

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

Download URL formulon-0.14.0-py3-none-any.whl
Size 1.4 MB
Tags Python 3
SHA-256 checksum
How to use checksums
b2c790f998989467ee7c36d02999a0426a59d52a44cfb7f166ce72be1e86c872
BLAKE2b-256 checksum
How to use checksums
3bcd4745d3505564c5ee016e31ca53edb87b8c0788ca7e58a028b7718d0ea0e0
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 11, 2026.

Transparency log

Release history Release notifications | RSS feed

0.15.2

1 release file

0.15.1

1 release file

0.15.0

1 release file

This release

0.14.0 This release

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