Python で一括再計算
スケジュールジョブ、ノートブック、データパイプラインの一部としてスプレッドシート再計算を組み込むパターンです。ブラウザで動くエンジンと同じものを、ホスト言語だけ Python に置き換えて動かします。
ワークブックの入出力は端にまとめる
最初にバイト列を読み込み、明示的に変更して再計算し、最後にバイト列を書き出します。無関係なデータ読み込みの処理をこの範囲に混ぜなければ、失敗の原因を切り分けやすく、ジョブのテストも書きやすくなります。
流れ
Workbook を包む with ブロックは、失敗分岐で例外が送出された場合も含め、ブロックを抜けるときにエンジンのハンドルを解放します。
ジョブの例
from pathlib import Path
from formulon import Workbook
def recalc_report(input_path: Path, output_path: Path, revenue: float) -> None:
with Workbook.load(input_path.read_bytes()) as wb:
wb.set_excel_profile_id("win-365-en_US")
wb.set_pinned_now(2026, 10, 9, 9, 30, 0)
wb.set_number(0, 3, 1, revenue) # Sheet1 の B4
wb.recalc()
output_path.write_bytes(wb.save())
recalc_report(Path("template.xlsx"), Path("report.xlsx"), 125_000.0)プロファイルと時刻はファイルに保存されないため、このジョブは実行のたびに両方を設定します。設定しないと、ロケールや日付に依存する結果が実行ごとに変わる可能性があります。詳しくは ロケールプロファイル を参照してください。
複数セルを変更する
from formulon import Workbook, ValueKind
INPUTS = [
(0, 3, 1, 125_000.0), # B4: revenue
(0, 4, 1, 80_000.0), # B5: COGS
(0, 5, 1, 12_000.0), # B6: marketing
]
with Workbook.load(template_bytes) as wb:
wb.set_excel_profile_id("win-365-en_US")
wb.set_pinned_now(2026, 10, 9, 9, 30, 0)
for sheet, row, col, value in INPUTS:
wb.set_number(sheet, row, col, value)
wb.recalc()
margin = wb.get_value(0, 8, 1) # B9: gross margin
if margin.kind is ValueKind.NUMBER and margin.number < 0:
raise RuntimeError(f"Negative margin: {margin.number}")
output_path.write_bytes(wb.save())セルの変更には主に set_number / set_text / set_formula を使います。座標は 0 始まりの (sheet, row, col) です。詳しくは ワークブック操作 を参照してください。
検証パターン
リポジトリに小さな検証用ワークブックを置きます。
python jobs/recalc_reports.py
formulon dump --profile win-365-en_US --now 2026-10-09T09:30:00 --values report.xlsx > report.values.txt
git diff --exit-code report.values.txtジョブを実行し、その出力を dump --values でスナップショットすると、ジョブのコードとワークブックのどちらの変更も検知できます。
揮発性の入力は要対処
NOW / TODAY / RAND / RANDBETWEEN は揮発性関数です。WEBSERVICE、CUBE 関数、STOCKHISTORY など外部サービス依存の関数はネットワークへアクセスせず、利用不可を表す固定の Excel エラーを返します。期待値スナップショットでは、揮発性の入力をテンプレート側で固定値に置き換えるか対象範囲から外し、外部サービス依存のセルは 数式カバレッジ に従って記録するか除外してください。
エラー処理
from formulon import Workbook, FormulonError, ValueKind
try:
with Workbook.load(blob) as wb:
wb.recalc()
value = wb.get_value(0, 0, 0)
if value.kind is ValueKind.ERROR:
# セルの Excel エラー ─ 例外にせずデータとして処理
log.warning("cell error: %s", value.error_code)
except FormulonError as e:
# ホスト失敗(読み込めないバイト列、その他エンジンのステータスエラー)
log.error("formulon host failure: %s", e)
raise適合性の確認
| ワークフロー | 推奨実行入口 |
|---|---|
| cron 駆動の夜間レポート | Python |
| Jupyter / Colab ノートブック | Python |
| ブラウザ内再計算 | WASM |
| 大規模処理を高スループットで行う Node サービス | Native Node |
| シェル駆動の CI スナップショット | CLI |
次に読むもの
- Python API ─ トップレベル API
- ワークブックの流れ ─ スクリプトの裏で動くエンジンの流れ
- CI でワークブックの回帰を検出 ─ Python とスナップショットの組み合わせ