From a0f51493ca8ce7e90169a41d96d037ef413b659f Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Thu, 22 Jan 2026 00:23:58 +1100 Subject: [PATCH 1/3] Refer to lazy importing, as lazy loading of images is separate --- src/PIL/Image.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/PIL/Image.py b/src/PIL/Image.py index dfd64ef19..88f79a792 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -323,7 +323,7 @@ def getmodebands(mode: str) -> int: _initialized = 0 -# Mapping from file extension to plugin module name for lazy loading +# Mapping from file extension to plugin module name for lazy importing _EXTENSION_PLUGIN: dict[str, str] = { # Common formats (preinit) ".bmp": "BmpImagePlugin", @@ -402,8 +402,8 @@ _EXTENSION_PLUGIN: dict[str, str] = { } -def _load_plugin_for_extension(ext: str | bytes) -> bool: - """Load only the plugin needed for a specific file extension.""" +def _import_plugin_for_extension(ext: str | bytes) -> bool: + """Import only the plugin needed for a specific file extension.""" if isinstance(ext, bytes): ext = ext.decode() if ext in EXTENSION: @@ -2634,8 +2634,8 @@ class Image: filename_ext = os.path.splitext(filename)[1].lower() ext = filename_ext.decode() if isinstance(filename_ext, bytes) else filename_ext - # Try loading only the plugin for this extension first - if not _load_plugin_for_extension(ext): + # Try importing only the plugin for this extension first + if not _import_plugin_for_extension(ext): preinit() if not format: @@ -3625,7 +3625,7 @@ def open( # Try to load just the plugin needed for this file extension # before falling back to preinit() which loads common plugins ext = os.path.splitext(filename)[1] if filename else "" - if not (ext and _load_plugin_for_extension(ext)): + if not (ext and _import_plugin_for_extension(ext)): preinit() warning_messages: list[str] = [] From a6b36f0b6bd91a899b6a4038b7f875ce5382776b Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Thu, 22 Jan 2026 00:28:26 +1100 Subject: [PATCH 2/3] format overrides file extension when saving --- src/PIL/Image.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/PIL/Image.py b/src/PIL/Image.py index 88f79a792..e7357cc27 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -2631,14 +2631,20 @@ class Image: # only set the name for metadata purposes filename = os.fspath(fp.name) - filename_ext = os.path.splitext(filename)[1].lower() - ext = filename_ext.decode() if isinstance(filename_ext, bytes) else filename_ext - - # Try importing only the plugin for this extension first - if not _import_plugin_for_extension(ext): + if format: preinit() + else: + filename_ext = os.path.splitext(filename)[1].lower() + ext = ( + filename_ext.decode() + if isinstance(filename_ext, bytes) + else filename_ext + ) + + # Try importing only the plugin for this extension first + if not _import_plugin_for_extension(ext): + preinit() - if not format: if ext not in EXTENSION: init() try: From 76d3116ef030e9abb960f6544a272d3060ed2353 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Thu, 22 Jan 2026 18:48:38 +1100 Subject: [PATCH 3/3] Added logger messages to match init() --- src/PIL/Image.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/PIL/Image.py b/src/PIL/Image.py index e7357cc27..7d007718d 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -414,9 +414,11 @@ def _import_plugin_for_extension(ext: str | bytes) -> bool: return False try: + logger.debug("Importing %s", plugin) __import__(f"PIL.{plugin}", globals(), locals(), []) return True - except ImportError: + except ImportError as e: + logger.debug("Image: failed to import %s: %s", plugin, e) return False