Skip to content

Five production workbook recipes

These recipes start with a copy of a workbook you control. Keep the original immutable, write each result to a new path, and review the compatibility matrix and known limitations before a production rollout.

1. Preserve a macro-enabled template while changing cells

Use modify mode when the requested change is narrow and unrelated workbook parts must survive.

from pathlib import Path
from zipfile import ZipFile

from wolfxl import load_workbook

source = Path("template.xlsm")
output = Path("template-updated.xlsm")

with ZipFile(source) as archive:
    original_vba = archive.read("xl/vbaProject.bin")

workbook = load_workbook(source, modify=True, keep_vba=True, keep_links=True)
workbook["Inputs"]["B4"] = 42
workbook.save(output)
workbook.close()

with ZipFile(output) as archive:
    assert archive.read("xl/vbaProject.bin") == original_vba

assert source.read_bytes() != b""
assert output.read_bytes() != source.read_bytes()

This checks the requested output exists and the VBA project bytes remain identical. Add checks for every drawing, control, link, or package part that forms part of your workbook contract.

Do not use this recipe to author or execute VBA.

2. Modify a large workbook without rebuilding the source file

Keep the source immutable and time only the operation your service performs.

from pathlib import Path
from time import perf_counter

from wolfxl import load_workbook

source = Path("large-report.xlsx")
output = Path("large-report-updated.xlsx")
source_digest = source.read_bytes()

started = perf_counter()
workbook = load_workbook(source, modify=True)
workbook["Status"]["B2"] = "Approved"
workbook.save(output)
workbook.close()
elapsed_seconds = perf_counter() - started

assert source.read_bytes() == source_digest
reloaded = load_workbook(output)
assert reloaded["Status"]["B2"].value == "Approved"
reloaded.close()
print({"elapsed_seconds": elapsed_seconds, "output_bytes": output.stat().st_size})

Record the workbook digest, Python and WolfXL versions, operating system, hardware, cold or warm state, and raw timing output before using the result in a capacity claim.

3. Verify formulas, charts, and pivots after saving

Formula text, drawing parts, and pivot parts are separate package concerns. Check each one explicitly.

from pathlib import Path
from zipfile import ZipFile

from openpyxl import load_workbook as openpyxl_load_workbook
from wolfxl import load_workbook

source = Path("dashboard.xlsx")
output = Path("dashboard-updated.xlsx")

workbook = load_workbook(source, modify=True)
workbook["Inputs"]["B2"] = 120_000
values = workbook.calculate()
assert "Summary!B12" in values
workbook.save(output)
workbook.close()

cross_read = openpyxl_load_workbook(output, data_only=False, read_only=False)
assert cross_read["Summary"]["B12"].value.startswith("=")
assert len(cross_read["Summary"]._charts) > 0  # openpyxl exposes loaded charts here
cross_read.close()

with ZipFile(output) as archive:
    names = set(archive.namelist())
    assert any(name.startswith("xl/charts/chart") for name in names)
    assert any(name.startswith("xl/pivotTables/pivotTable") for name in names)
    assert any(name.startswith("xl/pivotCache/") for name in names)

Replace the broad presence checks with exact expected part names and values for your workbook. A present chart or pivot part does not prove visual parity.

4. Benchmark one real openpyxl pipeline

Measure equivalent code paths and validate the same observable result before comparing elapsed time.

from pathlib import Path
from statistics import median
from tempfile import TemporaryDirectory
from time import perf_counter

import openpyxl
import wolfxl

SOURCE = Path("representative.xlsx")


def run(engine, output: Path) -> float:
    started = perf_counter()
    workbook = engine.load_workbook(SOURCE)
    total = sum(
        value or 0
        for row in workbook["Data"].iter_rows(min_col=4, max_col=4, values_only=True)
        for value in row
        if isinstance(value, (int, float))
    )
    workbook.close()
    output.write_text(str(total), encoding="utf-8")
    return perf_counter() - started


with TemporaryDirectory() as directory:
    root = Path(directory)
    wolfxl_times = [run(wolfxl, root / f"wolfxl-{index}.txt") for index in range(7)]
    openpyxl_times = [run(openpyxl, root / f"openpyxl-{index}.txt") for index in range(7)]

    assert (root / "wolfxl-0.txt").read_text() == (root / "openpyxl-0.txt").read_text()
    print({
        "wolfxl_median_seconds": median(wolfxl_times),
        "openpyxl_median_seconds": median(openpyxl_times),
    })

Run this in a clean environment and record exact package versions, source digest, hardware, cache policy, iteration count, and raw samples. The order above can favor the second engine through warmed file caches; alternate or isolate engine runs when that matters.

5. Migrate one load_workbook workflow with a rollback path

Keep the import decision behind one application-owned module so the old path remains available during qualification.

# excel_engine.py
import os

if os.environ.get("USE_WOLFXL") == "1":
    from wolfxl import load_workbook
else:
    from openpyxl import load_workbook
# report_job.py
from pathlib import Path

from excel_engine import load_workbook


def update_report(source: Path, output: Path) -> None:
    workbook = load_workbook(source)
    workbook["Summary"]["B2"] = "Ready"
    workbook.save(output)
    workbook.close()

Run the same representative fixture twice, once with USE_WOLFXL=0 and once with USE_WOLFXL=1. Compare the intended values and every package part that must remain stable. Promote the WolfXL path only after the accepted outputs match. Keep the environment flag through the observation window, then remove the openpyxl branch when rollback is no longer required.

For an existing template that needs package-preserving edits, use WolfXL modify=True in the WolfXL branch and define the expected difference from openpyxl's rebuild behavior rather than requiring byte-identical engine outputs.