diff --git a/Tests/test_file_dcx.py b/Tests/test_file_dcx.py index 28ebb91dc..52c0e13f4 100644 --- a/Tests/test_file_dcx.py +++ b/Tests/test_file_dcx.py @@ -20,6 +20,12 @@ class TestFileDcx(PillowTestCase): orig = hopper() self.assert_image_equal(im, orig) + def test_unclosed_file(self): + def open(): + im = Image.open(TEST_FILE) + im.load() + self.assert_warning(None, open) + def test_invalid_file(self): with open("Tests/images/flower.jpg", "rb") as fp: self.assertRaises(SyntaxError, diff --git a/Tests/test_file_fli.py b/Tests/test_file_fli.py index 2375d3749..77eaebaa5 100644 --- a/Tests/test_file_fli.py +++ b/Tests/test_file_fli.py @@ -27,6 +27,12 @@ class TestFileFli(PillowTestCase): self.assertEqual(im.info["duration"], 71) self.assertTrue(im.is_animated) + def test_unclosed_file(self): + def open(): + im = Image.open(static_test_file) + im.load() + self.assert_warning(None, open) + def test_tell(self): # Arrange im = Image.open(static_test_file) diff --git a/Tests/test_file_gif.py b/Tests/test_file_gif.py index d80b63249..1c4c8ebd2 100644 --- a/Tests/test_file_gif.py +++ b/Tests/test_file_gif.py @@ -33,6 +33,12 @@ class TestFileGif(PillowTestCase): self.assertEqual(im.format, "GIF") self.assertEqual(im.info["version"], b"GIF89a") + def test_unclosed_file(self): + def open(): + im = Image.open(TEST_GIF) + im.load() + self.assert_warning(None, open) + def test_invalid_file(self): invalid_file = "Tests/images/flower.jpg" diff --git a/Tests/test_file_im.py b/Tests/test_file_im.py index c99924767..f3349b736 100644 --- a/Tests/test_file_im.py +++ b/Tests/test_file_im.py @@ -15,6 +15,12 @@ class TestFileIm(PillowTestCase): self.assertEqual(im.size, (128, 128)) self.assertEqual(im.format, "IM") + def test_unclosed_file(self): + def open(): + im = Image.open(TEST_IM) + im.load() + self.assert_warning(None, open) + def test_tell(self): # Arrange im = Image.open(TEST_IM) diff --git a/Tests/test_file_mpo.py b/Tests/test_file_mpo.py index 70bb9b105..9f79d8cfa 100644 --- a/Tests/test_file_mpo.py +++ b/Tests/test_file_mpo.py @@ -31,6 +31,12 @@ class TestFileMpo(PillowTestCase): self.assertEqual(im.size, (640, 480)) self.assertEqual(im.format, "MPO") + def test_unclosed_file(self): + def open(): + im = Image.open(test_files[0]) + im.load() + self.assert_warning(None, open) + def test_app(self): for test_file in test_files: # Test APP/COM reader (@PIL135) diff --git a/Tests/test_file_spider.py b/Tests/test_file_spider.py index b54b92e04..4612b36a1 100644 --- a/Tests/test_file_spider.py +++ b/Tests/test_file_spider.py @@ -18,6 +18,12 @@ class TestImageSpider(PillowTestCase): self.assertEqual(im.size, (128, 128)) self.assertEqual(im.format, "SPIDER") + def test_unclosed_file(self): + def open(): + im = Image.open(TEST_FILE) + im.load() + self.assert_warning(None, open) + def test_save(self): # Arrange temp = self.tempfile('temp.spider') diff --git a/Tests/test_file_tiff.py b/Tests/test_file_tiff.py index 56ad69473..95a181363 100644 --- a/Tests/test_file_tiff.py +++ b/Tests/test_file_tiff.py @@ -40,6 +40,12 @@ class TestFileTiff(PillowTestCase): hopper("I").save(filename) Image.open(filename) + def test_unclosed_file(self): + def open(): + im = Image.open("Tests/images/multipage.tiff") + im.load() + self.assert_warning(None, open) + def test_mac_tiff(self): # Read RGBa images from macOS [@PIL136] diff --git a/src/PIL/DcxImagePlugin.py b/src/PIL/DcxImagePlugin.py index 204592759..1b72cbc99 100644 --- a/src/PIL/DcxImagePlugin.py +++ b/src/PIL/DcxImagePlugin.py @@ -81,6 +81,14 @@ class DcxImageFile(PcxImageFile): def tell(self): return self.frame + def _close__fp(self): + try: + self.__fp.close() + except AttributeError: + pass + finally: + self.__fp = None + Image.register_open(DcxImageFile.format, DcxImageFile, _accept) diff --git a/src/PIL/FliImagePlugin.py b/src/PIL/FliImagePlugin.py index b1eb9ae4d..1c8232fba 100644 --- a/src/PIL/FliImagePlugin.py +++ b/src/PIL/FliImagePlugin.py @@ -157,6 +157,14 @@ class FliImageFile(ImageFile.ImageFile): def tell(self): return self.__frame + def _close__fp(self): + try: + self.__fp.close() + except AttributeError: + pass + finally: + self.__fp = None + # # registry diff --git a/src/PIL/GifImagePlugin.py b/src/PIL/GifImagePlugin.py index 57bca07f7..3c8873738 100644 --- a/src/PIL/GifImagePlugin.py +++ b/src/PIL/GifImagePlugin.py @@ -302,6 +302,14 @@ class GifImageFile(ImageFile.ImageFile): self.im = self._prev_im self._prev_im = self.im.copy() + def _close__fp(self): + try: + self.__fp.close() + except AttributeError: + pass + finally: + self.__fp = None + # -------------------------------------------------------------------- # Write GIF files diff --git a/src/PIL/ImImagePlugin.py b/src/PIL/ImImagePlugin.py index 38b3f46f4..1a4fdb65a 100644 --- a/src/PIL/ImImagePlugin.py +++ b/src/PIL/ImImagePlugin.py @@ -290,6 +290,14 @@ class ImImageFile(ImageFile.ImageFile): def tell(self): return self.frame + def _close__fp(self): + try: + self.__fp.close() + except AttributeError: + pass + finally: + self.__fp = None + # # -------------------------------------------------------------------- # Save IM files diff --git a/src/PIL/Image.py b/src/PIL/Image.py index 1e47a50cd..82319e805 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -596,6 +596,8 @@ class Image(object): try: self.fp.close() self.fp = None + if hasattr(self, "_close__fp"): + self._close__fp() except Exception as msg: logger.debug("Error closing: %s", msg) @@ -613,6 +615,8 @@ class Image(object): and self.fp and self._exclusive_fp): self.fp.close() self.fp = None + if hasattr(self, "_close__fp"): + self._close__fp() def _copy(self): self.load() diff --git a/src/PIL/MicImagePlugin.py b/src/PIL/MicImagePlugin.py index 1dbb6a588..6e29e456d 100644 --- a/src/PIL/MicImagePlugin.py +++ b/src/PIL/MicImagePlugin.py @@ -95,9 +95,16 @@ class MicImageFile(TiffImagePlugin.TiffImageFile): self.frame = frame def tell(self): - return self.frame + def _close__fp(self): + try: + self.__fp.close() + except AttributeError: + pass + finally: + self.__fp = None + # # -------------------------------------------------------------------- diff --git a/src/PIL/MpoImagePlugin.py b/src/PIL/MpoImagePlugin.py index a1a8d655a..06b93d921 100644 --- a/src/PIL/MpoImagePlugin.py +++ b/src/PIL/MpoImagePlugin.py @@ -84,6 +84,14 @@ class MpoImageFile(JpegImagePlugin.JpegImageFile): def tell(self): return self.__frame + def _close__fp(self): + try: + self.__fp.close() + except AttributeError: + pass + finally: + self.__fp = None + # --------------------------------------------------------------------- # Registry stuff diff --git a/src/PIL/SpiderImagePlugin.py b/src/PIL/SpiderImagePlugin.py index 3f5795210..9dd7a7c03 100644 --- a/src/PIL/SpiderImagePlugin.py +++ b/src/PIL/SpiderImagePlugin.py @@ -193,6 +193,14 @@ class SpiderImageFile(ImageFile.ImageFile): from PIL import ImageTk return ImageTk.PhotoImage(self.convert2byte(), palette=256) + def _close__fp(self): + try: + self.__fp.close() + except AttributeError: + pass + finally: + self.__fp = None + # -------------------------------------------------------------------- # Image series diff --git a/src/PIL/TiffImagePlugin.py b/src/PIL/TiffImagePlugin.py index 5059a1324..5ae8211a4 100644 --- a/src/PIL/TiffImagePlugin.py +++ b/src/PIL/TiffImagePlugin.py @@ -1347,6 +1347,14 @@ class TiffImageFile(ImageFile.ImageFile): palette = [o8(b // 256) for b in self.tag_v2[COLORMAP]] self.palette = ImagePalette.raw("RGB;L", b"".join(palette)) + def _close__fp(self): + try: + self.__fp.close() + except AttributeError: + pass + finally: + self.__fp = None + # # --------------------------------------------------------------------