Skip to main content

Embeddable spreadsheet engine — parse, evaluate & mutate Excel workbooks at native speed

Project description

Formualizer for Python

Arrow Powered PyPI License: MIT/Apache-2.0 Documentation

Formualizer banner


Parse, evaluate, and mutate Excel workbooks at native speed from Python.

A Rust-powered spreadsheet engine with 320+ Excel-compatible functions, exposed through a clean Pythonic API. Tokenize formulas, walk ASTs, evaluate workbooks, and use SheetPort to treat spreadsheets as typed APIs.

Installation

pip install formualizer

Prebuilt wheels are available for Python 3.10-3.13 on Linux, macOS, and Windows. No Rust toolchain required.

Documentation

Full documentation at formualizer.dev:

Quick start

Evaluate a workbook

import formualizer as fz

wb = fz.Workbook()
s = wb.sheet("Sheet1")

s.set_value(1, 1, fz.LiteralValue.number(1000.0))   # A1: principal
s.set_value(2, 1, fz.LiteralValue.number(0.05))      # A2: annual rate
s.set_value(3, 1, fz.LiteralValue.number(12.0))       # A3: periods

s.set_formula(1, 2, "=PMT(A2/12, A3, -A1)")
print(wb.evaluate_cell("Sheet1", 1, 2))  # ~85.61

Load an XLSX and evaluate

import formualizer as fz

wb = fz.load_workbook("financial_model.xlsx", strategy="eager_all")
print(wb.evaluate_cell("Summary", 1, 2))

Recalculate XLSX cached values (writeback)

import formualizer as fz

# in-place
summary = fz.recalculate_file("financial_model.xlsx")
print(summary["status"], summary["evaluated"], summary["errors"])

# write to a new file
summary = fz.recalculate_file("financial_model.xlsx", output="financial_model.recalc.xlsx")

Formula text is preserved. Cached-value typing follows the active umya-spreadsheet implementation.

Parse and analyze formulas

from formualizer import parse
from formualizer.visitor import collect_references, collect_function_names

ast = parse("=SUMIFS(Revenue,Region,A1,Year,B1)")
print(ast.pretty())                          # indented AST tree
print(ast.to_formula())                      # canonical Excel string
print(collect_references(ast))               # [Revenue, Region, A1, Year, B1]
print(collect_function_names(ast))           # ['SUMIFS']

Key features

Capability Description
Tokenization Break formulas into structured Token objects with byte spans and operator metadata
Parsing Produce a rich AST with reference normalization, source tracking, and 64-bit structural fingerprints
320+ built-in functions Math, text, lookup (XLOOKUP, VLOOKUP), date/time, financial, statistics, database, engineering
Workbook evaluation Set values and formulas, evaluate cells/ranges, load XLSX/CSV/JSON
XLSX cache writeback recalculate_file(path, output=None) recalculates formulas and writes cached values back
Batch operations set_values_batch / set_formulas_batch for efficient bulk updates
Undo / redo Optional changelog with automatic action grouping — single edits are individually undoable
Evaluation planning Inspect the dependency graph and evaluation schedule before computing
SheetPort Treat spreadsheets as typed functions with YAML manifests, schema validation, and batch scenarios
Deterministic mode Inject clock, timezone, and RNG seed for reproducible evaluation
Visitor utilities walk_ast, collect_references, collect_function_names for ergonomic tree traversal
Rich errors Typed TokenizerError / ParserError / ExcelEvaluationError with position info

Workbook evaluation

import formualizer as fz

wb = fz.Workbook()
s = wb.sheet("Data")

# Set values and formulas
s.set_value(1, 1, fz.LiteralValue.number(100.0))
s.set_value(2, 1, fz.LiteralValue.number(200.0))
s.set_value(3, 1, fz.LiteralValue.number(300.0))
s.set_formula(4, 1, "=SUM(A1:A3)")
s.set_formula(4, 2, "=AVERAGE(A1:A3)")

print(wb.evaluate_cell("Data", 4, 1))  # 600.0
print(wb.evaluate_cell("Data", 4, 2))  # 200.0

Custom functions

Register workbook-local callbacks without forking Formualizer:

import formualizer as fz

wb = fz.Workbook(mode=fz.WorkbookMode.Ephemeral)
wb.add_sheet("Sheet1")

wb.register_function(
    "py_add",
    lambda a, b: a + b,
    min_args=2,
    max_args=2,
)

wb.set_formula("Sheet1", 1, 1, "=PY_ADD(20,22)")
print(wb.evaluate_cell("Sheet1", 1, 1))  # 42
print(wb.list_functions())
wb.unregister_function("py_add")

Key semantics:

  • Names are case-insensitive and stored canonically (py_add -> PY_ADD).
  • Custom functions are workbook-local and take precedence over global built-ins.
  • Built-in override is disabled by default; set allow_override_builtin=True to opt in.
  • Args are passed by value; range inputs arrive as nested Python lists.
  • Return Python primitives, datetime/date/time/timedelta, dict error objects, or nested lists for array spill output.
  • Python callback exceptions are sanitized and mapped to #VALUE!.

Runnable example: python bindings/python/examples/custom_function_registration.py

Batch operations

# Bulk-set values (auto-grouped as one undo step when changelog is enabled)
s.set_values_batch(1, 1, 3, 2, [
    [fz.LiteralValue.number(10.0), fz.LiteralValue.number(20.0)],
    [fz.LiteralValue.number(30.0), fz.LiteralValue.number(40.0)],
    [fz.LiteralValue.number(50.0), fz.LiteralValue.number(60.0)],
])

Undo / redo

The changelog is opt-in. Once enabled, every edit is tracked:

wb.set_changelog_enabled(True)

s.set_value(1, 1, fz.LiteralValue.number(10.0))
s.set_value(1, 1, fz.LiteralValue.number(20.0))
wb.undo()  # back to 10
wb.redo()  # back to 20

# Batch methods are auto-grouped as one undo step.
# For manual grouping of multiple calls:
wb.begin_action("update prices")
s.set_value(1, 1, fz.LiteralValue.number(100.0))
s.set_value(2, 1, fz.LiteralValue.number(200.0))
wb.end_action()
wb.undo()  # reverts both values at once

Evaluation planning

Inspect what the engine will compute before running:

plan = wb.get_eval_plan([("Sheet1", 1, 2)])
print(f"Vertices to evaluate: {plan.total_vertices_to_evaluate}")
print(f"Parallel layers: {plan.estimated_parallel_layers}")
for layer in plan.layers:
    print(f"  Layer: {layer.vertex_count} vertices, parallel={layer.parallel_eligible}")

SheetPort: spreadsheets as typed APIs

Define a YAML manifest to treat a spreadsheet as a typed function with validated inputs/outputs:

from formualizer import SheetPortSession, Workbook

manifest_yaml = """
spec: fio
spec_version: "0.3.0"
manifest:
  id: pricing-model
  name: Pricing Model
  workbook:
    uri: memory://pricing.xlsx
    locale: en-US
    date_system: 1900
ports:
  - id: base_price
    dir: in
    shape: scalar
    location: { a1: Inputs!A1 }
    schema: { type: number }
  - id: final_price
    dir: out
    shape: scalar
    location: { a1: Outputs!A1 }
    schema: { type: number }
"""

wb = Workbook()
wb.add_sheet("Inputs")
wb.add_sheet("Outputs")
wb.set_formula("Outputs", 1, 1, "=Inputs!A1*1.2")

session = SheetPortSession.from_manifest_yaml(manifest_yaml, wb)
session.write_inputs({"base_price": 100.0})
result = session.evaluate_once(freeze_volatile=True)
print(result["final_price"])  # 120.0

API reference

Top-level functions

tokenize(formula: str, dialect: FormulaDialect = None) -> Tokenizer
parse(formula: str, dialect: FormulaDialect = None) -> ASTNode
load_workbook(path: str, strategy: str = None) -> Workbook
recalculate_file(path: str, output: str | None = None) -> dict

Core classes

  • Workbook — create, load, evaluate, undo/redo. Supports from_path() and load_path() class methods.
  • Sheet — per-sheet facade for set_value, set_formula, get_cell, batch operations.
  • LiteralValue — typed values: .int(), .number(), .text(), .boolean(), .date(), .empty(), .error(), .array().
  • Tokenizer — iterable token sequence with .render() and .tokens.
  • ASTNode.pretty(), .to_formula(), .fingerprint(), .children(), .walk_refs().
  • CellRef / RangeRef / TableRef / NamedRangeRef — typed references.
  • SheetPortSession — bind manifests to workbooks, read/write typed ports, evaluate.
  • EvaluationConfig — tune parallel evaluation, warmup, range limits, date systems.

Visitor helpers (formualizer.visitor)

walk_ast(node, visitor_fn)              # DFS with VisitControl (CONTINUE/SKIP/STOP)
collect_references(node)                # -> list[ReferenceLike]
collect_function_names(node)            # -> list[str]
collect_nodes_by_type(node, "Function") # -> list[ASTNode]

Full type stubs are included in the package (.pyi files) for IDE autocompletion and mypy.


Building from source

Requires Rust >= 1.70 and maturin:

pip install maturin
cd bindings/python
maturin develop          # debug build
maturin develop --release  # optimized build

Testing

pip install formualizer[dev]
pytest bindings/python/tests
ruff check bindings/python
mypy bindings/python/formualizer

Workspace layout

formualizer/
  crates/                    # Rust core (parse, eval, workbook, sheetport)
  bindings/python/
    formualizer/             # Python package (helpers, visitor, type stubs)
    src/                     # PyO3 bridge (Rust -> Python)

The Python wheel links directly against the Rust crates — there is no runtime FFI overhead beyond the initial C-to-Rust boundary.

License

Dual-licensed under MIT or Apache-2.0, at your option.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

formualizer-0.4.3.tar.gz (931.4 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

formualizer-0.4.3-cp310-abi3-win_amd64.whl (5.5 MB view details)

Uploaded CPython 3.10+Windows x86-64

formualizer-0.4.3-cp310-abi3-musllinux_1_2_x86_64.whl (6.7 MB view details)

Uploaded CPython 3.10+musllinux: musl 1.2+ x86-64

formualizer-0.4.3-cp310-abi3-musllinux_1_2_aarch64.whl (6.5 MB view details)

Uploaded CPython 3.10+musllinux: musl 1.2+ ARM64

formualizer-0.4.3-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (6.6 MB view details)

Uploaded CPython 3.10+manylinux: glibc 2.17+ x86-64

formualizer-0.4.3-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (6.3 MB view details)

Uploaded CPython 3.10+manylinux: glibc 2.17+ ARM64

formualizer-0.4.3-cp310-abi3-macosx_11_0_arm64.whl (5.8 MB view details)

Uploaded CPython 3.10+macOS 11.0+ ARM64

formualizer-0.4.3-cp310-abi3-macosx_10_12_x86_64.whl (5.9 MB view details)

Uploaded CPython 3.10+macOS 10.12+ x86-64

File details

Details for the file formualizer-0.4.3.tar.gz.

File metadata

  • Download URL: formualizer-0.4.3.tar.gz
  • Upload date:
  • Size: 931.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.5 {"installer":{"name":"uv","version":"0.10.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for formualizer-0.4.3.tar.gz
Algorithm Hash digest
SHA256 6cc13df28b5fed468192f4bcdf3c6dcf3538a3ebc1e69fc6bdf6afee33dbad9d
MD5 9f16e7c83f29558541fb2f30a97f0ef1
BLAKE2b-256 4bba497f0927a313dc0a390130534b210d3590fadca6a4ccd7dae788bce73c8a

See more details on using hashes here.

File details

Details for the file formualizer-0.4.3-cp310-abi3-win_amd64.whl.

File metadata

  • Download URL: formualizer-0.4.3-cp310-abi3-win_amd64.whl
  • Upload date:
  • Size: 5.5 MB
  • Tags: CPython 3.10+, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.5 {"installer":{"name":"uv","version":"0.10.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for formualizer-0.4.3-cp310-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 0773547d8c4410e36d1113e8e03d1fed688b0f16b567737bee49256c795a0b5f
MD5 26ebfd89175af2dc3dcb9bff795e4743
BLAKE2b-256 a0d7788c23312ecfa0fe6174b74b5fe35258394d75409f1d1d5ae83782f31e3c

See more details on using hashes here.

File details

Details for the file formualizer-0.4.3-cp310-abi3-musllinux_1_2_x86_64.whl.

File metadata

  • Download URL: formualizer-0.4.3-cp310-abi3-musllinux_1_2_x86_64.whl
  • Upload date:
  • Size: 6.7 MB
  • Tags: CPython 3.10+, musllinux: musl 1.2+ x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.5 {"installer":{"name":"uv","version":"0.10.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for formualizer-0.4.3-cp310-abi3-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 8c6800ac2bb6495ea0a4bc0161d5aafeae39507a2e80d0362cd42331d96b71a8
MD5 39fc1e3aaeaed7f0bc47c7e88a97ac9d
BLAKE2b-256 74ec14bddfd1c6c7b3b34754d30e55ebb109af683afbc7ffcccbee4565b0db5b

See more details on using hashes here.

File details

Details for the file formualizer-0.4.3-cp310-abi3-musllinux_1_2_aarch64.whl.

File metadata

  • Download URL: formualizer-0.4.3-cp310-abi3-musllinux_1_2_aarch64.whl
  • Upload date:
  • Size: 6.5 MB
  • Tags: CPython 3.10+, musllinux: musl 1.2+ ARM64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.5 {"installer":{"name":"uv","version":"0.10.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for formualizer-0.4.3-cp310-abi3-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 3aa04dd4f252d0abcaa07a80ed84d61694c545c92559964276e881d30c6ec062
MD5 af76fd4fc9e87be773b2e2721dd5464e
BLAKE2b-256 659c6f8a302e1e2901415927c41f867b44f56abc7013b9ce7012be8d6543a323

See more details on using hashes here.

File details

Details for the file formualizer-0.4.3-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

  • Download URL: formualizer-0.4.3-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
  • Upload date:
  • Size: 6.6 MB
  • Tags: CPython 3.10+, manylinux: glibc 2.17+ x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.5 {"installer":{"name":"uv","version":"0.10.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for formualizer-0.4.3-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 c30b555154a0b4902eee5e725bb165251a870a80dc2e1348cea6e9aa32bcb51a
MD5 52c1480cb6d3e943906d4bd13ff82103
BLAKE2b-256 17073b450bbb65def003790ea66bb1fb0ed584bc4dd552e90d210fb85bb7a10f

See more details on using hashes here.

File details

Details for the file formualizer-0.4.3-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

  • Download URL: formualizer-0.4.3-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
  • Upload date:
  • Size: 6.3 MB
  • Tags: CPython 3.10+, manylinux: glibc 2.17+ ARM64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.5 {"installer":{"name":"uv","version":"0.10.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for formualizer-0.4.3-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 2cf24a4069b0c111d82a9ed540207ac05fe1166b890980d2634092b5844a9bc7
MD5 201dcbba62a8edb6e57e2f823b514617
BLAKE2b-256 7cd73947e37766c39321b1f76b5a1129b304ae3b35378130d06b8b641a56bf93

See more details on using hashes here.

File details

Details for the file formualizer-0.4.3-cp310-abi3-macosx_11_0_arm64.whl.

File metadata

  • Download URL: formualizer-0.4.3-cp310-abi3-macosx_11_0_arm64.whl
  • Upload date:
  • Size: 5.8 MB
  • Tags: CPython 3.10+, macOS 11.0+ ARM64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.5 {"installer":{"name":"uv","version":"0.10.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for formualizer-0.4.3-cp310-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 8a31b09fcd5df20d312c98112296a5cbc1f26018b17b14e1576eaadffbbfdf36
MD5 46f4f9e76b4691ea1e5c6b12fa4c54b1
BLAKE2b-256 e28026782bf83d16020b87afe86581fc3486e24ddc66ae1b6afa83bf0ddb6872

See more details on using hashes here.

File details

Details for the file formualizer-0.4.3-cp310-abi3-macosx_10_12_x86_64.whl.

File metadata

  • Download URL: formualizer-0.4.3-cp310-abi3-macosx_10_12_x86_64.whl
  • Upload date:
  • Size: 5.9 MB
  • Tags: CPython 3.10+, macOS 10.12+ x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.5 {"installer":{"name":"uv","version":"0.10.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for formualizer-0.4.3-cp310-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 503a2e64ee007d1bd1672ab6d271872b04f298b1f4d8a68fe7172cef38d9be8b
MD5 fd6c3b0629c456cd4110d8ca58c91634
BLAKE2b-256 e4b63e76574f61b69565af9a635ab6e67c3ddafdd01cd012998829225b2fe034

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page