# -*- coding: utf-8 -*- """Refresh TOC fields in one docx via a fresh Word process.""" from __future__ import annotations import hashlib import shutil import sys import tempfile import time from pathlib import Path WD_COLOR_BLACK = 0 WD_STAT_PAGES = 2 def retry(fn, times=8, wait=0.8): last = None for i in range(times): try: return fn() except Exception as exc: last = exc time.sleep(wait * (i + 1)) raise last def main() -> int: if len(sys.argv) < 2: return 2 src = Path(sys.argv[1]) tmp_dir = Path(tempfile.gettempdir()) / "aidop_toc_word" tmp_dir.mkdir(exist_ok=True) tmp = tmp_dir / f"{hashlib.md5(str(src).encode('utf-8')).hexdigest()}_{int(time.time())}.docx" shutil.copy2(src, tmp) import pythoncom import win32com.client as win32 pythoncom.CoInitialize() word = None doc = None try: word = retry(lambda: win32.DispatchEx("Word.Application")) word.Visible = False try: word.DisplayAlerts = 0 except Exception: pass try: word.AutomationSecurity = 3 except Exception: pass time.sleep(1) doc = retry( lambda: word.Documents.Open( str(tmp), ConfirmConversions=False, ReadOnly=False, AddToRecentFiles=False, ) ) time.sleep(1) retry(lambda: doc.Fields.Update()) def update_tocs(): for i in range(1, doc.TablesOfContents.Count + 1): doc.TablesOfContents(i).Update() retry(update_tocs) try: doc.Repaginate() except Exception: pass retry(update_tocs) for name in ("TOC 1", "TOC 2", "TOC 3", "TOC 4", "Hyperlink"): try: doc.Styles(name).Font.Color = WD_COLOR_BLACK except Exception: pass pages = retry(lambda: doc.ComputeStatistics(WD_STAT_PAGES)) lines = 0 if doc.TablesOfContents.Count: lines = len([x for x in doc.TablesOfContents(1).Range.Text.split("\r") if x.strip()]) retry(doc.Save) retry(lambda: doc.Close(False)) doc = None retry(word.Quit) word = None time.sleep(0.5) shutil.copy2(tmp, src) print(f"pages={pages} toc={lines}", flush=True) return 0 finally: try: if doc is not None: doc.Close(False) except Exception: pass try: if word is not None: word.Quit() except Exception: pass try: pythoncom.CoUninitialize() except Exception: pass try: tmp.unlink(missing_ok=True) except Exception: pass if __name__ == "__main__": raise SystemExit(main())