From 1036aa74a7d91eda68d3f3f0bf4f59a87c020b0b Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Thu, 16 May 2024 17:47:35 +1000 Subject: [PATCH 1/3] Added Image.WARN_POSSIBLE_FORMATS --- Tests/test_image.py | 11 +++++++++++ docs/reference/Image.rst | 5 +++++ src/PIL/Image.py | 15 ++++++++------- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/Tests/test_image.py b/Tests/test_image.py index 742d0dfe406..7ec4195e5cf 100644 --- a/Tests/test_image.py +++ b/Tests/test_image.py @@ -116,6 +116,17 @@ def test_open_formats(self) -> None: assert im.mode == "RGB" assert im.size == (128, 128) + def test_open_verbose_failure(self) -> None: + im = io.BytesIO(b"") + Image.WARN_POSSIBLE_FORMATS = True + try: + with pytest.warns(UserWarning): + with pytest.raises(UnidentifiedImageError): + with Image.open(im): + pass + finally: + Image.WARN_POSSIBLE_FORMATS = False + def test_width_height(self) -> None: im = Image.new("RGB", (1, 2)) assert im.width == 1 diff --git a/docs/reference/Image.rst b/docs/reference/Image.rst index 0d9b4d93d77..f25c9cd9d46 100644 --- a/docs/reference/Image.rst +++ b/docs/reference/Image.rst @@ -374,6 +374,11 @@ Constants Set to 89,478,485, approximately 0.25GB for a 24-bit (3 bpp) image. See :py:meth:`~PIL.Image.open` for more information about how this is used. +.. data:: WARN_POSSIBLE_FORMATS + + Set to false. If true, when an image cannot be identified, warnings will be raised + from formats that attempted to read the data. + Transpose methods ^^^^^^^^^^^^^^^^^ diff --git a/src/PIL/Image.py b/src/PIL/Image.py index 958b95e3b0f..89c64998141 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -76,6 +76,8 @@ class DecompressionBombError(Exception): pass +WARN_POSSIBLE_FORMATS: bool = False + # Limit to around a quarter gigabyte for a 24-bit (3 bpp) image MAX_IMAGE_PIXELS: int | None = int(1024 * 1024 * 1024 // 4 // 3) @@ -3344,7 +3346,7 @@ def open( preinit() - accept_warnings: list[str] = [] + warning_messages: list[str] = [] def _open_core( fp: IO[bytes], @@ -3360,16 +3362,15 @@ def _open_core( factory, accept = OPEN[i] result = not accept or accept(prefix) if isinstance(result, str): - accept_warnings.append(result) + warning_messages.append(result) elif result: fp.seek(0) im = factory(fp, filename) _decompression_bomb_check(im.size) return im - except (SyntaxError, IndexError, TypeError, struct.error): - # Leave disabled by default, spams the logs with image - # opening failures that are entirely expected. - # logger.debug("", exc_info=True) + except (SyntaxError, IndexError, TypeError, struct.error) as e: + if WARN_POSSIBLE_FORMATS: + warning_messages.append(i + " opening failed. " + str(e)) continue except BaseException: if exclusive_fp: @@ -3395,7 +3396,7 @@ def _open_core( if exclusive_fp: fp.close() - for message in accept_warnings: + for message in warning_messages: warnings.warn(message) msg = "cannot identify image file %r" % (filename if filename else fp) raise UnidentifiedImageError(msg) From 2a703a2d4c94eefb224de1cbd7c2209af643a258 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Fri, 17 May 2024 08:04:20 +1000 Subject: [PATCH 2/3] Removed continue --- src/PIL/Image.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/PIL/Image.py b/src/PIL/Image.py index 89c64998141..514a543c2d3 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -3371,7 +3371,6 @@ def _open_core( except (SyntaxError, IndexError, TypeError, struct.error) as e: if WARN_POSSIBLE_FORMATS: warning_messages.append(i + " opening failed. " + str(e)) - continue except BaseException: if exclusive_fp: fp.close() From 7554e2cfbf25ea3a9b2da322a36b06be2a840b56 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Fri, 17 May 2024 08:44:04 +1000 Subject: [PATCH 3/3] Use monkeypatch --- Tests/test_image.py | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/Tests/test_image.py b/Tests/test_image.py index 7ec4195e5cf..a03e5eced07 100644 --- a/Tests/test_image.py +++ b/Tests/test_image.py @@ -116,16 +116,14 @@ def test_open_formats(self) -> None: assert im.mode == "RGB" assert im.size == (128, 128) - def test_open_verbose_failure(self) -> None: + def test_open_verbose_failure(self, monkeypatch: pytest.MonkeyPatch) -> None: + monkeypatch.setattr(Image, "WARN_POSSIBLE_FORMATS", True) + im = io.BytesIO(b"") - Image.WARN_POSSIBLE_FORMATS = True - try: - with pytest.warns(UserWarning): - with pytest.raises(UnidentifiedImageError): - with Image.open(im): - pass - finally: - Image.WARN_POSSIBLE_FORMATS = False + with pytest.warns(UserWarning): + with pytest.raises(UnidentifiedImageError): + with Image.open(im): + pass def test_width_height(self) -> None: im = Image.new("RGB", (1, 2))