diff --git a/Tests/test_bmp_reference.py b/Tests/test_bmp_reference.py index e6a75e2c3..f7a60cfd7 100644 --- a/Tests/test_bmp_reference.py +++ b/Tests/test_bmp_reference.py @@ -24,8 +24,8 @@ class TestBmpReference(PillowTestCase): def open(f): try: - im = Image.open(f) - im.load() + with Image.open(f) as im: + im.load() except Exception: # as msg: pass @@ -48,8 +48,8 @@ class TestBmpReference(PillowTestCase): ] for f in self.get_files("q"): try: - im = Image.open(f) - im.load() + with Image.open(f) as im: + im.load() if os.path.basename(f) not in supported: print("Please add %s to the partially supported bmp specs." % f) except Exception: # as msg: @@ -89,17 +89,17 @@ class TestBmpReference(PillowTestCase): for f in self.get_files("g"): try: - im = Image.open(f) - im.load() - compare = Image.open(get_compare(f)) - compare.load() - if im.mode == "P": - # assert image similar doesn't really work - # with paletized image, since the palette might - # be differently ordered for an equivalent image. - im = im.convert("RGBA") - compare = im.convert("RGBA") - self.assert_image_similar(im, compare, 5) + with Image.open(f) as im: + im.load() + with Image.open(get_compare(f)) as compare: + compare.load() + if im.mode == "P": + # assert image similar doesn't really work + # with paletized image, since the palette might + # be differently ordered for an equivalent image. + im = im.convert("RGBA") + compare = im.convert("RGBA") + self.assert_image_similar(im, compare, 5) except Exception as msg: # there are three here that are unsupported: diff --git a/Tests/test_decompression_bomb.py b/Tests/test_decompression_bomb.py index 3afad674f..5d0d37099 100644 --- a/Tests/test_decompression_bomb.py +++ b/Tests/test_decompression_bomb.py @@ -14,7 +14,8 @@ class TestDecompressionBomb(PillowTestCase): def test_no_warning_small_file(self): # Implicit assert: no warning. # A warning would cause a failure. - Image.open(TEST_FILE) + with Image.open(TEST_FILE): + pass def test_no_warning_no_limit(self): # Arrange @@ -25,21 +26,28 @@ class TestDecompressionBomb(PillowTestCase): # Act / Assert # Implicit assert: no warning. # A warning would cause a failure. - Image.open(TEST_FILE) + with Image.open(TEST_FILE): + pass def test_warning(self): # Set limit to trigger warning on the test file Image.MAX_IMAGE_PIXELS = 128 * 128 - 1 self.assertEqual(Image.MAX_IMAGE_PIXELS, 128 * 128 - 1) - self.assert_warning(Image.DecompressionBombWarning, Image.open, TEST_FILE) + def open(): + with Image.open(TEST_FILE): + pass + + self.assert_warning(Image.DecompressionBombWarning, open) def test_exception(self): # Set limit to trigger exception on the test file Image.MAX_IMAGE_PIXELS = 64 * 128 - 1 self.assertEqual(Image.MAX_IMAGE_PIXELS, 64 * 128 - 1) - self.assertRaises(Image.DecompressionBombError, lambda: Image.open(TEST_FILE)) + with self.assertRaises(Image.DecompressionBombError): + with Image.open(TEST_FILE): + pass def test_exception_ico(self): with self.assertRaises(Image.DecompressionBombError): @@ -53,6 +61,7 @@ class TestDecompressionBomb(PillowTestCase): class TestDecompressionCrop(PillowTestCase): def setUp(self): self.src = hopper() + self.addCleanup(self.src.close) Image.MAX_IMAGE_PIXELS = self.src.height * self.src.width * 4 - 1 def tearDown(self): diff --git a/Tests/test_file_blp.py b/Tests/test_file_blp.py index 59951a890..8dbd82986 100644 --- a/Tests/test_file_blp.py +++ b/Tests/test_file_blp.py @@ -5,14 +5,14 @@ from .helper import PillowTestCase class TestFileBlp(PillowTestCase): def test_load_blp2_raw(self): - im = Image.open("Tests/images/blp/blp2_raw.blp") - target = Image.open("Tests/images/blp/blp2_raw.png") - self.assert_image_equal(im, target) + with Image.open("Tests/images/blp/blp2_raw.blp") as im: + with Image.open("Tests/images/blp/blp2_raw.png") as target: + self.assert_image_equal(im, target) def test_load_blp2_dxt1(self): - im = Image.open("Tests/images/blp/blp2_dxt1.blp") - target = Image.open("Tests/images/blp/blp2_dxt1.png") - self.assert_image_equal(im, target) + with Image.open("Tests/images/blp/blp2_dxt1.blp") as im: + with Image.open("Tests/images/blp/blp2_dxt1.png") as target: + self.assert_image_equal(im, target) def test_load_blp2_dxt1a(self): im = Image.open("Tests/images/blp/blp2_dxt1a.blp") diff --git a/Tests/test_file_bmp.py b/Tests/test_file_bmp.py index 2180835ba..e7f2c9315 100644 --- a/Tests/test_file_bmp.py +++ b/Tests/test_file_bmp.py @@ -46,13 +46,12 @@ class TestFileBmp(PillowTestCase): dpi = (72, 72) output = io.BytesIO() - im = hopper() - im.save(output, "BMP", dpi=dpi) + with hopper() as im: + im.save(output, "BMP", dpi=dpi) output.seek(0) - reloaded = Image.open(output) - - self.assertEqual(reloaded.info["dpi"], dpi) + with Image.open(output) as reloaded: + self.assertEqual(reloaded.info["dpi"], dpi) def test_save_bmp_with_dpi(self): # Test for #1301 @@ -72,24 +71,24 @@ class TestFileBmp(PillowTestCase): def test_load_dpi_rounding(self): # Round up - im = Image.open("Tests/images/hopper.bmp") - self.assertEqual(im.info["dpi"], (96, 96)) + with Image.open("Tests/images/hopper.bmp") as im: + self.assertEqual(im.info["dpi"], (96, 96)) # Round down - im = Image.open("Tests/images/hopper_roundDown.bmp") - self.assertEqual(im.info["dpi"], (72, 72)) + with Image.open("Tests/images/hopper_roundDown.bmp") as im: + self.assertEqual(im.info["dpi"], (72, 72)) def test_save_dpi_rounding(self): outfile = self.tempfile("temp.bmp") im = Image.open("Tests/images/hopper.bmp") im.save(outfile, dpi=(72.2, 72.2)) - reloaded = Image.open(outfile) - self.assertEqual(reloaded.info["dpi"], (72, 72)) + with Image.open(outfile) as reloaded: + self.assertEqual(reloaded.info["dpi"], (72, 72)) - im.save(outfile, dpi=(72.8, 72.8)) - reloaded = Image.open(outfile) - self.assertEqual(reloaded.info["dpi"], (73, 73)) + im.save(outfile, dpi=(72.8, 72.8)) + with Image.open(outfile) as reloaded: + self.assertEqual(reloaded.info["dpi"], (73, 73)) def test_load_dib(self): # test for #1293, Imagegrab returning Unsupported Bitfields Format diff --git a/Tests/test_file_bufrstub.py b/Tests/test_file_bufrstub.py index 37573e340..540d89719 100644 --- a/Tests/test_file_bufrstub.py +++ b/Tests/test_file_bufrstub.py @@ -8,14 +8,14 @@ TEST_FILE = "Tests/images/gfs.t06z.rassda.tm00.bufr_d" class TestFileBufrStub(PillowTestCase): def test_open(self): # Act - im = Image.open(TEST_FILE) + with Image.open(TEST_FILE) as im: - # Assert - self.assertEqual(im.format, "BUFR") + # Assert + self.assertEqual(im.format, "BUFR") - # Dummy data from the stub - self.assertEqual(im.mode, "F") - self.assertEqual(im.size, (1, 1)) + # Dummy data from the stub + self.assertEqual(im.mode, "F") + self.assertEqual(im.size, (1, 1)) def test_invalid_file(self): # Arrange @@ -28,10 +28,10 @@ class TestFileBufrStub(PillowTestCase): def test_load(self): # Arrange - im = Image.open(TEST_FILE) + with Image.open(TEST_FILE) as im: - # Act / Assert: stub cannot load without an implemented handler - self.assertRaises(IOError, im.load) + # Act / Assert: stub cannot load without an implemented handler + self.assertRaises(IOError, im.load) def test_save(self): # Arrange diff --git a/Tests/test_file_container.py b/Tests/test_file_container.py index 5f14001d9..2f931fb68 100644 --- a/Tests/test_file_container.py +++ b/Tests/test_file_container.py @@ -11,8 +11,8 @@ class TestFileContainer(PillowTestCase): dir(ContainerIO) def test_isatty(self): - im = hopper() - container = ContainerIO.ContainerIO(im, 0, 0) + with hopper() as im: + container = ContainerIO.ContainerIO(im, 0, 0) self.assertFalse(container.isatty()) diff --git a/Tests/test_file_dcx.py b/Tests/test_file_dcx.py index 4d3690d30..e9411dbf8 100644 --- a/Tests/test_file_dcx.py +++ b/Tests/test_file_dcx.py @@ -1,6 +1,8 @@ +import unittest + from PIL import DcxImagePlugin, Image -from .helper import PillowTestCase, hopper +from .helper import PillowTestCase, hopper, is_pypy # Created with ImageMagick: convert hopper.ppm hopper.dcx TEST_FILE = "Tests/images/hopper.dcx" @@ -11,19 +13,35 @@ class TestFileDcx(PillowTestCase): # Arrange # Act - im = Image.open(TEST_FILE) + with Image.open(TEST_FILE) as im: - # Assert - self.assertEqual(im.size, (128, 128)) - self.assertIsInstance(im, DcxImagePlugin.DcxImageFile) - orig = hopper() - self.assert_image_equal(im, orig) + # Assert + self.assertEqual(im.size, (128, 128)) + self.assertIsInstance(im, DcxImagePlugin.DcxImageFile) + orig = hopper() + self.assert_image_equal(im, orig) + @unittest.skipIf(is_pypy(), "Requires CPython") def test_unclosed_file(self): def open(): im = Image.open(TEST_FILE) im.load() + self.assert_warning(ResourceWarning, open) + + def test_closed_file(self): + def open(): + im = Image.open(TEST_FILE) + im.load() + im.close() + + self.assert_warning(None, open) + + def test_context_manager(self): + def open(): + with Image.open(TEST_FILE) as im: + im.load() + self.assert_warning(None, open) def test_invalid_file(self): @@ -32,34 +50,34 @@ class TestFileDcx(PillowTestCase): def test_tell(self): # Arrange - im = Image.open(TEST_FILE) + with Image.open(TEST_FILE) as im: - # Act - frame = im.tell() + # Act + frame = im.tell() - # Assert - self.assertEqual(frame, 0) + # Assert + self.assertEqual(frame, 0) def test_n_frames(self): - im = Image.open(TEST_FILE) - self.assertEqual(im.n_frames, 1) - self.assertFalse(im.is_animated) + with Image.open(TEST_FILE) as im: + self.assertEqual(im.n_frames, 1) + self.assertFalse(im.is_animated) def test_eoferror(self): - im = Image.open(TEST_FILE) - n_frames = im.n_frames + with Image.open(TEST_FILE) as im: + n_frames = im.n_frames - # Test seeking past the last frame - self.assertRaises(EOFError, im.seek, n_frames) - self.assertLess(im.tell(), n_frames) + # Test seeking past the last frame + self.assertRaises(EOFError, im.seek, n_frames) + self.assertLess(im.tell(), n_frames) - # Test that seeking to the last frame does not raise an error - im.seek(n_frames - 1) + # Test that seeking to the last frame does not raise an error + im.seek(n_frames - 1) def test_seek_too_far(self): # Arrange - im = Image.open(TEST_FILE) - frame = 999 # too big on purpose + with Image.open(TEST_FILE) as im: + frame = 999 # too big on purpose # Act / Assert self.assertRaises(EOFError, im.seek, frame) diff --git a/Tests/test_file_eps.py b/Tests/test_file_eps.py index 3459310df..9b1a1ec40 100644 --- a/Tests/test_file_eps.py +++ b/Tests/test_file_eps.py @@ -25,30 +25,30 @@ class TestFileEps(PillowTestCase): @unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available") def test_sanity(self): # Regular scale - image1 = Image.open(file1) - image1.load() - self.assertEqual(image1.mode, "RGB") - self.assertEqual(image1.size, (460, 352)) - self.assertEqual(image1.format, "EPS") + with Image.open(file1) as image1: + image1.load() + self.assertEqual(image1.mode, "RGB") + self.assertEqual(image1.size, (460, 352)) + self.assertEqual(image1.format, "EPS") - image2 = Image.open(file2) - image2.load() - self.assertEqual(image2.mode, "RGB") - self.assertEqual(image2.size, (360, 252)) - self.assertEqual(image2.format, "EPS") + with Image.open(file2) as image2: + image2.load() + self.assertEqual(image2.mode, "RGB") + self.assertEqual(image2.size, (360, 252)) + self.assertEqual(image2.format, "EPS") # Double scale - image1_scale2 = Image.open(file1) - image1_scale2.load(scale=2) - self.assertEqual(image1_scale2.mode, "RGB") - self.assertEqual(image1_scale2.size, (920, 704)) - self.assertEqual(image1_scale2.format, "EPS") + with Image.open(file1) as image1_scale2: + image1_scale2.load(scale=2) + self.assertEqual(image1_scale2.mode, "RGB") + self.assertEqual(image1_scale2.size, (920, 704)) + self.assertEqual(image1_scale2.format, "EPS") - image2_scale2 = Image.open(file2) - image2_scale2.load(scale=2) - self.assertEqual(image2_scale2.mode, "RGB") - self.assertEqual(image2_scale2.size, (720, 504)) - self.assertEqual(image2_scale2.format, "EPS") + with Image.open(file2) as image2_scale2: + image2_scale2.load(scale=2) + self.assertEqual(image2_scale2.mode, "RGB") + self.assertEqual(image2_scale2.size, (720, 504)) + self.assertEqual(image2_scale2.format, "EPS") def test_invalid_file(self): invalid_file = "Tests/images/flower.jpg" @@ -57,43 +57,42 @@ class TestFileEps(PillowTestCase): @unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available") def test_cmyk(self): - cmyk_image = Image.open("Tests/images/pil_sample_cmyk.eps") + with Image.open("Tests/images/pil_sample_cmyk.eps") as cmyk_image: - self.assertEqual(cmyk_image.mode, "CMYK") - self.assertEqual(cmyk_image.size, (100, 100)) - self.assertEqual(cmyk_image.format, "EPS") + self.assertEqual(cmyk_image.mode, "CMYK") + self.assertEqual(cmyk_image.size, (100, 100)) + self.assertEqual(cmyk_image.format, "EPS") - cmyk_image.load() - self.assertEqual(cmyk_image.mode, "RGB") + cmyk_image.load() + self.assertEqual(cmyk_image.mode, "RGB") - if "jpeg_decoder" in dir(Image.core): - target = Image.open("Tests/images/pil_sample_rgb.jpg") - self.assert_image_similar(cmyk_image, target, 10) + if "jpeg_decoder" in dir(Image.core): + target = Image.open("Tests/images/pil_sample_rgb.jpg") + self.assert_image_similar(cmyk_image, target, 10) @unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available") def test_showpage(self): # See https://github.com/python-pillow/Pillow/issues/2615 - plot_image = Image.open("Tests/images/reqd_showpage.eps") - target = Image.open("Tests/images/reqd_showpage.png") - - # should not crash/hang - plot_image.load() - # fonts could be slightly different - self.assert_image_similar(plot_image, target, 6) + with Image.open("Tests/images/reqd_showpage.eps") as plot_image: + with Image.open("Tests/images/reqd_showpage.png") as target: + # should not crash/hang + plot_image.load() + # fonts could be slightly different + self.assert_image_similar(plot_image, target, 6) @unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available") def test_file_object(self): # issue 479 - image1 = Image.open(file1) - with open(self.tempfile("temp_file.eps"), "wb") as fh: - image1.save(fh, "EPS") + with Image.open(file1) as image1: + with open(self.tempfile("temp_file.eps"), "wb") as fh: + image1.save(fh, "EPS") @unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available") def test_iobase_object(self): # issue 479 - image1 = Image.open(file1) - with io.open(self.tempfile("temp_iobase.eps"), "wb") as fh: - image1.save(fh, "EPS") + with Image.open(file1) as image1: + with io.open(self.tempfile("temp_iobase.eps"), "wb") as fh: + image1.save(fh, "EPS") @unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available") def test_bytesio_object(self): @@ -120,18 +119,18 @@ class TestFileEps(PillowTestCase): self.skipTest("zip/deflate support not available") # Zero bounding box - image1_scale1 = Image.open(file1) - image1_scale1.load() - image1_scale1_compare = Image.open(file1_compare).convert("RGB") - image1_scale1_compare.load() - self.assert_image_similar(image1_scale1, image1_scale1_compare, 5) + with Image.open(file1) as image1_scale1: + image1_scale1.load() + image1_scale1_compare = Image.open(file1_compare).convert("RGB") + image1_scale1_compare.load() + self.assert_image_similar(image1_scale1, image1_scale1_compare, 5) # Non-Zero bounding box - image2_scale1 = Image.open(file2) - image2_scale1.load() - image2_scale1_compare = Image.open(file2_compare).convert("RGB") - image2_scale1_compare.load() - self.assert_image_similar(image2_scale1, image2_scale1_compare, 10) + with Image.open(file2) as image2_scale1: + image2_scale1.load() + image2_scale1_compare = Image.open(file2_compare).convert("RGB") + image2_scale1_compare.load() + self.assert_image_similar(image2_scale1, image2_scale1_compare, 10) @unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available") def test_render_scale2(self): @@ -141,57 +140,44 @@ class TestFileEps(PillowTestCase): self.skipTest("zip/deflate support not available") # Zero bounding box - image1_scale2 = Image.open(file1) - image1_scale2.load(scale=2) - image1_scale2_compare = Image.open(file1_compare_scale2).convert("RGB") - image1_scale2_compare.load() - self.assert_image_similar(image1_scale2, image1_scale2_compare, 5) + with Image.open(file1) as image1_scale2: + image1_scale2.load(scale=2) + image1_scale2_compare = Image.open(file1_compare_scale2).convert("RGB") + image1_scale2_compare.load() + self.assert_image_similar(image1_scale2, image1_scale2_compare, 5) # Non-Zero bounding box - image2_scale2 = Image.open(file2) - image2_scale2.load(scale=2) - image2_scale2_compare = Image.open(file2_compare_scale2).convert("RGB") - image2_scale2_compare.load() - self.assert_image_similar(image2_scale2, image2_scale2_compare, 10) + with Image.open(file2) as image2_scale2: + image2_scale2.load(scale=2) + image2_scale2_compare = Image.open(file2_compare_scale2).convert("RGB") + image2_scale2_compare.load() + self.assert_image_similar(image2_scale2, image2_scale2_compare, 10) @unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available") def test_resize(self): - # Arrange - image1 = Image.open(file1) - image2 = Image.open(file2) - image3 = Image.open("Tests/images/illu10_preview.eps") - new_size = (100, 100) - - # Act - image1 = image1.resize(new_size) - image2 = image2.resize(new_size) - image3 = image3.resize(new_size) - - # Assert - self.assertEqual(image1.size, new_size) - self.assertEqual(image2.size, new_size) - self.assertEqual(image3.size, new_size) + files = [file1, file2, "Tests/images/illu10_preview.eps"] + for fn in files: + with Image.open(fn) as im: + new_size = (100, 100) + im = im.resize(new_size) + self.assertEqual(im.size, new_size) @unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available") def test_thumbnail(self): # Issue #619 # Arrange - image1 = Image.open(file1) - image2 = Image.open(file2) - new_size = (100, 100) - - # Act - image1.thumbnail(new_size) - image2.thumbnail(new_size) - - # Assert - self.assertEqual(max(image1.size), max(new_size)) - self.assertEqual(max(image2.size), max(new_size)) + files = [file1, file2] + for fn in files: + with Image.open(file1) as im: + new_size = (100, 100) + im.thumbnail(new_size) + self.assertEqual(max(im.size), max(new_size)) def test_read_binary_preview(self): # Issue 302 # open image with binary preview - Image.open(file3) + with Image.open(file3): + pass def _test_readline(self, t, ending): ending = "Failure with line ending: %s" % ( @@ -239,16 +225,16 @@ class TestFileEps(PillowTestCase): # Act / Assert for filename in FILES: - img = Image.open(filename) - self.assertEqual(img.mode, "RGB") + with Image.open(filename) as img: + self.assertEqual(img.mode, "RGB") @unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available") def test_emptyline(self): # Test file includes an empty line in the header data emptyline_file = "Tests/images/zero_bb_emptyline.eps" - image = Image.open(emptyline_file) - image.load() + with Image.open(emptyline_file) as image: + image.load() self.assertEqual(image.mode, "RGB") self.assertEqual(image.size, (460, 352)) self.assertEqual(image.format, "EPS") diff --git a/Tests/test_file_fitsstub.py b/Tests/test_file_fitsstub.py index 0221bab99..933e0fd12 100644 --- a/Tests/test_file_fitsstub.py +++ b/Tests/test_file_fitsstub.py @@ -8,14 +8,14 @@ TEST_FILE = "Tests/images/hopper.fits" class TestFileFitsStub(PillowTestCase): def test_open(self): # Act - im = Image.open(TEST_FILE) + with Image.open(TEST_FILE) as im: - # Assert - self.assertEqual(im.format, "FITS") + # Assert + self.assertEqual(im.format, "FITS") - # Dummy data from the stub - self.assertEqual(im.mode, "F") - self.assertEqual(im.size, (1, 1)) + # Dummy data from the stub + self.assertEqual(im.mode, "F") + self.assertEqual(im.size, (1, 1)) def test_invalid_file(self): # Arrange @@ -28,19 +28,19 @@ class TestFileFitsStub(PillowTestCase): def test_load(self): # Arrange - im = Image.open(TEST_FILE) + with Image.open(TEST_FILE) as im: - # Act / Assert: stub cannot load without an implemented handler - self.assertRaises(IOError, im.load) + # Act / Assert: stub cannot load without an implemented handler + self.assertRaises(IOError, im.load) def test_save(self): # Arrange - im = Image.open(TEST_FILE) - dummy_fp = None - dummy_filename = "dummy.filename" + with Image.open(TEST_FILE) as im: + dummy_fp = None + dummy_filename = "dummy.filename" - # Act / Assert: stub cannot save without an implemented handler - self.assertRaises(IOError, im.save, dummy_filename) - self.assertRaises( - IOError, FitsStubImagePlugin._save, im, dummy_fp, dummy_filename - ) + # Act / Assert: stub cannot save without an implemented handler + self.assertRaises(IOError, im.save, dummy_filename) + self.assertRaises( + IOError, FitsStubImagePlugin._save, im, dummy_fp, dummy_filename + ) diff --git a/Tests/test_file_fli.py b/Tests/test_file_fli.py index ad3e84a5b..895942d70 100644 --- a/Tests/test_file_fli.py +++ b/Tests/test_file_fli.py @@ -1,6 +1,8 @@ +import unittest + from PIL import FliImagePlugin, Image -from .helper import PillowTestCase +from .helper import PillowTestCase, is_pypy # created as an export of a palette image from Gimp2.6 # save as...-> hopper.fli, default options. @@ -12,36 +14,52 @@ animated_test_file = "Tests/images/a.fli" class TestFileFli(PillowTestCase): def test_sanity(self): - im = Image.open(static_test_file) - im.load() - self.assertEqual(im.mode, "P") - self.assertEqual(im.size, (128, 128)) - self.assertEqual(im.format, "FLI") - self.assertFalse(im.is_animated) + with Image.open(static_test_file) as im: + im.load() + self.assertEqual(im.mode, "P") + self.assertEqual(im.size, (128, 128)) + self.assertEqual(im.format, "FLI") + self.assertFalse(im.is_animated) - im = Image.open(animated_test_file) - self.assertEqual(im.mode, "P") - self.assertEqual(im.size, (320, 200)) - self.assertEqual(im.format, "FLI") - self.assertEqual(im.info["duration"], 71) - self.assertTrue(im.is_animated) + with Image.open(animated_test_file) as im: + self.assertEqual(im.mode, "P") + self.assertEqual(im.size, (320, 200)) + self.assertEqual(im.format, "FLI") + self.assertEqual(im.info["duration"], 71) + self.assertTrue(im.is_animated) + @unittest.skipIf(is_pypy(), "Requires CPython") def test_unclosed_file(self): def open(): im = Image.open(static_test_file) im.load() + self.assert_warning(ResourceWarning, open) + + def test_closed_file(self): + def open(): + im = Image.open(static_test_file) + im.load() + im.close() + + self.assert_warning(None, open) + + def test_context_manager(self): + def open(): + with Image.open(static_test_file) as im: + im.load() + self.assert_warning(None, open) def test_tell(self): # Arrange - im = Image.open(static_test_file) + with Image.open(static_test_file) as im: - # Act - frame = im.tell() + # Act + frame = im.tell() - # Assert - self.assertEqual(frame, 0) + # Assert + self.assertEqual(frame, 0) def test_invalid_file(self): invalid_file = "Tests/images/flower.jpg" @@ -49,50 +67,50 @@ class TestFileFli(PillowTestCase): self.assertRaises(SyntaxError, FliImagePlugin.FliImageFile, invalid_file) def test_n_frames(self): - im = Image.open(static_test_file) - self.assertEqual(im.n_frames, 1) - self.assertFalse(im.is_animated) + with Image.open(static_test_file) as im: + self.assertEqual(im.n_frames, 1) + self.assertFalse(im.is_animated) - im = Image.open(animated_test_file) - self.assertEqual(im.n_frames, 384) - self.assertTrue(im.is_animated) + with Image.open(animated_test_file) as im: + self.assertEqual(im.n_frames, 384) + self.assertTrue(im.is_animated) def test_eoferror(self): - im = Image.open(animated_test_file) - n_frames = im.n_frames + with Image.open(animated_test_file) as im: + n_frames = im.n_frames - # Test seeking past the last frame - self.assertRaises(EOFError, im.seek, n_frames) - self.assertLess(im.tell(), n_frames) + # Test seeking past the last frame + self.assertRaises(EOFError, im.seek, n_frames) + self.assertLess(im.tell(), n_frames) - # Test that seeking to the last frame does not raise an error - im.seek(n_frames - 1) + # Test that seeking to the last frame does not raise an error + im.seek(n_frames - 1) def test_seek_tell(self): - im = Image.open(animated_test_file) + with Image.open(animated_test_file) as im: - layer_number = im.tell() - self.assertEqual(layer_number, 0) + layer_number = im.tell() + self.assertEqual(layer_number, 0) - im.seek(0) - layer_number = im.tell() - self.assertEqual(layer_number, 0) + im.seek(0) + layer_number = im.tell() + self.assertEqual(layer_number, 0) - im.seek(1) - layer_number = im.tell() - self.assertEqual(layer_number, 1) + im.seek(1) + layer_number = im.tell() + self.assertEqual(layer_number, 1) - im.seek(2) - layer_number = im.tell() - self.assertEqual(layer_number, 2) + im.seek(2) + layer_number = im.tell() + self.assertEqual(layer_number, 2) - im.seek(1) - layer_number = im.tell() - self.assertEqual(layer_number, 1) + im.seek(1) + layer_number = im.tell() + self.assertEqual(layer_number, 1) def test_seek(self): - im = Image.open(animated_test_file) - im.seek(50) + with Image.open(animated_test_file) as im: + im.seek(50) - expected = Image.open("Tests/images/a_fli.png") - self.assert_image_equal(im, expected) + with Image.open("Tests/images/a_fli.png") as expected: + self.assert_image_equal(im, expected) diff --git a/Tests/test_file_gbr.py b/Tests/test_file_gbr.py index 659179a4e..4c26579a8 100644 --- a/Tests/test_file_gbr.py +++ b/Tests/test_file_gbr.py @@ -10,8 +10,6 @@ class TestFileGbr(PillowTestCase): self.assertRaises(SyntaxError, GbrImagePlugin.GbrImageFile, invalid_file) def test_gbr_file(self): - im = Image.open("Tests/images/gbr.gbr") - - target = Image.open("Tests/images/gbr.png") - - self.assert_image_equal(target, im) + with Image.open("Tests/images/gbr.gbr") as im: + with Image.open("Tests/images/gbr.png") as target: + self.assert_image_equal(target, im) diff --git a/Tests/test_file_gd.py b/Tests/test_file_gd.py index 6467d1e92..9208dcbff 100644 --- a/Tests/test_file_gd.py +++ b/Tests/test_file_gd.py @@ -7,9 +7,9 @@ TEST_GD_FILE = "Tests/images/hopper.gd" class TestFileGd(PillowTestCase): def test_sanity(self): - im = GdImageFile.open(TEST_GD_FILE) - self.assertEqual(im.size, (128, 128)) - self.assertEqual(im.format, "GD") + with GdImageFile.open(TEST_GD_FILE) as im: + self.assertEqual(im.size, (128, 128)) + self.assertEqual(im.format, "GD") def test_bad_mode(self): self.assertRaises(ValueError, GdImageFile.open, TEST_GD_FILE, "bad mode") diff --git a/Tests/test_file_gif.py b/Tests/test_file_gif.py index 4ff9727e1..7c1de5891 100644 --- a/Tests/test_file_gif.py +++ b/Tests/test_file_gif.py @@ -2,7 +2,7 @@ from io import BytesIO from PIL import GifImagePlugin, Image, ImageDraw, ImagePalette -from .helper import PillowTestCase, hopper, netpbm_available, unittest +from .helper import PillowTestCase, hopper, is_pypy, netpbm_available, unittest try: from PIL import _webp @@ -26,18 +26,34 @@ class TestFileGif(PillowTestCase): self.skipTest("gif support not available") # can this happen? def test_sanity(self): - im = Image.open(TEST_GIF) - im.load() - self.assertEqual(im.mode, "P") - self.assertEqual(im.size, (128, 128)) - self.assertEqual(im.format, "GIF") - self.assertEqual(im.info["version"], b"GIF89a") + with Image.open(TEST_GIF) as im: + im.load() + self.assertEqual(im.mode, "P") + self.assertEqual(im.size, (128, 128)) + self.assertEqual(im.format, "GIF") + self.assertEqual(im.info["version"], b"GIF89a") + @unittest.skipIf(is_pypy(), "Requires CPython") def test_unclosed_file(self): def open(): im = Image.open(TEST_GIF) im.load() + self.assert_warning(ResourceWarning, open) + + def test_closed_file(self): + def open(): + im = Image.open(TEST_GIF) + im.load() + im.close() + + self.assert_warning(None, open) + + def test_context_manager(self): + def open(): + with Image.open(TEST_GIF) as im: + im.load() + self.assert_warning(None, open) def test_invalid_file(self): @@ -112,67 +128,67 @@ class TestFileGif(PillowTestCase): out = self.tempfile("temp.gif") im = hopper() im.save(out) - reread = Image.open(out) + with Image.open(out) as reread: - self.assert_image_similar(reread.convert("RGB"), im, 50) + self.assert_image_similar(reread.convert("RGB"), im, 50) def test_roundtrip2(self): # see https://github.com/python-pillow/Pillow/issues/403 out = self.tempfile("temp.gif") - im = Image.open(TEST_GIF) - im2 = im.copy() - im2.save(out) - reread = Image.open(out) + with Image.open(TEST_GIF) as im: + im2 = im.copy() + im2.save(out) + with Image.open(out) as reread: - self.assert_image_similar(reread.convert("RGB"), hopper(), 50) + self.assert_image_similar(reread.convert("RGB"), hopper(), 50) def test_roundtrip_save_all(self): # Single frame image out = self.tempfile("temp.gif") im = hopper() im.save(out, save_all=True) - reread = Image.open(out) + with Image.open(out) as reread: - self.assert_image_similar(reread.convert("RGB"), im, 50) + self.assert_image_similar(reread.convert("RGB"), im, 50) # Multiframe image - im = Image.open("Tests/images/dispose_bgnd.gif") + with Image.open("Tests/images/dispose_bgnd.gif") as im: - out = self.tempfile("temp.gif") - im.save(out, save_all=True) - reread = Image.open(out) + out = self.tempfile("temp.gif") + im.save(out, save_all=True) + with Image.open(out) as reread: - self.assertEqual(reread.n_frames, 5) + self.assertEqual(reread.n_frames, 5) def test_headers_saving_for_animated_gifs(self): important_headers = ["background", "version", "duration", "loop"] # Multiframe image - im = Image.open("Tests/images/dispose_bgnd.gif") + with Image.open("Tests/images/dispose_bgnd.gif") as im: - info = im.info.copy() + info = im.info.copy() - out = self.tempfile("temp.gif") - im.save(out, save_all=True) - reread = Image.open(out) + out = self.tempfile("temp.gif") + im.save(out, save_all=True) + with Image.open(out) as reread: - for header in important_headers: - self.assertEqual(info[header], reread.info[header]) + for header in important_headers: + self.assertEqual(info[header], reread.info[header]) def test_palette_handling(self): # see https://github.com/python-pillow/Pillow/issues/513 - im = Image.open(TEST_GIF) - im = im.convert("RGB") + with Image.open(TEST_GIF) as im: + im = im.convert("RGB") - im = im.resize((100, 100), Image.LANCZOS) - im2 = im.convert("P", palette=Image.ADAPTIVE, colors=256) + im = im.resize((100, 100), Image.LANCZOS) + im2 = im.convert("P", palette=Image.ADAPTIVE, colors=256) - f = self.tempfile("temp.gif") - im2.save(f, optimize=True) + f = self.tempfile("temp.gif") + im2.save(f, optimize=True) - reloaded = Image.open(f) + with Image.open(f) as reloaded: - self.assert_image_similar(im, reloaded.convert("RGB"), 10) + self.assert_image_similar(im, reloaded.convert("RGB"), 10) def test_palette_434(self): # see https://github.com/python-pillow/Pillow/issues/434 @@ -185,108 +201,115 @@ class TestFileGif(PillowTestCase): return reloaded orig = "Tests/images/test.colors.gif" - im = Image.open(orig) + with Image.open(orig) as im: - self.assert_image_similar(im, roundtrip(im), 1) - self.assert_image_similar(im, roundtrip(im, optimize=True), 1) + with roundtrip(im) as reloaded: + self.assert_image_similar(im, reloaded, 1) + with roundtrip(im, optimize=True) as reloaded: + self.assert_image_similar(im, reloaded, 1) - im = im.convert("RGB") - # check automatic P conversion - reloaded = roundtrip(im).convert("RGB") - self.assert_image_equal(im, reloaded) + im = im.convert("RGB") + # check automatic P conversion + with roundtrip(im) as reloaded: + reloaded = reloaded.convert("RGB") + self.assert_image_equal(im, reloaded) @unittest.skipUnless(netpbm_available(), "netpbm not available") def test_save_netpbm_bmp_mode(self): - img = Image.open(TEST_GIF).convert("RGB") + with Image.open(TEST_GIF) as img: + img = img.convert("RGB") - tempfile = self.tempfile("temp.gif") - GifImagePlugin._save_netpbm(img, 0, tempfile) - self.assert_image_similar(img, Image.open(tempfile).convert("RGB"), 0) + tempfile = self.tempfile("temp.gif") + GifImagePlugin._save_netpbm(img, 0, tempfile) + with Image.open(tempfile) as reloaded: + self.assert_image_similar(img, reloaded.convert("RGB"), 0) @unittest.skipUnless(netpbm_available(), "netpbm not available") def test_save_netpbm_l_mode(self): - img = Image.open(TEST_GIF).convert("L") + with Image.open(TEST_GIF) as img: + img = img.convert("L") - tempfile = self.tempfile("temp.gif") - GifImagePlugin._save_netpbm(img, 0, tempfile) - self.assert_image_similar(img, Image.open(tempfile).convert("L"), 0) + tempfile = self.tempfile("temp.gif") + GifImagePlugin._save_netpbm(img, 0, tempfile) + with Image.open(tempfile) as reloaded: + self.assert_image_similar(img, reloaded.convert("L"), 0) def test_seek(self): - img = Image.open("Tests/images/dispose_none.gif") - framecount = 0 - try: - while True: - framecount += 1 - img.seek(img.tell() + 1) - except EOFError: - self.assertEqual(framecount, 5) + with Image.open("Tests/images/dispose_none.gif") as img: + framecount = 0 + try: + while True: + framecount += 1 + img.seek(img.tell() + 1) + except EOFError: + self.assertEqual(framecount, 5) def test_seek_info(self): - im = Image.open("Tests/images/iss634.gif") - info = im.info.copy() + with Image.open("Tests/images/iss634.gif") as im: + info = im.info.copy() - im.seek(1) - im.seek(0) + im.seek(1) + im.seek(0) - self.assertEqual(im.info, info) + self.assertEqual(im.info, info) def test_seek_rewind(self): - im = Image.open("Tests/images/iss634.gif") - im.seek(2) - im.seek(1) + with Image.open("Tests/images/iss634.gif") as im: + im.seek(2) + im.seek(1) - expected = Image.open("Tests/images/iss634.gif") - expected.seek(1) - self.assert_image_equal(im, expected) + with Image.open("Tests/images/iss634.gif") as expected: + expected.seek(1) + self.assert_image_equal(im, expected) def test_n_frames(self): for path, n_frames in [[TEST_GIF, 1], ["Tests/images/iss634.gif", 42]]: # Test is_animated before n_frames - im = Image.open(path) - self.assertEqual(im.is_animated, n_frames != 1) + with Image.open(path) as im: + self.assertEqual(im.is_animated, n_frames != 1) # Test is_animated after n_frames - im = Image.open(path) - self.assertEqual(im.n_frames, n_frames) - self.assertEqual(im.is_animated, n_frames != 1) + with Image.open(path) as im: + self.assertEqual(im.n_frames, n_frames) + self.assertEqual(im.is_animated, n_frames != 1) def test_eoferror(self): - im = Image.open(TEST_GIF) - n_frames = im.n_frames + with Image.open(TEST_GIF) as im: + n_frames = im.n_frames - # Test seeking past the last frame - self.assertRaises(EOFError, im.seek, n_frames) - self.assertLess(im.tell(), n_frames) + # Test seeking past the last frame + self.assertRaises(EOFError, im.seek, n_frames) + self.assertLess(im.tell(), n_frames) - # Test that seeking to the last frame does not raise an error - im.seek(n_frames - 1) + # Test that seeking to the last frame does not raise an error + im.seek(n_frames - 1) def test_dispose_none(self): - img = Image.open("Tests/images/dispose_none.gif") - try: - while True: - img.seek(img.tell() + 1) - self.assertEqual(img.disposal_method, 1) - except EOFError: - pass + with Image.open("Tests/images/dispose_none.gif") as img: + try: + while True: + img.seek(img.tell() + 1) + self.assertEqual(img.disposal_method, 1) + except EOFError: + pass def test_dispose_background(self): - img = Image.open("Tests/images/dispose_bgnd.gif") - try: - while True: - img.seek(img.tell() + 1) - self.assertEqual(img.disposal_method, 2) - except EOFError: - pass + with Image.open("Tests/images/dispose_bgnd.gif") as img: + try: + while True: + img.seek(img.tell() + 1) + self.assertEqual(img.disposal_method, 2) + except EOFError: + pass def test_dispose_previous(self): - img = Image.open("Tests/images/dispose_prev.gif") - try: - while True: - img.seek(img.tell() + 1) - self.assertEqual(img.disposal_method, 3) - except EOFError: - pass + with Image.open("Tests/images/dispose_prev.gif") as img: + try: + while True: + img.seek(img.tell() + 1) + self.assertEqual(img.disposal_method, 3) + except EOFError: + pass def test_save_dispose(self): out = self.tempfile("temp.gif") @@ -299,10 +322,10 @@ class TestFileGif(PillowTestCase): im_list[0].save( out, save_all=True, append_images=im_list[1:], disposal=method ) - img = Image.open(out) - for _ in range(2): - img.seek(img.tell() + 1) - self.assertEqual(img.disposal_method, method) + with Image.open(out) as img: + for _ in range(2): + img.seek(img.tell() + 1) + self.assertEqual(img.disposal_method, method) # check per frame disposal im_list[0].save( @@ -312,11 +335,11 @@ class TestFileGif(PillowTestCase): disposal=tuple(range(len(im_list))), ) - img = Image.open(out) + with Image.open(out) as img: - for i in range(2): - img.seek(img.tell() + 1) - self.assertEqual(img.disposal_method, i + 1) + for i in range(2): + img.seek(img.tell() + 1) + self.assertEqual(img.disposal_method, i + 1) def test_dispose2_palette(self): out = self.tempfile("temp.gif") @@ -336,17 +359,16 @@ class TestFileGif(PillowTestCase): im_list[0].save(out, save_all=True, append_images=im_list[1:], disposal=2) - img = Image.open(out) + with Image.open(out) as img: + for i, circle in enumerate(circles): + img.seek(i) + rgb_img = img.convert("RGB") - for i, circle in enumerate(circles): - img.seek(i) - rgb_img = img.convert("RGB") + # Check top left pixel matches background + self.assertEqual(rgb_img.getpixel((0, 0)), (255, 0, 0)) - # Check top left pixel matches background - self.assertEqual(rgb_img.getpixel((0, 0)), (255, 0, 0)) - - # Center remains red every frame - self.assertEqual(rgb_img.getpixel((50, 50)), circle) + # Center remains red every frame + self.assertEqual(rgb_img.getpixel((50, 50)), circle) def test_dispose2_diff(self): out = self.tempfile("temp.gif") @@ -375,20 +397,19 @@ class TestFileGif(PillowTestCase): out, save_all=True, append_images=im_list[1:], disposal=2, transparency=0 ) - img = Image.open(out) + with Image.open(out) as img: + for i, colours in enumerate(circles): + img.seek(i) + rgb_img = img.convert("RGBA") - for i, colours in enumerate(circles): - img.seek(i) - rgb_img = img.convert("RGBA") + # Check left circle is correct colour + self.assertEqual(rgb_img.getpixel((20, 50)), colours[0]) - # Check left circle is correct colour - self.assertEqual(rgb_img.getpixel((20, 50)), colours[0]) + # Check right circle is correct colour + self.assertEqual(rgb_img.getpixel((80, 50)), colours[1]) - # Check right circle is correct colour - self.assertEqual(rgb_img.getpixel((80, 50)), colours[1]) - - # Check BG is correct colour - self.assertEqual(rgb_img.getpixel((1, 1)), (255, 255, 255, 0)) + # Check BG is correct colour + self.assertEqual(rgb_img.getpixel((1, 1)), (255, 255, 255, 0)) def test_dispose2_background(self): out = self.tempfile("temp.gif") @@ -411,17 +432,17 @@ class TestFileGif(PillowTestCase): out, save_all=True, append_images=im_list[1:], disposal=[0, 2], background=1 ) - im = Image.open(out) - im.seek(1) - self.assertEqual(im.getpixel((0, 0)), 0) + with Image.open(out) as im: + im.seek(1) + self.assertEqual(im.getpixel((0, 0)), 0) def test_iss634(self): - img = Image.open("Tests/images/iss634.gif") - # seek to the second frame - img.seek(img.tell() + 1) - # all transparent pixels should be replaced with the color from the - # first frame - self.assertEqual(img.histogram()[img.info["transparency"]], 0) + with Image.open("Tests/images/iss634.gif") as img: + # seek to the second frame + img.seek(img.tell() + 1) + # all transparent pixels should be replaced with the color from the + # first frame + self.assertEqual(img.histogram()[img.info["transparency"]], 0) def test_duration(self): duration = 1000 @@ -433,8 +454,8 @@ class TestFileGif(PillowTestCase): im.info["duration"] = 100 im.save(out, duration=duration) - reread = Image.open(out) - self.assertEqual(reread.info["duration"], duration) + with Image.open(out) as reread: + self.assertEqual(reread.info["duration"], duration) def test_multiple_duration(self): duration_list = [1000, 2000, 3000] @@ -450,27 +471,27 @@ class TestFileGif(PillowTestCase): im_list[0].save( out, save_all=True, append_images=im_list[1:], duration=duration_list ) - reread = Image.open(out) + with Image.open(out) as reread: - for duration in duration_list: - self.assertEqual(reread.info["duration"], duration) - try: - reread.seek(reread.tell() + 1) - except EOFError: - pass + for duration in duration_list: + self.assertEqual(reread.info["duration"], duration) + try: + reread.seek(reread.tell() + 1) + except EOFError: + pass # duration as tuple im_list[0].save( out, save_all=True, append_images=im_list[1:], duration=tuple(duration_list) ) - reread = Image.open(out) + with Image.open(out) as reread: - for duration in duration_list: - self.assertEqual(reread.info["duration"], duration) - try: - reread.seek(reread.tell() + 1) - except EOFError: - pass + for duration in duration_list: + self.assertEqual(reread.info["duration"], duration) + try: + reread.seek(reread.tell() + 1) + except EOFError: + pass def test_identical_frames(self): duration_list = [1000, 1500, 2000, 4000] @@ -487,13 +508,13 @@ class TestFileGif(PillowTestCase): im_list[0].save( out, save_all=True, append_images=im_list[1:], duration=duration_list ) - reread = Image.open(out) + with Image.open(out) as reread: - # Assert that the first three frames were combined - self.assertEqual(reread.n_frames, 2) + # Assert that the first three frames were combined + self.assertEqual(reread.n_frames, 2) - # Assert that the new duration is the total of the identical frames - self.assertEqual(reread.info["duration"], 4500) + # Assert that the new duration is the total of the identical frames + self.assertEqual(reread.info["duration"], 4500) def test_identical_frames_to_single_frame(self): for duration in ([1000, 1500, 2000, 4000], (1000, 1500, 2000, 4000), 8500): @@ -507,13 +528,12 @@ class TestFileGif(PillowTestCase): im_list[0].save( out, save_all=True, append_images=im_list[1:], duration=duration ) - reread = Image.open(out) + with Image.open(out) as reread: + # Assert that all frames were combined + self.assertEqual(reread.n_frames, 1) - # Assert that all frames were combined - self.assertEqual(reread.n_frames, 1) - - # Assert that the new duration is the total of the identical frames - self.assertEqual(reread.info["duration"], 8500) + # Assert that the new duration is the total of the identical frames + self.assertEqual(reread.info["duration"], 8500) def test_number_of_loops(self): number_of_loops = 2 @@ -521,18 +541,18 @@ class TestFileGif(PillowTestCase): out = self.tempfile("temp.gif") im = Image.new("L", (100, 100), "#000") im.save(out, loop=number_of_loops) - reread = Image.open(out) + with Image.open(out) as reread: - self.assertEqual(reread.info["loop"], number_of_loops) + self.assertEqual(reread.info["loop"], number_of_loops) def test_background(self): out = self.tempfile("temp.gif") im = Image.new("L", (100, 100), "#000") im.info["background"] = 1 im.save(out) - reread = Image.open(out) + with Image.open(out) as reread: - self.assertEqual(reread.info["background"], im.info["background"]) + self.assertEqual(reread.info["background"], im.info["background"]) if HAVE_WEBP and _webp.HAVE_WEBPANIM: im = Image.open("Tests/images/hopper.webp") @@ -540,16 +560,18 @@ class TestFileGif(PillowTestCase): im.save(out) def test_comment(self): - im = Image.open(TEST_GIF) - self.assertEqual(im.info["comment"], b"File written by Adobe Photoshop\xa8 4.0") + with Image.open(TEST_GIF) as im: + self.assertEqual( + im.info["comment"], b"File written by Adobe Photoshop\xa8 4.0" + ) - out = self.tempfile("temp.gif") - im = Image.new("L", (100, 100), "#000") - im.info["comment"] = b"Test comment text" - im.save(out) - reread = Image.open(out) + out = self.tempfile("temp.gif") + im = Image.new("L", (100, 100), "#000") + im.info["comment"] = b"Test comment text" + im.save(out) + with Image.open(out) as reread: - self.assertEqual(reread.info["comment"], im.info["comment"]) + self.assertEqual(reread.info["comment"], im.info["comment"]) def test_comment_over_255(self): out = self.tempfile("temp.gif") @@ -559,22 +581,22 @@ class TestFileGif(PillowTestCase): comment += comment im.info["comment"] = comment im.save(out) - reread = Image.open(out) + with Image.open(out) as reread: - self.assertEqual(reread.info["comment"], comment) + self.assertEqual(reread.info["comment"], comment) def test_zero_comment_subblocks(self): - im = Image.open("Tests/images/hopper_zero_comment_subblocks.gif") - expected = Image.open(TEST_GIF) - self.assert_image_equal(im, expected) + with Image.open("Tests/images/hopper_zero_comment_subblocks.gif") as im: + with Image.open(TEST_GIF) as expected: + self.assert_image_equal(im, expected) def test_version(self): out = self.tempfile("temp.gif") def assertVersionAfterSave(im, version): im.save(out) - reread = Image.open(out) - self.assertEqual(reread.info["version"], version) + with Image.open(out) as reread: + self.assertEqual(reread.info["version"], version) # Test that GIF87a is used by default im = Image.new("L", (100, 100), "#000") @@ -590,12 +612,12 @@ class TestFileGif(PillowTestCase): assertVersionAfterSave(im, b"GIF89a") # Test that a GIF87a image is also saved in that format - im = Image.open("Tests/images/test.colors.gif") - assertVersionAfterSave(im, b"GIF87a") + with Image.open("Tests/images/test.colors.gif") as im: + assertVersionAfterSave(im, b"GIF87a") - # Test that a GIF89a image is also saved in that format - im.info["version"] = b"GIF89a" - assertVersionAfterSave(im, b"GIF87a") + # Test that a GIF89a image is also saved in that format + im.info["version"] = b"GIF89a" + assertVersionAfterSave(im, b"GIF87a") def test_append_images(self): out = self.tempfile("temp.gif") @@ -605,8 +627,8 @@ class TestFileGif(PillowTestCase): ims = [Image.new("RGB", (100, 100), color) for color in ["#0f0", "#00f"]] im.copy().save(out, save_all=True, append_images=ims) - reread = Image.open(out) - self.assertEqual(reread.n_frames, 3) + with Image.open(out) as reread: + self.assertEqual(reread.n_frames, 3) # Tests appending using a generator def imGenerator(ims): @@ -615,16 +637,16 @@ class TestFileGif(PillowTestCase): im.save(out, save_all=True, append_images=imGenerator(ims)) - reread = Image.open(out) - self.assertEqual(reread.n_frames, 3) + with Image.open(out) as reread: + self.assertEqual(reread.n_frames, 3) # Tests appending single and multiple frame images - im = Image.open("Tests/images/dispose_none.gif") - ims = [Image.open("Tests/images/dispose_prev.gif")] - im.save(out, save_all=True, append_images=ims) + with Image.open("Tests/images/dispose_none.gif") as im: + with Image.open("Tests/images/dispose_prev.gif") as im2: + im.save(out, save_all=True, append_images=[im2]) - reread = Image.open(out) - self.assertEqual(reread.n_frames, 10) + with Image.open(out) as reread: + self.assertEqual(reread.n_frames, 10) def test_transparent_optimize(self): # from issue #2195, if the transparent color is incorrectly @@ -642,9 +664,9 @@ class TestFileGif(PillowTestCase): out = self.tempfile("temp.gif") im.save(out, transparency=253) - reloaded = Image.open(out) + with Image.open(out) as reloaded: - self.assertEqual(reloaded.info["transparency"], 253) + self.assertEqual(reloaded.info["transparency"], 253) def test_rgb_transparency(self): out = self.tempfile("temp.gif") @@ -654,8 +676,8 @@ class TestFileGif(PillowTestCase): im.info["transparency"] = (255, 0, 0) self.assert_warning(UserWarning, im.save, out) - reloaded = Image.open(out) - self.assertNotIn("transparency", reloaded.info) + with Image.open(out) as reloaded: + self.assertNotIn("transparency", reloaded.info) # Multiple frames im = Image.new("RGB", (1, 1)) @@ -663,8 +685,8 @@ class TestFileGif(PillowTestCase): ims = [Image.new("RGB", (1, 1))] self.assert_warning(UserWarning, im.save, out, save_all=True, append_images=ims) - reloaded = Image.open(out) - self.assertNotIn("transparency", reloaded.info) + with Image.open(out) as reloaded: + self.assertNotIn("transparency", reloaded.info) def test_bbox(self): out = self.tempfile("temp.gif") @@ -673,8 +695,8 @@ class TestFileGif(PillowTestCase): ims = [Image.new("RGB", (100, 100), "#000")] im.save(out, save_all=True, append_images=ims) - reread = Image.open(out) - self.assertEqual(reread.n_frames, 2) + with Image.open(out) as reread: + self.assertEqual(reread.n_frames, 2) def test_palette_save_L(self): # generate an L mode image with a separate palette @@ -686,9 +708,9 @@ class TestFileGif(PillowTestCase): out = self.tempfile("temp.gif") im_l.save(out, palette=palette) - reloaded = Image.open(out) + with Image.open(out) as reloaded: - self.assert_image_equal(reloaded.convert("RGB"), im.convert("RGB")) + self.assert_image_equal(reloaded.convert("RGB"), im.convert("RGB")) def test_palette_save_P(self): # pass in a different palette, then construct what the image @@ -701,9 +723,9 @@ class TestFileGif(PillowTestCase): out = self.tempfile("temp.gif") im.save(out, palette=palette) - reloaded = Image.open(out) - im.putpalette(palette) - self.assert_image_equal(reloaded, im) + with Image.open(out) as reloaded: + im.putpalette(palette) + self.assert_image_equal(reloaded, im) def test_palette_save_ImagePalette(self): # pass in a different palette, as an ImagePalette.ImagePalette @@ -715,9 +737,9 @@ class TestFileGif(PillowTestCase): out = self.tempfile("temp.gif") im.save(out, palette=palette) - reloaded = Image.open(out) - im.putpalette(palette) - self.assert_image_equal(reloaded, im) + with Image.open(out) as reloaded: + im.putpalette(palette) + self.assert_image_equal(reloaded, im) def test_save_I(self): # Test saving something that would trigger the auto-convert to 'L' @@ -727,8 +749,8 @@ class TestFileGif(PillowTestCase): out = self.tempfile("temp.gif") im.save(out) - reloaded = Image.open(out) - self.assert_image_equal(reloaded.convert("L"), im.convert("L")) + with Image.open(out) as reloaded: + self.assert_image_equal(reloaded.convert("L"), im.convert("L")) def test_getdata(self): # test getheader/getdata against legacy values @@ -759,14 +781,13 @@ class TestFileGif(PillowTestCase): def test_lzw_bits(self): # see https://github.com/python-pillow/Pillow/issues/2811 - im = Image.open("Tests/images/issue_2811.gif") - - self.assertEqual(im.tile[0][3][0], 11) # LZW bits - # codec error prepatch - im.load() + with Image.open("Tests/images/issue_2811.gif") as im: + self.assertEqual(im.tile[0][3][0], 11) # LZW bits + # codec error prepatch + im.load() def test_extents(self): - im = Image.open("Tests/images/test_extents.gif") - self.assertEqual(im.size, (100, 100)) - im.seek(1) - self.assertEqual(im.size, (150, 150)) + with Image.open("Tests/images/test_extents.gif") as im: + self.assertEqual(im.size, (100, 100)) + im.seek(1) + self.assertEqual(im.size, (150, 150)) diff --git a/Tests/test_file_gribstub.py b/Tests/test_file_gribstub.py index d322e1c70..92d112ced 100644 --- a/Tests/test_file_gribstub.py +++ b/Tests/test_file_gribstub.py @@ -8,14 +8,14 @@ TEST_FILE = "Tests/images/WAlaska.wind.7days.grb" class TestFileGribStub(PillowTestCase): def test_open(self): # Act - im = Image.open(TEST_FILE) + with Image.open(TEST_FILE) as im: - # Assert - self.assertEqual(im.format, "GRIB") + # Assert + self.assertEqual(im.format, "GRIB") - # Dummy data from the stub - self.assertEqual(im.mode, "F") - self.assertEqual(im.size, (1, 1)) + # Dummy data from the stub + self.assertEqual(im.mode, "F") + self.assertEqual(im.size, (1, 1)) def test_invalid_file(self): # Arrange @@ -28,10 +28,10 @@ class TestFileGribStub(PillowTestCase): def test_load(self): # Arrange - im = Image.open(TEST_FILE) + with Image.open(TEST_FILE) as im: - # Act / Assert: stub cannot load without an implemented handler - self.assertRaises(IOError, im.load) + # Act / Assert: stub cannot load without an implemented handler + self.assertRaises(IOError, im.load) def test_save(self): # Arrange diff --git a/Tests/test_file_hdf5stub.py b/Tests/test_file_hdf5stub.py index c300bae20..cdaad0cf7 100644 --- a/Tests/test_file_hdf5stub.py +++ b/Tests/test_file_hdf5stub.py @@ -8,14 +8,14 @@ TEST_FILE = "Tests/images/hdf5.h5" class TestFileHdf5Stub(PillowTestCase): def test_open(self): # Act - im = Image.open(TEST_FILE) + with Image.open(TEST_FILE) as im: - # Assert - self.assertEqual(im.format, "HDF5") + # Assert + self.assertEqual(im.format, "HDF5") - # Dummy data from the stub - self.assertEqual(im.mode, "F") - self.assertEqual(im.size, (1, 1)) + # Dummy data from the stub + self.assertEqual(im.mode, "F") + self.assertEqual(im.size, (1, 1)) def test_invalid_file(self): # Arrange @@ -28,19 +28,19 @@ class TestFileHdf5Stub(PillowTestCase): def test_load(self): # Arrange - im = Image.open(TEST_FILE) + with Image.open(TEST_FILE) as im: - # Act / Assert: stub cannot load without an implemented handler - self.assertRaises(IOError, im.load) + # Act / Assert: stub cannot load without an implemented handler + self.assertRaises(IOError, im.load) def test_save(self): # Arrange - im = Image.open(TEST_FILE) - dummy_fp = None - dummy_filename = "dummy.filename" + with Image.open(TEST_FILE) as im: + dummy_fp = None + dummy_filename = "dummy.filename" - # Act / Assert: stub cannot save without an implemented handler - self.assertRaises(IOError, im.save, dummy_filename) - self.assertRaises( - IOError, Hdf5StubImagePlugin._save, im, dummy_fp, dummy_filename - ) + # Act / Assert: stub cannot save without an implemented handler + self.assertRaises(IOError, im.save, dummy_filename) + self.assertRaises( + IOError, Hdf5StubImagePlugin._save, im, dummy_fp, dummy_filename + ) diff --git a/Tests/test_file_icns.py b/Tests/test_file_icns.py index 2e33e0ae5..4d7f95ec3 100644 --- a/Tests/test_file_icns.py +++ b/Tests/test_file_icns.py @@ -15,14 +15,14 @@ class TestFileIcns(PillowTestCase): def test_sanity(self): # Loading this icon by default should result in the largest size # (512x512@2x) being loaded - im = Image.open(TEST_FILE) + with Image.open(TEST_FILE) as im: - # Assert that there is no unclosed file warning - self.assert_warning(None, im.load) + # Assert that there is no unclosed file warning + self.assert_warning(None, im.load) - self.assertEqual(im.mode, "RGBA") - self.assertEqual(im.size, (1024, 1024)) - self.assertEqual(im.format, "ICNS") + self.assertEqual(im.mode, "RGBA") + self.assertEqual(im.size, (1024, 1024)) + self.assertEqual(im.format, "ICNS") @unittest.skipIf(sys.platform != "darwin", "requires macOS") def test_save(self): @@ -56,31 +56,31 @@ class TestFileIcns(PillowTestCase): def test_sizes(self): # Check that we can load all of the sizes, and that the final pixel # dimensions are as expected - im = Image.open(TEST_FILE) - for w, h, r in im.info["sizes"]: - wr = w * r - hr = h * r - im.size = (w, h, r) - im.load() - self.assertEqual(im.mode, "RGBA") - self.assertEqual(im.size, (wr, hr)) + with Image.open(TEST_FILE) as im: + for w, h, r in im.info["sizes"]: + wr = w * r + hr = h * r + im.size = (w, h, r) + im.load() + self.assertEqual(im.mode, "RGBA") + self.assertEqual(im.size, (wr, hr)) - # Check that we cannot load an incorrect size - with self.assertRaises(ValueError): - im.size = (1, 1) + # Check that we cannot load an incorrect size + with self.assertRaises(ValueError): + im.size = (1, 1) def test_older_icon(self): # This icon was made with Icon Composer rather than iconutil; it still # uses PNG rather than JP2, however (since it was made on 10.9). - im = Image.open("Tests/images/pillow2.icns") - for w, h, r in im.info["sizes"]: - wr = w * r - hr = h * r - im2 = Image.open("Tests/images/pillow2.icns") - im2.size = (w, h, r) - im2.load() - self.assertEqual(im2.mode, "RGBA") - self.assertEqual(im2.size, (wr, hr)) + with Image.open("Tests/images/pillow2.icns") as im: + for w, h, r in im.info["sizes"]: + wr = w * r + hr = h * r + with Image.open("Tests/images/pillow2.icns") as im2: + im2.size = (w, h, r) + im2.load() + self.assertEqual(im2.mode, "RGBA") + self.assertEqual(im2.size, (wr, hr)) def test_jp2_icon(self): # This icon was made by using Uli Kusterer's oldiconutil to replace @@ -93,15 +93,15 @@ class TestFileIcns(PillowTestCase): if not enable_jpeg2k: return - im = Image.open("Tests/images/pillow3.icns") - for w, h, r in im.info["sizes"]: - wr = w * r - hr = h * r - im2 = Image.open("Tests/images/pillow3.icns") - im2.size = (w, h, r) - im2.load() - self.assertEqual(im2.mode, "RGBA") - self.assertEqual(im2.size, (wr, hr)) + with Image.open("Tests/images/pillow3.icns") as im: + for w, h, r in im.info["sizes"]: + wr = w * r + hr = h * r + with Image.open("Tests/images/pillow3.icns") as im2: + im2.size = (w, h, r) + im2.load() + self.assertEqual(im2.mode, "RGBA") + self.assertEqual(im2.size, (wr, hr)) def test_getimage(self): with open(TEST_FILE, "rb") as fp: diff --git a/Tests/test_file_ico.py b/Tests/test_file_ico.py index 8a01e417f..ac6b19041 100644 --- a/Tests/test_file_ico.py +++ b/Tests/test_file_ico.py @@ -9,8 +9,8 @@ TEST_ICO_FILE = "Tests/images/hopper.ico" class TestFileIco(PillowTestCase): def test_sanity(self): - im = Image.open(TEST_ICO_FILE) - im.load() + with Image.open(TEST_ICO_FILE) as im: + im.load() self.assertEqual(im.mode, "RGBA") self.assertEqual(im.size, (16, 16)) self.assertEqual(im.format, "ICO") @@ -46,22 +46,22 @@ class TestFileIco(PillowTestCase): self.assert_image_equal(reloaded, hopper().resize((32, 32), Image.LANCZOS)) def test_incorrect_size(self): - im = Image.open(TEST_ICO_FILE) - with self.assertRaises(ValueError): - im.size = (1, 1) + with Image.open(TEST_ICO_FILE) as im: + with self.assertRaises(ValueError): + im.size = (1, 1) def test_save_256x256(self): """Issue #2264 https://github.com/python-pillow/Pillow/issues/2264""" # Arrange - im = Image.open("Tests/images/hopper_256x256.ico") - outfile = self.tempfile("temp_saved_hopper_256x256.ico") + with Image.open("Tests/images/hopper_256x256.ico") as im: + outfile = self.tempfile("temp_saved_hopper_256x256.ico") - # Act - im.save(outfile) - im_saved = Image.open(outfile) + # Act + im.save(outfile) + with Image.open(outfile) as im_saved: - # Assert - self.assertEqual(im_saved.size, (256, 256)) + # Assert + self.assertEqual(im_saved.size, (256, 256)) def test_only_save_relevant_sizes(self): """Issue #2266 https://github.com/python-pillow/Pillow/issues/2266 @@ -69,35 +69,35 @@ class TestFileIco(PillowTestCase): and not in 16x16, 24x24, 32x32, 48x48, 48x48, 48x48, 48x48 sizes """ # Arrange - im = Image.open("Tests/images/python.ico") # 16x16, 32x32, 48x48 - outfile = self.tempfile("temp_saved_python.ico") + with Image.open("Tests/images/python.ico") as im: # 16x16, 32x32, 48x48 + outfile = self.tempfile("temp_saved_python.ico") + # Act + im.save(outfile) - # Act - im.save(outfile) - im_saved = Image.open(outfile) - - # Assert - self.assertEqual( - im_saved.info["sizes"], {(16, 16), (24, 24), (32, 32), (48, 48)} - ) + with Image.open(outfile) as im_saved: + # Assert + self.assertEqual( + im_saved.info["sizes"], {(16, 16), (24, 24), (32, 32), (48, 48)} + ) def test_unexpected_size(self): # This image has been manually hexedited to state that it is 16x32 # while the image within is still 16x16 - im = self.assert_warning( - UserWarning, Image.open, "Tests/images/hopper_unexpected.ico" - ) - self.assertEqual(im.size, (16, 16)) + def open(): + with Image.open("Tests/images/hopper_unexpected.ico") as im: + self.assertEqual(im.size, (16, 16)) + + self.assert_warning(UserWarning, open) def test_draw_reloaded(self): - im = Image.open(TEST_ICO_FILE) - outfile = self.tempfile("temp_saved_hopper_draw.ico") + with Image.open(TEST_ICO_FILE) as im: + outfile = self.tempfile("temp_saved_hopper_draw.ico") - draw = ImageDraw.Draw(im) - draw.line((0, 0) + im.size, "#f00") - im.save(outfile) + draw = ImageDraw.Draw(im) + draw.line((0, 0) + im.size, "#f00") + im.save(outfile) - im = Image.open(outfile) - im.save("Tests/images/hopper_draw.ico") - reloaded = Image.open("Tests/images/hopper_draw.ico") - self.assert_image_equal(im, reloaded) + with Image.open(outfile) as im: + im.save("Tests/images/hopper_draw.ico") + with Image.open("Tests/images/hopper_draw.ico") as reloaded: + self.assert_image_equal(im, reloaded) diff --git a/Tests/test_file_im.py b/Tests/test_file_im.py index 90e26efd5..1a5638523 100644 --- a/Tests/test_file_im.py +++ b/Tests/test_file_im.py @@ -1,6 +1,8 @@ +import unittest + from PIL import Image, ImImagePlugin -from .helper import PillowTestCase, hopper +from .helper import PillowTestCase, hopper, is_pypy # sample im TEST_IM = "Tests/images/hopper.im" @@ -8,53 +10,69 @@ TEST_IM = "Tests/images/hopper.im" class TestFileIm(PillowTestCase): def test_sanity(self): - im = Image.open(TEST_IM) - im.load() - self.assertEqual(im.mode, "RGB") - self.assertEqual(im.size, (128, 128)) - self.assertEqual(im.format, "IM") + with Image.open(TEST_IM) as im: + im.load() + self.assertEqual(im.mode, "RGB") + self.assertEqual(im.size, (128, 128)) + self.assertEqual(im.format, "IM") + @unittest.skipIf(is_pypy(), "Requires CPython") def test_unclosed_file(self): def open(): im = Image.open(TEST_IM) im.load() + self.assert_warning(ResourceWarning, open) + + def test_closed_file(self): + def open(): + im = Image.open(TEST_IM) + im.load() + im.close() + + self.assert_warning(None, open) + + def test_context_manager(self): + def open(): + with Image.open(TEST_IM) as im: + im.load() + self.assert_warning(None, open) def test_tell(self): # Arrange - im = Image.open(TEST_IM) + with Image.open(TEST_IM) as im: - # Act - frame = im.tell() + # Act + frame = im.tell() # Assert self.assertEqual(frame, 0) def test_n_frames(self): - im = Image.open(TEST_IM) - self.assertEqual(im.n_frames, 1) - self.assertFalse(im.is_animated) + with Image.open(TEST_IM) as im: + self.assertEqual(im.n_frames, 1) + self.assertFalse(im.is_animated) def test_eoferror(self): - im = Image.open(TEST_IM) - n_frames = im.n_frames + with Image.open(TEST_IM) as im: + n_frames = im.n_frames - # Test seeking past the last frame - self.assertRaises(EOFError, im.seek, n_frames) - self.assertLess(im.tell(), n_frames) + # Test seeking past the last frame + self.assertRaises(EOFError, im.seek, n_frames) + self.assertLess(im.tell(), n_frames) - # Test that seeking to the last frame does not raise an error - im.seek(n_frames - 1) + # Test that seeking to the last frame does not raise an error + im.seek(n_frames - 1) def test_roundtrip(self): for mode in ["RGB", "P", "PA"]: out = self.tempfile("temp.im") im = hopper(mode) im.save(out) - reread = Image.open(out) + with Image.open(out) as reread: - self.assert_image_equal(reread, im) + self.assert_image_equal(reread, im) def test_save_unsupported_mode(self): out = self.tempfile("temp.im") diff --git a/Tests/test_file_iptc.py b/Tests/test_file_iptc.py index 800563af1..1dd18a759 100644 --- a/Tests/test_file_iptc.py +++ b/Tests/test_file_iptc.py @@ -8,20 +8,20 @@ TEST_FILE = "Tests/images/iptc.jpg" class TestFileIptc(PillowTestCase): def test_getiptcinfo_jpg_none(self): # Arrange - im = hopper() + with hopper() as im: - # Act - iptc = IptcImagePlugin.getiptcinfo(im) + # Act + iptc = IptcImagePlugin.getiptcinfo(im) # Assert self.assertIsNone(iptc) def test_getiptcinfo_jpg_found(self): # Arrange - im = Image.open(TEST_FILE) + with Image.open(TEST_FILE) as im: - # Act - iptc = IptcImagePlugin.getiptcinfo(im) + # Act + iptc = IptcImagePlugin.getiptcinfo(im) # Assert self.assertIsInstance(iptc, dict) @@ -30,10 +30,10 @@ class TestFileIptc(PillowTestCase): def test_getiptcinfo_tiff_none(self): # Arrange - im = Image.open("Tests/images/hopper.tif") + with Image.open("Tests/images/hopper.tif") as im: - # Act - iptc = IptcImagePlugin.getiptcinfo(im) + # Act + iptc = IptcImagePlugin.getiptcinfo(im) # Assert self.assertIsNone(iptc) diff --git a/Tests/test_file_jpeg.py b/Tests/test_file_jpeg.py index 5a34a3faa..35f2c0940 100644 --- a/Tests/test_file_jpeg.py +++ b/Tests/test_file_jpeg.py @@ -53,14 +53,14 @@ class TestFileJpeg(PillowTestCase): def test_app(self): # Test APP/COM reader (@PIL135) - im = Image.open(TEST_FILE) - self.assertEqual( - im.applist[0], ("APP0", b"JFIF\x00\x01\x01\x01\x00`\x00`\x00\x00") - ) - self.assertEqual( - im.applist[1], ("COM", b"File written by Adobe Photoshop\xa8 4.0\x00") - ) - self.assertEqual(len(im.applist), 2) + with Image.open(TEST_FILE) as im: + self.assertEqual( + im.applist[0], ("APP0", b"JFIF\x00\x01\x01\x01\x00`\x00`\x00\x00") + ) + self.assertEqual( + im.applist[1], ("COM", b"File written by Adobe Photoshop\xa8 4.0\x00") + ) + self.assertEqual(len(im.applist), 2) def test_cmyk(self): # Test CMYK handling. Thanks to Tim and Charlie for test data, @@ -99,20 +99,20 @@ class TestFileJpeg(PillowTestCase): def test_icc(self): # Test ICC support - im1 = Image.open("Tests/images/rgb.jpg") - icc_profile = im1.info["icc_profile"] - self.assertEqual(len(icc_profile), 3144) - # Roundtrip via physical file. - f = self.tempfile("temp.jpg") - im1.save(f, icc_profile=icc_profile) - im2 = Image.open(f) - self.assertEqual(im2.info.get("icc_profile"), icc_profile) - # Roundtrip via memory buffer. - im1 = self.roundtrip(hopper()) - im2 = self.roundtrip(hopper(), icc_profile=icc_profile) - self.assert_image_equal(im1, im2) - self.assertFalse(im1.info.get("icc_profile")) - self.assertTrue(im2.info.get("icc_profile")) + with Image.open("Tests/images/rgb.jpg") as im1: + icc_profile = im1.info["icc_profile"] + self.assertEqual(len(icc_profile), 3144) + # Roundtrip via physical file. + f = self.tempfile("temp.jpg") + im1.save(f, icc_profile=icc_profile) + with Image.open(f) as im2: + self.assertEqual(im2.info.get("icc_profile"), icc_profile) + # Roundtrip via memory buffer. + im1 = self.roundtrip(hopper()) + im2 = self.roundtrip(hopper(), icc_profile=icc_profile) + self.assert_image_equal(im1, im2) + self.assertFalse(im1.info.get("icc_profile")) + self.assertTrue(im2.info.get("icc_profile")) def test_icc_big(self): # Make sure that the "extra" support handles large blocks @@ -205,24 +205,24 @@ class TestFileJpeg(PillowTestCase): im.save(f, "JPEG", quality=90, exif=b"1" * 65532) def test_exif_typeerror(self): - im = Image.open("Tests/images/exif_typeerror.jpg") - # Should not raise a TypeError - im._getexif() + with Image.open("Tests/images/exif_typeerror.jpg") as im: + # Should not raise a TypeError + im._getexif() def test_exif_gps(self): # Arrange - im = Image.open("Tests/images/exif_gps.jpg") - gps_index = 34853 - expected_exif_gps = { - 0: b"\x00\x00\x00\x01", - 2: (4294967295, 1), - 5: b"\x01", - 30: 65535, - 29: "1999:99:99 99:99:99", - } + with Image.open("Tests/images/exif_gps.jpg") as im: + gps_index = 34853 + expected_exif_gps = { + 0: b"\x00\x00\x00\x01", + 2: (4294967295, 1), + 5: b"\x01", + 30: 65535, + 29: "1999:99:99 99:99:99", + } - # Act - exif = im._getexif() + # Act + exif = im._getexif() # Assert self.assertEqual(exif[gps_index], expected_exif_gps) @@ -256,17 +256,17 @@ class TestFileJpeg(PillowTestCase): 33434: (4294967295, 1), } - im = Image.open("Tests/images/exif_gps.jpg") - exif = im._getexif() + with Image.open("Tests/images/exif_gps.jpg") as im: + exif = im._getexif() for tag, value in expected_exif.items(): self.assertEqual(value, exif[tag]) def test_exif_gps_typeerror(self): - im = Image.open("Tests/images/exif_gps_typeerror.jpg") + with Image.open("Tests/images/exif_gps_typeerror.jpg") as im: - # Should not raise a TypeError - im._getexif() + # Should not raise a TypeError + im._getexif() def test_progressive_compat(self): im1 = self.roundtrip(hopper()) @@ -329,13 +329,13 @@ class TestFileJpeg(PillowTestCase): self.assertRaises(TypeError, self.roundtrip, hopper(), subsampling="1:1:1") def test_exif(self): - im = Image.open("Tests/images/pil_sample_rgb.jpg") - info = im._getexif() - self.assertEqual(info[305], "Adobe Photoshop CS Macintosh") + with Image.open("Tests/images/pil_sample_rgb.jpg") as im: + info = im._getexif() + self.assertEqual(info[305], "Adobe Photoshop CS Macintosh") def test_mp(self): - im = Image.open("Tests/images/pil_sample_rgb.jpg") - self.assertIsNone(im._getmp()) + with Image.open("Tests/images/pil_sample_rgb.jpg") as im: + self.assertIsNone(im._getmp()) def test_quality_keep(self): # RGB @@ -354,11 +354,13 @@ class TestFileJpeg(PillowTestCase): def test_junk_jpeg_header(self): # https://github.com/python-pillow/Pillow/issues/630 filename = "Tests/images/junk_jpeg_header.jpg" - Image.open(filename) + with Image.open(filename): + pass def test_ff00_jpeg_header(self): filename = "Tests/images/jpeg_ff00_header.jpg" - Image.open(filename) + with Image.open(filename): + pass def test_truncated_jpeg_should_read_all_the_data(self): filename = "Tests/images/truncated_jpeg.jpg" @@ -370,14 +372,13 @@ class TestFileJpeg(PillowTestCase): def test_truncated_jpeg_throws_IOError(self): filename = "Tests/images/truncated_jpeg.jpg" - im = Image.open(filename) + with Image.open(filename) as im: + with self.assertRaises(IOError): + im.load() - with self.assertRaises(IOError): - im.load() - - # Test that the error is raised if loaded a second time - with self.assertRaises(IOError): - im.load() + # Test that the error is raised if loaded a second time + with self.assertRaises(IOError): + im.load() def _n_qtables_helper(self, n, test_file): im = Image.open(test_file) @@ -483,9 +484,9 @@ class TestFileJpeg(PillowTestCase): @unittest.skipUnless(djpeg_available(), "djpeg not available") def test_load_djpeg(self): - img = Image.open(TEST_FILE) - img.load_djpeg() - self.assert_image_similar(img, Image.open(TEST_FILE), 0) + with Image.open(TEST_FILE) as img: + img.load_djpeg() + self.assert_image_similar(img, Image.open(TEST_FILE), 0) @unittest.skipUnless(cjpeg_available(), "cjpeg not available") def test_save_cjpeg(self): @@ -525,10 +526,10 @@ class TestFileJpeg(PillowTestCase): # Act # Shouldn't raise error fn = "Tests/images/sugarshack_bad_mpo_header.jpg" - im = self.assert_warning(UserWarning, Image.open, fn) + with self.assert_warning(UserWarning, Image.open, fn) as im: - # Assert - self.assertEqual(im.format, "JPEG") + # Assert + self.assertEqual(im.format, "JPEG") def test_save_correct_modes(self): out = BytesIO() @@ -558,106 +559,106 @@ class TestFileJpeg(PillowTestCase): def test_load_dpi_rounding(self): # Round up - im = Image.open("Tests/images/iptc_roundUp.jpg") - self.assertEqual(im.info["dpi"], (44, 44)) + with Image.open("Tests/images/iptc_roundUp.jpg") as im: + self.assertEqual(im.info["dpi"], (44, 44)) # Round down - im = Image.open("Tests/images/iptc_roundDown.jpg") - self.assertEqual(im.info["dpi"], (2, 2)) + with Image.open("Tests/images/iptc_roundDown.jpg") as im: + self.assertEqual(im.info["dpi"], (2, 2)) def test_save_dpi_rounding(self): outfile = self.tempfile("temp.jpg") im = Image.open("Tests/images/hopper.jpg") im.save(outfile, dpi=(72.2, 72.2)) - reloaded = Image.open(outfile) - self.assertEqual(reloaded.info["dpi"], (72, 72)) + with Image.open(outfile) as reloaded: + self.assertEqual(reloaded.info["dpi"], (72, 72)) - im.save(outfile, dpi=(72.8, 72.8)) - reloaded = Image.open(outfile) - self.assertEqual(reloaded.info["dpi"], (73, 73)) + im.save(outfile, dpi=(72.8, 72.8)) + with Image.open(outfile) as reloaded: + self.assertEqual(reloaded.info["dpi"], (73, 73)) def test_dpi_tuple_from_exif(self): # Arrange # This Photoshop CC 2017 image has DPI in EXIF not metadata # EXIF XResolution is (2000000, 10000) - im = Image.open("Tests/images/photoshop-200dpi.jpg") + with Image.open("Tests/images/photoshop-200dpi.jpg") as im: - # Act / Assert - self.assertEqual(im.info.get("dpi"), (200, 200)) + # Act / Assert + self.assertEqual(im.info.get("dpi"), (200, 200)) def test_dpi_int_from_exif(self): # Arrange # This image has DPI in EXIF not metadata # EXIF XResolution is 72 - im = Image.open("Tests/images/exif-72dpi-int.jpg") + with Image.open("Tests/images/exif-72dpi-int.jpg") as im: - # Act / Assert - self.assertEqual(im.info.get("dpi"), (72, 72)) + # Act / Assert + self.assertEqual(im.info.get("dpi"), (72, 72)) def test_dpi_from_dpcm_exif(self): # Arrange # This is photoshop-200dpi.jpg with EXIF resolution unit set to cm: # exiftool -exif:ResolutionUnit=cm photoshop-200dpi.jpg - im = Image.open("Tests/images/exif-200dpcm.jpg") + with Image.open("Tests/images/exif-200dpcm.jpg") as im: - # Act / Assert - self.assertEqual(im.info.get("dpi"), (508, 508)) + # Act / Assert + self.assertEqual(im.info.get("dpi"), (508, 508)) def test_dpi_exif_zero_division(self): # Arrange # This is photoshop-200dpi.jpg with EXIF resolution set to 0/0: # exiftool -XResolution=0/0 -YResolution=0/0 photoshop-200dpi.jpg - im = Image.open("Tests/images/exif-dpi-zerodivision.jpg") + with Image.open("Tests/images/exif-dpi-zerodivision.jpg") as im: - # Act / Assert - # This should return the default, and not raise a ZeroDivisionError - self.assertEqual(im.info.get("dpi"), (72, 72)) + # Act / Assert + # This should return the default, and not raise a ZeroDivisionError + self.assertEqual(im.info.get("dpi"), (72, 72)) def test_no_dpi_in_exif(self): # Arrange # This is photoshop-200dpi.jpg with resolution removed from EXIF: # exiftool "-*resolution*"= photoshop-200dpi.jpg - im = Image.open("Tests/images/no-dpi-in-exif.jpg") + with Image.open("Tests/images/no-dpi-in-exif.jpg") as im: - # Act / Assert - # "When the image resolution is unknown, 72 [dpi] is designated." - # http://www.exiv2.org/tags.html - self.assertEqual(im.info.get("dpi"), (72, 72)) + # Act / Assert + # "When the image resolution is unknown, 72 [dpi] is designated." + # http://www.exiv2.org/tags.html + self.assertEqual(im.info.get("dpi"), (72, 72)) def test_invalid_exif(self): # This is no-dpi-in-exif with the tiff header of the exif block # hexedited from MM * to FF FF FF FF - im = Image.open("Tests/images/invalid-exif.jpg") + with Image.open("Tests/images/invalid-exif.jpg") as im: - # This should return the default, and not a SyntaxError or - # OSError for unidentified image. - self.assertEqual(im.info.get("dpi"), (72, 72)) + # This should return the default, and not a SyntaxError or + # OSError for unidentified image. + self.assertEqual(im.info.get("dpi"), (72, 72)) def test_ifd_offset_exif(self): # Arrange # This image has been manually hexedited to have an IFD offset of 10, # in contrast to normal 8 - im = Image.open("Tests/images/exif-ifd-offset.jpg") + with Image.open("Tests/images/exif-ifd-offset.jpg") as im: - # Act / Assert - self.assertEqual(im._getexif()[306], "2017:03:13 23:03:09") + # Act / Assert + self.assertEqual(im._getexif()[306], "2017:03:13 23:03:09") def test_photoshop(self): - im = Image.open("Tests/images/photoshop-200dpi.jpg") - self.assertEqual( - im.info["photoshop"][0x03ED], - { - "XResolution": 200.0, - "DisplayedUnitsX": 1, - "YResolution": 200.0, - "DisplayedUnitsY": 1, - }, - ) + with Image.open("Tests/images/photoshop-200dpi.jpg") as im: + self.assertEqual( + im.info["photoshop"][0x03ED], + { + "XResolution": 200.0, + "DisplayedUnitsX": 1, + "YResolution": 200.0, + "DisplayedUnitsY": 1, + }, + ) # This image does not contain a Photoshop header string - im = Image.open("Tests/images/app13.jpg") - self.assertNotIn("photoshop", im.info) + with Image.open("Tests/images/app13.jpg") as im: + self.assertNotIn("photoshop", im.info) @unittest.skipUnless(is_win32(), "Windows only") diff --git a/Tests/test_file_jpeg2k.py b/Tests/test_file_jpeg2k.py index 72b374a0b..dac1d0ec0 100644 --- a/Tests/test_file_jpeg2k.py +++ b/Tests/test_file_jpeg2k.py @@ -42,9 +42,9 @@ class TestFileJpeg2k(PillowTestCase): self.assertEqual(im.get_format_mimetype(), "image/jp2") def test_jpf(self): - im = Image.open("Tests/images/balloon.jpf") - self.assertEqual(im.format, "JPEG2000") - self.assertEqual(im.get_format_mimetype(), "image/jpx") + with Image.open("Tests/images/balloon.jpf") as im: + self.assertEqual(im.format, "JPEG2000") + self.assertEqual(im.get_format_mimetype(), "image/jpx") def test_invalid_file(self): invalid_file = "Tests/images/flower.jpg" diff --git a/Tests/test_file_libtiff.py b/Tests/test_file_libtiff.py index 3372a68f0..e7c3615c2 100644 --- a/Tests/test_file_libtiff.py +++ b/Tests/test_file_libtiff.py @@ -144,15 +144,14 @@ class TestFileLibTiff(LibTiffTestCase): def test_write_metadata(self): """ Test metadata writing through libtiff """ for legacy_api in [False, True]: - img = Image.open("Tests/images/hopper_g4.tif") f = self.tempfile("temp.tiff") + with Image.open("Tests/images/hopper_g4.tif") as img: + img.save(f, tiffinfo=img.tag) - img.save(f, tiffinfo=img.tag) - - if legacy_api: - original = img.tag.named() - else: - original = img.tag_v2.named() + if legacy_api: + original = img.tag.named() + else: + original = img.tag_v2.named() # PhotometricInterpretation is set from SAVE_INFO, # not the original image. @@ -163,11 +162,11 @@ class TestFileLibTiff(LibTiffTestCase): "PhotometricInterpretation", ] - loaded = Image.open(f) - if legacy_api: - reloaded = loaded.tag.named() - else: - reloaded = loaded.tag_v2.named() + with Image.open(f) as loaded: + if legacy_api: + reloaded = loaded.tag.named() + else: + reloaded = loaded.tag_v2.named() for tag, value in itertools.chain(reloaded.items(), original.items()): if tag not in ignored: @@ -302,21 +301,21 @@ class TestFileLibTiff(LibTiffTestCase): out = self.tempfile("temp.tif") im.save(out, tiffinfo=tiffinfo) - reloaded = Image.open(out) - for tag, value in tiffinfo.items(): - reloaded_value = reloaded.tag_v2[tag] - if ( - isinstance(reloaded_value, TiffImagePlugin.IFDRational) - and libtiff - ): - # libtiff does not support real RATIONALS - self.assertAlmostEqual(float(reloaded_value), float(value)) - continue + with Image.open(out) as reloaded: + for tag, value in tiffinfo.items(): + reloaded_value = reloaded.tag_v2[tag] + if ( + isinstance(reloaded_value, TiffImagePlugin.IFDRational) + and libtiff + ): + # libtiff does not support real RATIONALS + self.assertAlmostEqual(float(reloaded_value), float(value)) + continue - if libtiff and isinstance(value, bytes): - value = value.decode() + if libtiff and isinstance(value, bytes): + value = value.decode() - self.assertEqual(reloaded_value, value) + self.assertEqual(reloaded_value, value) # Test with types ifd = TiffImagePlugin.ImageFileDirectory_v2() @@ -343,8 +342,8 @@ class TestFileLibTiff(LibTiffTestCase): TiffImagePlugin.WRITE_LIBTIFF = True im.save(out, dpi=(72, 72)) TiffImagePlugin.WRITE_LIBTIFF = False - reloaded = Image.open(out) - self.assertEqual(reloaded.info["dpi"], (72.0, 72.0)) + with Image.open(out) as reloaded: + self.assertEqual(reloaded.info["dpi"], (72.0, 72.0)) def test_g3_compression(self): i = Image.open("Tests/images/hopper_g4_500.tif") @@ -412,9 +411,9 @@ class TestFileLibTiff(LibTiffTestCase): orig.tag[269] = "temp.tif" orig.save(out) - reread = Image.open(out) - self.assertEqual("temp.tif", reread.tag_v2[269]) - self.assertEqual("temp.tif", reread.tag[269][0]) + with Image.open(out) as reread: + self.assertEqual("temp.tif", reread.tag_v2[269]) + self.assertEqual("temp.tif", reread.tag[269][0]) def test_12bit_rawmode(self): """ Are we generating the same interpretation @@ -521,36 +520,36 @@ class TestFileLibTiff(LibTiffTestCase): def test_multipage(self): # issue #862 TiffImagePlugin.READ_LIBTIFF = True - im = Image.open("Tests/images/multipage.tiff") - # file is a multipage tiff, 10x10 green, 10x10 red, 20x20 blue + with Image.open("Tests/images/multipage.tiff") as im: + # file is a multipage tiff, 10x10 green, 10x10 red, 20x20 blue - im.seek(0) - self.assertEqual(im.size, (10, 10)) - self.assertEqual(im.convert("RGB").getpixel((0, 0)), (0, 128, 0)) - self.assertTrue(im.tag.next) + im.seek(0) + self.assertEqual(im.size, (10, 10)) + self.assertEqual(im.convert("RGB").getpixel((0, 0)), (0, 128, 0)) + self.assertTrue(im.tag.next) - im.seek(1) - self.assertEqual(im.size, (10, 10)) - self.assertEqual(im.convert("RGB").getpixel((0, 0)), (255, 0, 0)) - self.assertTrue(im.tag.next) + im.seek(1) + self.assertEqual(im.size, (10, 10)) + self.assertEqual(im.convert("RGB").getpixel((0, 0)), (255, 0, 0)) + self.assertTrue(im.tag.next) - im.seek(2) - self.assertFalse(im.tag.next) - self.assertEqual(im.size, (20, 20)) - self.assertEqual(im.convert("RGB").getpixel((0, 0)), (0, 0, 255)) + im.seek(2) + self.assertFalse(im.tag.next) + self.assertEqual(im.size, (20, 20)) + self.assertEqual(im.convert("RGB").getpixel((0, 0)), (0, 0, 255)) TiffImagePlugin.READ_LIBTIFF = False def test_multipage_nframes(self): # issue #862 TiffImagePlugin.READ_LIBTIFF = True - im = Image.open("Tests/images/multipage.tiff") - frames = im.n_frames - self.assertEqual(frames, 3) - for _ in range(frames): - im.seek(0) - # Should not raise ValueError: I/O operation on closed file - im.load() + with Image.open("Tests/images/multipage.tiff") as im: + frames = im.n_frames + self.assertEqual(frames, 3) + for _ in range(frames): + im.seek(0) + # Should not raise ValueError: I/O operation on closed file + im.load() TiffImagePlugin.READ_LIBTIFF = False @@ -656,9 +655,9 @@ class TestFileLibTiff(LibTiffTestCase): # /usr/bin/gs -q -sDEVICE=tiffg3 -sOutputFile=total-pages-zero.tif # -dNOPAUSE /tmp/test.pdf -c quit infile = "Tests/images/total-pages-zero.tif" - im = Image.open(infile) - # Should not divide by zero - im.save(outfile) + with Image.open(infile) as im: + # Should not divide by zero + im.save(outfile) def test_fd_duplication(self): # https://github.com/python-pillow/Pillow/issues/1651 @@ -686,21 +685,21 @@ class TestFileLibTiff(LibTiffTestCase): self.assertEqual(icc, icc_libtiff) def test_multipage_compression(self): - im = Image.open("Tests/images/compression.tif") + with Image.open("Tests/images/compression.tif") as im: - im.seek(0) - self.assertEqual(im._compression, "tiff_ccitt") - self.assertEqual(im.size, (10, 10)) + im.seek(0) + self.assertEqual(im._compression, "tiff_ccitt") + self.assertEqual(im.size, (10, 10)) - im.seek(1) - self.assertEqual(im._compression, "packbits") - self.assertEqual(im.size, (10, 10)) - im.load() + im.seek(1) + self.assertEqual(im._compression, "packbits") + self.assertEqual(im.size, (10, 10)) + im.load() - im.seek(0) - self.assertEqual(im._compression, "tiff_ccitt") - self.assertEqual(im.size, (10, 10)) - im.load() + im.seek(0) + self.assertEqual(im._compression, "tiff_ccitt") + self.assertEqual(im.size, (10, 10)) + im.load() def test_save_tiff_with_jpegtables(self): # Arrange @@ -836,8 +835,8 @@ class TestFileLibTiff(LibTiffTestCase): def test_no_rows_per_strip(self): # This image does not have a RowsPerStrip TIFF tag infile = "Tests/images/no_rows_per_strip.tif" - im = Image.open(infile) - im.load() + with Image.open(infile) as im: + im.load() self.assertEqual(im.size, (950, 975)) def test_orientation(self): diff --git a/Tests/test_file_mic.py b/Tests/test_file_mic.py index 5ec110c80..f9ea7712c 100644 --- a/Tests/test_file_mic.py +++ b/Tests/test_file_mic.py @@ -16,42 +16,42 @@ TEST_FILE = "Tests/images/hopper.mic" @unittest.skipUnless(features.check("libtiff"), "libtiff not installed") class TestFileMic(PillowTestCase): def test_sanity(self): - im = Image.open(TEST_FILE) - im.load() - self.assertEqual(im.mode, "RGBA") - self.assertEqual(im.size, (128, 128)) - self.assertEqual(im.format, "MIC") + with Image.open(TEST_FILE) as im: + im.load() + self.assertEqual(im.mode, "RGBA") + self.assertEqual(im.size, (128, 128)) + self.assertEqual(im.format, "MIC") - # Adjust for the gamma of 2.2 encoded into the file - lut = ImagePalette.make_gamma_lut(1 / 2.2) - im = Image.merge("RGBA", [chan.point(lut) for chan in im.split()]) + # Adjust for the gamma of 2.2 encoded into the file + lut = ImagePalette.make_gamma_lut(1 / 2.2) + im = Image.merge("RGBA", [chan.point(lut) for chan in im.split()]) - im2 = hopper("RGBA") - self.assert_image_similar(im, im2, 10) + im2 = hopper("RGBA") + self.assert_image_similar(im, im2, 10) def test_n_frames(self): - im = Image.open(TEST_FILE) + with Image.open(TEST_FILE) as im: - self.assertEqual(im.n_frames, 1) + self.assertEqual(im.n_frames, 1) def test_is_animated(self): - im = Image.open(TEST_FILE) + with Image.open(TEST_FILE) as im: - self.assertFalse(im.is_animated) + self.assertFalse(im.is_animated) def test_tell(self): - im = Image.open(TEST_FILE) + with Image.open(TEST_FILE) as im: - self.assertEqual(im.tell(), 0) + self.assertEqual(im.tell(), 0) def test_seek(self): - im = Image.open(TEST_FILE) + with Image.open(TEST_FILE) as im: - im.seek(0) - self.assertEqual(im.tell(), 0) + im.seek(0) + self.assertEqual(im.tell(), 0) - self.assertRaises(EOFError, im.seek, 99) - self.assertEqual(im.tell(), 0) + self.assertRaises(EOFError, im.seek, 99) + self.assertEqual(im.tell(), 0) def test_invalid_file(self): # Test an invalid OLE file diff --git a/Tests/test_file_mpo.py b/Tests/test_file_mpo.py index 82ecf6457..9c8a2b468 100644 --- a/Tests/test_file_mpo.py +++ b/Tests/test_file_mpo.py @@ -1,8 +1,9 @@ +import unittest from io import BytesIO from PIL import Image -from .helper import PillowTestCase +from .helper import PillowTestCase, is_pypy test_files = ["Tests/images/sugarshack.mpo", "Tests/images/frozenpond.mpo"] @@ -25,78 +26,97 @@ class TestFileMpo(PillowTestCase): def test_sanity(self): for test_file in test_files: - im = Image.open(test_file) - im.load() - self.assertEqual(im.mode, "RGB") - self.assertEqual(im.size, (640, 480)) - self.assertEqual(im.format, "MPO") + with Image.open(test_file) as im: + im.load() + self.assertEqual(im.mode, "RGB") + self.assertEqual(im.size, (640, 480)) + self.assertEqual(im.format, "MPO") + @unittest.skipIf(is_pypy(), "Requires CPython") def test_unclosed_file(self): def open(): im = Image.open(test_files[0]) im.load() + self.assert_warning(ResourceWarning, open) + + def test_closed_file(self): + def open(): + im = Image.open(test_files[0]) + im.load() + im.close() + + self.assert_warning(None, open) + + def test_context_manager(self): + def open(): + with Image.open(test_files[0]) as im: + im.load() + self.assert_warning(None, open) def test_app(self): for test_file in test_files: # Test APP/COM reader (@PIL135) - im = Image.open(test_file) - self.assertEqual(im.applist[0][0], "APP1") - self.assertEqual(im.applist[1][0], "APP2") - self.assertEqual( - im.applist[1][1][:16], b"MPF\x00MM\x00*\x00\x00\x00\x08\x00\x03\xb0\x00" - ) - self.assertEqual(len(im.applist), 2) + with Image.open(test_file) as im: + self.assertEqual(im.applist[0][0], "APP1") + self.assertEqual(im.applist[1][0], "APP2") + self.assertEqual( + im.applist[1][1][:16], + b"MPF\x00MM\x00*\x00\x00\x00\x08\x00\x03\xb0\x00", + ) + self.assertEqual(len(im.applist), 2) def test_exif(self): for test_file in test_files: - im = Image.open(test_file) - info = im._getexif() - self.assertEqual(info[272], "Nintendo 3DS") - self.assertEqual(info[296], 2) - self.assertEqual(info[34665], 188) + with Image.open(test_file) as im: + info = im._getexif() + self.assertEqual(info[272], "Nintendo 3DS") + self.assertEqual(info[296], 2) + self.assertEqual(info[34665], 188) def test_frame_size(self): # This image has been hexedited to contain a different size # in the EXIF data of the second frame - im = Image.open("Tests/images/sugarshack_frame_size.mpo") - self.assertEqual(im.size, (640, 480)) + with Image.open("Tests/images/sugarshack_frame_size.mpo") as im: + self.assertEqual(im.size, (640, 480)) - im.seek(1) - self.assertEqual(im.size, (680, 480)) + im.seek(1) + self.assertEqual(im.size, (680, 480)) def test_parallax(self): # Nintendo - im = Image.open("Tests/images/sugarshack.mpo") - exif = im.getexif() - self.assertEqual(exif.get_ifd(0x927C)[0x1101]["Parallax"], -44.798187255859375) + with Image.open("Tests/images/sugarshack.mpo") as im: + exif = im.getexif() + self.assertEqual( + exif.get_ifd(0x927C)[0x1101]["Parallax"], -44.798187255859375 + ) # Fujifilm - im = Image.open("Tests/images/fujifilm.mpo") - im.seek(1) - exif = im.getexif() - self.assertEqual(exif.get_ifd(0x927C)[0xB211], -3.125) + with Image.open("Tests/images/fujifilm.mpo") as im: + im.seek(1) + exif = im.getexif() + self.assertEqual(exif.get_ifd(0x927C)[0xB211], -3.125) def test_mp(self): for test_file in test_files: - im = Image.open(test_file) - mpinfo = im._getmp() - self.assertEqual(mpinfo[45056], b"0100") - self.assertEqual(mpinfo[45057], 2) + with Image.open(test_file) as im: + mpinfo = im._getmp() + self.assertEqual(mpinfo[45056], b"0100") + self.assertEqual(mpinfo[45057], 2) def test_mp_offset(self): # This image has been manually hexedited to have an IFD offset of 10 # in APP2 data, in contrast to normal 8 - im = Image.open("Tests/images/sugarshack_ifd_offset.mpo") - mpinfo = im._getmp() - self.assertEqual(mpinfo[45056], b"0100") - self.assertEqual(mpinfo[45057], 2) + with Image.open("Tests/images/sugarshack_ifd_offset.mpo") as im: + mpinfo = im._getmp() + self.assertEqual(mpinfo[45056], b"0100") + self.assertEqual(mpinfo[45057], 2) def test_mp_attribute(self): for test_file in test_files: - im = Image.open(test_file) - mpinfo = im._getmp() + with Image.open(test_file) as im: + mpinfo = im._getmp() frameNumber = 0 for mpentry in mpinfo[45058]: mpattr = mpentry["Attribute"] @@ -113,62 +133,62 @@ class TestFileMpo(PillowTestCase): def test_seek(self): for test_file in test_files: - im = Image.open(test_file) - self.assertEqual(im.tell(), 0) - # prior to first image raises an error, both blatant and borderline - self.assertRaises(EOFError, im.seek, -1) - self.assertRaises(EOFError, im.seek, -523) - # after the final image raises an error, - # both blatant and borderline - self.assertRaises(EOFError, im.seek, 2) - self.assertRaises(EOFError, im.seek, 523) - # bad calls shouldn't change the frame - self.assertEqual(im.tell(), 0) - # this one will work - im.seek(1) - self.assertEqual(im.tell(), 1) - # and this one, too - im.seek(0) - self.assertEqual(im.tell(), 0) + with Image.open(test_file) as im: + self.assertEqual(im.tell(), 0) + # prior to first image raises an error, both blatant and borderline + self.assertRaises(EOFError, im.seek, -1) + self.assertRaises(EOFError, im.seek, -523) + # after the final image raises an error, + # both blatant and borderline + self.assertRaises(EOFError, im.seek, 2) + self.assertRaises(EOFError, im.seek, 523) + # bad calls shouldn't change the frame + self.assertEqual(im.tell(), 0) + # this one will work + im.seek(1) + self.assertEqual(im.tell(), 1) + # and this one, too + im.seek(0) + self.assertEqual(im.tell(), 0) def test_n_frames(self): - im = Image.open("Tests/images/sugarshack.mpo") - self.assertEqual(im.n_frames, 2) - self.assertTrue(im.is_animated) + with Image.open("Tests/images/sugarshack.mpo") as im: + self.assertEqual(im.n_frames, 2) + self.assertTrue(im.is_animated) def test_eoferror(self): - im = Image.open("Tests/images/sugarshack.mpo") - n_frames = im.n_frames + with Image.open("Tests/images/sugarshack.mpo") as im: + n_frames = im.n_frames - # Test seeking past the last frame - self.assertRaises(EOFError, im.seek, n_frames) - self.assertLess(im.tell(), n_frames) + # Test seeking past the last frame + self.assertRaises(EOFError, im.seek, n_frames) + self.assertLess(im.tell(), n_frames) - # Test that seeking to the last frame does not raise an error - im.seek(n_frames - 1) + # Test that seeking to the last frame does not raise an error + im.seek(n_frames - 1) def test_image_grab(self): for test_file in test_files: - im = Image.open(test_file) - self.assertEqual(im.tell(), 0) - im0 = im.tobytes() - im.seek(1) - self.assertEqual(im.tell(), 1) - im1 = im.tobytes() - im.seek(0) - self.assertEqual(im.tell(), 0) - im02 = im.tobytes() - self.assertEqual(im0, im02) - self.assertNotEqual(im0, im1) + with Image.open(test_file) as im: + self.assertEqual(im.tell(), 0) + im0 = im.tobytes() + im.seek(1) + self.assertEqual(im.tell(), 1) + im1 = im.tobytes() + im.seek(0) + self.assertEqual(im.tell(), 0) + im02 = im.tobytes() + self.assertEqual(im0, im02) + self.assertNotEqual(im0, im1) def test_save(self): # Note that only individual frames can be saved at present for test_file in test_files: - im = Image.open(test_file) - self.assertEqual(im.tell(), 0) - jpg0 = self.frame_roundtrip(im) - self.assert_image_similar(im, jpg0, 30) - im.seek(1) - self.assertEqual(im.tell(), 1) - jpg1 = self.frame_roundtrip(im) - self.assert_image_similar(im, jpg1, 30) + with Image.open(test_file) as im: + self.assertEqual(im.tell(), 0) + jpg0 = self.frame_roundtrip(im) + self.assert_image_similar(im, jpg0, 30) + im.seek(1) + self.assertEqual(im.tell(), 1) + jpg1 = self.frame_roundtrip(im) + self.assert_image_similar(im, jpg1, 30) diff --git a/Tests/test_file_pdf.py b/Tests/test_file_pdf.py index 25c2f6bf6..c4f64a0a0 100644 --- a/Tests/test_file_pdf.py +++ b/Tests/test_file_pdf.py @@ -82,27 +82,27 @@ class TestFilePdf(PillowTestCase): self.helper_save_as_pdf("RGB", save_all=True) # Multiframe image - im = Image.open("Tests/images/dispose_bgnd.gif") + with Image.open("Tests/images/dispose_bgnd.gif") as im: - outfile = self.tempfile("temp.pdf") - im.save(outfile, save_all=True) + outfile = self.tempfile("temp.pdf") + im.save(outfile, save_all=True) - self.assertTrue(os.path.isfile(outfile)) - self.assertGreater(os.path.getsize(outfile), 0) + self.assertTrue(os.path.isfile(outfile)) + self.assertGreater(os.path.getsize(outfile), 0) - # Append images - ims = [hopper()] - im.copy().save(outfile, save_all=True, append_images=ims) + # Append images + ims = [hopper()] + im.copy().save(outfile, save_all=True, append_images=ims) - self.assertTrue(os.path.isfile(outfile)) - self.assertGreater(os.path.getsize(outfile), 0) + self.assertTrue(os.path.isfile(outfile)) + self.assertGreater(os.path.getsize(outfile), 0) - # Test appending using a generator - def imGenerator(ims): - for im in ims: - yield im + # Test appending using a generator + def imGenerator(ims): + for im in ims: + yield im - im.save(outfile, save_all=True, append_images=imGenerator(ims)) + im.save(outfile, save_all=True, append_images=imGenerator(ims)) self.assertTrue(os.path.isfile(outfile)) self.assertGreater(os.path.getsize(outfile), 0) @@ -116,10 +116,10 @@ class TestFilePdf(PillowTestCase): def test_multiframe_normal_save(self): # Test saving a multiframe image without save_all - im = Image.open("Tests/images/dispose_bgnd.gif") + with Image.open("Tests/images/dispose_bgnd.gif") as im: - outfile = self.tempfile("temp.pdf") - im.save(outfile) + outfile = self.tempfile("temp.pdf") + im.save(outfile) self.assertTrue(os.path.isfile(outfile)) self.assertGreater(os.path.getsize(outfile), 0) diff --git a/Tests/test_file_png.py b/Tests/test_file_png.py index 07e84ef72..ee2a95255 100644 --- a/Tests/test_file_png.py +++ b/Tests/test_file_png.py @@ -81,12 +81,12 @@ class TestFilePng(PillowTestCase): hopper("RGB").save(test_file) - im = Image.open(test_file) - im.load() - self.assertEqual(im.mode, "RGB") - self.assertEqual(im.size, (128, 128)) - self.assertEqual(im.format, "PNG") - self.assertEqual(im.get_format_mimetype(), "image/png") + with Image.open(test_file) as im: + im.load() + self.assertEqual(im.mode, "RGB") + self.assertEqual(im.size, (128, 128)) + self.assertEqual(im.format, "PNG") + self.assertEqual(im.get_format_mimetype(), "image/png") for mode in ["1", "L", "P", "RGB", "I", "I;16"]: im = hopper(mode) @@ -393,12 +393,12 @@ class TestFilePng(PillowTestCase): def test_load_dpi_rounding(self): # Round up - im = Image.open(TEST_PNG_FILE) - self.assertEqual(im.info["dpi"], (96, 96)) + with Image.open(TEST_PNG_FILE) as im: + self.assertEqual(im.info["dpi"], (96, 96)) # Round down - im = Image.open("Tests/images/icc_profile_none.png") - self.assertEqual(im.info["dpi"], (72, 72)) + with Image.open("Tests/images/icc_profile_none.png") as im: + self.assertEqual(im.info["dpi"], (72, 72)) def test_save_dpi_rounding(self): im = Image.open(TEST_PNG_FILE) @@ -462,8 +462,13 @@ class TestFilePng(PillowTestCase): if py3: rt_text(" Aa" + chr(0xA0) + chr(0xC4) + chr(0xFF)) # Latin1 rt_text(chr(0x400) + chr(0x472) + chr(0x4FF)) # Cyrillic - # CJK: - rt_text(chr(0x4E00) + chr(0x66F0) + chr(0x9FBA) + chr(0x3042) + chr(0xAC00)) + rt_text( + chr(0x4E00) + + chr(0x66F0) + + chr(0x9FBA) # CJK + + chr(0x3042) + + chr(0xAC00) + ) rt_text("A" + chr(0xC4) + chr(0x472) + chr(0x3042)) # Combined def test_scary(self): @@ -509,19 +514,19 @@ class TestFilePng(PillowTestCase): def test_trns_null(self): # Check reading images with null tRNS value, issue #1239 test_file = "Tests/images/tRNS_null_1x1.png" - im = Image.open(test_file) + with Image.open(test_file) as im: - self.assertEqual(im.info["transparency"], 0) + self.assertEqual(im.info["transparency"], 0) def test_save_icc_profile(self): - im = Image.open("Tests/images/icc_profile_none.png") - self.assertIsNone(im.info["icc_profile"]) + with Image.open("Tests/images/icc_profile_none.png") as im: + self.assertIsNone(im.info["icc_profile"]) - with_icc = Image.open("Tests/images/icc_profile.png") - expected_icc = with_icc.info["icc_profile"] + with Image.open("Tests/images/icc_profile.png") as with_icc: + expected_icc = with_icc.info["icc_profile"] - im = roundtrip(im, icc_profile=expected_icc) - self.assertEqual(im.info["icc_profile"], expected_icc) + im = roundtrip(im, icc_profile=expected_icc) + self.assertEqual(im.info["icc_profile"], expected_icc) def test_discard_icc_profile(self): im = Image.open("Tests/images/icc_profile.png") @@ -614,8 +619,8 @@ class TestFilePng(PillowTestCase): test_file = self.tempfile("temp.png") im.save(test_file) - reloaded = Image.open(test_file) - exif = reloaded._getexif() + with Image.open(test_file) as reloaded: + exif = reloaded._getexif() self.assertEqual(exif[274], 1) def test_exif_from_jpg(self): @@ -624,8 +629,8 @@ class TestFilePng(PillowTestCase): test_file = self.tempfile("temp.png") im.save(test_file) - reloaded = Image.open(test_file) - exif = reloaded._getexif() + with Image.open(test_file) as reloaded: + exif = reloaded._getexif() self.assertEqual(exif[305], "Adobe Photoshop CS Macintosh") def test_exif_argument(self): @@ -634,8 +639,8 @@ class TestFilePng(PillowTestCase): test_file = self.tempfile("temp.png") im.save(test_file, exif=b"exifstring") - reloaded = Image.open(test_file) - self.assertEqual(reloaded.info["exif"], b"Exif\x00\x00exifstring") + with Image.open(test_file) as reloaded: + self.assertEqual(reloaded.info["exif"], b"Exif\x00\x00exifstring") @unittest.skipUnless( HAVE_WEBP and _webp.HAVE_WEBPANIM, "WebP support not installed with animation" diff --git a/Tests/test_file_ppm.py b/Tests/test_file_ppm.py index 5d2a0bc69..226687fa3 100644 --- a/Tests/test_file_ppm.py +++ b/Tests/test_file_ppm.py @@ -66,10 +66,10 @@ class TestFilePpm(PillowTestCase): with open(path, "w") as f: f.write("P4\n128 128\n255") - im = Image.open(path) - self.assertEqual(im.get_format_mimetype(), "image/x-portable-bitmap") + with Image.open(path) as im: + self.assertEqual(im.get_format_mimetype(), "image/x-portable-bitmap") with open(path, "w") as f: f.write("PyCMYK\n128 128\n255") - im = Image.open(path) - self.assertEqual(im.get_format_mimetype(), "image/x-portable-anymap") + with Image.open(path) as im: + self.assertEqual(im.get_format_mimetype(), "image/x-portable-anymap") diff --git a/Tests/test_file_psd.py b/Tests/test_file_psd.py index 8381ceaef..f57deff6a 100644 --- a/Tests/test_file_psd.py +++ b/Tests/test_file_psd.py @@ -1,26 +1,45 @@ +import unittest + from PIL import Image, PsdImagePlugin -from .helper import PillowTestCase, hopper +from .helper import PillowTestCase, hopper, is_pypy test_file = "Tests/images/hopper.psd" class TestImagePsd(PillowTestCase): def test_sanity(self): - im = Image.open(test_file) - im.load() - self.assertEqual(im.mode, "RGB") - self.assertEqual(im.size, (128, 128)) - self.assertEqual(im.format, "PSD") + with Image.open(test_file) as im: + im.load() + self.assertEqual(im.mode, "RGB") + self.assertEqual(im.size, (128, 128)) + self.assertEqual(im.format, "PSD") - im2 = hopper() - self.assert_image_similar(im, im2, 4.8) + im2 = hopper() + self.assert_image_similar(im, im2, 4.8) + @unittest.skipIf(is_pypy(), "Requires CPython") def test_unclosed_file(self): def open(): im = Image.open(test_file) im.load() + self.assert_warning(ResourceWarning, open) + + def test_closed_file(self): + def open(): + im = Image.open(test_file) + im.load() + im.close() + + self.assert_warning(None, open) + + def test_context_manager(self): + def open(): + im = Image.open(test_file) + im.load() + im.close() + self.assert_warning(None, open) def test_invalid_file(self): @@ -29,64 +48,63 @@ class TestImagePsd(PillowTestCase): self.assertRaises(SyntaxError, PsdImagePlugin.PsdImageFile, invalid_file) def test_n_frames(self): - im = Image.open("Tests/images/hopper_merged.psd") - self.assertEqual(im.n_frames, 1) - self.assertFalse(im.is_animated) + with Image.open("Tests/images/hopper_merged.psd") as im: + self.assertEqual(im.n_frames, 1) + self.assertFalse(im.is_animated) - im = Image.open(test_file) - self.assertEqual(im.n_frames, 2) - self.assertTrue(im.is_animated) + with Image.open(test_file) as im: + self.assertEqual(im.n_frames, 2) + self.assertTrue(im.is_animated) def test_eoferror(self): - im = Image.open(test_file) - # PSD seek index starts at 1 rather than 0 - n_frames = im.n_frames + 1 + with Image.open(test_file) as im: + # PSD seek index starts at 1 rather than 0 + n_frames = im.n_frames + 1 - # Test seeking past the last frame - self.assertRaises(EOFError, im.seek, n_frames) - self.assertLess(im.tell(), n_frames) + # Test seeking past the last frame + self.assertRaises(EOFError, im.seek, n_frames) + self.assertLess(im.tell(), n_frames) - # Test that seeking to the last frame does not raise an error - im.seek(n_frames - 1) + # Test that seeking to the last frame does not raise an error + im.seek(n_frames - 1) def test_seek_tell(self): - im = Image.open(test_file) + with Image.open(test_file) as im: - layer_number = im.tell() - self.assertEqual(layer_number, 1) + layer_number = im.tell() + self.assertEqual(layer_number, 1) - self.assertRaises(EOFError, im.seek, 0) + self.assertRaises(EOFError, im.seek, 0) - im.seek(1) - layer_number = im.tell() - self.assertEqual(layer_number, 1) + im.seek(1) + layer_number = im.tell() + self.assertEqual(layer_number, 1) - im.seek(2) - layer_number = im.tell() - self.assertEqual(layer_number, 2) + im.seek(2) + layer_number = im.tell() + self.assertEqual(layer_number, 2) def test_seek_eoferror(self): - im = Image.open(test_file) + with Image.open(test_file) as im: - self.assertRaises(EOFError, im.seek, -1) + self.assertRaises(EOFError, im.seek, -1) def test_open_after_exclusive_load(self): - im = Image.open(test_file) - im.load() - im.seek(im.tell() + 1) - im.load() + with Image.open(test_file) as im: + im.load() + im.seek(im.tell() + 1) + im.load() def test_icc_profile(self): - im = Image.open(test_file) - self.assertIn("icc_profile", im.info) + with Image.open(test_file) as im: + self.assertIn("icc_profile", im.info) - icc_profile = im.info["icc_profile"] - self.assertEqual(len(icc_profile), 3144) + icc_profile = im.info["icc_profile"] + self.assertEqual(len(icc_profile), 3144) def test_no_icc_profile(self): - im = Image.open("Tests/images/hopper_merged.psd") - - self.assertNotIn("icc_profile", im.info) + with Image.open("Tests/images/hopper_merged.psd") as im: + self.assertNotIn("icc_profile", im.info) def test_combined_larger_than_size(self): # The 'combined' sizes of the individual parts is larger than the diff --git a/Tests/test_file_spider.py b/Tests/test_file_spider.py index 340208486..5940c2ff2 100644 --- a/Tests/test_file_spider.py +++ b/Tests/test_file_spider.py @@ -1,26 +1,43 @@ import tempfile +import unittest from io import BytesIO from PIL import Image, ImageSequence, SpiderImagePlugin -from .helper import PillowTestCase, hopper +from .helper import PillowTestCase, hopper, is_pypy TEST_FILE = "Tests/images/hopper.spider" class TestImageSpider(PillowTestCase): def test_sanity(self): - im = Image.open(TEST_FILE) - im.load() - self.assertEqual(im.mode, "F") - self.assertEqual(im.size, (128, 128)) - self.assertEqual(im.format, "SPIDER") + with Image.open(TEST_FILE) as im: + im.load() + self.assertEqual(im.mode, "F") + self.assertEqual(im.size, (128, 128)) + self.assertEqual(im.format, "SPIDER") + @unittest.skipIf(is_pypy(), "Requires CPython") def test_unclosed_file(self): def open(): im = Image.open(TEST_FILE) im.load() + self.assert_warning(ResourceWarning, open) + + def test_closed_file(self): + def open(): + im = Image.open(TEST_FILE) + im.load() + im.close() + + self.assert_warning(None, open) + + def test_context_manager(self): + def open(): + with Image.open(TEST_FILE) as im: + im.load() + self.assert_warning(None, open) def test_save(self): @@ -32,10 +49,10 @@ class TestImageSpider(PillowTestCase): im.save(temp, "SPIDER") # Assert - im2 = Image.open(temp) - self.assertEqual(im2.mode, "F") - self.assertEqual(im2.size, (128, 128)) - self.assertEqual(im2.format, "SPIDER") + with Image.open(temp) as im2: + self.assertEqual(im2.mode, "F") + self.assertEqual(im2.size, (128, 128)) + self.assertEqual(im2.format, "SPIDER") def test_tempfile(self): # Arrange @@ -57,18 +74,18 @@ class TestImageSpider(PillowTestCase): def test_tell(self): # Arrange - im = Image.open(TEST_FILE) + with Image.open(TEST_FILE) as im: - # Act - index = im.tell() + # Act + index = im.tell() - # Assert - self.assertEqual(index, 0) + # Assert + self.assertEqual(index, 0) def test_n_frames(self): - im = Image.open(TEST_FILE) - self.assertEqual(im.n_frames, 1) - self.assertFalse(im.is_animated) + with Image.open(TEST_FILE) as im: + self.assertEqual(im.n_frames, 1) + self.assertFalse(im.is_animated) def test_loadImageSeries(self): # Arrange @@ -109,15 +126,14 @@ class TestImageSpider(PillowTestCase): self.assertRaises(IOError, Image.open, invalid_file) def test_nonstack_file(self): - im = Image.open(TEST_FILE) - - self.assertRaises(EOFError, im.seek, 0) + with Image.open(TEST_FILE) as im: + self.assertRaises(EOFError, im.seek, 0) def test_nonstack_dos(self): - im = Image.open(TEST_FILE) - for i, frame in enumerate(ImageSequence.Iterator(im)): - if i > 1: - self.fail("Non-stack DOS file test failed") + with Image.open(TEST_FILE) as im: + for i, frame in enumerate(ImageSequence.Iterator(im)): + if i > 1: + self.fail("Non-stack DOS file test failed") # for issue #4093 def test_odd_size(self): diff --git a/Tests/test_file_tar.py b/Tests/test_file_tar.py index c4666a65a..f381eef7e 100644 --- a/Tests/test_file_tar.py +++ b/Tests/test_file_tar.py @@ -1,6 +1,8 @@ +import unittest + from PIL import Image, TarIO -from .helper import PillowTestCase +from .helper import PillowTestCase, is_pypy codecs = dir(Image.core) @@ -19,17 +21,30 @@ class TestFileTar(PillowTestCase): ["jpeg_decoder", "hopper.jpg", "JPEG"], ]: if codec in codecs: - tar = TarIO.TarIO(TEST_TAR_FILE, test_path) - im = Image.open(tar) - im.load() - self.assertEqual(im.mode, "RGB") - self.assertEqual(im.size, (128, 128)) - self.assertEqual(im.format, format) + with TarIO.TarIO(TEST_TAR_FILE, test_path) as tar: + im = Image.open(tar) + im.load() + self.assertEqual(im.mode, "RGB") + self.assertEqual(im.size, (128, 128)) + self.assertEqual(im.format, format) + + @unittest.skipIf(is_pypy(), "Requires CPython") + def test_unclosed_file(self): + def open(): + TarIO.TarIO(TEST_TAR_FILE, "hopper.jpg") + + self.assert_warning(ResourceWarning, open) def test_close(self): - tar = TarIO.TarIO(TEST_TAR_FILE, "hopper.jpg") - tar.close() + def open(): + tar = TarIO.TarIO(TEST_TAR_FILE, "hopper.jpg") + tar.close() + + self.assert_warning(None, open) def test_contextmanager(self): - with TarIO.TarIO(TEST_TAR_FILE, "hopper.jpg"): - pass + def open(): + with TarIO.TarIO(TEST_TAR_FILE, "hopper.jpg"): + pass + + self.assert_warning(None, open) diff --git a/Tests/test_file_tga.py b/Tests/test_file_tga.py index abbebe0eb..bd5c32c5b 100644 --- a/Tests/test_file_tga.py +++ b/Tests/test_file_tga.py @@ -76,20 +76,20 @@ class TestFileTga(PillowTestCase): test_file = "Tests/images/tga_id_field.tga" # Act - im = Image.open(test_file) + with Image.open(test_file) as im: - # Assert - self.assertEqual(im.size, (100, 100)) + # Assert + self.assertEqual(im.size, (100, 100)) def test_id_field_rle(self): # tga file with id field test_file = "Tests/images/rgb32rle.tga" # Act - im = Image.open(test_file) + with Image.open(test_file) as im: - # Assert - self.assertEqual(im.size, (199, 199)) + # Assert + self.assertEqual(im.size, (199, 199)) def test_save(self): test_file = "Tests/images/tga_id_field.tga" @@ -99,14 +99,14 @@ class TestFileTga(PillowTestCase): # Save im.save(out) - test_im = Image.open(out) - self.assertEqual(test_im.size, (100, 100)) - self.assertEqual(test_im.info["id_section"], im.info["id_section"]) + with Image.open(out) as test_im: + self.assertEqual(test_im.size, (100, 100)) + self.assertEqual(test_im.info["id_section"], im.info["id_section"]) # RGBA save im.convert("RGBA").save(out) - test_im = Image.open(out) - self.assertEqual(test_im.size, (100, 100)) + with Image.open(out) as test_im: + self.assertEqual(test_im.size, (100, 100)) def test_save_id_section(self): test_file = "Tests/images/rgb32rle.tga" @@ -116,27 +116,27 @@ class TestFileTga(PillowTestCase): # Check there is no id section im.save(out) - test_im = Image.open(out) - self.assertNotIn("id_section", test_im.info) + with Image.open(out) as test_im: + self.assertNotIn("id_section", test_im.info) # Save with custom id section im.save(out, id_section=b"Test content") - test_im = Image.open(out) - self.assertEqual(test_im.info["id_section"], b"Test content") + with Image.open(out) as test_im: + self.assertEqual(test_im.info["id_section"], b"Test content") # Save with custom id section greater than 255 characters id_section = b"Test content" * 25 self.assert_warning(UserWarning, lambda: im.save(out, id_section=id_section)) - test_im = Image.open(out) - self.assertEqual(test_im.info["id_section"], id_section[:255]) + with Image.open(out) as test_im: + self.assertEqual(test_im.info["id_section"], id_section[:255]) test_file = "Tests/images/tga_id_field.tga" - im = Image.open(test_file) + with Image.open(test_file) as im: - # Save with no id section - im.save(out, id_section="") - test_im = Image.open(out) - self.assertNotIn("id_section", test_im.info) + # Save with no id section + im.save(out, id_section="") + with Image.open(out) as test_im: + self.assertNotIn("id_section", test_im.info) def test_save_orientation(self): test_file = "Tests/images/rgb32rle.tga" @@ -146,8 +146,8 @@ class TestFileTga(PillowTestCase): out = self.tempfile("temp.tga") im.save(out, orientation=1) - test_im = Image.open(out) - self.assertEqual(test_im.info["orientation"], 1) + with Image.open(out) as test_im: + self.assertEqual(test_im.info["orientation"], 1) def test_save_rle(self): test_file = "Tests/images/rgb32rle.tga" @@ -158,19 +158,19 @@ class TestFileTga(PillowTestCase): # Save im.save(out) - test_im = Image.open(out) - self.assertEqual(test_im.size, (199, 199)) - self.assertEqual(test_im.info["compression"], "tga_rle") + with Image.open(out) as test_im: + self.assertEqual(test_im.size, (199, 199)) + self.assertEqual(test_im.info["compression"], "tga_rle") # Save without compression im.save(out, compression=None) - test_im = Image.open(out) - self.assertNotIn("compression", test_im.info) + with Image.open(out) as test_im: + self.assertNotIn("compression", test_im.info) # RGBA save im.convert("RGBA").save(out) - test_im = Image.open(out) - self.assertEqual(test_im.size, (199, 199)) + with Image.open(out) as test_im: + self.assertEqual(test_im.size, (199, 199)) test_file = "Tests/images/tga_id_field.tga" im = Image.open(test_file) @@ -178,8 +178,8 @@ class TestFileTga(PillowTestCase): # Save with compression im.save(out, compression="tga_rle") - test_im = Image.open(out) - self.assertEqual(test_im.info["compression"], "tga_rle") + with Image.open(out) as test_im: + self.assertEqual(test_im.info["compression"], "tga_rle") def test_save_l_transparency(self): # There are 559 transparent pixels in la.tga. diff --git a/Tests/test_file_tiff.py b/Tests/test_file_tiff.py index a335e5e7a..ccaa91920 100644 --- a/Tests/test_file_tiff.py +++ b/Tests/test_file_tiff.py @@ -6,7 +6,7 @@ from PIL import Image, TiffImagePlugin from PIL._util import py3 from PIL.TiffImagePlugin import RESOLUTION_UNIT, X_RESOLUTION, Y_RESOLUTION -from .helper import PillowTestCase, hopper, is_win32, unittest +from .helper import PillowTestCase, hopper, is_pypy, is_win32, unittest logger = logging.getLogger(__name__) @@ -18,32 +18,53 @@ class TestFileTiff(PillowTestCase): hopper("RGB").save(filename) - im = Image.open(filename) - im.load() + with Image.open(filename) as im: + im.load() self.assertEqual(im.mode, "RGB") self.assertEqual(im.size, (128, 128)) self.assertEqual(im.format, "TIFF") hopper("1").save(filename) - Image.open(filename) + with Image.open(filename): + pass hopper("L").save(filename) - Image.open(filename) + with Image.open(filename): + pass hopper("P").save(filename) - Image.open(filename) + with Image.open(filename): + pass hopper("RGB").save(filename) - Image.open(filename) + with Image.open(filename): + pass hopper("I").save(filename) - Image.open(filename) + with Image.open(filename): + pass + @unittest.skipIf(is_pypy(), "Requires CPython") def test_unclosed_file(self): def open(): im = Image.open("Tests/images/multipage.tiff") im.load() + self.assert_warning(ResourceWarning, open) + + def test_closed_file(self): + def open(): + im = Image.open("Tests/images/multipage.tiff") + im.load() + im.close() + + self.assert_warning(None, open) + + def test_context_manager(self): + def open(): + with Image.open("Tests/images/multipage.tiff") as im: + im.load() + self.assert_warning(None, open) def test_mac_tiff(self): @@ -75,55 +96,55 @@ class TestFileTiff(PillowTestCase): def test_xyres_tiff(self): filename = "Tests/images/pil168.tif" - im = Image.open(filename) + with Image.open(filename) as im: - # legacy api - self.assertIsInstance(im.tag[X_RESOLUTION][0], tuple) - self.assertIsInstance(im.tag[Y_RESOLUTION][0], tuple) + # legacy api + self.assertIsInstance(im.tag[X_RESOLUTION][0], tuple) + self.assertIsInstance(im.tag[Y_RESOLUTION][0], tuple) - # v2 api - self.assertIsInstance(im.tag_v2[X_RESOLUTION], TiffImagePlugin.IFDRational) - self.assertIsInstance(im.tag_v2[Y_RESOLUTION], TiffImagePlugin.IFDRational) + # v2 api + self.assertIsInstance(im.tag_v2[X_RESOLUTION], TiffImagePlugin.IFDRational) + self.assertIsInstance(im.tag_v2[Y_RESOLUTION], TiffImagePlugin.IFDRational) - self.assertEqual(im.info["dpi"], (72.0, 72.0)) + self.assertEqual(im.info["dpi"], (72.0, 72.0)) def test_xyres_fallback_tiff(self): filename = "Tests/images/compression.tif" - im = Image.open(filename) + with Image.open(filename) as im: - # v2 api - self.assertIsInstance(im.tag_v2[X_RESOLUTION], TiffImagePlugin.IFDRational) - self.assertIsInstance(im.tag_v2[Y_RESOLUTION], TiffImagePlugin.IFDRational) - self.assertRaises(KeyError, lambda: im.tag_v2[RESOLUTION_UNIT]) + # v2 api + self.assertIsInstance(im.tag_v2[X_RESOLUTION], TiffImagePlugin.IFDRational) + self.assertIsInstance(im.tag_v2[Y_RESOLUTION], TiffImagePlugin.IFDRational) + self.assertRaises(KeyError, lambda: im.tag_v2[RESOLUTION_UNIT]) - # Legacy. - self.assertEqual(im.info["resolution"], (100.0, 100.0)) - # Fallback "inch". - self.assertEqual(im.info["dpi"], (100.0, 100.0)) + # Legacy. + self.assertEqual(im.info["resolution"], (100.0, 100.0)) + # Fallback "inch". + self.assertEqual(im.info["dpi"], (100.0, 100.0)) def test_int_resolution(self): filename = "Tests/images/pil168.tif" - im = Image.open(filename) + with Image.open(filename) as im: - # Try to read a file where X,Y_RESOLUTION are ints - im.tag_v2[X_RESOLUTION] = 71 - im.tag_v2[Y_RESOLUTION] = 71 - im._setup() - self.assertEqual(im.info["dpi"], (71.0, 71.0)) + # Try to read a file where X,Y_RESOLUTION are ints + im.tag_v2[X_RESOLUTION] = 71 + im.tag_v2[Y_RESOLUTION] = 71 + im._setup() + self.assertEqual(im.info["dpi"], (71.0, 71.0)) def test_load_dpi_rounding(self): for resolutionUnit, dpi in ((None, (72, 73)), (2, (72, 73)), (3, (183, 185))): - im = Image.open( + with Image.open( "Tests/images/hopper_roundDown_" + str(resolutionUnit) + ".tif" - ) - self.assertEqual(im.tag_v2.get(RESOLUTION_UNIT), resolutionUnit) - self.assertEqual(im.info["dpi"], (dpi[0], dpi[0])) + ) as im: + self.assertEqual(im.tag_v2.get(RESOLUTION_UNIT), resolutionUnit) + self.assertEqual(im.info["dpi"], (dpi[0], dpi[0])) - im = Image.open( + with Image.open( "Tests/images/hopper_roundUp_" + str(resolutionUnit) + ".tif" - ) - self.assertEqual(im.tag_v2.get(RESOLUTION_UNIT), resolutionUnit) - self.assertEqual(im.info["dpi"], (dpi[1], dpi[1])) + ) as im: + self.assertEqual(im.tag_v2.get(RESOLUTION_UNIT), resolutionUnit) + self.assertEqual(im.info["dpi"], (dpi[1], dpi[1])) def test_save_dpi_rounding(self): outfile = self.tempfile("temp.tif") @@ -155,9 +176,9 @@ class TestFileTiff(PillowTestCase): TiffImagePlugin.PREFIXES.pop() def test_bad_exif(self): - i = Image.open("Tests/images/hopper_bad_exif.jpg") - # Should not raise struct.error. - self.assert_warning(UserWarning, i._getexif) + with Image.open("Tests/images/hopper_bad_exif.jpg") as i: + # Should not raise struct.error. + self.assert_warning(UserWarning, i._getexif) def test_save_rgba(self): im = hopper("RGBA") @@ -238,44 +259,44 @@ class TestFileTiff(PillowTestCase): ["Tests/images/multipage-lastframe.tif", 1], ["Tests/images/multipage.tiff", 3], ]: - im = Image.open(path) - self.assertEqual(im.n_frames, n_frames) - self.assertEqual(im.is_animated, n_frames != 1) + with Image.open(path) as im: + self.assertEqual(im.n_frames, n_frames) + self.assertEqual(im.is_animated, n_frames != 1) def test_eoferror(self): - im = Image.open("Tests/images/multipage-lastframe.tif") - n_frames = im.n_frames + with Image.open("Tests/images/multipage-lastframe.tif") as im: + n_frames = im.n_frames - # Test seeking past the last frame - self.assertRaises(EOFError, im.seek, n_frames) - self.assertLess(im.tell(), n_frames) + # Test seeking past the last frame + self.assertRaises(EOFError, im.seek, n_frames) + self.assertLess(im.tell(), n_frames) - # Test that seeking to the last frame does not raise an error - im.seek(n_frames - 1) + # Test that seeking to the last frame does not raise an error + im.seek(n_frames - 1) def test_multipage(self): # issue #862 - im = Image.open("Tests/images/multipage.tiff") - # file is a multipage tiff: 10x10 green, 10x10 red, 20x20 blue + with Image.open("Tests/images/multipage.tiff") as im: + # file is a multipage tiff: 10x10 green, 10x10 red, 20x20 blue - im.seek(0) - self.assertEqual(im.size, (10, 10)) - self.assertEqual(im.convert("RGB").getpixel((0, 0)), (0, 128, 0)) + im.seek(0) + self.assertEqual(im.size, (10, 10)) + self.assertEqual(im.convert("RGB").getpixel((0, 0)), (0, 128, 0)) - im.seek(1) - im.load() - self.assertEqual(im.size, (10, 10)) - self.assertEqual(im.convert("RGB").getpixel((0, 0)), (255, 0, 0)) + im.seek(1) + im.load() + self.assertEqual(im.size, (10, 10)) + self.assertEqual(im.convert("RGB").getpixel((0, 0)), (255, 0, 0)) - im.seek(0) - im.load() - self.assertEqual(im.size, (10, 10)) - self.assertEqual(im.convert("RGB").getpixel((0, 0)), (0, 128, 0)) + im.seek(0) + im.load() + self.assertEqual(im.size, (10, 10)) + self.assertEqual(im.convert("RGB").getpixel((0, 0)), (0, 128, 0)) - im.seek(2) - im.load() - self.assertEqual(im.size, (20, 20)) - self.assertEqual(im.convert("RGB").getpixel((0, 0)), (0, 0, 255)) + im.seek(2) + im.load() + self.assertEqual(im.size, (20, 20)) + self.assertEqual(im.convert("RGB").getpixel((0, 0)), (0, 0, 255)) def test_multipage_last_frame(self): im = Image.open("Tests/images/multipage-lastframe.tif") @@ -285,62 +306,62 @@ class TestFileTiff(PillowTestCase): def test___str__(self): filename = "Tests/images/pil136.tiff" - im = Image.open(filename) + with Image.open(filename) as im: - # Act - ret = str(im.ifd) + # Act + ret = str(im.ifd) - # Assert - self.assertIsInstance(ret, str) + # Assert + self.assertIsInstance(ret, str) def test_dict(self): # Arrange filename = "Tests/images/pil136.tiff" - im = Image.open(filename) + with Image.open(filename) as im: - # v2 interface - v2_tags = { - 256: 55, - 257: 43, - 258: (8, 8, 8, 8), - 259: 1, - 262: 2, - 296: 2, - 273: (8,), - 338: (1,), - 277: 4, - 279: (9460,), - 282: 72.0, - 283: 72.0, - 284: 1, - } - self.assertEqual(dict(im.tag_v2), v2_tags) + # v2 interface + v2_tags = { + 256: 55, + 257: 43, + 258: (8, 8, 8, 8), + 259: 1, + 262: 2, + 296: 2, + 273: (8,), + 338: (1,), + 277: 4, + 279: (9460,), + 282: 72.0, + 283: 72.0, + 284: 1, + } + self.assertEqual(dict(im.tag_v2), v2_tags) - # legacy interface - legacy_tags = { - 256: (55,), - 257: (43,), - 258: (8, 8, 8, 8), - 259: (1,), - 262: (2,), - 296: (2,), - 273: (8,), - 338: (1,), - 277: (4,), - 279: (9460,), - 282: ((720000, 10000),), - 283: ((720000, 10000),), - 284: (1,), - } - self.assertEqual(dict(im.tag), legacy_tags) + # legacy interface + legacy_tags = { + 256: (55,), + 257: (43,), + 258: (8, 8, 8, 8), + 259: (1,), + 262: (2,), + 296: (2,), + 273: (8,), + 338: (1,), + 277: (4,), + 279: (9460,), + 282: ((720000, 10000),), + 283: ((720000, 10000),), + 284: (1,), + } + self.assertEqual(dict(im.tag), legacy_tags) def test__delitem__(self): filename = "Tests/images/pil136.tiff" - im = Image.open(filename) - len_before = len(dict(im.ifd)) - del im.ifd[256] - len_after = len(dict(im.ifd)) - self.assertEqual(len_before, len_after + 1) + with Image.open(filename) as im: + len_before = len(dict(im.ifd)) + del im.ifd[256] + len_after = len(dict(im.ifd)) + self.assertEqual(len_before, len_after + 1) def test_load_byte(self): for legacy_api in [False, True]: @@ -369,16 +390,16 @@ class TestFileTiff(PillowTestCase): def test_seek(self): filename = "Tests/images/pil136.tiff" - im = Image.open(filename) - im.seek(0) - self.assertEqual(im.tell(), 0) + with Image.open(filename) as im: + im.seek(0) + self.assertEqual(im.tell(), 0) def test_seek_eof(self): filename = "Tests/images/pil136.tiff" - im = Image.open(filename) - self.assertEqual(im.tell(), 0) - self.assertRaises(EOFError, im.seek, -1) - self.assertRaises(EOFError, im.seek, 1) + with Image.open(filename) as im: + self.assertEqual(im.tell(), 0) + self.assertRaises(EOFError, im.seek, -1) + self.assertRaises(EOFError, im.seek, 1) def test__limit_rational_int(self): from PIL.TiffImagePlugin import _limit_rational @@ -439,15 +460,15 @@ class TestFileTiff(PillowTestCase): kwargs = {"resolution_unit": "inch", "x_resolution": 72, "y_resolution": 36} filename = self.tempfile("temp.tif") hopper("RGB").save(filename, **kwargs) - im = Image.open(filename) + with Image.open(filename) as im: - # legacy interface - self.assertEqual(im.tag[X_RESOLUTION][0][0], 72) - self.assertEqual(im.tag[Y_RESOLUTION][0][0], 36) + # legacy interface + self.assertEqual(im.tag[X_RESOLUTION][0][0], 72) + self.assertEqual(im.tag[Y_RESOLUTION][0][0], 36) - # v2 interface - self.assertEqual(im.tag_v2[X_RESOLUTION], 72) - self.assertEqual(im.tag_v2[Y_RESOLUTION], 36) + # v2 interface + self.assertEqual(im.tag_v2[X_RESOLUTION], 72) + self.assertEqual(im.tag_v2[Y_RESOLUTION], 36) def test_roundtrip_tiff_uint16(self): # Test an image of all '0' values @@ -480,9 +501,8 @@ class TestFileTiff(PillowTestCase): def test_strip_planar_raw_with_overviews(self): # gdaladdo tiff_strip_planar_raw2.tif 2 4 8 16 infile = "Tests/images/tiff_strip_planar_raw_with_overviews.tif" - im = Image.open(infile) - - self.assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png") + with Image.open(infile) as im: + self.assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png") def test_tiled_planar_raw(self): # gdal_translate -of GTiff -co TILED=YES -co BLOCKXSIZE=32 \ @@ -545,9 +565,8 @@ class TestFileTiff(PillowTestCase): # Try save-load round trip to make sure both handle icc_profile. tmpfile = self.tempfile("temp.tif") im.save(tmpfile, "TIFF", compression="raw") - reloaded = Image.open(tmpfile) - - self.assertEqual(b"Dummy value", reloaded.info["icc_profile"]) + with Image.open(tmpfile) as reloaded: + self.assertEqual(b"Dummy value", reloaded.info["icc_profile"]) def test_close_on_load_exclusive(self): # similar to test_fd_leak, but runs on unixlike os diff --git a/Tests/test_file_tiff_metadata.py b/Tests/test_file_tiff_metadata.py index 170cac71e..09b510511 100644 --- a/Tests/test_file_tiff_metadata.py +++ b/Tests/test_file_tiff_metadata.py @@ -52,77 +52,81 @@ class TestFileTiffMetadata(PillowTestCase): img.save(f, tiffinfo=info) - loaded = Image.open(f) + with Image.open(f) as loaded: - self.assertEqual(loaded.tag[ImageJMetaDataByteCounts], (len(bindata),)) - self.assertEqual(loaded.tag_v2[ImageJMetaDataByteCounts], (len(bindata),)) + self.assertEqual(loaded.tag[ImageJMetaDataByteCounts], (len(bindata),)) + self.assertEqual(loaded.tag_v2[ImageJMetaDataByteCounts], (len(bindata),)) - self.assertEqual(loaded.tag[ImageJMetaData], bindata) - self.assertEqual(loaded.tag_v2[ImageJMetaData], bindata) + self.assertEqual(loaded.tag[ImageJMetaData], bindata) + self.assertEqual(loaded.tag_v2[ImageJMetaData], bindata) - self.assertEqual(loaded.tag[ImageDescription], (reloaded_textdata,)) - self.assertEqual(loaded.tag_v2[ImageDescription], reloaded_textdata) + self.assertEqual(loaded.tag[ImageDescription], (reloaded_textdata,)) + self.assertEqual(loaded.tag_v2[ImageDescription], reloaded_textdata) - loaded_float = loaded.tag[tag_ids["RollAngle"]][0] - self.assertAlmostEqual(loaded_float, floatdata, places=5) - loaded_double = loaded.tag[tag_ids["YawAngle"]][0] - self.assertAlmostEqual(loaded_double, doubledata) + loaded_float = loaded.tag[tag_ids["RollAngle"]][0] + self.assertAlmostEqual(loaded_float, floatdata, places=5) + loaded_double = loaded.tag[tag_ids["YawAngle"]][0] + self.assertAlmostEqual(loaded_double, doubledata) # check with 2 element ImageJMetaDataByteCounts, issue #2006 info[ImageJMetaDataByteCounts] = (8, len(bindata) - 8) img.save(f, tiffinfo=info) - loaded = Image.open(f) + with Image.open(f) as loaded: - self.assertEqual(loaded.tag[ImageJMetaDataByteCounts], (8, len(bindata) - 8)) - self.assertEqual(loaded.tag_v2[ImageJMetaDataByteCounts], (8, len(bindata) - 8)) + self.assertEqual( + loaded.tag[ImageJMetaDataByteCounts], (8, len(bindata) - 8) + ) + self.assertEqual( + loaded.tag_v2[ImageJMetaDataByteCounts], (8, len(bindata) - 8) + ) def test_read_metadata(self): - img = Image.open("Tests/images/hopper_g4.tif") + with Image.open("Tests/images/hopper_g4.tif") as img: - self.assertEqual( - { - "YResolution": IFDRational(4294967295, 113653537), - "PlanarConfiguration": 1, - "BitsPerSample": (1,), - "ImageLength": 128, - "Compression": 4, - "FillOrder": 1, - "RowsPerStrip": 128, - "ResolutionUnit": 3, - "PhotometricInterpretation": 0, - "PageNumber": (0, 1), - "XResolution": IFDRational(4294967295, 113653537), - "ImageWidth": 128, - "Orientation": 1, - "StripByteCounts": (1968,), - "SamplesPerPixel": 1, - "StripOffsets": (8,), - }, - img.tag_v2.named(), - ) + self.assertEqual( + { + "YResolution": IFDRational(4294967295, 113653537), + "PlanarConfiguration": 1, + "BitsPerSample": (1,), + "ImageLength": 128, + "Compression": 4, + "FillOrder": 1, + "RowsPerStrip": 128, + "ResolutionUnit": 3, + "PhotometricInterpretation": 0, + "PageNumber": (0, 1), + "XResolution": IFDRational(4294967295, 113653537), + "ImageWidth": 128, + "Orientation": 1, + "StripByteCounts": (1968,), + "SamplesPerPixel": 1, + "StripOffsets": (8,), + }, + img.tag_v2.named(), + ) - self.assertEqual( - { - "YResolution": ((4294967295, 113653537),), - "PlanarConfiguration": (1,), - "BitsPerSample": (1,), - "ImageLength": (128,), - "Compression": (4,), - "FillOrder": (1,), - "RowsPerStrip": (128,), - "ResolutionUnit": (3,), - "PhotometricInterpretation": (0,), - "PageNumber": (0, 1), - "XResolution": ((4294967295, 113653537),), - "ImageWidth": (128,), - "Orientation": (1,), - "StripByteCounts": (1968,), - "SamplesPerPixel": (1,), - "StripOffsets": (8,), - }, - img.tag.named(), - ) + self.assertEqual( + { + "YResolution": ((4294967295, 113653537),), + "PlanarConfiguration": (1,), + "BitsPerSample": (1,), + "ImageLength": (128,), + "Compression": (4,), + "FillOrder": (1,), + "RowsPerStrip": (128,), + "ResolutionUnit": (3,), + "PhotometricInterpretation": (0,), + "PageNumber": (0, 1), + "XResolution": ((4294967295, 113653537),), + "ImageWidth": (128,), + "Orientation": (1,), + "StripByteCounts": (1968,), + "SamplesPerPixel": (1,), + "StripOffsets": (8,), + }, + img.tag.named(), + ) def test_write_metadata(self): """ Test metadata writing through the python code """ @@ -131,10 +135,10 @@ class TestFileTiffMetadata(PillowTestCase): f = self.tempfile("temp.tiff") img.save(f, tiffinfo=img.tag) - loaded = Image.open(f) + with Image.open(f) as loaded: - original = img.tag_v2.named() - reloaded = loaded.tag_v2.named() + original = img.tag_v2.named() + reloaded = loaded.tag_v2.named() for k, v in original.items(): if isinstance(v, IFDRational): @@ -187,18 +191,18 @@ class TestFileTiffMetadata(PillowTestCase): out = self.tempfile("temp.tiff") im.save(out) - reloaded = Image.open(out) - self.assertNotIsInstance(im.info["icc_profile"], tuple) - self.assertEqual(im.info["icc_profile"], reloaded.info["icc_profile"]) + with Image.open(out) as reloaded: + self.assertNotIsInstance(im.info["icc_profile"], tuple) + self.assertEqual(im.info["icc_profile"], reloaded.info["icc_profile"]) def test_iccprofile_binary(self): # https://github.com/python-pillow/Pillow/issues/1526 # We should be able to load this, # but probably won't be able to save it. - im = Image.open("Tests/images/hopper.iccprofile_binary.tif") - self.assertEqual(im.tag_v2.tagtype[34675], 1) - self.assertTrue(im.info["icc_profile"]) + with Image.open("Tests/images/hopper.iccprofile_binary.tif") as im: + self.assertEqual(im.tag_v2.tagtype[34675], 1) + self.assertTrue(im.info["icc_profile"]) def test_iccprofile_save_png(self): im = Image.open("Tests/images/hopper.iccprofile.tif") @@ -218,9 +222,9 @@ class TestFileTiffMetadata(PillowTestCase): out = self.tempfile("temp.tiff") im.save(out, tiffinfo=info, compression="raw") - reloaded = Image.open(out) - self.assertEqual(0, reloaded.tag_v2[41988].numerator) - self.assertEqual(0, reloaded.tag_v2[41988].denominator) + with Image.open(out) as reloaded: + self.assertEqual(0, reloaded.tag_v2[41988].numerator) + self.assertEqual(0, reloaded.tag_v2[41988].denominator) def test_empty_values(self): data = io.BytesIO( @@ -243,9 +247,9 @@ class TestFileTiffMetadata(PillowTestCase): self.assertIsInstance(im.tag_v2[34377][0], bytes) out = self.tempfile("temp.tiff") im.save(out) - reloaded = Image.open(out) - self.assertEqual(len(reloaded.tag_v2[34377]), 1) - self.assertIsInstance(reloaded.tag_v2[34377][0], bytes) + with Image.open(out) as reloaded: + self.assertEqual(len(reloaded.tag_v2[34377]), 1) + self.assertIsInstance(reloaded.tag_v2[34377][0], bytes) def test_too_many_entries(self): ifd = TiffImagePlugin.ImageFileDirectory_v2() diff --git a/Tests/test_file_webp.py b/Tests/test_file_webp.py index 4d44f47b6..35ce3dba7 100644 --- a/Tests/test_file_webp.py +++ b/Tests/test_file_webp.py @@ -158,19 +158,19 @@ class TestFileWebp(PillowTestCase): HAVE_WEBP and _webp.HAVE_WEBPANIM, "WebP save all not available" ) def test_background_from_gif(self): - im = Image.open("Tests/images/chi.gif") - original_value = im.convert("RGB").getpixel((1, 1)) + with Image.open("Tests/images/chi.gif") as im: + original_value = im.convert("RGB").getpixel((1, 1)) - # Save as WEBP - out_webp = self.tempfile("temp.webp") - im.save(out_webp, save_all=True) + # Save as WEBP + out_webp = self.tempfile("temp.webp") + im.save(out_webp, save_all=True) # Save as GIF out_gif = self.tempfile("temp.gif") Image.open(out_webp).save(out_gif) - reread = Image.open(out_gif) - reread_value = reread.convert("RGB").getpixel((1, 1)) + with Image.open(out_gif) as reread: + reread_value = reread.convert("RGB").getpixel((1, 1)) difference = sum( [abs(original_value[i] - reread_value[i]) for i in range(0, 3)] ) diff --git a/Tests/test_file_webp_alpha.py b/Tests/test_file_webp_alpha.py index f2f10d7b7..9693f691f 100644 --- a/Tests/test_file_webp_alpha.py +++ b/Tests/test_file_webp_alpha.py @@ -103,7 +103,8 @@ class TestFileWebpAlpha(PillowTestCase): temp_file = self.tempfile("temp.webp") file_path = "Tests/images/transparent.gif" - Image.open(file_path).save(temp_file) + with Image.open(file_path) as im: + im.save(temp_file) image = Image.open(temp_file) self.assertEqual(image.mode, "RGBA") @@ -112,6 +113,7 @@ class TestFileWebpAlpha(PillowTestCase): image.load() image.getdata() - target = Image.open(file_path).convert("RGBA") + with Image.open(file_path) as im: + target = im.convert("RGBA") self.assert_image_similar(image, target, 25.0) diff --git a/Tests/test_file_webp_animated.py b/Tests/test_file_webp_animated.py index dec74d0d0..a5d71093d 100644 --- a/Tests/test_file_webp_animated.py +++ b/Tests/test_file_webp_animated.py @@ -28,13 +28,13 @@ class TestFileWebpAnimation(PillowTestCase): attributes correctly. """ - im = Image.open("Tests/images/hopper.webp") - self.assertEqual(im.n_frames, 1) - self.assertFalse(im.is_animated) + with Image.open("Tests/images/hopper.webp") as im: + self.assertEqual(im.n_frames, 1) + self.assertFalse(im.is_animated) - im = Image.open("Tests/images/iss634.webp") - self.assertEqual(im.n_frames, 42) - self.assertTrue(im.is_animated) + with Image.open("Tests/images/iss634.webp") as im: + self.assertEqual(im.n_frames, 42) + self.assertTrue(im.is_animated) def test_write_animation_L(self): """ @@ -43,23 +43,23 @@ class TestFileWebpAnimation(PillowTestCase): visually similar. """ - orig = Image.open("Tests/images/iss634.gif") - self.assertGreater(orig.n_frames, 1) + with Image.open("Tests/images/iss634.gif") as orig: + self.assertGreater(orig.n_frames, 1) - temp_file = self.tempfile("temp.webp") - orig.save(temp_file, save_all=True) - im = Image.open(temp_file) - self.assertEqual(im.n_frames, orig.n_frames) + temp_file = self.tempfile("temp.webp") + orig.save(temp_file, save_all=True) + im = Image.open(temp_file) + self.assertEqual(im.n_frames, orig.n_frames) - # Compare first and last frames to the original animated GIF - orig.load() - im.load() - self.assert_image_similar(im, orig.convert("RGBA"), 25.0) - orig.seek(orig.n_frames - 1) - im.seek(im.n_frames - 1) - orig.load() - im.load() - self.assert_image_similar(im, orig.convert("RGBA"), 25.0) + # Compare first and last frames to the original animated GIF + orig.load() + im.load() + self.assert_image_similar(im, orig.convert("RGBA"), 25.0) + orig.seek(orig.n_frames - 1) + im.seek(im.n_frames - 1) + orig.load() + im.load() + self.assert_image_similar(im, orig.convert("RGBA"), 25.0) def test_write_animation_RGB(self): """ diff --git a/Tests/test_file_webp_metadata.py b/Tests/test_file_webp_metadata.py index 6351dc1e1..6a25ea261 100644 --- a/Tests/test_file_webp_metadata.py +++ b/Tests/test_file_webp_metadata.py @@ -24,21 +24,21 @@ class TestFileWebpMetadata(PillowTestCase): def test_read_exif_metadata(self): file_path = "Tests/images/flower.webp" - image = Image.open(file_path) + with Image.open(file_path) as image: - self.assertEqual(image.format, "WEBP") - exif_data = image.info.get("exif", None) - self.assertTrue(exif_data) + self.assertEqual(image.format, "WEBP") + exif_data = image.info.get("exif", None) + self.assertTrue(exif_data) - exif = image._getexif() + exif = image._getexif() - # camera make - self.assertEqual(exif[271], "Canon") + # camera make + self.assertEqual(exif[271], "Canon") - jpeg_image = Image.open("Tests/images/flower.jpg") - expected_exif = jpeg_image.info["exif"] + with Image.open("Tests/images/flower.jpg") as jpeg_image: + expected_exif = jpeg_image.info["exif"] - self.assertEqual(exif_data, expected_exif) + self.assertEqual(exif_data, expected_exif) def test_write_exif_metadata(self): file_path = "Tests/images/flower.jpg" @@ -60,17 +60,17 @@ class TestFileWebpMetadata(PillowTestCase): def test_read_icc_profile(self): file_path = "Tests/images/flower2.webp" - image = Image.open(file_path) + with Image.open(file_path) as image: - self.assertEqual(image.format, "WEBP") - self.assertTrue(image.info.get("icc_profile", None)) + self.assertEqual(image.format, "WEBP") + self.assertTrue(image.info.get("icc_profile", None)) - icc = image.info["icc_profile"] + icc = image.info["icc_profile"] - jpeg_image = Image.open("Tests/images/flower2.jpg") - expected_icc = jpeg_image.info["icc_profile"] + with Image.open("Tests/images/flower2.jpg") as jpeg_image: + expected_icc = jpeg_image.info["icc_profile"] - self.assertEqual(icc, expected_icc) + self.assertEqual(icc, expected_icc) def test_write_icc_metadata(self): file_path = "Tests/images/flower2.jpg" @@ -126,10 +126,10 @@ class TestFileWebpMetadata(PillowTestCase): xmp=xmp_data, ) - image = Image.open(temp_file) - self.assertIn("icc_profile", image.info) - self.assertIn("exif", image.info) - self.assertIn("xmp", image.info) - self.assertEqual(iccp_data, image.info.get("icc_profile", None)) - self.assertEqual(exif_data, image.info.get("exif", None)) - self.assertEqual(xmp_data, image.info.get("xmp", None)) + with Image.open(temp_file) as image: + self.assertIn("icc_profile", image.info) + self.assertIn("exif", image.info) + self.assertIn("xmp", image.info) + self.assertEqual(iccp_data, image.info.get("icc_profile", None)) + self.assertEqual(exif_data, image.info.get("exif", None)) + self.assertEqual(xmp_data, image.info.get("xmp", None)) diff --git a/Tests/test_file_wmf.py b/Tests/test_file_wmf.py index cea0cec5b..c07bbf60a 100644 --- a/Tests/test_file_wmf.py +++ b/Tests/test_file_wmf.py @@ -7,24 +7,24 @@ class TestFileWmf(PillowTestCase): def test_load_raw(self): # Test basic EMF open and rendering - im = Image.open("Tests/images/drawing.emf") - if hasattr(Image.core, "drawwmf"): - # Currently, support for WMF/EMF is Windows-only - im.load() - # Compare to reference rendering - imref = Image.open("Tests/images/drawing_emf_ref.png") - imref.load() - self.assert_image_similar(im, imref, 0) + with Image.open("Tests/images/drawing.emf") as im: + if hasattr(Image.core, "drawwmf"): + # Currently, support for WMF/EMF is Windows-only + im.load() + # Compare to reference rendering + imref = Image.open("Tests/images/drawing_emf_ref.png") + imref.load() + self.assert_image_similar(im, imref, 0) # Test basic WMF open and rendering - im = Image.open("Tests/images/drawing.wmf") - if hasattr(Image.core, "drawwmf"): - # Currently, support for WMF/EMF is Windows-only - im.load() - # Compare to reference rendering - imref = Image.open("Tests/images/drawing_wmf_ref.png") - imref.load() - self.assert_image_similar(im, imref, 2.0) + with Image.open("Tests/images/drawing.wmf") as im: + if hasattr(Image.core, "drawwmf"): + # Currently, support for WMF/EMF is Windows-only + im.load() + # Compare to reference rendering + imref = Image.open("Tests/images/drawing_wmf_ref.png") + imref.load() + self.assert_image_similar(im, imref, 2.0) def test_register_handler(self): class TestHandler: @@ -46,12 +46,12 @@ class TestFileWmf(PillowTestCase): def test_load_dpi_rounding(self): # Round up - im = Image.open("Tests/images/drawing.emf") - self.assertEqual(im.info["dpi"], 1424) + with Image.open("Tests/images/drawing.emf") as im: + self.assertEqual(im.info["dpi"], 1424) # Round down - im = Image.open("Tests/images/drawing_roundDown.emf") - self.assertEqual(im.info["dpi"], 1426) + with Image.open("Tests/images/drawing_roundDown.emf") as im: + self.assertEqual(im.info["dpi"], 1426) def test_save(self): im = hopper() diff --git a/Tests/test_file_xbm.py b/Tests/test_file_xbm.py index 3d2259a21..5a1eb54bc 100644 --- a/Tests/test_file_xbm.py +++ b/Tests/test_file_xbm.py @@ -42,11 +42,11 @@ class TestFileXbm(PillowTestCase): filename = "Tests/images/hopper.xbm" # Act - im = Image.open(filename) + with Image.open(filename) as im: - # Assert - self.assertEqual(im.mode, "1") - self.assertEqual(im.size, (128, 128)) + # Assert + self.assertEqual(im.mode, "1") + self.assertEqual(im.size, (128, 128)) def test_open_filename_with_underscore(self): # Arrange @@ -54,8 +54,8 @@ class TestFileXbm(PillowTestCase): filename = "Tests/images/hopper_underscore.xbm" # Act - im = Image.open(filename) + with Image.open(filename) as im: - # Assert - self.assertEqual(im.mode, "1") - self.assertEqual(im.size, (128, 128)) + # Assert + self.assertEqual(im.mode, "1") + self.assertEqual(im.size, (128, 128)) diff --git a/Tests/test_file_xpm.py b/Tests/test_file_xpm.py index a49b7c8dd..a4ea8c491 100644 --- a/Tests/test_file_xpm.py +++ b/Tests/test_file_xpm.py @@ -23,11 +23,11 @@ class TestFileXpm(PillowTestCase): def test_load_read(self): # Arrange - im = Image.open(TEST_FILE) - dummy_bytes = 1 + with Image.open(TEST_FILE) as im: + dummy_bytes = 1 - # Act - data = im.load_read(dummy_bytes) + # Act + data = im.load_read(dummy_bytes) # Assert self.assertEqual(len(data), 16384) diff --git a/Tests/test_image.py b/Tests/test_image.py index 54a7680c6..b494b17dc 100644 --- a/Tests/test_image.py +++ b/Tests/test_image.py @@ -97,9 +97,9 @@ class TestImage(PillowTestCase): def test_pathlib(self): from PIL.Image import Path - im = Image.open(Path("Tests/images/multipage-mmap.tiff")) - self.assertEqual(im.mode, "P") - self.assertEqual(im.size, (10, 10)) + with Image.open(Path("Tests/images/multipage-mmap.tiff")) as im: + self.assertEqual(im.mode, "P") + self.assertEqual(im.size, (10, 10)) im = Image.open(Path("Tests/images/hopper.jpg")) self.assertEqual(im.mode, "RGB") @@ -346,7 +346,8 @@ class TestImage(PillowTestCase): def test_registered_extensions(self): # Arrange # Open an image to trigger plugin registration - Image.open("Tests/images/rgb.jpg") + with Image.open("Tests/images/rgb.jpg"): + pass # Act extensions = Image.registered_extensions() @@ -448,10 +449,10 @@ class TestImage(PillowTestCase): def test_offset_not_implemented(self): # Arrange - im = hopper() + with hopper() as im: - # Act / Assert - self.assertRaises(NotImplementedError, im.offset, None) + # Act / Assert + self.assertRaises(NotImplementedError, im.offset, None) def test_fromstring(self): self.assertRaises(NotImplementedError, Image.fromstring) @@ -522,8 +523,8 @@ class TestImage(PillowTestCase): def test_remap_palette(self): # Test illegal image mode - im = hopper() - self.assertRaises(ValueError, im.remap_palette, None) + with hopper() as im: + self.assertRaises(ValueError, im.remap_palette, None) def test__new(self): from PIL import ImagePalette @@ -587,12 +588,12 @@ class TestImage(PillowTestCase): def test_overrun(self): for file in ["fli_overrun.bin", "sgi_overrun.bin", "pcx_overrun.bin"]: - im = Image.open(os.path.join("Tests/images", file)) - try: - im.load() - self.assertFail() - except IOError as e: - self.assertEqual(str(e), "buffer overrun when reading image file") + with Image.open(os.path.join("Tests/images", file)) as im: + try: + im.load() + self.assertFail() + except IOError as e: + self.assertEqual(str(e), "buffer overrun when reading image file") class MockEncoder(object): diff --git a/Tests/test_image_convert.py b/Tests/test_image_convert.py index abbd2a45f..80fa9f513 100644 --- a/Tests/test_image_convert.py +++ b/Tests/test_image_convert.py @@ -144,11 +144,11 @@ class TestImageConvert(PillowTestCase): def test_gif_with_rgba_palette_to_p(self): # See https://github.com/python-pillow/Pillow/issues/2433 - im = Image.open("Tests/images/hopper.gif") - im.info["transparency"] = 255 - im.load() - self.assertEqual(im.palette.mode, "RGBA") - im_p = im.convert("P") + with Image.open("Tests/images/hopper.gif") as im: + im.info["transparency"] = 255 + im.load() + self.assertEqual(im.palette.mode, "RGBA") + im_p = im.convert("P") # Should not raise ValueError: unrecognized raw mode im_p.load() diff --git a/Tests/test_image_fromqimage.py b/Tests/test_image_fromqimage.py index d7556a680..bf3a250f3 100644 --- a/Tests/test_image_fromqimage.py +++ b/Tests/test_image_fromqimage.py @@ -5,12 +5,15 @@ from .test_imageqt import PillowQtTestCase class TestFromQImage(PillowQtTestCase, PillowTestCase): - - files_to_test = [ - hopper(), - Image.open("Tests/images/transparent.png"), - Image.open("Tests/images/7x13.png"), - ] + def setUp(self): + super(TestFromQImage, self).setUp() + self.files_to_test = [ + hopper(), + Image.open("Tests/images/transparent.png"), + Image.open("Tests/images/7x13.png"), + ] + for im in self.files_to_test: + self.addCleanup(im.close) def roundtrip(self, expected): # PIL -> Qt diff --git a/Tests/test_image_mode.py b/Tests/test_image_mode.py index e23957916..1d41d8609 100644 --- a/Tests/test_image_mode.py +++ b/Tests/test_image_mode.py @@ -6,8 +6,8 @@ from .helper import PillowTestCase, hopper class TestImageMode(PillowTestCase): def test_sanity(self): - im = hopper() - im.mode + with hopper() as im: + im.mode from PIL import ImageMode diff --git a/Tests/test_image_resize.py b/Tests/test_image_resize.py index 7c35be570..2538dd378 100644 --- a/Tests/test_image_resize.py +++ b/Tests/test_image_resize.py @@ -148,5 +148,5 @@ class TestImageResize(PillowTestCase): resize(mode, (188, 214)) # Test unknown resampling filter - im = hopper() - self.assertRaises(ValueError, im.resize, (10, 10), "unknown") + with hopper() as im: + self.assertRaises(ValueError, im.resize, (10, 10), "unknown") diff --git a/Tests/test_image_thumbnail.py b/Tests/test_image_thumbnail.py index bd7c98c28..d1224f075 100644 --- a/Tests/test_image_thumbnail.py +++ b/Tests/test_image_thumbnail.py @@ -39,11 +39,11 @@ class TestImageThumbnail(PillowTestCase): def test_no_resize(self): # Check that draft() can resize the image to the destination size - im = Image.open("Tests/images/hopper.jpg") - im.draft(None, (64, 64)) - self.assertEqual(im.size, (64, 64)) + with Image.open("Tests/images/hopper.jpg") as im: + im.draft(None, (64, 64)) + self.assertEqual(im.size, (64, 64)) # Test thumbnail(), where only draft() is necessary to resize the image - im = Image.open("Tests/images/hopper.jpg") - im.thumbnail((64, 64)) - self.assert_image(im, im.mode, (64, 64)) + with Image.open("Tests/images/hopper.jpg") as im: + im.thumbnail((64, 64)) + self.assert_image(im, im.mode, (64, 64)) diff --git a/Tests/test_image_transform.py b/Tests/test_image_transform.py index a0e54176a..e00a22a3d 100644 --- a/Tests/test_image_transform.py +++ b/Tests/test_image_transform.py @@ -156,21 +156,21 @@ class TestImageTransform(PillowTestCase): self.test_mesh() def test_missing_method_data(self): - im = hopper() - self.assertRaises(ValueError, im.transform, (100, 100), None) + with hopper() as im: + self.assertRaises(ValueError, im.transform, (100, 100), None) def test_unknown_resampling_filter(self): - im = hopper() - (w, h) = im.size - for resample in (Image.BOX, "unknown"): - self.assertRaises( - ValueError, - im.transform, - (100, 100), - Image.EXTENT, - (0, 0, w, h), - resample, - ) + with hopper() as im: + (w, h) = im.size + for resample in (Image.BOX, "unknown"): + self.assertRaises( + ValueError, + im.transform, + (100, 100), + Image.EXTENT, + (0, 0, w, h), + resample, + ) class TestImageTransformAffine(PillowTestCase): diff --git a/Tests/test_imagecms.py b/Tests/test_imagecms.py index 10465e739..97f81fb3f 100644 --- a/Tests/test_imagecms.py +++ b/Tests/test_imagecms.py @@ -58,10 +58,10 @@ class TestImageCms(PillowTestCase): i = ImageCms.applyTransform(hopper(), t) self.assert_image(i, "RGB", (128, 128)) - i = hopper() - t = ImageCms.buildTransform(SRGB, SRGB, "RGB", "RGB") - ImageCms.applyTransform(hopper(), t, inPlace=True) - self.assert_image(i, "RGB", (128, 128)) + with hopper() as i: + t = ImageCms.buildTransform(SRGB, SRGB, "RGB", "RGB") + ImageCms.applyTransform(hopper(), t, inPlace=True) + self.assert_image(i, "RGB", (128, 128)) p = ImageCms.createProfile("sRGB") o = ImageCms.getOpenProfile(SRGB) @@ -151,8 +151,8 @@ class TestImageCms(PillowTestCase): def test_extensions(self): # extensions - i = Image.open("Tests/images/rgb.jpg") - p = ImageCms.getOpenProfile(BytesIO(i.info["icc_profile"])) + with Image.open("Tests/images/rgb.jpg") as i: + p = ImageCms.getOpenProfile(BytesIO(i.info["icc_profile"])) self.assertEqual( ImageCms.getProfileName(p).strip(), "IEC 61966-2.1 Default RGB colour space - sRGB", @@ -166,9 +166,10 @@ class TestImageCms(PillowTestCase): self.assertRaises(ValueError, t.apply_in_place, hopper("RGBA")) # the procedural pyCMS API uses PyCMSError for all sorts of errors - self.assertRaises( - ImageCms.PyCMSError, ImageCms.profileToProfile, hopper(), "foo", "bar" - ) + with hopper() as im: + self.assertRaises( + ImageCms.PyCMSError, ImageCms.profileToProfile, im, "foo", "bar" + ) self.assertRaises( ImageCms.PyCMSError, ImageCms.buildTransform, "foo", "bar", "RGB", "RGB" ) @@ -266,8 +267,8 @@ class TestImageCms(PillowTestCase): self.assert_image_similar(hopper(), out, 2) def test_profile_tobytes(self): - i = Image.open("Tests/images/rgb.jpg") - p = ImageCms.getOpenProfile(BytesIO(i.info["icc_profile"])) + with Image.open("Tests/images/rgb.jpg") as i: + p = ImageCms.getOpenProfile(BytesIO(i.info["icc_profile"])) p2 = ImageCms.getOpenProfile(BytesIO(p.tobytes())) diff --git a/Tests/test_imagedraw.py b/Tests/test_imagedraw.py index bfc2c3c9c..75e658d65 100644 --- a/Tests/test_imagedraw.py +++ b/Tests/test_imagedraw.py @@ -45,10 +45,10 @@ class TestImageDraw(PillowTestCase): draw.rectangle(list(range(4))) def test_valueerror(self): - im = Image.open("Tests/images/chi.gif") + with Image.open("Tests/images/chi.gif") as im: - draw = ImageDraw.Draw(im) - draw.line((0, 0), fill=(0, 0, 0)) + draw = ImageDraw.Draw(im) + draw.line((0, 0), fill=(0, 0, 0)) def test_mode_mismatch(self): im = hopper("RGB").copy() diff --git a/Tests/test_imagefile.py b/Tests/test_imagefile.py index a367f62df..dad408e93 100644 --- a/Tests/test_imagefile.py +++ b/Tests/test_imagefile.py @@ -115,13 +115,13 @@ class TestImageFile(PillowTestCase): if "zip_encoder" not in codecs: self.skipTest("PNG (zlib) encoder not available") - im = Image.open("Tests/images/truncated_image.png") - with self.assertRaises(IOError): - im.load() + with Image.open("Tests/images/truncated_image.png") as im: + with self.assertRaises(IOError): + im.load() - # Test that the error is raised if loaded a second time - with self.assertRaises(IOError): - im.load() + # Test that the error is raised if loaded a second time + with self.assertRaises(IOError): + im.load() def test_truncated_without_errors(self): if "zip_encoder" not in codecs: @@ -258,12 +258,12 @@ class TestPyDecoder(PillowTestCase): exif[40963] = 455 exif[11] = "Pillow test" im.save(out, exif=exif) - reloaded = Image.open(out) - reloaded_exif = reloaded.getexif() - self.assertEqual(reloaded_exif[258], 8) - self.assertNotIn(40960, exif) - self.assertEqual(reloaded_exif[40963], 455) - self.assertEqual(exif[11], "Pillow test") + with Image.open(out) as reloaded: + reloaded_exif = reloaded.getexif() + self.assertEqual(reloaded_exif[258], 8) + self.assertNotIn(40960, exif) + self.assertEqual(reloaded_exif[40963], 455) + self.assertEqual(exif[11], "Pillow test") im = Image.open("Tests/images/no-dpi-in-exif.jpg") # Big endian exif = im.getexif() @@ -278,12 +278,12 @@ class TestPyDecoder(PillowTestCase): exif[40963] = 455 exif[305] = "Pillow test" im.save(out, exif=exif) - reloaded = Image.open(out) - reloaded_exif = reloaded.getexif() - self.assertEqual(reloaded_exif[258], 8) - self.assertNotIn(40960, exif) - self.assertEqual(reloaded_exif[40963], 455) - self.assertEqual(exif[305], "Pillow test") + with Image.open(out) as reloaded: + reloaded_exif = reloaded.getexif() + self.assertEqual(reloaded_exif[258], 8) + self.assertNotIn(40960, exif) + self.assertEqual(reloaded_exif[40963], 455) + self.assertEqual(exif[305], "Pillow test") @unittest.skipIf( not HAVE_WEBP or not _webp.HAVE_WEBPANIM, @@ -300,11 +300,11 @@ class TestPyDecoder(PillowTestCase): exif[305] = "Pillow test" def check_exif(): - reloaded = Image.open(out) - reloaded_exif = reloaded.getexif() - self.assertEqual(reloaded_exif[258], 8) - self.assertEqual(reloaded_exif[40963], 455) - self.assertEqual(exif[305], "Pillow test") + with Image.open(out) as reloaded: + reloaded_exif = reloaded.getexif() + self.assertEqual(reloaded_exif[258], 8) + self.assertEqual(reloaded_exif[40963], 455) + self.assertEqual(exif[305], "Pillow test") im.save(out, exif=exif) check_exif() @@ -323,23 +323,13 @@ class TestPyDecoder(PillowTestCase): exif[305] = "Pillow test" im.save(out, exif=exif) - reloaded = Image.open(out) - reloaded_exif = reloaded.getexif() - self.assertEqual(reloaded_exif, {258: 8, 40963: 455, 305: "Pillow test"}) + with Image.open(out) as reloaded: + reloaded_exif = reloaded.getexif() + self.assertEqual(reloaded_exif, {258: 8, 40963: 455, 305: "Pillow test"}) def test_exif_interop(self): - im = Image.open("Tests/images/flower.jpg") - exif = im.getexif() - self.assertEqual( - exif.get_ifd(0xA005), {1: "R98", 2: b"0100", 4097: 2272, 4098: 1704} - ) - - def test_exif_shared(self): - im = Image.open("Tests/images/exif.png") - exif = im.getexif() - self.assertIs(im.getexif(), exif) - - def test_exif_str(self): - im = Image.open("Tests/images/exif.png") - exif = im.getexif() - self.assertEqual(str(exif), "{274: 1}") + with Image.open("Tests/images/flower.jpg") as im: + exif = im.getexif() + self.assertEqual( + exif.get_ifd(0xA005), {1: "R98", 2: b"0100", 4097: 2272, 4098: 1704} + ) diff --git a/Tests/test_imageops_usm.py b/Tests/test_imageops_usm.py index 8340c5f0d..4ed8a83a7 100644 --- a/Tests/test_imageops_usm.py +++ b/Tests/test_imageops_usm.py @@ -2,57 +2,61 @@ from PIL import Image, ImageFilter from .helper import PillowTestCase -im = Image.open("Tests/images/hopper.ppm") -snakes = Image.open("Tests/images/color_snakes.png") - class TestImageOpsUsm(PillowTestCase): + def setUp(self): + super(TestImageOpsUsm, self).setUp() + self.im = Image.open("Tests/images/hopper.ppm") + self.addCleanup(self.im.close) + self.snakes = Image.open("Tests/images/color_snakes.png") + self.addCleanup(self.snakes.close) + def test_filter_api(self): test_filter = ImageFilter.GaussianBlur(2.0) - i = im.filter(test_filter) + i = self.im.filter(test_filter) self.assertEqual(i.mode, "RGB") self.assertEqual(i.size, (128, 128)) test_filter = ImageFilter.UnsharpMask(2.0, 125, 8) - i = im.filter(test_filter) + i = self.im.filter(test_filter) self.assertEqual(i.mode, "RGB") self.assertEqual(i.size, (128, 128)) def test_usm_formats(self): usm = ImageFilter.UnsharpMask - self.assertRaises(ValueError, im.convert("1").filter, usm) - im.convert("L").filter(usm) - self.assertRaises(ValueError, im.convert("I").filter, usm) - self.assertRaises(ValueError, im.convert("F").filter, usm) - im.convert("RGB").filter(usm) - im.convert("RGBA").filter(usm) - im.convert("CMYK").filter(usm) - self.assertRaises(ValueError, im.convert("YCbCr").filter, usm) + self.assertRaises(ValueError, self.im.convert("1").filter, usm) + self.im.convert("L").filter(usm) + self.assertRaises(ValueError, self.im.convert("I").filter, usm) + self.assertRaises(ValueError, self.im.convert("F").filter, usm) + self.im.convert("RGB").filter(usm) + self.im.convert("RGBA").filter(usm) + self.im.convert("CMYK").filter(usm) + self.assertRaises(ValueError, self.im.convert("YCbCr").filter, usm) def test_blur_formats(self): blur = ImageFilter.GaussianBlur - self.assertRaises(ValueError, im.convert("1").filter, blur) - blur(im.convert("L")) - self.assertRaises(ValueError, im.convert("I").filter, blur) - self.assertRaises(ValueError, im.convert("F").filter, blur) - im.convert("RGB").filter(blur) - im.convert("RGBA").filter(blur) - im.convert("CMYK").filter(blur) - self.assertRaises(ValueError, im.convert("YCbCr").filter, blur) + self.assertRaises(ValueError, self.im.convert("1").filter, blur) + blur(self.im.convert("L")) + self.assertRaises(ValueError, self.im.convert("I").filter, blur) + self.assertRaises(ValueError, self.im.convert("F").filter, blur) + self.im.convert("RGB").filter(blur) + self.im.convert("RGBA").filter(blur) + self.im.convert("CMYK").filter(blur) + self.assertRaises(ValueError, self.im.convert("YCbCr").filter, blur) def test_usm_accuracy(self): - src = snakes.convert("RGB") + src = self.snakes.convert("RGB") i = src.filter(ImageFilter.UnsharpMask(5, 1024, 0)) # Image should not be changed because it have only 0 and 255 levels. self.assertEqual(i.tobytes(), src.tobytes()) def test_blur_accuracy(self): - i = snakes.filter(ImageFilter.GaussianBlur(0.4)) + i = self.snakes.filter(ImageFilter.GaussianBlur(0.4)) # These pixels surrounded with pixels with 255 intensity. # They must be very close to 255. for x, y, c in [ diff --git a/Tests/test_imagesequence.py b/Tests/test_imagesequence.py index 1eea839da..17f8100b7 100644 --- a/Tests/test_imagesequence.py +++ b/Tests/test_imagesequence.py @@ -24,25 +24,25 @@ class TestImageSequence(PillowTestCase): self.assertRaises(AttributeError, ImageSequence.Iterator, 0) def test_iterator(self): - im = Image.open("Tests/images/multipage.tiff") - i = ImageSequence.Iterator(im) - for index in range(0, im.n_frames): - self.assertEqual(i[index], next(i)) - self.assertRaises(IndexError, lambda: i[index + 1]) - self.assertRaises(StopIteration, next, i) + with Image.open("Tests/images/multipage.tiff") as im: + i = ImageSequence.Iterator(im) + for index in range(0, im.n_frames): + self.assertEqual(i[index], next(i)) + self.assertRaises(IndexError, lambda: i[index + 1]) + self.assertRaises(StopIteration, next, i) def test_iterator_min_frame(self): - im = Image.open("Tests/images/hopper.psd") - i = ImageSequence.Iterator(im) - for index in range(1, im.n_frames): - self.assertEqual(i[index], next(i)) + with Image.open("Tests/images/hopper.psd") as im: + i = ImageSequence.Iterator(im) + for index in range(1, im.n_frames): + self.assertEqual(i[index], next(i)) def _test_multipage_tiff(self): - im = Image.open("Tests/images/multipage.tiff") - for index, frame in enumerate(ImageSequence.Iterator(im)): - frame.load() - self.assertEqual(index, im.tell()) - frame.convert("RGB") + with Image.open("Tests/images/multipage.tiff") as im: + for index, frame in enumerate(ImageSequence.Iterator(im)): + frame.load() + self.assertEqual(index, im.tell()) + frame.convert("RGB") def test_tiff(self): self._test_multipage_tiff() @@ -58,41 +58,41 @@ class TestImageSequence(PillowTestCase): TiffImagePlugin.READ_LIBTIFF = False def test_consecutive(self): - im = Image.open("Tests/images/multipage.tiff") - firstFrame = None - for frame in ImageSequence.Iterator(im): - if firstFrame is None: - firstFrame = frame.copy() - for frame in ImageSequence.Iterator(im): - self.assert_image_equal(frame, firstFrame) - break + with Image.open("Tests/images/multipage.tiff") as im: + firstFrame = None + for frame in ImageSequence.Iterator(im): + if firstFrame is None: + firstFrame = frame.copy() + for frame in ImageSequence.Iterator(im): + self.assert_image_equal(frame, firstFrame) + break def test_palette_mmap(self): # Using mmap in ImageFile can require to reload the palette. - im = Image.open("Tests/images/multipage-mmap.tiff") - color1 = im.getpalette()[0:3] - im.seek(0) - color2 = im.getpalette()[0:3] - self.assertEqual(color1, color2) + with Image.open("Tests/images/multipage-mmap.tiff") as im: + color1 = im.getpalette()[0:3] + im.seek(0) + color2 = im.getpalette()[0:3] + self.assertEqual(color1, color2) def test_all_frames(self): # Test a single image - im = Image.open("Tests/images/iss634.gif") - ims = ImageSequence.all_frames(im) + with Image.open("Tests/images/iss634.gif") as im: + ims = ImageSequence.all_frames(im) - self.assertEqual(len(ims), 42) - for i, im_frame in enumerate(ims): - self.assertFalse(im_frame is im) + self.assertEqual(len(ims), 42) + for i, im_frame in enumerate(ims): + self.assertFalse(im_frame is im) - im.seek(i) - self.assert_image_equal(im, im_frame) + im.seek(i) + self.assert_image_equal(im, im_frame) - # Test a series of images - ims = ImageSequence.all_frames([im, hopper(), im]) - self.assertEqual(len(ims), 85) + # Test a series of images + ims = ImageSequence.all_frames([im, hopper(), im]) + self.assertEqual(len(ims), 85) - # Test an operation - ims = ImageSequence.all_frames(im, lambda im_frame: im_frame.rotate(90)) - for i, im_frame in enumerate(ims): - im.seek(i) - self.assert_image_equal(im.rotate(90), im_frame) + # Test an operation + ims = ImageSequence.all_frames(im, lambda im_frame: im_frame.rotate(90)) + for i, im_frame in enumerate(ims): + im.seek(i) + self.assert_image_equal(im.rotate(90), im_frame) diff --git a/Tests/test_imageshow.py b/Tests/test_imageshow.py index aac48d6c0..225c8a6a9 100644 --- a/Tests/test_imageshow.py +++ b/Tests/test_imageshow.py @@ -27,8 +27,8 @@ class TestImageShow(PillowTestCase): ImageShow.register(viewer, -1) for mode in ("1", "I;16", "LA", "RGB", "RGBA"): - im = hopper(mode) - self.assertTrue(ImageShow.show(im)) + with hopper() as im: + self.assertTrue(ImageShow.show(im)) self.assertTrue(viewer.methodCalled) # Restore original state diff --git a/Tests/test_locale.py b/Tests/test_locale.py index cbec8b965..e4b2806e3 100644 --- a/Tests/test_locale.py +++ b/Tests/test_locale.py @@ -26,13 +26,15 @@ path = "Tests/images/hopper.jpg" class TestLocale(PillowTestCase): def test_sanity(self): - Image.open(path) + with Image.open(path): + pass try: locale.setlocale(locale.LC_ALL, "polish") except locale.Error: unittest.skip("Polish locale not available") try: - Image.open(path) + with Image.open(path): + pass finally: locale.setlocale(locale.LC_ALL, (None, None)) diff --git a/Tests/test_map.py b/Tests/test_map.py index 8d4e32219..25e24e2fb 100644 --- a/Tests/test_map.py +++ b/Tests/test_map.py @@ -23,9 +23,9 @@ class TestMap(PillowTestCase): Image.MAX_IMAGE_PIXELS = None # This image hits the offset test. - im = Image.open("Tests/images/l2rgb_read.bmp") - with self.assertRaises((ValueError, MemoryError, IOError)): - im.load() + with Image.open("Tests/images/l2rgb_read.bmp") as im: + with self.assertRaises((ValueError, MemoryError, IOError)): + im.load() Image.MAX_IMAGE_PIXELS = max_pixels diff --git a/Tests/test_mode_i16.py b/Tests/test_mode_i16.py index b1cf2a233..649148699 100644 --- a/Tests/test_mode_i16.py +++ b/Tests/test_mode_i16.py @@ -43,10 +43,10 @@ class TestModeI16(PillowTestCase): filename = self.tempfile("temp.im") imIn.save(filename) - imOut = Image.open(filename) + with Image.open(filename) as imOut: - self.verify(imIn) - self.verify(imOut) + self.verify(imIn) + self.verify(imOut) imOut = imIn.crop((0, 0, w, h)) self.verify(imOut) diff --git a/Tests/test_shell_injection.py b/Tests/test_shell_injection.py index 97774a0a4..3e74647eb 100644 --- a/Tests/test_shell_injection.py +++ b/Tests/test_shell_injection.py @@ -24,7 +24,8 @@ class TestShellInjection(PillowTestCase): dest_file = self.tempfile(filename) save_func(src_img, 0, dest_file) # If file can't be opened, shell injection probably occurred - Image.open(dest_file).load() + with Image.open(dest_file) as im: + im.load() @unittest.skipUnless(djpeg_available(), "djpeg not available") def test_load_djpeg_filename(self): @@ -32,8 +33,8 @@ class TestShellInjection(PillowTestCase): src_file = self.tempfile(filename) shutil.copy(TEST_JPG, src_file) - im = Image.open(src_file) - im.load_djpeg() + with Image.open(src_file) as im: + im.load_djpeg() @unittest.skipUnless(cjpeg_available(), "cjpeg not available") def test_save_cjpeg_filename(self): @@ -42,10 +43,12 @@ class TestShellInjection(PillowTestCase): @unittest.skipUnless(netpbm_available(), "netpbm not available") def test_save_netpbm_filename_bmp_mode(self): - im = Image.open(TEST_GIF).convert("RGB") - self.assert_save_filename_check(im, GifImagePlugin._save_netpbm) + with Image.open(TEST_GIF) as im: + im = im.convert("RGB") + self.assert_save_filename_check(im, GifImagePlugin._save_netpbm) @unittest.skipUnless(netpbm_available(), "netpbm not available") def test_save_netpbm_filename_l_mode(self): - im = Image.open(TEST_GIF).convert("L") - self.assert_save_filename_check(im, GifImagePlugin._save_netpbm) + with Image.open(TEST_GIF) as im: + im = im.convert("L") + self.assert_save_filename_check(im, GifImagePlugin._save_netpbm) diff --git a/Tests/test_tiff_ifdrational.py b/Tests/test_tiff_ifdrational.py index f210c8737..dedbbfe6d 100644 --- a/Tests/test_tiff_ifdrational.py +++ b/Tests/test_tiff_ifdrational.py @@ -54,5 +54,7 @@ class Test_IFDRational(PillowTestCase): res = IFDRational(301, 1) im.save(out, dpi=(res, res), compression="raw") - reloaded = Image.open(out) - self.assertEqual(float(IFDRational(301, 1)), float(reloaded.tag_v2[282])) + with Image.open(out) as reloaded: + self.assertEqual( + float(IFDRational(301, 1)), float(reloaded.tag_v2[282]) + ) diff --git a/docs/handbook/tutorial.rst b/docs/handbook/tutorial.rst index 16090b040..e5da549c3 100644 --- a/docs/handbook/tutorial.rst +++ b/docs/handbook/tutorial.rst @@ -99,9 +99,9 @@ Create JPEG thumbnails outfile = os.path.splitext(infile)[0] + ".thumbnail" if infile != outfile: try: - im = Image.open(infile) - im.thumbnail(size) - im.save(outfile, "JPEG") + with Image.open(infile) as im: + im.thumbnail(size) + im.save(outfile, "JPEG") except IOError: print("cannot create thumbnail for", infile) @@ -267,7 +267,8 @@ Converting between modes :: from PIL import Image - im = Image.open("hopper.ppm").convert("L") + with Image.open("hopper.ppm") as im: + im = im.convert("L") The library supports transformations between each supported mode and the “L” and “RGB” modes. To convert between other modes, you may have to use an @@ -383,15 +384,15 @@ Reading sequences from PIL import Image - im = Image.open("animation.gif") - im.seek(1) # skip to the second frame + with Image.open("animation.gif") as im: + im.seek(1) # skip to the second frame - try: - while 1: - im.seek(im.tell()+1) - # do something to im - except EOFError: - pass # end of sequence + try: + while 1: + im.seek(im.tell()+1) + # do something to im + except EOFError: + pass # end of sequence As seen in this example, you’ll get an :py:exc:`EOFError` exception when the sequence ends. @@ -422,32 +423,34 @@ Drawing Postscript from PIL import Image from PIL import PSDraw - im = Image.open("hopper.ppm") - title = "hopper" - box = (1*72, 2*72, 7*72, 10*72) # in points + with Image.open("hopper.ppm") as im: + title = "hopper" + box = (1*72, 2*72, 7*72, 10*72) # in points - ps = PSDraw.PSDraw() # default is sys.stdout - ps.begin_document(title) + ps = PSDraw.PSDraw() # default is sys.stdout + ps.begin_document(title) - # draw the image (75 dpi) - ps.image(box, im, 75) - ps.rectangle(box) + # draw the image (75 dpi) + ps.image(box, im, 75) + ps.rectangle(box) - # draw title - ps.setfont("HelveticaNarrow-Bold", 36) - ps.text((3*72, 4*72), title) + # draw title + ps.setfont("HelveticaNarrow-Bold", 36) + ps.text((3*72, 4*72), title) - ps.end_document() + ps.end_document() More on reading images ---------------------- As described earlier, the :py:func:`~PIL.Image.open` function of the :py:mod:`~PIL.Image` module is used to open an image file. In most cases, you -simply pass it the filename as an argument:: +simply pass it the filename as an argument. ``Image.open()`` can be used a +context manager:: from PIL import Image - im = Image.open("hopper.ppm") + with Image.open("hopper.ppm") as im: + ... If everything goes well, the result is an :py:class:`PIL.Image.Image` object. Otherwise, an :exc:`IOError` exception is raised. @@ -513,12 +516,12 @@ This is only available for JPEG and MPO files. :: from PIL import Image - from __future__ import print_function - im = Image.open(file) - print("original =", im.mode, im.size) - im.draft("L", (100, 100)) - print("draft =", im.mode, im.size) + with Image.open(file) as im: + print("original =", im.mode, im.size) + + im.draft("L", (100, 100)) + print("draft =", im.mode, im.size) This prints something like:: diff --git a/docs/reference/open_files.rst b/docs/reference/open_files.rst index e26d9e639..ed0ab1a0c 100644 --- a/docs/reference/open_files.rst +++ b/docs/reference/open_files.rst @@ -8,27 +8,25 @@ object, or a file-like object. Pillow uses the filename or ``Path`` to open a file, so for the rest of this article, they will all be treated as a file-like object. -The first four of these items are equivalent, the last is dangerous -and may fail:: +The following are all equivalent:: from PIL import Image import io import pathlib - im = Image.open('test.jpg') + with Image.open('test.jpg') as im: + ... - im2 = Image.open(pathlib.Path('test.jpg')) + with Image.open(pathlib.Path('test.jpg')) as im2: + ... - f = open('test.jpg', 'rb') - im3 = Image.open(f) + with open('test.jpg', 'rb') as f: + im3 = Image.open(f) + ... with open('test.jpg', 'rb') as f: im4 = Image.open(io.BytesIO(f.read())) - - # Dangerous FAIL: - with open('test.jpg', 'rb') as f: - im5 = Image.open(f) - im5.load() # FAILS, closed file + ... If a filename or a path-like object is passed to Pillow, then the resulting file object opened by Pillow may also be closed by Pillow after the @@ -38,13 +36,6 @@ have multiple frames. Pillow cannot in general close and reopen a file, so any access to that file needs to be prior to the close. -Issues ------- - -* Using the file context manager to provide a file-like object to - Pillow is dangerous unless the context of the image is limited to - the context of the file. - Image Lifecycle --------------- @@ -70,9 +61,9 @@ Image Lifecycle ... # image operations here. -The lifecycle of a single-frame image is relatively simple. The file -must remain open until the ``load()`` or ``close()`` function is -called. +The lifecycle of a single-frame image is relatively simple. The file must +remain open until the ``load()`` or ``close()`` function is called or the +context manager exits. Multi-frame images are more complicated. The ``load()`` method is not a terminal method, so it should not close the underlying file. In general, @@ -87,14 +78,16 @@ Complications libtiff (if working on an actual file). Since libtiff closes the file descriptor internally, it is duplicated prior to passing it into libtiff. -* I don't think that there's any way to make this safe without - changing the lazy loading:: +* After a file has been closed, operations that require file access will fail:: - # Dangerous FAIL: with open('test.jpg', 'rb') as f: im5 = Image.open(f) im5.load() # FAILS, closed file + with Image.open('test.jpg') as im6: + pass + im6.load() # FAILS, closed file + Proposed File Handling ---------------------- @@ -104,5 +97,6 @@ Proposed File Handling * ``Image.Image.seek()`` should never close the image file. -* Users of the library should call ``Image.Image.close()`` on any - multi-frame image to ensure that the underlying file is closed. +* Users of the library should use a context manager or call + ``Image.Image.close()`` on any image opened with a filename or ``Path`` + object to ensure that the underlying file is closed. diff --git a/selftest.py b/selftest.py index dcac54a5a..99ca940ec 100755 --- a/selftest.py +++ b/selftest.py @@ -42,8 +42,8 @@ def testimage(): Or open existing files: - >>> im = Image.open("Tests/images/hopper.gif") - >>> _info(im) + >>> with Image.open("Tests/images/hopper.gif") as im: + ... _info(im) ('GIF', 'P', (128, 128)) >>> _info(Image.open("Tests/images/hopper.ppm")) ('PPM', 'RGB', (128, 128)) diff --git a/src/PIL/Image.py b/src/PIL/Image.py index 474ca1e88..d65810d8b 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -622,11 +622,6 @@ class Image(object): # object is gone. self.im = deferred_error(ValueError("Operation on closed image")) - if sys.version_info.major >= 3: - - def __del__(self): - self.__exit__() - def _copy(self): self.load() self.im = self.im.copy() diff --git a/src/PIL/ImageFile.py b/src/PIL/ImageFile.py index a275f95d2..7d5229b8e 100644 --- a/src/PIL/ImageFile.py +++ b/src/PIL/ImageFile.py @@ -103,21 +103,24 @@ class ImageFile(Image.Image): self._exclusive_fp = None try: - self._open() - except ( - IndexError, # end of data - TypeError, # end of data (ord) - KeyError, # unsupported mode - EOFError, # got header but not the first frame - struct.error, - ) as v: + try: + self._open() + except ( + IndexError, # end of data + TypeError, # end of data (ord) + KeyError, # unsupported mode + EOFError, # got header but not the first frame + struct.error, + ) as v: + raise SyntaxError(v) + + if not self.mode or self.size[0] <= 0: + raise SyntaxError("not identified by this driver") + except BaseException: # close the file only if we have opened it this constructor if self._exclusive_fp: self.fp.close() - raise SyntaxError(v) - - if not self.mode or self.size[0] <= 0: - raise SyntaxError("not identified by this driver") + raise def draft(self, mode, size): """Set draft mode""" diff --git a/src/PIL/SpiderImagePlugin.py b/src/PIL/SpiderImagePlugin.py index f1cae4d9f..c7b6fa5f8 100644 --- a/src/PIL/SpiderImagePlugin.py +++ b/src/PIL/SpiderImagePlugin.py @@ -219,7 +219,8 @@ def loadImageSeries(filelist=None): print("unable to find %s" % img) continue try: - im = Image.open(img).convert2byte() + with Image.open(img) as im: + im = im.convert2byte() except Exception: if not isSpiderImage(img): print(img + " is not a Spider image file") diff --git a/src/PIL/TarIO.py b/src/PIL/TarIO.py index 92a08aefb..dc479b905 100644 --- a/src/PIL/TarIO.py +++ b/src/PIL/TarIO.py @@ -15,7 +15,6 @@ # import io -import sys from . import ContainerIO @@ -64,10 +63,5 @@ class TarIO(ContainerIO.ContainerIO): def __exit__(self, *args): self.close() - if sys.version_info.major >= 3: - - def __del__(self): - self.close() - def close(self): self.fh.close()