From 777f01132a79b7a3879030acc26c7eff13e10f20 Mon Sep 17 00:00:00 2001 From: Simon Hardy-Francis Date: Thu, 22 Oct 2026 15:42:21 -0700 Subject: [PATCH 1/4] Only build TIFF tag debug messages when debug logging is enabled ImageFileDirectory_v2.load() built a debug message for every IFD entry, including a tag-name lookup and a repr() of the value, even when debug logging was disabled. Check logger.isEnabledFor() once per IFD and only build and log the message when it will be emitted. Assisted-by: LLM Signed-off-by: Simon Hardy-Francis --- Tests/test_file_tiff_metadata.py | 11 +++++++++++ src/PIL/TiffImagePlugin.py | 30 +++++++++++++++++++----------- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/Tests/test_file_tiff_metadata.py b/Tests/test_file_tiff_metadata.py index b42f0ec0ed5..c1e18626340 100644 --- a/Tests/test_file_tiff_metadata.py +++ b/Tests/test_file_tiff_metadata.py @@ -1,6 +1,7 @@ from __future__ import annotations import io +import logging import struct import pytest @@ -582,3 +583,13 @@ def test_empty_subifd(tmp_path: Path) -> None: with Image.open(out) as reloaded: exif = reloaded.getexif() assert exif.get_ifd(TiffImagePlugin.EXIFIFD) == {} + + +def test_load_debug_logging(caplog: pytest.LogCaptureFixture) -> None: + with caplog.at_level(logging.DEBUG, logger="PIL.TiffImagePlugin"): + with Image.open("Tests/images/hopper.tif"): + pass + assert ( + "tag: ImageWidth (256) - type: short (3) - value: b'\\x80\\x00'" + in caplog.messages + ) diff --git a/src/PIL/TiffImagePlugin.py b/src/PIL/TiffImagePlugin.py index 9dccd8f031a..844319d452c 100644 --- a/src/PIL/TiffImagePlugin.py +++ b/src/PIL/TiffImagePlugin.py @@ -911,6 +911,7 @@ def load(self, fp: IO[bytes]) -> None: else self._unpack("H", self._ensure_read(fp, 2)) )[0] total_size = 0 + debug = logger.isEnabledFor(logging.DEBUG) for i in range(tag_count): tag, typ, count, data = ( self._unpack("HHQ8s", self._ensure_read(fp, 20)) @@ -920,20 +921,25 @@ def load(self, fp: IO[bytes]) -> None: if tag in self._tagdata: continue - tagname = TiffTags.lookup(tag, self.group).name - typname = TYPES.get(typ, "unknown") - msg = f"tag: {tagname} ({tag}) - type: {typname} ({typ})" + # Only build the debug message if it will be logged + msg = "" + if debug: + tagname = TiffTags.lookup(tag, self.group).name + typname = TYPES.get(typ, "unknown") + msg = f"tag: {tagname} ({tag}) - type: {typname} ({typ})" try: unit_size, handler = self._load_dispatch[typ] except KeyError: - logger.debug("%s - unsupported type %s", msg, typ) + if debug: + logger.debug("%s - unsupported type %s", msg, typ) continue # ignore unsupported type size = count * unit_size if size > (8 if self._bigtiff else 4): here = fp.tell() (offset,) = self._unpack("Q" if self._bigtiff else "L", data) - msg += f" Tag Location: {here} - Data Location: {offset}" + if debug: + msg += f" Tag Location: {here} - Data Location: {offset}" if offset >= 2**63: warnings.warn("Tag offset too large") continue @@ -956,20 +962,22 @@ def load(self, fp: IO[bytes]) -> None: f"Expecting to read {size} bytes but only got {len(data)}." f" Skipping tag {tag}" ) - logger.debug(msg) + if debug: + logger.debug(msg) continue if not data: - logger.debug(msg) + if debug: + logger.debug(msg) continue self._tagdata[tag] = data self.tagtype[tag] = typ - msg += " - value: " - msg += f"" if size > 32 else repr(data) - - logger.debug(msg) + if debug: + msg += " - value: " + msg += f"" if size > 32 else repr(data) + logger.debug(msg) (self.next,) = ( self._unpack("Q", self._ensure_read(fp, 8)) From 4b5c981cd36834e9130432a03fe820ffaef85148 Mon Sep 17 00:00:00 2001 From: Simon Hardy-Francis Date: Thu, 22 Oct 2026 15:59:50 -0700 Subject: [PATCH 2/4] Log unconditionally in rarely taken branches logger.debug() already does nothing when debug logging is disabled, and these branches are not on the hot path. Assisted-by: LLM Signed-off-by: Simon Hardy-Francis --- src/PIL/TiffImagePlugin.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/PIL/TiffImagePlugin.py b/src/PIL/TiffImagePlugin.py index 844319d452c..33a527e6c6c 100644 --- a/src/PIL/TiffImagePlugin.py +++ b/src/PIL/TiffImagePlugin.py @@ -931,8 +931,7 @@ def load(self, fp: IO[bytes]) -> None: try: unit_size, handler = self._load_dispatch[typ] except KeyError: - if debug: - logger.debug("%s - unsupported type %s", msg, typ) + logger.debug("%s - unsupported type %s", msg, typ) continue # ignore unsupported type size = count * unit_size if size > (8 if self._bigtiff else 4): @@ -962,13 +961,11 @@ def load(self, fp: IO[bytes]) -> None: f"Expecting to read {size} bytes but only got {len(data)}." f" Skipping tag {tag}" ) - if debug: - logger.debug(msg) + logger.debug(msg) continue if not data: - if debug: - logger.debug(msg) + logger.debug(msg) continue self._tagdata[tag] = data From b795d4f45471335fb18e138b2715f001e3c736a2 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Fri, 23 Oct 2026 12:01:56 +1100 Subject: [PATCH 3/4] Remove test --- Tests/test_file_tiff_metadata.py | 11 ----------- src/PIL/TiffImagePlugin.py | 1 - 2 files changed, 12 deletions(-) diff --git a/Tests/test_file_tiff_metadata.py b/Tests/test_file_tiff_metadata.py index c1e18626340..b42f0ec0ed5 100644 --- a/Tests/test_file_tiff_metadata.py +++ b/Tests/test_file_tiff_metadata.py @@ -1,7 +1,6 @@ from __future__ import annotations import io -import logging import struct import pytest @@ -583,13 +582,3 @@ def test_empty_subifd(tmp_path: Path) -> None: with Image.open(out) as reloaded: exif = reloaded.getexif() assert exif.get_ifd(TiffImagePlugin.EXIFIFD) == {} - - -def test_load_debug_logging(caplog: pytest.LogCaptureFixture) -> None: - with caplog.at_level(logging.DEBUG, logger="PIL.TiffImagePlugin"): - with Image.open("Tests/images/hopper.tif"): - pass - assert ( - "tag: ImageWidth (256) - type: short (3) - value: b'\\x80\\x00'" - in caplog.messages - ) diff --git a/src/PIL/TiffImagePlugin.py b/src/PIL/TiffImagePlugin.py index 33a527e6c6c..ae095bb2a5a 100644 --- a/src/PIL/TiffImagePlugin.py +++ b/src/PIL/TiffImagePlugin.py @@ -921,7 +921,6 @@ def load(self, fp: IO[bytes]) -> None: if tag in self._tagdata: continue - # Only build the debug message if it will be logged msg = "" if debug: tagname = TiffTags.lookup(tag, self.group).name From 24e5dfc57cde2b8c89bc79ab0bb005277a6e2127 Mon Sep 17 00:00:00 2001 From: Simon Hardy-Francis Date: Thu, 22 Oct 2026 19:46:44 -0700 Subject: [PATCH 4/4] Comment out debug logging in IFD load() As suggested in review, so it can be restored when debugging Pillow. Assisted-by: LLM Signed-off-by: Simon Hardy-Francis --- src/PIL/TiffImagePlugin.py | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/src/PIL/TiffImagePlugin.py b/src/PIL/TiffImagePlugin.py index ae095bb2a5a..7f023d08e5c 100644 --- a/src/PIL/TiffImagePlugin.py +++ b/src/PIL/TiffImagePlugin.py @@ -911,7 +911,6 @@ def load(self, fp: IO[bytes]) -> None: else self._unpack("H", self._ensure_read(fp, 2)) )[0] total_size = 0 - debug = logger.isEnabledFor(logging.DEBUG) for i in range(tag_count): tag, typ, count, data = ( self._unpack("HHQ8s", self._ensure_read(fp, 20)) @@ -921,23 +920,20 @@ def load(self, fp: IO[bytes]) -> None: if tag in self._tagdata: continue - msg = "" - if debug: - tagname = TiffTags.lookup(tag, self.group).name - typname = TYPES.get(typ, "unknown") - msg = f"tag: {tagname} ({tag}) - type: {typname} ({typ})" + # tagname = TiffTags.lookup(tag, self.group).name + # typname = TYPES.get(typ, "unknown") + # msg = f"tag: {tagname} ({tag}) - type: {typname} ({typ})" try: unit_size, handler = self._load_dispatch[typ] except KeyError: - logger.debug("%s - unsupported type %s", msg, typ) + # logger.debug("%s - unsupported type %s", msg, typ) continue # ignore unsupported type size = count * unit_size if size > (8 if self._bigtiff else 4): here = fp.tell() (offset,) = self._unpack("Q" if self._bigtiff else "L", data) - if debug: - msg += f" Tag Location: {here} - Data Location: {offset}" + # msg += f" Tag Location: {here} - Data Location: {offset}" if offset >= 2**63: warnings.warn("Tag offset too large") continue @@ -960,20 +956,20 @@ def load(self, fp: IO[bytes]) -> None: f"Expecting to read {size} bytes but only got {len(data)}." f" Skipping tag {tag}" ) - logger.debug(msg) + # logger.debug(msg) continue if not data: - logger.debug(msg) + # logger.debug(msg) continue self._tagdata[tag] = data self.tagtype[tag] = typ - if debug: - msg += " - value: " - msg += f"" if size > 32 else repr(data) - logger.debug(msg) + # msg += " - value: " + # msg += f"" if size > 32 else repr(data) + + # logger.debug(msg) (self.next,) = ( self._unpack("Q", self._ensure_read(fp, 8))