From ad52abf0699460675570f092a282523a5b64d26a Mon Sep 17 00:00:00 2001 From: jpirnay Date: Sun, 10 May 2026 10:35:51 +0200 Subject: [PATCH] Close source TTFont after instantiateVariableFont rebind instantiateVariableFont with default inplace=False returns a *new* TTFont; rebinding `font` strands the source TTFont and its file handle open until GC. The trailing font.close() then closes only the new pinned-instance object. Capture the source as a separate reference and close both with nested try/finally: inner finally closes the static instance after save (or on save failure), outer finally closes the source unconditionally. --- lib/EpdFont/scripts/build-sd-fonts.py | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/lib/EpdFont/scripts/build-sd-fonts.py b/lib/EpdFont/scripts/build-sd-fonts.py index 2e794e81..81957119 100644 --- a/lib/EpdFont/scripts/build-sd-fonts.py +++ b/lib/EpdFont/scripts/build-sd-fonts.py @@ -81,14 +81,22 @@ def extract_static_instance(source_path: Path, axes: dict, family_name: str, sty old.unlink() print(f" Extracting static instance: {family_name}/{style_name} ({axis_key})") - font = TTFont(str(source_path)) - # `static` was removed (or never existed) in current fontTools; it raises - # TypeError under recent releases. updateFontNames=True keeps the saved - # name table accurate; optimize=False skips a gvar pass that's wasted - # when every axis is fully pinned. - font = instantiateVariableFont(font, axes, updateFontNames=True, optimize=False) - font.save(str(cached)) - font.close() + # Keep separate handles for the source variable font and the static + # instance: instantiateVariableFont with default inplace=False returns a + # *new* TTFont, so rebinding `font` would otherwise strand the source's + # file handle open until GC runs. + # + # updateFontNames=True keeps the saved name table accurate; optimize=False + # skips a gvar pass that's wasted when every axis is fully pinned. + source_font = TTFont(str(source_path)) + try: + font = instantiateVariableFont(source_font, axes, updateFontNames=True, optimize=False) + try: + font.save(str(cached)) + finally: + font.close() + finally: + source_font.close() return cached