From b25ece364b5e7d9f97df38ca82b15c83c98daf6c Mon Sep 17 00:00:00 2001 From: Raphael Vieira Rossi Date: Thu, 16 Nov 2023 16:46:11 -0300 Subject: [PATCH 1/3] fix: check object Image has attribute 'fp' when closes --- Tests/test_image.py | 15 +++++++++++++++ src/PIL/Image.py | 13 +++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/Tests/test_image.py b/Tests/test_image.py index 9efd4c4677d..0c684334658 100644 --- a/Tests/test_image.py +++ b/Tests/test_image.py @@ -1014,6 +1014,21 @@ def test_fli_overrun2(self): except OSError as e: assert str(e) == "buffer overrun when reading image file" + @pytest.fixture(scope="function") + def inject_caplog(self, caplog): + self._caplog = caplog + + @pytest.mark.usefixtures("inject_caplog") + def test_close_graceful(self): + with Image.open("Tests/images/hopper.jpg") as im: + copy = im.copy() + im.close() + copy.close() + + assert len(self._caplog.records) == 0 + assert im.fp is None + assert copy.fp is None + class MockEncoder: pass diff --git a/src/PIL/Image.py b/src/PIL/Image.py index 546d9020334..c873a93e7c7 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -550,12 +550,13 @@ def close(self): more information. """ try: - if getattr(self, "_fp", False): - if self._fp != self.fp: - self._fp.close() - self._fp = DeferredError(ValueError("Operation on closed image")) - if self.fp: - self.fp.close() + if hasattr(self, "fp"): + if getattr(self, "_fp", False): + if self._fp != self.fp: + self._fp.close() + self._fp = DeferredError(ValueError("Operation on closed image")) + if self.fp: + self.fp.close() self.fp = None except Exception as msg: logger.debug("Error closing: %s", msg) From 67e12532028649cc68f12ff6e6a06480fbe147f1 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Fri, 17 Nov 2023 08:32:25 +1100 Subject: [PATCH 2/3] Do not assign new fp attribute to image when closing --- Tests/test_image.py | 1 - src/PIL/Image.py | 10 +++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/Tests/test_image.py b/Tests/test_image.py index 0c684334658..243e7170746 100644 --- a/Tests/test_image.py +++ b/Tests/test_image.py @@ -1027,7 +1027,6 @@ def test_close_graceful(self): assert len(self._caplog.records) == 0 assert im.fp is None - assert copy.fp is None class MockEncoder: diff --git a/src/PIL/Image.py b/src/PIL/Image.py index c873a93e7c7..d435b561720 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -549,17 +549,17 @@ def close(self): :py:meth:`~PIL.Image.Image.load` method. See :ref:`file-handling` for more information. """ - try: - if hasattr(self, "fp"): + if hasattr(self, "fp"): + try: if getattr(self, "_fp", False): if self._fp != self.fp: self._fp.close() self._fp = DeferredError(ValueError("Operation on closed image")) if self.fp: self.fp.close() - self.fp = None - except Exception as msg: - logger.debug("Error closing: %s", msg) + self.fp = None + except Exception as msg: + logger.debug("Error closing: %s", msg) if getattr(self, "map", None): self.map = None From 5f33175b200cef385a2f84f430519a162e387a38 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Fri, 17 Nov 2023 08:37:46 +1100 Subject: [PATCH 3/3] Fixed checking that no debug messages were logged --- Tests/test_image.py | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/Tests/test_image.py b/Tests/test_image.py index 243e7170746..f0861bb4f81 100644 --- a/Tests/test_image.py +++ b/Tests/test_image.py @@ -1,4 +1,5 @@ import io +import logging import os import shutil import sys @@ -1014,18 +1015,13 @@ def test_fli_overrun2(self): except OSError as e: assert str(e) == "buffer overrun when reading image file" - @pytest.fixture(scope="function") - def inject_caplog(self, caplog): - self._caplog = caplog - - @pytest.mark.usefixtures("inject_caplog") - def test_close_graceful(self): + def test_close_graceful(self, caplog): with Image.open("Tests/images/hopper.jpg") as im: copy = im.copy() - im.close() - copy.close() - - assert len(self._caplog.records) == 0 + with caplog.at_level(logging.DEBUG): + im.close() + copy.close() + assert len(caplog.records) == 0 assert im.fp is None