Skip to content

I Tried Server-Side Excel Formula Evaluation in Python: Here's What Actually Works

I spent three days trying to evaluate an Excel formula in Python on a Linux server. Three days. The formula was simple - =PMT(A2/12, A3, -A1) for a loan payment calculation. What I learned is that the Python ecosystem has a gaping hole when it comes to server-side Excel formula evaluation.

Let me save you those three days.

The Problem That Breaks Most Projects

You’re building a Python backend. Maybe it’s a REST API that needs to calculate loan payments. Maybe it’s a data pipeline that processes Excel files uploaded by users. Maybe it’s a financial reporting service.

It doesn’t matter. The scenario is always the same:

User uploads Excel file with formulas
|
v
Your Python backend reads the file
|
v
You need the CALCULATED values
|
v
Everything breaks

I tried the obvious approaches first.

Approach 1: openpyxl - The False Hope

openpyxl is the standard for reading Excel files in Python. It’s mature, well-documented, and everyone uses it. I installed it, loaded my workbook, and grabbed the cell value:

from openpyxl import load_workbook
wb = load_workbook('loan_calc.xlsx')
ws = wb['Sheet1']
print(ws['B10'].value) # I expected: 299.71
# I got: =PMT(A2/12, A3, -A1)

That’s a string. Not the calculated value - just the formula text. openpyxl can read and write Excel files, but it has no formula evaluation engine. It reads what’s in the file, and if Excel hasn’t calculated the value and saved it, you’re stuck.

I could open the file in Excel first and save it - but this is a server. There’s no Excel on this server.

Approach 2: pandas - The Wrong Tool Altogether

Maybe I thought, pandas reads Excel files all the time:

import pandas as pd
df = pd.read_excel('loan_calc.xlsx')
print(df.iloc[9, 1]) # Returns cached value or NaN

This “works” only if Excel has previously calculated and saved the values. If you’re generating files programmatically or processing data from external sources, there’s no cached value. pandas also doesn’t implement Excel’s calculation logic - df.sum() is not the same as Excel SUM(). Different error handling, different blank handling, different type coercion.

Approach 3: xlwings - The Platform Trap

xlwings is brilliant for desktop automation. It connects Python to Excel and can evaluate formulas:

import xlwings as xw
wb = xw.Book('loan_calc.xlsx')
result = wb.sheets[0].range('B10').value # Works!

The problem? xlwings requires Excel to be installed. On my Linux server? No Excel. In my Docker container? No Excel. On AWS Lambda? No Excel.

xlwings works on: Windows, macOS (with Excel)
xlwings fails on: Linux, Docker, Cloud Functions, CI/CD pipelines

Every server environment I’ve worked with runs Linux. xlwings was never an option.

The Solution: Formualizer

I found Formualizer while searching for “Python Excel calculation engine without Excel.” It’s a Rust-powered spreadsheet engine with Python bindings that evaluates Excel formulas without requiring Excel installation.

Here’s what makes it different:

FeatureopenpyxlpandasxlwingsFormualizer
Read XLSXYesYesYesYes
Write XLSXYesYesYesYes
Evaluate FormulasNoNoYes*Yes
Linux SupportYesYesNoYes
Docker ReadyYesYesNoYes
Excel RequiredNoNoYesNo
FunctionsN/AN/AExcel’s320+

*xlwings requires Excel installed on Windows/macOS only

The key advantage: Formularizer is pure Python with a Rust engine under the hood. It works anywhere Python runs, and it’s MIT/Apache-2.0 licensed for commercial use.

My First Working Example

I installed it and ran the same loan calculation:

Terminal window
pip install formualizer
import formualizer as fz
# Create workbook
wb = fz.Workbook()
s = wb.sheet("LoanCalc")
# Set input values
s.set_value(1, 1, fz.LiteralValue.number(10000.0)) # A1: Principal
s.set_value(2, 1, fz.LiteralValue.number(0.05)) # A2: Annual rate (5%)
s.set_value(3, 1, fz.LiteralValue.number(36.0)) # A3: Months
# Set formula: PMT(rate/12, periods, -principal)
s.set_formula(1, 2, "=PMT(A2/12, A3, -A1)")
# Evaluate
result = wb.evaluate_cell("LoanCalc", 1, 2)
print(f"Monthly payment: ${result:.2f}")
# Output: Monthly payment: $299.71

That $299.71 matches what Excel returns. On my Linux server. Without Excel installed.

Why This Matters

Here’s where it clicked for me. I was building a loan comparison API:

User: "I need to compare loan options"
|
v
My API: Receives principal, rate, months for 3 different lenders
|
v
Formualizer: Calculates PMT for each, computes total interest
|
v
API returns: Sorted list of best options with monthly payments

This works in:

  • Docker containers
  • AWS Lambda
  • Google Cloud Functions
  • Kubernetes pods
  • Any Linux environment

No COM automation. No Windows server. No licensing headaches.

Real-World Patterns I’ve Used

REST API with FastAPI

from fastapi import FastAPI
from pydantic import BaseModel
import formualizer as fz
app = FastAPI()
class LoanRequest(BaseModel):
principal: float
annual_rate: float
months: int
@app.post("/calculate-loan")
async def calculate_loan(request: LoanRequest):
wb = fz.Workbook()
s = wb.sheet("Calc")
s.set_value(1, 1, fz.LiteralValue.number(request.principal))
s.set_value(2, 1, fz.LiteralValue.number(request.annual_rate))
s.set_value(3, 1, fz.LiteralValue.number(request.months))
s.set_formula(1, 2, "=PMT(A2/12, A3, -A1)")
monthly_payment = wb.evaluate_cell("Calc", 1, 2)
return {"monthly_payment": round(monthly_payment, 2)}

Background Task with Celery

Financial calculations often take time. Offload to a Celery worker:

from celery import Celery
import formualizer as fz
app = Celery('tasks', broker='redis://localhost:6379/0')
@app.task
def generate_report(data: dict) -> dict:
wb = fz.Workbook()
s = wb.sheet("Report")
s.set_value(1, 1, fz.LiteralValue.number(data['revenue']))
s.set_value(2, 1, fz.LiteralValue.number(data['costs']))
s.set_value(3, 1, fz.LiteralValue.number(data['tax_rate']))
s.set_formula(1, 2, "=A1-A2") # Gross profit
s.set_formula(2, 2, "=(A1-A2)/A1") # Margin
s.set_formula(3, 2, "=B1*(1-A3)") # Net profit
return {
"gross_profit": wb.evaluate_cell("Report", 1, 2),
"margin": wb.evaluate_cell("Report", 2, 2),
"net_profit": wb.evaluate_cell("Report", 3, 2),
}

Batch Processing

For large datasets, use batch operations:

# Slower: individual operations
for i in range(1000):
s.set_value(i, 1, fz.LiteralValue.number(i * 1.0))
# Faster: batch operation
data = [[fz.LiteralValue.number(i * 1.0)] for i in range(1000)]
s.set_values_batch(1, 1, data)

What I Wish I Knew Earlier

Function Coverage

Formualizer supports 320+ Excel functions. The ones I’ve used most:

  • Financial: PMT, PV, FV, NPV, IRR, RATE, NPER
  • Math: SUM, AVERAGE, ROUND, CEILING, FLOOR
  • Logical: IF, AND, OR, IFERROR, IFS
  • Text: CONCATENATE, LEFT, RIGHT, MID, TRIM

If you need a specific function, check the GitHub repo - coverage is solid for typical financial/logical use cases.

Error Handling

Excel errors propagate as values:

s.set_value(1, 1, fz.LiteralValue.number(100.0))
s.set_value(2, 1, fz.LiteralValue.number(0.0))
s.set_formula(1, 2, "=A1/A2") # Returns #DIV/0! error
# Use IFERROR for safe fallbacks
s.set_formula(2, 2, "=IFERROR(A1/A2, 0)")

Docker Deployment

This is the game-changer:

FROM python:3.11-slim
RUN pip install formualizer fastapi uvicorn
COPY app.py .
CMD ["uvicorn", "app:app", "--host", "0.0.0.0"]

No Excel. No external dependencies. Just Python.

When NOT to Use Formualizer

Be honest about your use case:

  • Reading existing Excel files: openpyxl is fine (just read values)
  • Data analysis: pandas is your tool
  • Windows desktop automation: xlwings works beautifully
  • Need 100% Excel compatibility: No pure-Python solution is perfect; consider Microsoft Graph API if you need Excel online

The Bottom Line

The Python ecosystem lacks a good answer for server-side Excel formula evaluation. For years, the only real options were:

  1. Install Excel on Windows servers (expensive, fragile)
  2. Use xlwings locally only (not server-compatible)
  3. Pre-calculate in Excel (no dynamic calculations)

Formularizer fills this gap. It’s not perfect - function coverage is ~320 vs Excel’s 500+, and some edge cases differ. But for typical financial calculations, reporting, and data processing, it works.

I now use Formularizer in every Python project that needs Excel-compatible calculations. No more “open in Excel first” workarounds. No more Windows-only servers. Just calculations that work.

Final Words + More Resources

My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me

Here are also the most important links from this article along with some further resources that will help you in this scope:

Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!

Comments