scripts/recalc.py
scripts/recalc.pyBrowse 2 files
620 tokens
2,724 bytes
Token encoding: o200k_base
Snapshot 24fd22b
← Back to SKILL.md
1#!/usr/bin/env python32"""Recalculate an .xlsx file's formulas using LibreOffice headless.3 4Usage: python recalc.py <path.xlsx> [timeout_seconds]5 6openpyxl writes formula strings but does not compute them. Downstream scripts7that open the file with data_only=True get None for every formula cell until8something has actually calculated the workbook. Excel does this on open;9headless pipelines need LibreOffice (or similar) to do it explicitly.10 11Exits 0 on success (workbook recomputed and resaved in place), non-zero on12failure. Writes status JSON to stdout either way.13"""14 15import json16import shutil17import subprocess18import sys19import tempfile20from pathlib import Path21 22 23def find_libreoffice() -> str | None:24 for cmd in ("libreoffice", "soffice"):25 path = shutil.which(cmd)26 if path:27 return path28 return None29 30 31def recalc(xlsx_path: str, timeout: int = 60) -> dict:32 src = Path(xlsx_path).resolve()33 if not src.exists():34 return {"status": "error", "error": f"File not found: {src}"}35 36 lo = find_libreoffice()37 if lo is None:38 return {39 "status": "error",40 "error": "libreoffice not found on PATH — install it or recalc in a real Excel session",41 }42 43 with tempfile.TemporaryDirectory() as td:44 try:45 subprocess.run(46 [47 lo,48 "--headless",49 "--calc",50 "--convert-to",51 "xlsx",52 str(src),53 "--outdir",54 td,55 ],56 check=True,57 capture_output=True,58 timeout=timeout,59 )60 except subprocess.TimeoutExpired:61 return {"status": "error", "error": f"libreoffice timed out after {timeout}s"}62 except subprocess.CalledProcessError as e:63 return {64 "status": "error",65 "error": f"libreoffice exited {e.returncode}: {e.stderr.decode(errors='replace')[:500]}",66 }67 68 produced = Path(td) / src.name69 if not produced.exists():70 return {"status": "error", "error": "libreoffice did not produce output file"}71 72 shutil.copy(produced, src)73 74 return {"status": "success", "file": str(src)}75 76 77def main():78 if len(sys.argv) < 2:79 print("Usage: python recalc.py <path.xlsx> [timeout_seconds]", file=sys.stderr)80 sys.exit(2)81 timeout = int(sys.argv[2]) if len(sys.argv) > 2 else 6082 result = recalc(sys.argv[1], timeout=timeout)83 print(json.dumps(result, indent=2))84 sys.exit(0 if result["status"] == "success" else 1)85 86 87if __name__ == "__main__":88 main()89