Merge pull request #4446 from hugovk/convert-asserts

Convert some tests to pytest style
This commit is contained in:
Andrew Murray 2020-02-23 21:48:51 +11:00 committed by GitHub
commit de179eb5c6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 1368 additions and 1295 deletions

View File

@ -49,7 +49,7 @@ class BenchCffiAccess(PillowTestCase):
caccess = im.im.pixel_access(False) caccess = im.im.pixel_access(False)
access = PyAccess.new(im, False) access = PyAccess.new(im, False)
self.assertEqual(caccess[(0, 0)], access[(0, 0)]) assert caccess[(0, 0)] == access[(0, 0)]
print("Size: %sx%s" % im.size) print("Size: %sx%s" % im.size)
timer(iterate_get, "PyAccess - get", im.size, access) timer(iterate_get, "PyAccess - get", im.size, access)

View File

@ -26,7 +26,7 @@ class TestImagingLeaks(PillowTestCase):
mem_limit = mem + 1 mem_limit = mem + 1
continue continue
msg = "memory usage limit exceeded after %d iterations" % (i + 1) msg = "memory usage limit exceeded after %d iterations" % (i + 1)
self.assertLessEqual(mem, mem_limit, msg) assert mem <= mem_limit, msg
def test_leak_putdata(self): def test_leak_putdata(self):
im = Image.new("RGB", (25, 25)) im = Image.new("RGB", (25, 25))

View File

@ -1,10 +1,9 @@
import unittest
from array import array from array import array
import pytest import pytest
from PIL import Image, ImageFilter from PIL import Image, ImageFilter
from .helper import PillowTestCase, assert_image_equal from .helper import assert_image_equal
try: try:
import numpy import numpy
@ -12,7 +11,7 @@ except ImportError:
numpy = None numpy = None
class TestColorLut3DCoreAPI(PillowTestCase): class TestColorLut3DCoreAPI:
def generate_identity_table(self, channels, size): def generate_identity_table(self, channels, size):
if isinstance(size, tuple): if isinstance(size, tuple):
size1D, size2D, size3D = size size1D, size2D, size3D = size
@ -42,37 +41,37 @@ class TestColorLut3DCoreAPI(PillowTestCase):
def test_wrong_args(self): def test_wrong_args(self):
im = Image.new("RGB", (10, 10), 0) im = Image.new("RGB", (10, 10), 0)
with self.assertRaisesRegex(ValueError, "filter"): with pytest.raises(ValueError, match="filter"):
im.im.color_lut_3d("RGB", Image.CUBIC, *self.generate_identity_table(3, 3)) im.im.color_lut_3d("RGB", Image.CUBIC, *self.generate_identity_table(3, 3))
with self.assertRaisesRegex(ValueError, "image mode"): with pytest.raises(ValueError, match="image mode"):
im.im.color_lut_3d( im.im.color_lut_3d(
"wrong", Image.LINEAR, *self.generate_identity_table(3, 3) "wrong", Image.LINEAR, *self.generate_identity_table(3, 3)
) )
with self.assertRaisesRegex(ValueError, "table_channels"): with pytest.raises(ValueError, match="table_channels"):
im.im.color_lut_3d("RGB", Image.LINEAR, *self.generate_identity_table(5, 3)) im.im.color_lut_3d("RGB", Image.LINEAR, *self.generate_identity_table(5, 3))
with self.assertRaisesRegex(ValueError, "table_channels"): with pytest.raises(ValueError, match="table_channels"):
im.im.color_lut_3d("RGB", Image.LINEAR, *self.generate_identity_table(1, 3)) im.im.color_lut_3d("RGB", Image.LINEAR, *self.generate_identity_table(1, 3))
with self.assertRaisesRegex(ValueError, "table_channels"): with pytest.raises(ValueError, match="table_channels"):
im.im.color_lut_3d("RGB", Image.LINEAR, *self.generate_identity_table(2, 3)) im.im.color_lut_3d("RGB", Image.LINEAR, *self.generate_identity_table(2, 3))
with self.assertRaisesRegex(ValueError, "Table size"): with pytest.raises(ValueError, match="Table size"):
im.im.color_lut_3d( im.im.color_lut_3d(
"RGB", Image.LINEAR, *self.generate_identity_table(3, (1, 3, 3)) "RGB", Image.LINEAR, *self.generate_identity_table(3, (1, 3, 3))
) )
with self.assertRaisesRegex(ValueError, "Table size"): with pytest.raises(ValueError, match="Table size"):
im.im.color_lut_3d( im.im.color_lut_3d(
"RGB", Image.LINEAR, *self.generate_identity_table(3, (66, 3, 3)) "RGB", Image.LINEAR, *self.generate_identity_table(3, (66, 3, 3))
) )
with self.assertRaisesRegex(ValueError, r"size1D \* size2D \* size3D"): with pytest.raises(ValueError, match=r"size1D \* size2D \* size3D"):
im.im.color_lut_3d("RGB", Image.LINEAR, 3, 2, 2, 2, [0, 0, 0] * 7) im.im.color_lut_3d("RGB", Image.LINEAR, 3, 2, 2, 2, [0, 0, 0] * 7)
with self.assertRaisesRegex(ValueError, r"size1D \* size2D \* size3D"): with pytest.raises(ValueError, match=r"size1D \* size2D \* size3D"):
im.im.color_lut_3d("RGB", Image.LINEAR, 3, 2, 2, 2, [0, 0, 0] * 9) im.im.color_lut_3d("RGB", Image.LINEAR, 3, 2, 2, 2, [0, 0, 0] * 9)
with pytest.raises(TypeError): with pytest.raises(TypeError):
@ -105,25 +104,25 @@ class TestColorLut3DCoreAPI(PillowTestCase):
) )
def test_wrong_mode(self): def test_wrong_mode(self):
with self.assertRaisesRegex(ValueError, "wrong mode"): with pytest.raises(ValueError, match="wrong mode"):
im = Image.new("L", (10, 10), 0) im = Image.new("L", (10, 10), 0)
im.im.color_lut_3d("RGB", Image.LINEAR, *self.generate_identity_table(3, 3)) im.im.color_lut_3d("RGB", Image.LINEAR, *self.generate_identity_table(3, 3))
with self.assertRaisesRegex(ValueError, "wrong mode"): with pytest.raises(ValueError, match="wrong mode"):
im = Image.new("RGB", (10, 10), 0) im = Image.new("RGB", (10, 10), 0)
im.im.color_lut_3d("L", Image.LINEAR, *self.generate_identity_table(3, 3)) im.im.color_lut_3d("L", Image.LINEAR, *self.generate_identity_table(3, 3))
with self.assertRaisesRegex(ValueError, "wrong mode"): with pytest.raises(ValueError, match="wrong mode"):
im = Image.new("L", (10, 10), 0) im = Image.new("L", (10, 10), 0)
im.im.color_lut_3d("L", Image.LINEAR, *self.generate_identity_table(3, 3)) im.im.color_lut_3d("L", Image.LINEAR, *self.generate_identity_table(3, 3))
with self.assertRaisesRegex(ValueError, "wrong mode"): with pytest.raises(ValueError, match="wrong mode"):
im = Image.new("RGB", (10, 10), 0) im = Image.new("RGB", (10, 10), 0)
im.im.color_lut_3d( im.im.color_lut_3d(
"RGBA", Image.LINEAR, *self.generate_identity_table(3, 3) "RGBA", Image.LINEAR, *self.generate_identity_table(3, 3)
) )
with self.assertRaisesRegex(ValueError, "wrong mode"): with pytest.raises(ValueError, match="wrong mode"):
im = Image.new("RGB", (10, 10), 0) im = Image.new("RGB", (10, 10), 0)
im.im.color_lut_3d("RGB", Image.LINEAR, *self.generate_identity_table(4, 3)) im.im.color_lut_3d("RGB", Image.LINEAR, *self.generate_identity_table(4, 3))
@ -271,33 +270,33 @@ class TestColorLut3DCoreAPI(PillowTestCase):
assert transformed[205, 205] == (255, 255, 0) assert transformed[205, 205] == (255, 255, 0)
class TestColorLut3DFilter(PillowTestCase): class TestColorLut3DFilter:
def test_wrong_args(self): def test_wrong_args(self):
with self.assertRaisesRegex(ValueError, "should be either an integer"): with pytest.raises(ValueError, match="should be either an integer"):
ImageFilter.Color3DLUT("small", [1]) ImageFilter.Color3DLUT("small", [1])
with self.assertRaisesRegex(ValueError, "should be either an integer"): with pytest.raises(ValueError, match="should be either an integer"):
ImageFilter.Color3DLUT((11, 11), [1]) ImageFilter.Color3DLUT((11, 11), [1])
with self.assertRaisesRegex(ValueError, r"in \[2, 65\] range"): with pytest.raises(ValueError, match=r"in \[2, 65\] range"):
ImageFilter.Color3DLUT((11, 11, 1), [1]) ImageFilter.Color3DLUT((11, 11, 1), [1])
with self.assertRaisesRegex(ValueError, r"in \[2, 65\] range"): with pytest.raises(ValueError, match=r"in \[2, 65\] range"):
ImageFilter.Color3DLUT((11, 11, 66), [1]) ImageFilter.Color3DLUT((11, 11, 66), [1])
with self.assertRaisesRegex(ValueError, "table should have .+ items"): with pytest.raises(ValueError, match="table should have .+ items"):
ImageFilter.Color3DLUT((3, 3, 3), [1, 1, 1]) ImageFilter.Color3DLUT((3, 3, 3), [1, 1, 1])
with self.assertRaisesRegex(ValueError, "table should have .+ items"): with pytest.raises(ValueError, match="table should have .+ items"):
ImageFilter.Color3DLUT((3, 3, 3), [[1, 1, 1]] * 2) ImageFilter.Color3DLUT((3, 3, 3), [[1, 1, 1]] * 2)
with self.assertRaisesRegex(ValueError, "should have a length of 4"): with pytest.raises(ValueError, match="should have a length of 4"):
ImageFilter.Color3DLUT((3, 3, 3), [[1, 1, 1]] * 27, channels=4) ImageFilter.Color3DLUT((3, 3, 3), [[1, 1, 1]] * 27, channels=4)
with self.assertRaisesRegex(ValueError, "should have a length of 3"): with pytest.raises(ValueError, match="should have a length of 3"):
ImageFilter.Color3DLUT((2, 2, 2), [[1, 1]] * 8) ImageFilter.Color3DLUT((2, 2, 2), [[1, 1]] * 8)
with self.assertRaisesRegex(ValueError, "Only 3 or 4 output"): with pytest.raises(ValueError, match="Only 3 or 4 output"):
ImageFilter.Color3DLUT((2, 2, 2), [[1, 1]] * 8, channels=2) ImageFilter.Color3DLUT((2, 2, 2), [[1, 1]] * 8, channels=2)
def test_convert_table(self): def test_convert_table(self):
@ -317,10 +316,10 @@ class TestColorLut3DFilter(PillowTestCase):
assert tuple(lut.size) == (2, 2, 2) assert tuple(lut.size) == (2, 2, 2)
assert lut.table == list(range(4)) * 8 assert lut.table == list(range(4)) * 8
@unittest.skipIf(numpy is None, "Numpy is not installed") @pytest.mark.skipif(numpy is None, reason="NumPy not installed")
def test_numpy_sources(self): def test_numpy_sources(self):
table = numpy.ones((5, 6, 7, 3), dtype=numpy.float16) table = numpy.ones((5, 6, 7, 3), dtype=numpy.float16)
with self.assertRaisesRegex(ValueError, "should have either channels"): with pytest.raises(ValueError, match="should have either channels"):
lut = ImageFilter.Color3DLUT((5, 6, 7), table) lut = ImageFilter.Color3DLUT((5, 6, 7), table)
table = numpy.ones((7, 6, 5, 3), dtype=numpy.float16) table = numpy.ones((7, 6, 5, 3), dtype=numpy.float16)
@ -350,7 +349,7 @@ class TestColorLut3DFilter(PillowTestCase):
table[0] = 33 table[0] = 33
assert lut.table[0] == 33 assert lut.table[0] == 33
@unittest.skipIf(numpy is None, "Numpy is not installed") @pytest.mark.skipif(numpy is None, reason="NumPy not installed")
def test_numpy_formats(self): def test_numpy_formats(self):
g = Image.linear_gradient("L") g = Image.linear_gradient("L")
im = Image.merge( im = Image.merge(
@ -359,12 +358,12 @@ class TestColorLut3DFilter(PillowTestCase):
lut = ImageFilter.Color3DLUT.generate((7, 9, 11), lambda r, g, b: (r, g, b)) lut = ImageFilter.Color3DLUT.generate((7, 9, 11), lambda r, g, b: (r, g, b))
lut.table = numpy.array(lut.table, dtype=numpy.float32)[:-1] lut.table = numpy.array(lut.table, dtype=numpy.float32)[:-1]
with self.assertRaisesRegex(ValueError, "should have table_channels"): with pytest.raises(ValueError, match="should have table_channels"):
im.filter(lut) im.filter(lut)
lut = ImageFilter.Color3DLUT.generate((7, 9, 11), lambda r, g, b: (r, g, b)) lut = ImageFilter.Color3DLUT.generate((7, 9, 11), lambda r, g, b: (r, g, b))
lut.table = numpy.array(lut.table, dtype=numpy.float32).reshape((7 * 9 * 11), 3) lut.table = numpy.array(lut.table, dtype=numpy.float32).reshape((7 * 9 * 11), 3)
with self.assertRaisesRegex(ValueError, "should have table_channels"): with pytest.raises(ValueError, match="should have table_channels"):
im.filter(lut) im.filter(lut)
lut = ImageFilter.Color3DLUT.generate((7, 9, 11), lambda r, g, b: (r, g, b)) lut = ImageFilter.Color3DLUT.generate((7, 9, 11), lambda r, g, b: (r, g, b))
@ -402,17 +401,17 @@ class TestColorLut3DFilter(PillowTestCase):
) )
class TestGenerateColorLut3D(PillowTestCase): class TestGenerateColorLut3D:
def test_wrong_channels_count(self): def test_wrong_channels_count(self):
with self.assertRaisesRegex(ValueError, "3 or 4 output channels"): with pytest.raises(ValueError, match="3 or 4 output channels"):
ImageFilter.Color3DLUT.generate( ImageFilter.Color3DLUT.generate(
5, channels=2, callback=lambda r, g, b: (r, g, b) 5, channels=2, callback=lambda r, g, b: (r, g, b)
) )
with self.assertRaisesRegex(ValueError, "should have either channels"): with pytest.raises(ValueError, match="should have either channels"):
ImageFilter.Color3DLUT.generate(5, lambda r, g, b: (r, g, b, r)) ImageFilter.Color3DLUT.generate(5, lambda r, g, b: (r, g, b, r))
with self.assertRaisesRegex(ValueError, "should have either channels"): with pytest.raises(ValueError, match="should have either channels"):
ImageFilter.Color3DLUT.generate( ImageFilter.Color3DLUT.generate(
5, channels=4, callback=lambda r, g, b: (r, g, b) 5, channels=4, callback=lambda r, g, b: (r, g, b)
) )
@ -450,17 +449,17 @@ class TestGenerateColorLut3D(PillowTestCase):
assert im == im.filter(lut) assert im == im.filter(lut)
class TestTransformColorLut3D(PillowTestCase): class TestTransformColorLut3D:
def test_wrong_args(self): def test_wrong_args(self):
source = ImageFilter.Color3DLUT.generate(5, lambda r, g, b: (r, g, b)) source = ImageFilter.Color3DLUT.generate(5, lambda r, g, b: (r, g, b))
with self.assertRaisesRegex(ValueError, "Only 3 or 4 output"): with pytest.raises(ValueError, match="Only 3 or 4 output"):
source.transform(lambda r, g, b: (r, g, b), channels=8) source.transform(lambda r, g, b: (r, g, b), channels=8)
with self.assertRaisesRegex(ValueError, "should have either channels"): with pytest.raises(ValueError, match="should have either channels"):
source.transform(lambda r, g, b: (r, g, b), channels=4) source.transform(lambda r, g, b: (r, g, b), channels=4)
with self.assertRaisesRegex(ValueError, "should have either channels"): with pytest.raises(ValueError, match="should have either channels"):
source.transform(lambda r, g, b: (r, g, b, 1)) source.transform(lambda r, g, b: (r, g, b, 1))
with pytest.raises(TypeError): with pytest.raises(TypeError):

View File

@ -1,65 +1,65 @@
import io import io
import unittest
import pytest import pytest
from PIL import EpsImagePlugin, Image, features from PIL import EpsImagePlugin, Image, features
from .helper import PillowTestCase, assert_image_similar, hopper, skip_unless_feature from .helper import assert_image_similar, hopper, skip_unless_feature
HAS_GHOSTSCRIPT = EpsImagePlugin.has_ghostscript() HAS_GHOSTSCRIPT = EpsImagePlugin.has_ghostscript()
# Our two EPS test files (they are identical except for their bounding boxes) # Our two EPS test files (they are identical except for their bounding boxes)
file1 = "Tests/images/zero_bb.eps" FILE1 = "Tests/images/zero_bb.eps"
file2 = "Tests/images/non_zero_bb.eps" FILE2 = "Tests/images/non_zero_bb.eps"
# Due to palletization, we'll need to convert these to RGB after load # Due to palletization, we'll need to convert these to RGB after load
file1_compare = "Tests/images/zero_bb.png" FILE1_COMPARE = "Tests/images/zero_bb.png"
file1_compare_scale2 = "Tests/images/zero_bb_scale2.png" FILE1_COMPARE_SCALE2 = "Tests/images/zero_bb_scale2.png"
file2_compare = "Tests/images/non_zero_bb.png" FILE2_COMPARE = "Tests/images/non_zero_bb.png"
file2_compare_scale2 = "Tests/images/non_zero_bb_scale2.png" FILE2_COMPARE_SCALE2 = "Tests/images/non_zero_bb_scale2.png"
# EPS test files with binary preview # EPS test files with binary preview
file3 = "Tests/images/binary_preview_map.eps" FILE3 = "Tests/images/binary_preview_map.eps"
class TestFileEps(PillowTestCase): @pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available")
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available") def test_sanity():
def test_sanity(self):
# Regular scale # Regular scale
with Image.open(file1) as image1: with Image.open(FILE1) as image1:
image1.load() image1.load()
assert image1.mode == "RGB" assert image1.mode == "RGB"
assert image1.size == (460, 352) assert image1.size == (460, 352)
assert image1.format == "EPS" assert image1.format == "EPS"
with Image.open(file2) as image2: with Image.open(FILE2) as image2:
image2.load() image2.load()
assert image2.mode == "RGB" assert image2.mode == "RGB"
assert image2.size == (360, 252) assert image2.size == (360, 252)
assert image2.format == "EPS" assert image2.format == "EPS"
# Double scale # Double scale
with Image.open(file1) as image1_scale2: with Image.open(FILE1) as image1_scale2:
image1_scale2.load(scale=2) image1_scale2.load(scale=2)
assert image1_scale2.mode == "RGB" assert image1_scale2.mode == "RGB"
assert image1_scale2.size == (920, 704) assert image1_scale2.size == (920, 704)
assert image1_scale2.format == "EPS" assert image1_scale2.format == "EPS"
with Image.open(file2) as image2_scale2: with Image.open(FILE2) as image2_scale2:
image2_scale2.load(scale=2) image2_scale2.load(scale=2)
assert image2_scale2.mode == "RGB" assert image2_scale2.mode == "RGB"
assert image2_scale2.size == (720, 504) assert image2_scale2.size == (720, 504)
assert image2_scale2.format == "EPS" assert image2_scale2.format == "EPS"
def test_invalid_file(self):
def test_invalid_file():
invalid_file = "Tests/images/flower.jpg" invalid_file = "Tests/images/flower.jpg"
with pytest.raises(SyntaxError): with pytest.raises(SyntaxError):
EpsImagePlugin.EpsImageFile(invalid_file) EpsImagePlugin.EpsImageFile(invalid_file)
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available")
def test_cmyk(self): @pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available")
def test_cmyk():
with Image.open("Tests/images/pil_sample_cmyk.eps") as cmyk_image: with Image.open("Tests/images/pil_sample_cmyk.eps") as cmyk_image:
assert cmyk_image.mode == "CMYK" assert cmyk_image.mode == "CMYK"
@ -73,8 +73,9 @@ class TestFileEps(PillowTestCase):
with Image.open("Tests/images/pil_sample_rgb.jpg") as target: with Image.open("Tests/images/pil_sample_rgb.jpg") as target:
assert_image_similar(cmyk_image, target, 10) assert_image_similar(cmyk_image, target, 10)
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available")
def test_showpage(self): @pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available")
def test_showpage():
# See https://github.com/python-pillow/Pillow/issues/2615 # See https://github.com/python-pillow/Pillow/issues/2615
with Image.open("Tests/images/reqd_showpage.eps") as plot_image: with Image.open("Tests/images/reqd_showpage.eps") as plot_image:
with Image.open("Tests/images/reqd_showpage.png") as target: with Image.open("Tests/images/reqd_showpage.png") as target:
@ -83,108 +84,124 @@ class TestFileEps(PillowTestCase):
# fonts could be slightly different # fonts could be slightly different
assert_image_similar(plot_image, target, 6) assert_image_similar(plot_image, target, 6)
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available")
def test_file_object(self): @pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available")
def test_file_object(tmp_path):
# issue 479 # issue 479
with Image.open(file1) as image1: with Image.open(FILE1) as image1:
with open(self.tempfile("temp_file.eps"), "wb") as fh: with open(str(tmp_path / "temp.eps"), "wb") as fh:
image1.save(fh, "EPS") image1.save(fh, "EPS")
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available")
def test_iobase_object(self): @pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available")
def test_iobase_object(tmp_path):
# issue 479 # issue 479
with Image.open(file1) as image1: with Image.open(FILE1) as image1:
with open(self.tempfile("temp_iobase.eps"), "wb") as fh: with open(str(tmp_path / "temp_iobase.eps"), "wb") as fh:
image1.save(fh, "EPS") image1.save(fh, "EPS")
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available")
def test_bytesio_object(self): @pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available")
with open(file1, "rb") as f: def test_bytesio_object():
with open(FILE1, "rb") as f:
img_bytes = io.BytesIO(f.read()) img_bytes = io.BytesIO(f.read())
with Image.open(img_bytes) as img: with Image.open(img_bytes) as img:
img.load() img.load()
with Image.open(file1_compare) as image1_scale1_compare: with Image.open(FILE1_COMPARE) as image1_scale1_compare:
image1_scale1_compare = image1_scale1_compare.convert("RGB") image1_scale1_compare = image1_scale1_compare.convert("RGB")
image1_scale1_compare.load() image1_scale1_compare.load()
assert_image_similar(img, image1_scale1_compare, 5) assert_image_similar(img, image1_scale1_compare, 5)
def test_image_mode_not_supported(self):
def test_image_mode_not_supported(tmp_path):
im = hopper("RGBA") im = hopper("RGBA")
tmpfile = self.tempfile("temp.eps") tmpfile = str(tmp_path / "temp.eps")
with pytest.raises(ValueError): with pytest.raises(ValueError):
im.save(tmpfile) im.save(tmpfile)
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available")
@skip_unless_feature("zlib") @pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available")
def test_render_scale1(self): @skip_unless_feature("zlib")
def test_render_scale1():
# We need png support for these render test # We need png support for these render test
# Zero bounding box # Zero bounding box
with Image.open(file1) as image1_scale1: with Image.open(FILE1) as image1_scale1:
image1_scale1.load() image1_scale1.load()
with Image.open(file1_compare) as image1_scale1_compare: with Image.open(FILE1_COMPARE) as image1_scale1_compare:
image1_scale1_compare = image1_scale1_compare.convert("RGB") image1_scale1_compare = image1_scale1_compare.convert("RGB")
image1_scale1_compare.load() image1_scale1_compare.load()
assert_image_similar(image1_scale1, image1_scale1_compare, 5) assert_image_similar(image1_scale1, image1_scale1_compare, 5)
# Non-Zero bounding box # Non-Zero bounding box
with Image.open(file2) as image2_scale1: with Image.open(FILE2) as image2_scale1:
image2_scale1.load() image2_scale1.load()
with Image.open(file2_compare) as image2_scale1_compare: with Image.open(FILE2_COMPARE) as image2_scale1_compare:
image2_scale1_compare = image2_scale1_compare.convert("RGB") image2_scale1_compare = image2_scale1_compare.convert("RGB")
image2_scale1_compare.load() image2_scale1_compare.load()
assert_image_similar(image2_scale1, image2_scale1_compare, 10) assert_image_similar(image2_scale1, image2_scale1_compare, 10)
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available")
@skip_unless_feature("zlib") @pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available")
def test_render_scale2(self): @skip_unless_feature("zlib")
def test_render_scale2():
# We need png support for these render test # We need png support for these render test
# Zero bounding box # Zero bounding box
with Image.open(file1) as image1_scale2: with Image.open(FILE1) as image1_scale2:
image1_scale2.load(scale=2) image1_scale2.load(scale=2)
with Image.open(file1_compare_scale2) as image1_scale2_compare: with Image.open(FILE1_COMPARE_SCALE2) as image1_scale2_compare:
image1_scale2_compare = image1_scale2_compare.convert("RGB") image1_scale2_compare = image1_scale2_compare.convert("RGB")
image1_scale2_compare.load() image1_scale2_compare.load()
assert_image_similar(image1_scale2, image1_scale2_compare, 5) assert_image_similar(image1_scale2, image1_scale2_compare, 5)
# Non-Zero bounding box # Non-Zero bounding box
with Image.open(file2) as image2_scale2: with Image.open(FILE2) as image2_scale2:
image2_scale2.load(scale=2) image2_scale2.load(scale=2)
with Image.open(file2_compare_scale2) as image2_scale2_compare: with Image.open(FILE2_COMPARE_SCALE2) as image2_scale2_compare:
image2_scale2_compare = image2_scale2_compare.convert("RGB") image2_scale2_compare = image2_scale2_compare.convert("RGB")
image2_scale2_compare.load() image2_scale2_compare.load()
assert_image_similar(image2_scale2, image2_scale2_compare, 10) assert_image_similar(image2_scale2, image2_scale2_compare, 10)
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available")
def test_resize(self): @pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available")
files = [file1, file2, "Tests/images/illu10_preview.eps"] def test_resize():
files = [FILE1, FILE2, "Tests/images/illu10_preview.eps"]
for fn in files: for fn in files:
with Image.open(fn) as im: with Image.open(fn) as im:
new_size = (100, 100) new_size = (100, 100)
im = im.resize(new_size) im = im.resize(new_size)
assert im.size == new_size assert im.size == new_size
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available")
def test_thumbnail(self): @pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available")
def test_thumbnail():
# Issue #619 # Issue #619
# Arrange # Arrange
files = [file1, file2] files = [FILE1, FILE2]
for fn in files: for fn in files:
with Image.open(file1) as im: with Image.open(FILE1) as im:
new_size = (100, 100) new_size = (100, 100)
im.thumbnail(new_size) im.thumbnail(new_size)
assert max(im.size) == max(new_size) assert max(im.size) == max(new_size)
def test_read_binary_preview(self):
def test_read_binary_preview():
# Issue 302 # Issue 302
# open image with binary preview # open image with binary preview
with Image.open(file3): with Image.open(FILE3):
pass pass
def _test_readline(self, t, ending):
def test_readline(tmp_path):
# check all the freaking line endings possible from the spec
# test_string = u'something\r\nelse\n\rbaz\rbif\n'
line_endings = ["\r\n", "\n", "\n\r", "\r"]
strings = ["something", "else", "baz", "bif"]
def _test_readline(t, ending):
ending = "Failure with line ending: %s" % ( ending = "Failure with line ending: %s" % (
"".join("%s" % ord(s) for s in ending) "".join("%s" % ord(s) for s in ending)
) )
@ -193,32 +210,27 @@ class TestFileEps(PillowTestCase):
assert t.readline().strip("\r\n") == "baz", ending assert t.readline().strip("\r\n") == "baz", ending
assert t.readline().strip("\r\n") == "bif", ending assert t.readline().strip("\r\n") == "bif", ending
def _test_readline_io_psfile(self, test_string, ending): def _test_readline_io_psfile(test_string, ending):
f = io.BytesIO(test_string.encode("latin-1")) f = io.BytesIO(test_string.encode("latin-1"))
t = EpsImagePlugin.PSFile(f) t = EpsImagePlugin.PSFile(f)
self._test_readline(t, ending) _test_readline(t, ending)
def _test_readline_file_psfile(self, test_string, ending): def _test_readline_file_psfile(test_string, ending):
f = self.tempfile("temp.txt") f = str(tmp_path / "temp.txt")
with open(f, "wb") as w: with open(f, "wb") as w:
w.write(test_string.encode("latin-1")) w.write(test_string.encode("latin-1"))
with open(f, "rb") as r: with open(f, "rb") as r:
t = EpsImagePlugin.PSFile(r) t = EpsImagePlugin.PSFile(r)
self._test_readline(t, ending) _test_readline(t, ending)
def test_readline(self):
# check all the freaking line endings possible from the spec
# test_string = u'something\r\nelse\n\rbaz\rbif\n'
line_endings = ["\r\n", "\n", "\n\r", "\r"]
strings = ["something", "else", "baz", "bif"]
for ending in line_endings: for ending in line_endings:
s = ending.join(strings) s = ending.join(strings)
self._test_readline_io_psfile(s, ending) _test_readline_io_psfile(s, ending)
self._test_readline_file_psfile(s, ending) _test_readline_file_psfile(s, ending)
def test_open_eps(self):
def test_open_eps():
# https://github.com/python-pillow/Pillow/issues/1104 # https://github.com/python-pillow/Pillow/issues/1104
# Arrange # Arrange
FILES = [ FILES = [
@ -233,8 +245,9 @@ class TestFileEps(PillowTestCase):
with Image.open(filename) as img: with Image.open(filename) as img:
assert img.mode == "RGB" assert img.mode == "RGB"
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available")
def test_emptyline(self): @pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available")
def test_emptyline():
# Test file includes an empty line in the header data # Test file includes an empty line in the header data
emptyline_file = "Tests/images/zero_bb_emptyline.eps" emptyline_file = "Tests/images/zero_bb_emptyline.eps"

View File

@ -1,11 +1,9 @@
import unittest
from io import BytesIO from io import BytesIO
import pytest import pytest
from PIL import GifImagePlugin, Image, ImageDraw, ImagePalette, features from PIL import GifImagePlugin, Image, ImageDraw, ImagePalette, features
from .helper import ( from .helper import (
PillowTestCase,
assert_image_equal, assert_image_equal,
assert_image_similar, assert_image_similar,
hopper, hopper,
@ -20,8 +18,7 @@ with open(TEST_GIF, "rb") as f:
data = f.read() data = f.read()
class TestFileGif(PillowTestCase): def test_sanity():
def test_sanity(self):
with Image.open(TEST_GIF) as im: with Image.open(TEST_GIF) as im:
im.load() im.load()
assert im.mode == "P" assert im.mode == "P"
@ -29,15 +26,17 @@ class TestFileGif(PillowTestCase):
assert im.format == "GIF" assert im.format == "GIF"
assert im.info["version"] == b"GIF89a" assert im.info["version"] == b"GIF89a"
@unittest.skipIf(is_pypy(), "Requires CPython")
def test_unclosed_file(self): @pytest.mark.skipif(is_pypy(), reason="Requires CPython")
def test_unclosed_file():
def open(): def open():
im = Image.open(TEST_GIF) im = Image.open(TEST_GIF)
im.load() im.load()
pytest.warns(ResourceWarning, open) pytest.warns(ResourceWarning, open)
def test_closed_file(self):
def test_closed_file():
def open(): def open():
im = Image.open(TEST_GIF) im = Image.open(TEST_GIF)
im.load() im.load()
@ -45,20 +44,23 @@ class TestFileGif(PillowTestCase):
pytest.warns(None, open) pytest.warns(None, open)
def test_context_manager(self):
def test_context_manager():
def open(): def open():
with Image.open(TEST_GIF) as im: with Image.open(TEST_GIF) as im:
im.load() im.load()
pytest.warns(None, open) pytest.warns(None, open)
def test_invalid_file(self):
def test_invalid_file():
invalid_file = "Tests/images/flower.jpg" invalid_file = "Tests/images/flower.jpg"
with pytest.raises(SyntaxError): with pytest.raises(SyntaxError):
GifImagePlugin.GifImageFile(invalid_file) GifImagePlugin.GifImageFile(invalid_file)
def test_optimize(self):
def test_optimize():
def test_grayscale(optimize): def test_grayscale(optimize):
im = Image.new("L", (1, 1), 0) im = Image.new("L", (1, 1), 0)
filename = BytesIO() filename = BytesIO()
@ -76,7 +78,8 @@ class TestFileGif(PillowTestCase):
assert test_bilevel(0) == 800 assert test_bilevel(0) == 800
assert test_bilevel(1) == 800 assert test_bilevel(1) == 800
def test_optimize_correctness(self):
def test_optimize_correctness():
# 256 color Palette image, posterize to > 128 and < 128 levels # 256 color Palette image, posterize to > 128 and < 128 levels
# Size bigger and smaller than 512x512 # Size bigger and smaller than 512x512
# Check the palette for number of colors allocated. # Check the palette for number of colors allocated.
@ -92,9 +95,7 @@ class TestFileGif(PillowTestCase):
outfile.seek(0) outfile.seek(0)
with Image.open(outfile) as reloaded: with Image.open(outfile) as reloaded:
# check palette length # check palette length
palette_length = max( palette_length = max(i + 1 for i, v in enumerate(reloaded.histogram()) if v)
i + 1 for i, v in enumerate(reloaded.histogram()) if v
)
assert expected_palette_length == palette_length assert expected_palette_length == palette_length
assert_image_equal(im.convert("RGB"), reloaded.convert("RGB")) assert_image_equal(im.convert("RGB"), reloaded.convert("RGB"))
@ -109,28 +110,31 @@ class TestFileGif(PillowTestCase):
check(64, 513, 256) check(64, 513, 256)
check(4, 513, 256) check(4, 513, 256)
# other limits that don't optimize the palette # Other limits that don't optimize the palette
check(129, 511, 256) check(129, 511, 256)
check(255, 511, 256) check(255, 511, 256)
check(256, 511, 256) check(256, 511, 256)
def test_optimize_full_l(self):
def test_optimize_full_l():
im = Image.frombytes("L", (16, 16), bytes(range(256))) im = Image.frombytes("L", (16, 16), bytes(range(256)))
test_file = BytesIO() test_file = BytesIO()
im.save(test_file, "GIF", optimize=True) im.save(test_file, "GIF", optimize=True)
assert im.mode == "L" assert im.mode == "L"
def test_roundtrip(self):
out = self.tempfile("temp.gif") def test_roundtrip(tmp_path):
out = str(tmp_path / "temp.gif")
im = hopper() im = hopper()
im.save(out) im.save(out)
with Image.open(out) as reread: with Image.open(out) as reread:
assert_image_similar(reread.convert("RGB"), im, 50) assert_image_similar(reread.convert("RGB"), im, 50)
def test_roundtrip2(self):
def test_roundtrip2(tmp_path):
# see https://github.com/python-pillow/Pillow/issues/403 # see https://github.com/python-pillow/Pillow/issues/403
out = self.tempfile("temp.gif") out = str(tmp_path / "temp.gif")
with Image.open(TEST_GIF) as im: with Image.open(TEST_GIF) as im:
im2 = im.copy() im2 = im.copy()
im2.save(out) im2.save(out)
@ -138,9 +142,10 @@ class TestFileGif(PillowTestCase):
assert_image_similar(reread.convert("RGB"), hopper(), 50) assert_image_similar(reread.convert("RGB"), hopper(), 50)
def test_roundtrip_save_all(self):
def test_roundtrip_save_all(tmp_path):
# Single frame image # Single frame image
out = self.tempfile("temp.gif") out = str(tmp_path / "temp.gif")
im = hopper() im = hopper()
im.save(out, save_all=True) im.save(out, save_all=True)
with Image.open(out) as reread: with Image.open(out) as reread:
@ -149,28 +154,29 @@ class TestFileGif(PillowTestCase):
# Multiframe image # Multiframe image
with Image.open("Tests/images/dispose_bgnd.gif") as im: with Image.open("Tests/images/dispose_bgnd.gif") as im:
out = str(tmp_path / "temp.gif")
out = self.tempfile("temp.gif")
im.save(out, save_all=True) im.save(out, save_all=True)
with Image.open(out) as reread:
with Image.open(out) as reread:
assert reread.n_frames == 5 assert reread.n_frames == 5
def test_headers_saving_for_animated_gifs(self):
def test_headers_saving_for_animated_gifs(tmp_path):
important_headers = ["background", "version", "duration", "loop"] important_headers = ["background", "version", "duration", "loop"]
# Multiframe image # Multiframe image
with Image.open("Tests/images/dispose_bgnd.gif") as im: with Image.open("Tests/images/dispose_bgnd.gif") as im:
info = im.info.copy() info = im.info.copy()
out = self.tempfile("temp.gif") out = str(tmp_path / "temp.gif")
im.save(out, save_all=True) im.save(out, save_all=True)
with Image.open(out) as reread: with Image.open(out) as reread:
for header in important_headers: for header in important_headers:
assert info[header] == reread.info[header] assert info[header] == reread.info[header]
def test_palette_handling(self):
def test_palette_handling(tmp_path):
# see https://github.com/python-pillow/Pillow/issues/513 # see https://github.com/python-pillow/Pillow/issues/513
with Image.open(TEST_GIF) as im: with Image.open(TEST_GIF) as im:
@ -179,18 +185,19 @@ class TestFileGif(PillowTestCase):
im = im.resize((100, 100), Image.LANCZOS) im = im.resize((100, 100), Image.LANCZOS)
im2 = im.convert("P", palette=Image.ADAPTIVE, colors=256) im2 = im.convert("P", palette=Image.ADAPTIVE, colors=256)
f = self.tempfile("temp.gif") f = str(tmp_path / "temp.gif")
im2.save(f, optimize=True) im2.save(f, optimize=True)
with Image.open(f) as reloaded: with Image.open(f) as reloaded:
assert_image_similar(im, reloaded.convert("RGB"), 10) assert_image_similar(im, reloaded.convert("RGB"), 10)
def test_palette_434(self):
def test_palette_434(tmp_path):
# see https://github.com/python-pillow/Pillow/issues/434 # see https://github.com/python-pillow/Pillow/issues/434
def roundtrip(im, *args, **kwargs): def roundtrip(im, *args, **kwargs):
out = self.tempfile("temp.gif") out = str(tmp_path / "temp.gif")
im.copy().save(out, *args, **kwargs) im.copy().save(out, *args, **kwargs)
reloaded = Image.open(out) reloaded = Image.open(out)
@ -210,37 +217,41 @@ class TestFileGif(PillowTestCase):
reloaded = reloaded.convert("RGB") reloaded = reloaded.convert("RGB")
assert_image_equal(im, reloaded) assert_image_equal(im, reloaded)
@unittest.skipUnless(netpbm_available(), "netpbm not available")
def test_save_netpbm_bmp_mode(self): @pytest.mark.skipif(not netpbm_available(), reason="Netpbm not available")
def test_save_netpbm_bmp_mode(tmp_path):
with Image.open(TEST_GIF) as img: with Image.open(TEST_GIF) as img:
img = img.convert("RGB") img = img.convert("RGB")
tempfile = self.tempfile("temp.gif") tempfile = str(tmp_path / "temp.gif")
GifImagePlugin._save_netpbm(img, 0, tempfile) GifImagePlugin._save_netpbm(img, 0, tempfile)
with Image.open(tempfile) as reloaded: with Image.open(tempfile) as reloaded:
assert_image_similar(img, reloaded.convert("RGB"), 0) assert_image_similar(img, reloaded.convert("RGB"), 0)
@unittest.skipUnless(netpbm_available(), "netpbm not available")
def test_save_netpbm_l_mode(self): @pytest.mark.skipif(not netpbm_available(), reason="Netpbm not available")
def test_save_netpbm_l_mode(tmp_path):
with Image.open(TEST_GIF) as img: with Image.open(TEST_GIF) as img:
img = img.convert("L") img = img.convert("L")
tempfile = self.tempfile("temp.gif") tempfile = str(tmp_path / "temp.gif")
GifImagePlugin._save_netpbm(img, 0, tempfile) GifImagePlugin._save_netpbm(img, 0, tempfile)
with Image.open(tempfile) as reloaded: with Image.open(tempfile) as reloaded:
assert_image_similar(img, reloaded.convert("L"), 0) assert_image_similar(img, reloaded.convert("L"), 0)
def test_seek(self):
def test_seek():
with Image.open("Tests/images/dispose_none.gif") as img: with Image.open("Tests/images/dispose_none.gif") as img:
framecount = 0 frame_count = 0
try: try:
while True: while True:
framecount += 1 frame_count += 1
img.seek(img.tell() + 1) img.seek(img.tell() + 1)
except EOFError: except EOFError:
assert framecount == 5 assert frame_count == 5
def test_seek_info(self):
def test_seek_info():
with Image.open("Tests/images/iss634.gif") as im: with Image.open("Tests/images/iss634.gif") as im:
info = im.info.copy() info = im.info.copy()
@ -249,7 +260,8 @@ class TestFileGif(PillowTestCase):
assert im.info == info assert im.info == info
def test_seek_rewind(self):
def test_seek_rewind():
with Image.open("Tests/images/iss634.gif") as im: with Image.open("Tests/images/iss634.gif") as im:
im.seek(2) im.seek(2)
im.seek(1) im.seek(1)
@ -258,7 +270,8 @@ class TestFileGif(PillowTestCase):
expected.seek(1) expected.seek(1)
assert_image_equal(im, expected) assert_image_equal(im, expected)
def test_n_frames(self):
def test_n_frames():
for path, n_frames in [[TEST_GIF, 1], ["Tests/images/iss634.gif", 42]]: for path, n_frames in [[TEST_GIF, 1], ["Tests/images/iss634.gif", 42]]:
# Test is_animated before n_frames # Test is_animated before n_frames
with Image.open(path) as im: with Image.open(path) as im:
@ -269,7 +282,8 @@ class TestFileGif(PillowTestCase):
assert im.n_frames == n_frames assert im.n_frames == n_frames
assert im.is_animated == (n_frames != 1) assert im.is_animated == (n_frames != 1)
def test_eoferror(self):
def test_eoferror():
with Image.open(TEST_GIF) as im: with Image.open(TEST_GIF) as im:
n_frames = im.n_frames n_frames = im.n_frames
@ -281,7 +295,8 @@ class TestFileGif(PillowTestCase):
# Test that seeking to the last frame does not raise an error # Test that seeking to the last frame does not raise an error
im.seek(n_frames - 1) im.seek(n_frames - 1)
def test_dispose_none(self):
def test_dispose_none():
with Image.open("Tests/images/dispose_none.gif") as img: with Image.open("Tests/images/dispose_none.gif") as img:
try: try:
while True: while True:
@ -290,7 +305,8 @@ class TestFileGif(PillowTestCase):
except EOFError: except EOFError:
pass pass
def test_dispose_background(self):
def test_dispose_background():
with Image.open("Tests/images/dispose_bgnd.gif") as img: with Image.open("Tests/images/dispose_bgnd.gif") as img:
try: try:
while True: while True:
@ -299,7 +315,8 @@ class TestFileGif(PillowTestCase):
except EOFError: except EOFError:
pass pass
def test_dispose_previous(self):
def test_dispose_previous():
with Image.open("Tests/images/dispose_prev.gif") as img: with Image.open("Tests/images/dispose_prev.gif") as img:
try: try:
while True: while True:
@ -308,23 +325,22 @@ class TestFileGif(PillowTestCase):
except EOFError: except EOFError:
pass pass
def test_save_dispose(self):
out = self.tempfile("temp.gif") def test_save_dispose(tmp_path):
out = str(tmp_path / "temp.gif")
im_list = [ im_list = [
Image.new("L", (100, 100), "#000"), Image.new("L", (100, 100), "#000"),
Image.new("L", (100, 100), "#111"), Image.new("L", (100, 100), "#111"),
Image.new("L", (100, 100), "#222"), Image.new("L", (100, 100), "#222"),
] ]
for method in range(0, 4): for method in range(0, 4):
im_list[0].save( im_list[0].save(out, save_all=True, append_images=im_list[1:], disposal=method)
out, save_all=True, append_images=im_list[1:], disposal=method
)
with Image.open(out) as img: with Image.open(out) as img:
for _ in range(2): for _ in range(2):
img.seek(img.tell() + 1) img.seek(img.tell() + 1)
assert img.disposal_method == method assert img.disposal_method == method
# check per frame disposal # Check per frame disposal
im_list[0].save( im_list[0].save(
out, out,
save_all=True, save_all=True,
@ -338,8 +354,9 @@ class TestFileGif(PillowTestCase):
img.seek(img.tell() + 1) img.seek(img.tell() + 1)
assert img.disposal_method == i + 1 assert img.disposal_method == i + 1
def test_dispose2_palette(self):
out = self.tempfile("temp.gif") def test_dispose2_palette(tmp_path):
out = str(tmp_path / "temp.gif")
# 4 backgrounds: White, Grey, Black, Red # 4 backgrounds: White, Grey, Black, Red
circles = [(255, 255, 255), (153, 153, 153), (0, 0, 0), (255, 0, 0)] circles = [(255, 255, 255), (153, 153, 153), (0, 0, 0), (255, 0, 0)]
@ -367,8 +384,9 @@ class TestFileGif(PillowTestCase):
# Center remains red every frame # Center remains red every frame
assert rgb_img.getpixel((50, 50)) == circle assert rgb_img.getpixel((50, 50)) == circle
def test_dispose2_diff(self):
out = self.tempfile("temp.gif") def test_dispose2_diff(tmp_path):
out = str(tmp_path / "temp.gif")
# 4 frames: red/blue, red/red, blue/blue, red/blue # 4 frames: red/blue, red/red, blue/blue, red/blue
circles = [ circles = [
@ -408,8 +426,9 @@ class TestFileGif(PillowTestCase):
# Check BG is correct colour # Check BG is correct colour
assert rgb_img.getpixel((1, 1)) == (255, 255, 255, 0) assert rgb_img.getpixel((1, 1)) == (255, 255, 255, 0)
def test_dispose2_background(self):
out = self.tempfile("temp.gif") def test_dispose2_background(tmp_path):
out = str(tmp_path / "temp.gif")
im_list = [] im_list = []
@ -433,18 +452,19 @@ class TestFileGif(PillowTestCase):
im.seek(1) im.seek(1)
assert im.getpixel((0, 0)) == 0 assert im.getpixel((0, 0)) == 0
def test_iss634(self):
def test_iss634():
with Image.open("Tests/images/iss634.gif") as img: with Image.open("Tests/images/iss634.gif") as img:
# seek to the second frame # Seek to the second frame
img.seek(img.tell() + 1) img.seek(img.tell() + 1)
# all transparent pixels should be replaced with the color from the # All transparent pixels should be replaced with the color from the first frame
# first frame
assert img.histogram()[img.info["transparency"]] == 0 assert img.histogram()[img.info["transparency"]] == 0
def test_duration(self):
def test_duration(tmp_path):
duration = 1000 duration = 1000
out = self.tempfile("temp.gif") out = str(tmp_path / "temp.gif")
im = Image.new("L", (100, 100), "#000") im = Image.new("L", (100, 100), "#000")
# Check that the argument has priority over the info settings # Check that the argument has priority over the info settings
@ -454,17 +474,18 @@ class TestFileGif(PillowTestCase):
with Image.open(out) as reread: with Image.open(out) as reread:
assert reread.info["duration"] == duration assert reread.info["duration"] == duration
def test_multiple_duration(self):
def test_multiple_duration(tmp_path):
duration_list = [1000, 2000, 3000] duration_list = [1000, 2000, 3000]
out = self.tempfile("temp.gif") out = str(tmp_path / "temp.gif")
im_list = [ im_list = [
Image.new("L", (100, 100), "#000"), Image.new("L", (100, 100), "#000"),
Image.new("L", (100, 100), "#111"), Image.new("L", (100, 100), "#111"),
Image.new("L", (100, 100), "#222"), Image.new("L", (100, 100), "#222"),
] ]
# duration as list # Duration as list
im_list[0].save( im_list[0].save(
out, save_all=True, append_images=im_list[1:], duration=duration_list out, save_all=True, append_images=im_list[1:], duration=duration_list
) )
@ -477,7 +498,7 @@ class TestFileGif(PillowTestCase):
except EOFError: except EOFError:
pass pass
# duration as tuple # Duration as tuple
im_list[0].save( im_list[0].save(
out, save_all=True, append_images=im_list[1:], duration=tuple(duration_list) out, save_all=True, append_images=im_list[1:], duration=tuple(duration_list)
) )
@ -490,10 +511,11 @@ class TestFileGif(PillowTestCase):
except EOFError: except EOFError:
pass pass
def test_identical_frames(self):
def test_identical_frames(tmp_path):
duration_list = [1000, 1500, 2000, 4000] duration_list = [1000, 1500, 2000, 4000]
out = self.tempfile("temp.gif") out = str(tmp_path / "temp.gif")
im_list = [ im_list = [
Image.new("L", (100, 100), "#000"), Image.new("L", (100, 100), "#000"),
Image.new("L", (100, 100), "#000"), Image.new("L", (100, 100), "#000"),
@ -501,7 +523,7 @@ class TestFileGif(PillowTestCase):
Image.new("L", (100, 100), "#111"), Image.new("L", (100, 100), "#111"),
] ]
# duration as list # Duration as list
im_list[0].save( im_list[0].save(
out, save_all=True, append_images=im_list[1:], duration=duration_list out, save_all=True, append_images=im_list[1:], duration=duration_list
) )
@ -513,9 +535,10 @@ class TestFileGif(PillowTestCase):
# Assert that the new duration is the total of the identical frames # Assert that the new duration is the total of the identical frames
assert reread.info["duration"] == 4500 assert reread.info["duration"] == 4500
def test_identical_frames_to_single_frame(self):
def test_identical_frames_to_single_frame(tmp_path):
for duration in ([1000, 1500, 2000, 4000], (1000, 1500, 2000, 4000), 8500): for duration in ([1000, 1500, 2000, 4000], (1000, 1500, 2000, 4000), 8500):
out = self.tempfile("temp.gif") out = str(tmp_path / "temp.gif")
im_list = [ im_list = [
Image.new("L", (100, 100), "#000"), Image.new("L", (100, 100), "#000"),
Image.new("L", (100, 100), "#000"), Image.new("L", (100, 100), "#000"),
@ -532,18 +555,20 @@ class TestFileGif(PillowTestCase):
# Assert that the new duration is the total of the identical frames # Assert that the new duration is the total of the identical frames
assert reread.info["duration"] == 8500 assert reread.info["duration"] == 8500
def test_number_of_loops(self):
def test_number_of_loops(tmp_path):
number_of_loops = 2 number_of_loops = 2
out = self.tempfile("temp.gif") out = str(tmp_path / "temp.gif")
im = Image.new("L", (100, 100), "#000") im = Image.new("L", (100, 100), "#000")
im.save(out, loop=number_of_loops) im.save(out, loop=number_of_loops)
with Image.open(out) as reread: with Image.open(out) as reread:
assert reread.info["loop"] == number_of_loops assert reread.info["loop"] == number_of_loops
def test_background(self):
out = self.tempfile("temp.gif") def test_background(tmp_path):
out = str(tmp_path / "temp.gif")
im = Image.new("L", (100, 100), "#000") im = Image.new("L", (100, 100), "#000")
im.info["background"] = 1 im.info["background"] = 1
im.save(out) im.save(out)
@ -556,11 +581,12 @@ class TestFileGif(PillowTestCase):
assert isinstance(im.info["background"], tuple) assert isinstance(im.info["background"], tuple)
im.save(out) im.save(out)
def test_comment(self):
def test_comment(tmp_path):
with Image.open(TEST_GIF) as im: with Image.open(TEST_GIF) as im:
assert im.info["comment"] == b"File written by Adobe Photoshop\xa8 4.0" assert im.info["comment"] == b"File written by Adobe Photoshop\xa8 4.0"
out = self.tempfile("temp.gif") out = str(tmp_path / "temp.gif")
im = Image.new("L", (100, 100), "#000") im = Image.new("L", (100, 100), "#000")
im.info["comment"] = b"Test comment text" im.info["comment"] = b"Test comment text"
im.save(out) im.save(out)
@ -572,8 +598,9 @@ class TestFileGif(PillowTestCase):
with Image.open(out) as reread: with Image.open(out) as reread:
assert reread.info["comment"] == im.info["comment"].encode() assert reread.info["comment"] == im.info["comment"].encode()
def test_comment_over_255(self):
out = self.tempfile("temp.gif") def test_comment_over_255(tmp_path):
out = str(tmp_path / "temp.gif")
im = Image.new("L", (100, 100), "#000") im = Image.new("L", (100, 100), "#000")
comment = b"Test comment text" comment = b"Test comment text"
while len(comment) < 256: while len(comment) < 256:
@ -584,13 +611,15 @@ class TestFileGif(PillowTestCase):
assert reread.info["comment"] == comment assert reread.info["comment"] == comment
def test_zero_comment_subblocks(self):
def test_zero_comment_subblocks():
with Image.open("Tests/images/hopper_zero_comment_subblocks.gif") as im: with Image.open("Tests/images/hopper_zero_comment_subblocks.gif") as im:
with Image.open(TEST_GIF) as expected: with Image.open(TEST_GIF) as expected:
assert_image_equal(im, expected) assert_image_equal(im, expected)
def test_version(self):
out = self.tempfile("temp.gif") def test_version(tmp_path):
out = str(tmp_path / "temp.gif")
def assertVersionAfterSave(im, version): def assertVersionAfterSave(im, version):
im.save(out) im.save(out)
@ -618,8 +647,9 @@ class TestFileGif(PillowTestCase):
im.info["version"] = b"GIF89a" im.info["version"] = b"GIF89a"
assertVersionAfterSave(im, b"GIF87a") assertVersionAfterSave(im, b"GIF87a")
def test_append_images(self):
out = self.tempfile("temp.gif") def test_append_images(tmp_path):
out = str(tmp_path / "temp.gif")
# Test appending single frame images # Test appending single frame images
im = Image.new("RGB", (100, 100), "#f00") im = Image.new("RGB", (100, 100), "#f00")
@ -646,12 +676,12 @@ class TestFileGif(PillowTestCase):
with Image.open(out) as reread: with Image.open(out) as reread:
assert reread.n_frames == 10 assert reread.n_frames == 10
def test_transparent_optimize(self):
# from issue #2195, if the transparent color is incorrectly def test_transparent_optimize(tmp_path):
# optimized out, gif loses transparency # From issue #2195, if the transparent color is incorrectly optimized out, GIF loses
# Need a palette that isn't using the 0 color, and one # transparency.
# that's > 128 items where the transparent color is actually # Need a palette that isn't using the 0 color, and one that's > 128 items where the
# the top palette entry to trigger the bug. # transparent color is actually the top palette entry to trigger the bug.
data = bytes(range(1, 254)) data = bytes(range(1, 254))
palette = ImagePalette.ImagePalette("RGB", list(range(256)) * 3) palette = ImagePalette.ImagePalette("RGB", list(range(256)) * 3)
@ -660,14 +690,15 @@ class TestFileGif(PillowTestCase):
im.frombytes(data) im.frombytes(data)
im.putpalette(palette) im.putpalette(palette)
out = self.tempfile("temp.gif") out = str(tmp_path / "temp.gif")
im.save(out, transparency=253) im.save(out, transparency=253)
with Image.open(out) as reloaded: with Image.open(out) as reloaded:
assert reloaded.info["transparency"] == 253 assert reloaded.info["transparency"] == 253
def test_rgb_transparency(self):
out = self.tempfile("temp.gif") def test_rgb_transparency(tmp_path):
out = str(tmp_path / "temp.gif")
# Single frame # Single frame
im = Image.new("RGB", (1, 1)) im = Image.new("RGB", (1, 1))
@ -686,8 +717,9 @@ class TestFileGif(PillowTestCase):
with Image.open(out) as reloaded: with Image.open(out) as reloaded:
assert "transparency" not in reloaded.info assert "transparency" not in reloaded.info
def test_bbox(self):
out = self.tempfile("temp.gif") def test_bbox(tmp_path):
out = str(tmp_path / "temp.gif")
im = Image.new("RGB", (100, 100), "#fff") im = Image.new("RGB", (100, 100), "#fff")
ims = [Image.new("RGB", (100, 100), "#000")] ims = [Image.new("RGB", (100, 100), "#000")]
@ -696,63 +728,66 @@ class TestFileGif(PillowTestCase):
with Image.open(out) as reread: with Image.open(out) as reread:
assert reread.n_frames == 2 assert reread.n_frames == 2
def test_palette_save_L(self):
# generate an L mode image with a separate palette def test_palette_save_L(tmp_path):
# Generate an L mode image with a separate palette
im = hopper("P") im = hopper("P")
im_l = Image.frombytes("L", im.size, im.tobytes()) im_l = Image.frombytes("L", im.size, im.tobytes())
palette = bytes(im.getpalette()) palette = bytes(im.getpalette())
out = self.tempfile("temp.gif") out = str(tmp_path / "temp.gif")
im_l.save(out, palette=palette) im_l.save(out, palette=palette)
with Image.open(out) as reloaded: with Image.open(out) as reloaded:
assert_image_equal(reloaded.convert("RGB"), im.convert("RGB")) 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 def test_palette_save_P(tmp_path):
# would look like. # Pass in a different palette, then construct what the image would look like.
# Forcing a non-straight grayscale palette. # Forcing a non-straight grayscale palette.
im = hopper("P") im = hopper("P")
palette = bytes([255 - i // 3 for i in range(768)]) palette = bytes([255 - i // 3 for i in range(768)])
out = self.tempfile("temp.gif") out = str(tmp_path / "temp.gif")
im.save(out, palette=palette) im.save(out, palette=palette)
with Image.open(out) as reloaded: with Image.open(out) as reloaded:
im.putpalette(palette) im.putpalette(palette)
assert_image_equal(reloaded, im) assert_image_equal(reloaded, im)
def test_palette_save_ImagePalette(self):
# pass in a different palette, as an ImagePalette.ImagePalette def test_palette_save_ImagePalette(tmp_path):
# Pass in a different palette, as an ImagePalette.ImagePalette
# effectively the same as test_palette_save_P # effectively the same as test_palette_save_P
im = hopper("P") im = hopper("P")
palette = ImagePalette.ImagePalette("RGB", list(range(256))[::-1] * 3) palette = ImagePalette.ImagePalette("RGB", list(range(256))[::-1] * 3)
out = self.tempfile("temp.gif") out = str(tmp_path / "temp.gif")
im.save(out, palette=palette) im.save(out, palette=palette)
with Image.open(out) as reloaded: with Image.open(out) as reloaded:
im.putpalette(palette) im.putpalette(palette)
assert_image_equal(reloaded, im) assert_image_equal(reloaded, im)
def test_save_I(self):
def test_save_I(tmp_path):
# Test saving something that would trigger the auto-convert to 'L' # Test saving something that would trigger the auto-convert to 'L'
im = hopper("I") im = hopper("I")
out = self.tempfile("temp.gif") out = str(tmp_path / "temp.gif")
im.save(out) im.save(out)
with Image.open(out) as reloaded: with Image.open(out) as reloaded:
assert_image_equal(reloaded.convert("L"), im.convert("L")) assert_image_equal(reloaded.convert("L"), im.convert("L"))
def test_getdata(self):
# test getheader/getdata against legacy values def test_getdata():
# Create a 'P' image with holes in the palette # Test getheader/getdata against legacy values.
# Create a 'P' image with holes in the palette.
im = Image._wedge().resize((16, 16), Image.NEAREST) im = Image._wedge().resize((16, 16), Image.NEAREST)
im.putpalette(ImagePalette.ImagePalette("RGB")) im.putpalette(ImagePalette.ImagePalette("RGB"))
im.info = {"background": 0} im.info = {"background": 0}
@ -777,14 +812,16 @@ class TestFileGif(PillowTestCase):
finally: finally:
GifImagePlugin._FORCE_OPTIMIZE = False GifImagePlugin._FORCE_OPTIMIZE = False
def test_lzw_bits(self):
def test_lzw_bits():
# see https://github.com/python-pillow/Pillow/issues/2811 # see https://github.com/python-pillow/Pillow/issues/2811
with Image.open("Tests/images/issue_2811.gif") as im: with Image.open("Tests/images/issue_2811.gif") as im:
assert im.tile[0][3][0] == 11 # LZW bits assert im.tile[0][3][0] == 11 # LZW bits
# codec error prepatch # codec error prepatch
im.load() im.load()
def test_extents(self):
def test_extents():
with Image.open("Tests/images/test_extents.gif") as im: with Image.open("Tests/images/test_extents.gif") as im:
assert im.size == (100, 100) assert im.size == (100, 100)
im.seek(1) im.seek(1)

View File

@ -1,20 +1,18 @@
import io import io
import sys import sys
import unittest
import pytest import pytest
from PIL import IcnsImagePlugin, Image from PIL import IcnsImagePlugin, Image
from .helper import PillowTestCase, assert_image_equal, assert_image_similar from .helper import assert_image_equal, assert_image_similar
# sample icon file # sample icon file
TEST_FILE = "Tests/images/pillow.icns" TEST_FILE = "Tests/images/pillow.icns"
enable_jpeg2k = hasattr(Image.core, "jp2klib_version") ENABLE_JPEG2K = hasattr(Image.core, "jp2klib_version")
class TestFileIcns(PillowTestCase): def test_sanity():
def test_sanity(self):
# Loading this icon by default should result in the largest size # Loading this icon by default should result in the largest size
# (512x512@2x) being loaded # (512x512@2x) being loaded
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
@ -26,9 +24,10 @@ class TestFileIcns(PillowTestCase):
assert im.size == (1024, 1024) assert im.size == (1024, 1024)
assert im.format == "ICNS" assert im.format == "ICNS"
@unittest.skipIf(sys.platform != "darwin", "requires macOS")
def test_save(self): @pytest.mark.skipif(sys.platform != "darwin", reason="Requires macOS")
temp_file = self.tempfile("temp.icns") def test_save(tmp_path):
temp_file = str(tmp_path / "temp.icns")
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
im.save(temp_file) im.save(temp_file)
@ -38,9 +37,10 @@ class TestFileIcns(PillowTestCase):
assert reread.size == (1024, 1024) assert reread.size == (1024, 1024)
assert reread.format == "ICNS" assert reread.format == "ICNS"
@unittest.skipIf(sys.platform != "darwin", "requires macOS")
def test_save_append_images(self): @pytest.mark.skipif(sys.platform != "darwin", reason="Requires macOS")
temp_file = self.tempfile("temp.icns") def test_save_append_images(tmp_path):
temp_file = str(tmp_path / "temp.icns")
provided_im = Image.new("RGBA", (32, 32), (255, 0, 0, 128)) provided_im = Image.new("RGBA", (32, 32), (255, 0, 0, 128))
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
@ -54,7 +54,8 @@ class TestFileIcns(PillowTestCase):
reread.load() reread.load()
assert_image_equal(reread, provided_im) assert_image_equal(reread, provided_im)
def test_sizes(self):
def test_sizes():
# Check that we can load all of the sizes, and that the final pixel # Check that we can load all of the sizes, and that the final pixel
# dimensions are as expected # dimensions are as expected
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
@ -70,7 +71,8 @@ class TestFileIcns(PillowTestCase):
with pytest.raises(ValueError): with pytest.raises(ValueError):
im.size = (1, 1) im.size = (1, 1)
def test_older_icon(self):
def test_older_icon():
# This icon was made with Icon Composer rather than iconutil; it still # 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). # uses PNG rather than JP2, however (since it was made on 10.9).
with Image.open("Tests/images/pillow2.icns") as im: with Image.open("Tests/images/pillow2.icns") as im:
@ -83,7 +85,8 @@ class TestFileIcns(PillowTestCase):
assert im2.mode == "RGBA" assert im2.mode == "RGBA"
assert im2.size == (wr, hr) assert im2.size == (wr, hr)
def test_jp2_icon(self):
def test_jp2_icon():
# This icon was made by using Uli Kusterer's oldiconutil to replace # This icon was made by using Uli Kusterer's oldiconutil to replace
# the PNG images with JPEG 2000 ones. The advantage of doing this is # the PNG images with JPEG 2000 ones. The advantage of doing this is
# that OS X 10.5 supports JPEG 2000 but not PNG; some commercial # that OS X 10.5 supports JPEG 2000 but not PNG; some commercial
@ -91,7 +94,7 @@ class TestFileIcns(PillowTestCase):
# (oldiconutil is here: https://github.com/uliwitness/oldiconutil) # (oldiconutil is here: https://github.com/uliwitness/oldiconutil)
if not enable_jpeg2k: if not ENABLE_JPEG2K:
return return
with Image.open("Tests/images/pillow3.icns") as im: with Image.open("Tests/images/pillow3.icns") as im:
@ -104,7 +107,8 @@ class TestFileIcns(PillowTestCase):
assert im2.mode == "RGBA" assert im2.mode == "RGBA"
assert im2.size == (wr, hr) assert im2.size == (wr, hr)
def test_getimage(self):
def test_getimage():
with open(TEST_FILE, "rb") as fp: with open(TEST_FILE, "rb") as fp:
icns_file = IcnsImagePlugin.IcnsFile(fp) icns_file = IcnsImagePlugin.IcnsFile(fp)
@ -116,7 +120,8 @@ class TestFileIcns(PillowTestCase):
assert im.mode == "RGBA" assert im.mode == "RGBA"
assert im.size == (512, 512) assert im.size == (512, 512)
def test_not_an_icns_file(self):
def test_not_an_icns_file():
with io.BytesIO(b"invalid\n") as fp: with io.BytesIO(b"invalid\n") as fp:
with pytest.raises(SyntaxError): with pytest.raises(SyntaxError):
IcnsImagePlugin.IcnsFile(fp) IcnsImagePlugin.IcnsFile(fp)

View File

@ -3,13 +3,12 @@ import io
import pytest import pytest
from PIL import IcoImagePlugin, Image, ImageDraw from PIL import IcoImagePlugin, Image, ImageDraw
from .helper import PillowTestCase, assert_image_equal, hopper from .helper import assert_image_equal, hopper
TEST_ICO_FILE = "Tests/images/hopper.ico" TEST_ICO_FILE = "Tests/images/hopper.ico"
class TestFileIco(PillowTestCase): def test_sanity():
def test_sanity(self):
with Image.open(TEST_ICO_FILE) as im: with Image.open(TEST_ICO_FILE) as im:
im.load() im.load()
assert im.mode == "RGBA" assert im.mode == "RGBA"
@ -17,17 +16,19 @@ class TestFileIco(PillowTestCase):
assert im.format == "ICO" assert im.format == "ICO"
assert im.get_format_mimetype() == "image/x-icon" assert im.get_format_mimetype() == "image/x-icon"
def test_invalid_file(self):
def test_invalid_file():
with open("Tests/images/flower.jpg", "rb") as fp: with open("Tests/images/flower.jpg", "rb") as fp:
with pytest.raises(SyntaxError): with pytest.raises(SyntaxError):
IcoImagePlugin.IcoImageFile(fp) IcoImagePlugin.IcoImageFile(fp)
def test_save_to_bytes(self):
def test_save_to_bytes():
output = io.BytesIO() output = io.BytesIO()
im = hopper() im = hopper()
im.save(output, "ico", sizes=[(32, 32), (64, 64)]) im.save(output, "ico", sizes=[(32, 32), (64, 64)])
# the default image # The default image
output.seek(0) output.seek(0)
with Image.open(output) as reloaded: with Image.open(output) as reloaded:
assert reloaded.info["sizes"] == {(32, 32), (64, 64)} assert reloaded.info["sizes"] == {(32, 32), (64, 64)}
@ -37,7 +38,7 @@ class TestFileIco(PillowTestCase):
assert reloaded.format == "ICO" assert reloaded.format == "ICO"
assert_image_equal(reloaded, hopper().resize((64, 64), Image.LANCZOS)) assert_image_equal(reloaded, hopper().resize((64, 64), Image.LANCZOS))
# the other one # The other one
output.seek(0) output.seek(0)
with Image.open(output) as reloaded: with Image.open(output) as reloaded:
reloaded.size = (32, 32) reloaded.size = (32, 32)
@ -47,16 +48,18 @@ class TestFileIco(PillowTestCase):
assert reloaded.format == "ICO" assert reloaded.format == "ICO"
assert_image_equal(reloaded, hopper().resize((32, 32), Image.LANCZOS)) assert_image_equal(reloaded, hopper().resize((32, 32), Image.LANCZOS))
def test_incorrect_size(self):
def test_incorrect_size():
with Image.open(TEST_ICO_FILE) as im: with Image.open(TEST_ICO_FILE) as im:
with pytest.raises(ValueError): with pytest.raises(ValueError):
im.size = (1, 1) im.size = (1, 1)
def test_save_256x256(self):
def test_save_256x256(tmp_path):
"""Issue #2264 https://github.com/python-pillow/Pillow/issues/2264""" """Issue #2264 https://github.com/python-pillow/Pillow/issues/2264"""
# Arrange # Arrange
with Image.open("Tests/images/hopper_256x256.ico") as im: with Image.open("Tests/images/hopper_256x256.ico") as im:
outfile = self.tempfile("temp_saved_hopper_256x256.ico") outfile = str(tmp_path / "temp_saved_hopper_256x256.ico")
# Act # Act
im.save(outfile) im.save(outfile)
@ -65,14 +68,15 @@ class TestFileIco(PillowTestCase):
# Assert # Assert
assert im_saved.size == (256, 256) assert im_saved.size == (256, 256)
def test_only_save_relevant_sizes(self):
def test_only_save_relevant_sizes(tmp_path):
"""Issue #2266 https://github.com/python-pillow/Pillow/issues/2266 """Issue #2266 https://github.com/python-pillow/Pillow/issues/2266
Should save in 16x16, 24x24, 32x32, 48x48 sizes Should save in 16x16, 24x24, 32x32, 48x48 sizes
and not in 16x16, 24x24, 32x32, 48x48, 48x48, 48x48, 48x48 sizes and not in 16x16, 24x24, 32x32, 48x48, 48x48, 48x48, 48x48 sizes
""" """
# Arrange # Arrange
with Image.open("Tests/images/python.ico") as im: # 16x16, 32x32, 48x48 with Image.open("Tests/images/python.ico") as im: # 16x16, 32x32, 48x48
outfile = self.tempfile("temp_saved_python.ico") outfile = str(tmp_path / "temp_saved_python.ico")
# Act # Act
im.save(outfile) im.save(outfile)
@ -80,7 +84,8 @@ class TestFileIco(PillowTestCase):
# Assert # Assert
assert im_saved.info["sizes"] == {(16, 16), (24, 24), (32, 32), (48, 48)} assert im_saved.info["sizes"] == {(16, 16), (24, 24), (32, 32), (48, 48)}
def test_unexpected_size(self):
def test_unexpected_size():
# This image has been manually hexedited to state that it is 16x32 # This image has been manually hexedited to state that it is 16x32
# while the image within is still 16x16 # while the image within is still 16x16
def open(): def open():
@ -89,9 +94,10 @@ class TestFileIco(PillowTestCase):
pytest.warns(UserWarning, open) pytest.warns(UserWarning, open)
def test_draw_reloaded(self):
def test_draw_reloaded(tmp_path):
with Image.open(TEST_ICO_FILE) as im: with Image.open(TEST_ICO_FILE) as im:
outfile = self.tempfile("temp_saved_hopper_draw.ico") outfile = str(tmp_path / "temp_saved_hopper_draw.ico")
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
draw.line((0, 0) + im.size, "#f00") draw.line((0, 0) + im.size, "#f00")

View File

@ -1,4 +1,5 @@
import os import os
import re
from io import BytesIO from io import BytesIO
import pytest import pytest
@ -42,7 +43,7 @@ class TestFileJpeg(PillowTestCase):
def test_sanity(self): def test_sanity(self):
# internal version number # internal version number
self.assertRegex(Image.core.jpeglib_version, r"\d+\.\d+$") assert re.search(r"\d+\.\d+$", Image.core.jpeglib_version)
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
im.load() im.load()

View File

@ -1,3 +1,4 @@
import re
from io import BytesIO from io import BytesIO
import pytest import pytest
@ -34,7 +35,7 @@ class TestFileJpeg2k(PillowTestCase):
def test_sanity(self): def test_sanity(self):
# Internal version number # Internal version number
self.assertRegex(Image.core.jp2klib_version, r"\d+\.\d+\.\d+$") assert re.search(r"\d+\.\d+\.\d+$", Image.core.jp2klib_version)
with Image.open("Tests/images/test-card-lossless.jp2") as im: with Image.open("Tests/images/test-card-lossless.jp2") as im:
px = im.load() px = im.load()

View File

@ -295,7 +295,9 @@ class TestFileLibTiff(LibTiffTestCase):
and libtiff and libtiff
): ):
# libtiff does not support real RATIONALS # libtiff does not support real RATIONALS
self.assertAlmostEqual(float(reloaded_value), float(value)) assert (
round(abs(float(reloaded_value) - float(value)), 7) == 0
)
continue continue
if libtiff and isinstance(value, bytes): if libtiff and isinstance(value, bytes):

View File

@ -1,19 +1,17 @@
import os import os
import unittest
import pytest import pytest
from PIL import Image, MspImagePlugin from PIL import Image, MspImagePlugin
from .helper import PillowTestCase, assert_image_equal, hopper from .helper import assert_image_equal, hopper
TEST_FILE = "Tests/images/hopper.msp" TEST_FILE = "Tests/images/hopper.msp"
EXTRA_DIR = "Tests/images/picins" EXTRA_DIR = "Tests/images/picins"
YA_EXTRA_DIR = "Tests/images/msp" YA_EXTRA_DIR = "Tests/images/msp"
class TestFileMsp(PillowTestCase): def test_sanity(tmp_path):
def test_sanity(self): test_file = str(tmp_path / "temp.msp")
test_file = self.tempfile("temp.msp")
hopper("1").save(test_file) hopper("1").save(test_file)
@ -23,13 +21,15 @@ class TestFileMsp(PillowTestCase):
assert im.size == (128, 128) assert im.size == (128, 128)
assert im.format == "MSP" assert im.format == "MSP"
def test_invalid_file(self):
def test_invalid_file():
invalid_file = "Tests/images/flower.jpg" invalid_file = "Tests/images/flower.jpg"
with pytest.raises(SyntaxError): with pytest.raises(SyntaxError):
MspImagePlugin.MspImageFile(invalid_file) MspImagePlugin.MspImageFile(invalid_file)
def test_bad_checksum(self):
def test_bad_checksum():
# Arrange # Arrange
# This was created by forcing Pillow to save with checksum=0 # This was created by forcing Pillow to save with checksum=0
bad_checksum = "Tests/images/hopper_bad_checksum.msp" bad_checksum = "Tests/images/hopper_bad_checksum.msp"
@ -38,7 +38,8 @@ class TestFileMsp(PillowTestCase):
with pytest.raises(SyntaxError): with pytest.raises(SyntaxError):
MspImagePlugin.MspImageFile(bad_checksum) MspImagePlugin.MspImageFile(bad_checksum)
def test_open_windows_v1(self):
def test_open_windows_v1():
# Arrange # Arrange
# Act # Act
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
@ -47,13 +48,17 @@ class TestFileMsp(PillowTestCase):
assert_image_equal(im, hopper("1")) assert_image_equal(im, hopper("1"))
assert isinstance(im, MspImagePlugin.MspImageFile) assert isinstance(im, MspImagePlugin.MspImageFile)
def _assert_file_image_equal(self, source_path, target_path):
def _assert_file_image_equal(source_path, target_path):
with Image.open(source_path) as im: with Image.open(source_path) as im:
with Image.open(target_path) as target: with Image.open(target_path) as target:
assert_image_equal(im, target) assert_image_equal(im, target)
@unittest.skipUnless(os.path.exists(EXTRA_DIR), "Extra image files not installed")
def test_open_windows_v2(self): @pytest.mark.skipif(
not os.path.exists(EXTRA_DIR), reason="Extra image files not installed"
)
def test_open_windows_v2():
files = ( files = (
os.path.join(EXTRA_DIR, f) os.path.join(EXTRA_DIR, f)
@ -61,22 +66,24 @@ class TestFileMsp(PillowTestCase):
if os.path.splitext(f)[1] == ".msp" if os.path.splitext(f)[1] == ".msp"
) )
for path in files: for path in files:
self._assert_file_image_equal(path, path.replace(".msp", ".png")) _assert_file_image_equal(path, path.replace(".msp", ".png"))
@unittest.skipIf(
not os.path.exists(YA_EXTRA_DIR), "Even More Extra image files not installed" @pytest.mark.skipif(
) not os.path.exists(YA_EXTRA_DIR), reason="Even More Extra image files not installed"
def test_msp_v2(self): )
def test_msp_v2():
for f in os.listdir(YA_EXTRA_DIR): for f in os.listdir(YA_EXTRA_DIR):
if ".MSP" not in f: if ".MSP" not in f:
continue continue
path = os.path.join(YA_EXTRA_DIR, f) path = os.path.join(YA_EXTRA_DIR, f)
self._assert_file_image_equal(path, path.replace(".MSP", ".png")) _assert_file_image_equal(path, path.replace(".MSP", ".png"))
def test_cannot_save_wrong_mode(self):
def test_cannot_save_wrong_mode(tmp_path):
# Arrange # Arrange
im = hopper() im = hopper()
filename = self.tempfile("temp.msp") filename = str(tmp_path / "temp.msp")
# Act/Assert # Act/Assert
with pytest.raises(IOError): with pytest.raises(IOError):

View File

@ -1,3 +1,4 @@
import re
import unittest import unittest
import zlib import zlib
from io import BytesIO from io import BytesIO
@ -75,7 +76,7 @@ class TestFilePng(PillowTestCase):
def test_sanity(self): def test_sanity(self):
# internal version number # internal version number
self.assertRegex(Image.core.zlib_version, r"\d+\.\d+\.\d+(\.\d+)?$") assert re.search(r"\d+\.\d+\.\d+(\.\d+)?$", Image.core.zlib_version)
test_file = self.tempfile("temp.png") test_file = self.tempfile("temp.png")

View File

@ -1,32 +1,32 @@
import tempfile import tempfile
import unittest
from io import BytesIO from io import BytesIO
import pytest import pytest
from PIL import Image, ImageSequence, SpiderImagePlugin from PIL import Image, ImageSequence, SpiderImagePlugin
from .helper import PillowTestCase, assert_image_equal, hopper, is_pypy from .helper import assert_image_equal, hopper, is_pypy
TEST_FILE = "Tests/images/hopper.spider" TEST_FILE = "Tests/images/hopper.spider"
class TestImageSpider(PillowTestCase): def test_sanity():
def test_sanity(self):
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
im.load() im.load()
assert im.mode == "F" assert im.mode == "F"
assert im.size == (128, 128) assert im.size == (128, 128)
assert im.format == "SPIDER" assert im.format == "SPIDER"
@unittest.skipIf(is_pypy(), "Requires CPython")
def test_unclosed_file(self): @pytest.mark.skipif(is_pypy(), reason="Requires CPython")
def test_unclosed_file():
def open(): def open():
im = Image.open(TEST_FILE) im = Image.open(TEST_FILE)
im.load() im.load()
pytest.warns(ResourceWarning, open) pytest.warns(ResourceWarning, open)
def test_closed_file(self):
def test_closed_file():
def open(): def open():
im = Image.open(TEST_FILE) im = Image.open(TEST_FILE)
im.load() im.load()
@ -34,16 +34,18 @@ class TestImageSpider(PillowTestCase):
pytest.warns(None, open) pytest.warns(None, open)
def test_context_manager(self):
def test_context_manager():
def open(): def open():
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
im.load() im.load()
pytest.warns(None, open) pytest.warns(None, open)
def test_save(self):
def test_save(tmp_path):
# Arrange # Arrange
temp = self.tempfile("temp.spider") temp = str(tmp_path / "temp.spider")
im = hopper() im = hopper()
# Act # Act
@ -55,7 +57,8 @@ class TestImageSpider(PillowTestCase):
assert im2.size == (128, 128) assert im2.size == (128, 128)
assert im2.format == "SPIDER" assert im2.format == "SPIDER"
def test_tempfile(self):
def test_tempfile():
# Arrange # Arrange
im = hopper() im = hopper()
@ -70,10 +73,12 @@ class TestImageSpider(PillowTestCase):
assert reloaded.size == (128, 128) assert reloaded.size == (128, 128)
assert reloaded.format == "SPIDER" assert reloaded.format == "SPIDER"
def test_isSpiderImage(self):
def test_is_spider_image():
assert SpiderImagePlugin.isSpiderImage(TEST_FILE) assert SpiderImagePlugin.isSpiderImage(TEST_FILE)
def test_tell(self):
def test_tell():
# Arrange # Arrange
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
@ -83,12 +88,14 @@ class TestImageSpider(PillowTestCase):
# Assert # Assert
assert index == 0 assert index == 0
def test_n_frames(self):
def test_n_frames():
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
assert im.n_frames == 1 assert im.n_frames == 1
assert not im.is_animated assert not im.is_animated
def test_loadImageSeries(self):
def test_load_image_series():
# Arrange # Arrange
not_spider_file = "Tests/images/hopper.ppm" not_spider_file = "Tests/images/hopper.ppm"
file_list = [TEST_FILE, not_spider_file, "path/not_found.ext"] file_list = [TEST_FILE, not_spider_file, "path/not_found.ext"]
@ -101,7 +108,8 @@ class TestImageSpider(PillowTestCase):
assert isinstance(img_list[0], Image.Image) assert isinstance(img_list[0], Image.Image)
assert img_list[0].size == (128, 128) assert img_list[0].size == (128, 128)
def test_loadImageSeries_no_input(self):
def test_load_image_series_no_input():
# Arrange # Arrange
file_list = None file_list = None
@ -111,7 +119,8 @@ class TestImageSpider(PillowTestCase):
# Assert # Assert
assert img_list is None assert img_list is None
def test_isInt_not_a_number(self):
def test_is_int_not_a_number():
# Arrange # Arrange
not_a_number = "a" not_a_number = "a"
@ -121,24 +130,28 @@ class TestImageSpider(PillowTestCase):
# Assert # Assert
assert ret == 0 assert ret == 0
def test_invalid_file(self):
def test_invalid_file():
invalid_file = "Tests/images/invalid.spider" invalid_file = "Tests/images/invalid.spider"
with pytest.raises(IOError): with pytest.raises(IOError):
Image.open(invalid_file) Image.open(invalid_file)
def test_nonstack_file(self):
def test_nonstack_file():
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
with pytest.raises(EOFError): with pytest.raises(EOFError):
im.seek(0) im.seek(0)
def test_nonstack_dos(self):
def test_nonstack_dos():
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
for i, frame in enumerate(ImageSequence.Iterator(im)): for i, frame in enumerate(ImageSequence.Iterator(im)):
assert i <= 1, "Non-stack DOS file test failed" assert i <= 1, "Non-stack DOS file test failed"
# for issue #4093
def test_odd_size(self): # for issue #4093
def test_odd_size():
data = BytesIO() data = BytesIO()
width = 100 width = 100
im = Image.new("F", (width, 64)) im = Image.new("F", (width, 64))

View File

@ -65,9 +65,9 @@ class TestFileTiffMetadata(PillowTestCase):
assert loaded.tag_v2[ImageDescription] == reloaded_textdata assert loaded.tag_v2[ImageDescription] == reloaded_textdata
loaded_float = loaded.tag[tag_ids["RollAngle"]][0] loaded_float = loaded.tag[tag_ids["RollAngle"]][0]
self.assertAlmostEqual(loaded_float, floatdata, places=5) assert round(abs(loaded_float - floatdata), 5) == 0
loaded_double = loaded.tag[tag_ids["YawAngle"]][0] loaded_double = loaded.tag[tag_ids["YawAngle"]][0]
self.assertAlmostEqual(loaded_double, doubledata) assert round(abs(loaded_double - doubledata), 7) == 0
# check with 2 element ImageJMetaDataByteCounts, issue #2006 # check with 2 element ImageJMetaDataByteCounts, issue #2006

View File

@ -2,13 +2,11 @@ import io
import os import os
import shutil import shutil
import tempfile import tempfile
import unittest
import pytest import pytest
from PIL import Image, ImageDraw, ImagePalette, UnidentifiedImageError from PIL import Image, ImageDraw, ImagePalette, UnidentifiedImageError
from .helper import ( from .helper import (
PillowTestCase,
assert_image_equal, assert_image_equal,
assert_image_similar, assert_image_similar,
assert_not_all_same, assert_not_all_same,
@ -17,7 +15,7 @@ from .helper import (
) )
class TestImage(PillowTestCase): class TestImage:
def test_image_modes_success(self): def test_image_modes_success(self):
for mode in [ for mode in [
"1", "1",
@ -109,7 +107,7 @@ class TestImage(PillowTestCase):
with pytest.raises(ValueError): with pytest.raises(ValueError):
Image.open(io.StringIO()) Image.open(io.StringIO())
def test_pathlib(self): def test_pathlib(self, tmp_path):
from PIL.Image import Path from PIL.Image import Path
with Image.open(Path("Tests/images/multipage-mmap.tiff")) as im: with Image.open(Path("Tests/images/multipage-mmap.tiff")) as im:
@ -120,13 +118,13 @@ class TestImage(PillowTestCase):
assert im.mode == "RGB" assert im.mode == "RGB"
assert im.size == (128, 128) assert im.size == (128, 128)
temp_file = self.tempfile("temp.jpg") temp_file = str(tmp_path / "temp.jpg")
if os.path.exists(temp_file): if os.path.exists(temp_file):
os.remove(temp_file) os.remove(temp_file)
im.save(Path(temp_file)) im.save(Path(temp_file))
def test_fp_name(self): def test_fp_name(self, tmp_path):
temp_file = self.tempfile("temp.jpg") temp_file = str(tmp_path / "temp.jpg")
class FP: class FP:
def write(a, b): def write(a, b):
@ -148,9 +146,9 @@ class TestImage(PillowTestCase):
with Image.open(fp) as reloaded: with Image.open(fp) as reloaded:
assert_image_similar(im, reloaded, 20) assert_image_similar(im, reloaded, 20)
def test_unknown_extension(self): def test_unknown_extension(self, tmp_path):
im = hopper() im = hopper()
temp_file = self.tempfile("temp.unknown") temp_file = str(tmp_path / "temp.unknown")
with pytest.raises(ValueError): with pytest.raises(ValueError):
im.save(temp_file) im.save(temp_file)
@ -164,25 +162,25 @@ class TestImage(PillowTestCase):
im.paste(0, (0, 0, 100, 100)) im.paste(0, (0, 0, 100, 100))
assert not im.readonly assert not im.readonly
@unittest.skipIf(is_win32(), "Test requires opening tempfile twice") @pytest.mark.skipif(is_win32(), reason="Test requires opening tempfile twice")
def test_readonly_save(self): def test_readonly_save(self, tmp_path):
temp_file = self.tempfile("temp.bmp") temp_file = str(tmp_path / "temp.bmp")
shutil.copy("Tests/images/rgb32bf-rgba.bmp", temp_file) shutil.copy("Tests/images/rgb32bf-rgba.bmp", temp_file)
with Image.open(temp_file) as im: with Image.open(temp_file) as im:
assert im.readonly assert im.readonly
im.save(temp_file) im.save(temp_file)
def test_dump(self): def test_dump(self, tmp_path):
im = Image.new("L", (10, 10)) im = Image.new("L", (10, 10))
im._dump(self.tempfile("temp_L.ppm")) im._dump(str(tmp_path / "temp_L.ppm"))
im = Image.new("RGB", (10, 10)) im = Image.new("RGB", (10, 10))
im._dump(self.tempfile("temp_RGB.ppm")) im._dump(str(tmp_path / "temp_RGB.ppm"))
im = Image.new("HSV", (10, 10)) im = Image.new("HSV", (10, 10))
with pytest.raises(ValueError): with pytest.raises(ValueError):
im._dump(self.tempfile("temp_HSV.ppm")) im._dump(str(tmp_path / "temp_HSV.ppm"))
def test_comparison_with_other_type(self): def test_comparison_with_other_type(self):
# Arrange # Arrange
@ -434,8 +432,7 @@ class TestImage(PillowTestCase):
assert_image_similar(im2, im3, 110) assert_image_similar(im2, im3, 110)
def test_check_size(self): def test_check_size(self):
# Checking that the _check_size function throws value errors # Checking that the _check_size function throws value errors when we want it to
# when we want it to.
with pytest.raises(ValueError): with pytest.raises(ValueError):
Image.new("RGB", 0) # not a tuple Image.new("RGB", 0) # not a tuple
with pytest.raises(ValueError): with pytest.raises(ValueError):
@ -587,11 +584,11 @@ class TestImage(PillowTestCase):
expected = Image.new(mode, (100, 100), color) expected = Image.new(mode, (100, 100), color)
assert_image_equal(im.convert(mode), expected) assert_image_equal(im.convert(mode), expected)
def test_no_resource_warning_on_save(self): def test_no_resource_warning_on_save(self, tmp_path):
# https://github.com/python-pillow/Pillow/issues/835 # https://github.com/python-pillow/Pillow/issues/835
# Arrange # Arrange
test_file = "Tests/images/hopper.png" test_file = "Tests/images/hopper.png"
temp_file = self.tempfile("temp.jpg") temp_file = str(tmp_path / "temp.jpg")
# Act/Assert # Act/Assert
with Image.open(test_file) as im: with Image.open(test_file) as im:
@ -623,14 +620,14 @@ class TestImage(PillowTestCase):
with Image.open(os.path.join("Tests/images", file)) as im: with Image.open(os.path.join("Tests/images", file)) as im:
try: try:
im.load() im.load()
self.assertFail() assert False
except OSError as e: except OSError as e:
assert str(e) == "buffer overrun when reading image file" assert str(e) == "buffer overrun when reading image file"
with Image.open("Tests/images/fli_overrun2.bin") as im: with Image.open("Tests/images/fli_overrun2.bin") as im:
try: try:
im.seek(1) im.seek(1)
self.assertFail() assert False
except OSError as e: except OSError as e:
assert str(e) == "buffer overrun when reading image file" assert str(e) == "buffer overrun when reading image file"
@ -645,7 +642,7 @@ def mock_encode(*args):
return encoder return encoder
class TestRegistry(PillowTestCase): class TestRegistry:
def test_encode_registry(self): def test_encode_registry(self):
Image.register_encoder("MOCK", mock_encode) Image.register_encoder("MOCK", mock_encode)

View File

@ -228,9 +228,8 @@ class TestCffi(AccessTest):
assert access[(x, y)] == caccess[(x, y)] assert access[(x, y)] == caccess[(x, y)]
# Access an out-of-range pixel # Access an out-of-range pixel
self.assertRaises( with pytest.raises(ValueError):
ValueError, lambda: access[(access.xsize + 1, access.ysize + 1)] access[(access.xsize + 1, access.ysize + 1)]
)
def test_get_vs_c(self): def test_get_vs_c(self):
rgb = hopper("RGB") rgb = hopper("RGB")

View File

@ -1,13 +1,12 @@
import unittest
from contextlib import contextmanager from contextlib import contextmanager
import pytest import pytest
from PIL import Image, ImageDraw from PIL import Image, ImageDraw
from .helper import PillowTestCase, assert_image_equal, assert_image_similar, hopper from .helper import assert_image_equal, assert_image_similar, hopper
class TestImagingResampleVulnerability(PillowTestCase): class TestImagingResampleVulnerability:
# see https://github.com/python-pillow/Pillow/issues/1710 # see https://github.com/python-pillow/Pillow/issues/1710
def test_overflow(self): def test_overflow(self):
im = hopper("L") im = hopper("L")
@ -43,7 +42,7 @@ class TestImagingResampleVulnerability(PillowTestCase):
assert im.tobytes() != copy.tobytes() assert im.tobytes() != copy.tobytes()
class TestImagingCoreResampleAccuracy(PillowTestCase): class TestImagingCoreResampleAccuracy:
def make_case(self, mode, size, color): def make_case(self, mode, size, color):
"""Makes a sample image with two dark and two bright squares. """Makes a sample image with two dark and two bright squares.
For example: For example:
@ -219,7 +218,7 @@ class TestImagingCoreResampleAccuracy(PillowTestCase):
assert_image_equal(im, ref) assert_image_equal(im, ref)
class CoreResampleConsistencyTest(PillowTestCase): class CoreResampleConsistencyTest:
def make_case(self, mode, fill): def make_case(self, mode, fill):
im = Image.new(mode, (512, 9), fill) im = Image.new(mode, (512, 9), fill)
return im.resize((9, 512), Image.LANCZOS), im.load()[0, 0] return im.resize((9, 512), Image.LANCZOS), im.load()[0, 0]
@ -254,7 +253,7 @@ class CoreResampleConsistencyTest(PillowTestCase):
self.run_case(self.make_case("F", 1.192093e-07)) self.run_case(self.make_case("F", 1.192093e-07))
class CoreResampleAlphaCorrectTest(PillowTestCase): class CoreResampleAlphaCorrectTest:
def make_levels_case(self, mode): def make_levels_case(self, mode):
i = Image.new(mode, (256, 16)) i = Image.new(mode, (256, 16))
px = i.load() px = i.load()
@ -275,7 +274,7 @@ class CoreResampleAlphaCorrectTest(PillowTestCase):
len(used_colors), y len(used_colors), y
) )
@unittest.skip("current implementation isn't precise enough") @pytest.mark.skip("Current implementation isn't precise enough")
def test_levels_rgba(self): def test_levels_rgba(self):
case = self.make_levels_case("RGBA") case = self.make_levels_case("RGBA")
self.run_levels_case(case.resize((512, 32), Image.BOX)) self.run_levels_case(case.resize((512, 32), Image.BOX))
@ -284,7 +283,7 @@ class CoreResampleAlphaCorrectTest(PillowTestCase):
self.run_levels_case(case.resize((512, 32), Image.BICUBIC)) self.run_levels_case(case.resize((512, 32), Image.BICUBIC))
self.run_levels_case(case.resize((512, 32), Image.LANCZOS)) self.run_levels_case(case.resize((512, 32), Image.LANCZOS))
@unittest.skip("current implementation isn't precise enough") @pytest.mark.skip("Current implementation isn't precise enough")
def test_levels_la(self): def test_levels_la(self):
case = self.make_levels_case("LA") case = self.make_levels_case("LA")
self.run_levels_case(case.resize((512, 32), Image.BOX)) self.run_levels_case(case.resize((512, 32), Image.BOX))
@ -330,7 +329,7 @@ class CoreResampleAlphaCorrectTest(PillowTestCase):
self.run_dirty_case(case.resize((20, 20), Image.LANCZOS), (255,)) self.run_dirty_case(case.resize((20, 20), Image.LANCZOS), (255,))
class CoreResamplePassesTest(PillowTestCase): class CoreResamplePassesTest:
@contextmanager @contextmanager
def count(self, diff): def count(self, diff):
count = Image.core.get_stats()["new_count"] count = Image.core.get_stats()["new_count"]
@ -373,7 +372,7 @@ class CoreResamplePassesTest(PillowTestCase):
assert_image_similar(with_box, cropped, 0.1) assert_image_similar(with_box, cropped, 0.1)
class CoreResampleCoefficientsTest(PillowTestCase): class CoreResampleCoefficientsTest:
def test_reduce(self): def test_reduce(self):
test_color = 254 test_color = 254
@ -402,7 +401,7 @@ class CoreResampleCoefficientsTest(PillowTestCase):
assert histogram[0x100 * 3 + 0xFF] == 0x10000 assert histogram[0x100 * 3 + 0xFF] == 0x10000
class CoreResampleBoxTest(PillowTestCase): class CoreResampleBoxTest:
def test_wrong_arguments(self): def test_wrong_arguments(self):
im = hopper() im = hopper()
for resample in ( for resample in (
@ -418,24 +417,24 @@ class CoreResampleBoxTest(PillowTestCase):
im.resize((32, 32), resample, (20, 20, 20, 100)) im.resize((32, 32), resample, (20, 20, 20, 100))
im.resize((32, 32), resample, (20, 20, 100, 20)) im.resize((32, 32), resample, (20, 20, 100, 20))
with self.assertRaisesRegex(TypeError, "must be sequence of length 4"): with pytest.raises(TypeError, match="must be sequence of length 4"):
im.resize((32, 32), resample, (im.width, im.height)) im.resize((32, 32), resample, (im.width, im.height))
with self.assertRaisesRegex(ValueError, "can't be negative"): with pytest.raises(ValueError, match="can't be negative"):
im.resize((32, 32), resample, (-20, 20, 100, 100)) im.resize((32, 32), resample, (-20, 20, 100, 100))
with self.assertRaisesRegex(ValueError, "can't be negative"): with pytest.raises(ValueError, match="can't be negative"):
im.resize((32, 32), resample, (20, -20, 100, 100)) im.resize((32, 32), resample, (20, -20, 100, 100))
with self.assertRaisesRegex(ValueError, "can't be empty"): with pytest.raises(ValueError, match="can't be empty"):
im.resize((32, 32), resample, (20.1, 20, 20, 100)) im.resize((32, 32), resample, (20.1, 20, 20, 100))
with self.assertRaisesRegex(ValueError, "can't be empty"): with pytest.raises(ValueError, match="can't be empty"):
im.resize((32, 32), resample, (20, 20.1, 100, 20)) im.resize((32, 32), resample, (20, 20.1, 100, 20))
with self.assertRaisesRegex(ValueError, "can't be empty"): with pytest.raises(ValueError, match="can't be empty"):
im.resize((32, 32), resample, (20.1, 20.1, 20, 20)) im.resize((32, 32), resample, (20.1, 20.1, 20, 20))
with self.assertRaisesRegex(ValueError, "can't exceed"): with pytest.raises(ValueError, match="can't exceed"):
im.resize((32, 32), resample, (0, 0, im.width + 1, im.height)) im.resize((32, 32), resample, (0, 0, im.width + 1, im.height))
with self.assertRaisesRegex(ValueError, "can't exceed"): with pytest.raises(ValueError, match="can't exceed"):
im.resize((32, 32), resample, (0, 0, im.width, im.height + 1)) im.resize((32, 32), resample, (0, 0, im.width, im.height + 1))
def resize_tiled(self, im, dst_size, xtiles, ytiles): def resize_tiled(self, im, dst_size, xtiles, ytiles):
@ -480,7 +479,7 @@ class CoreResampleBoxTest(PillowTestCase):
# error with box should be much smaller than without # error with box should be much smaller than without
assert_image_similar(reference, with_box, 6) assert_image_similar(reference, with_box, 6)
with self.assertRaisesRegex(AssertionError, r"difference 29\."): with pytest.raises(AssertionError, match=r"difference 29\."):
assert_image_similar(reference, without_box, 5) assert_image_similar(reference, without_box, 5)
def test_formats(self): def test_formats(self):
@ -518,7 +517,7 @@ class CoreResampleBoxTest(PillowTestCase):
]: ]:
res = im.resize(size, Image.LANCZOS, box) res = im.resize(size, Image.LANCZOS, box)
assert res.size == size assert res.size == size
with self.assertRaisesRegex(AssertionError, r"difference \d"): with pytest.raises(AssertionError, match=r"difference \d"):
# check that the difference at least that much # check that the difference at least that much
assert_image_similar( assert_image_similar(
res, im.crop(box), 20, ">>> {} {}".format(size, box) res, im.crop(box), 20, ">>> {} {}".format(size, box)

View File

@ -66,7 +66,7 @@ class TestImageFont(PillowTestCase):
) )
def test_sanity(self): def test_sanity(self):
self.assertRegex(ImageFont.core.freetype2_version, r"\d+\.\d+\.\d+$") assert re.search(r"\d+\.\d+\.\d+$", ImageFont.core.freetype2_version)
def test_font_properties(self): def test_font_properties(self):
ttf = self.get_font() ttf = self.get_font()

View File

@ -1,8 +1,7 @@
import unittest import pytest
from PIL import Image, ImageDraw, ImageFont from PIL import Image, ImageDraw, ImageFont
from .helper import PillowTestCase, assert_image_similar from .helper import assert_image_similar
image_font_installed = True image_font_installed = True
try: try:
@ -11,14 +10,11 @@ except ImportError:
image_font_installed = False image_font_installed = False
@unittest.skipUnless(image_font_installed, "image font not installed") @pytest.mark.skipif(not image_font_installed, reason="Image font not installed")
class TestImageFontBitmap(PillowTestCase): def test_similar():
def test_similar(self):
text = "EmbeddedBitmap" text = "EmbeddedBitmap"
font_outline = ImageFont.truetype(font="Tests/fonts/DejaVuSans.ttf", size=24) font_outline = ImageFont.truetype(font="Tests/fonts/DejaVuSans.ttf", size=24)
font_bitmap = ImageFont.truetype( font_bitmap = ImageFont.truetype(font="Tests/fonts/DejaVuSans-bitmap.ttf", size=24)
font="Tests/fonts/DejaVuSans-bitmap.ttf", size=24
)
size_outline = font_outline.getsize(text) size_outline = font_outline.getsize(text)
size_bitmap = font_bitmap.getsize(text) size_bitmap = font_bitmap.getsize(text)
size_final = ( size_final = (
@ -30,16 +26,13 @@ class TestImageFontBitmap(PillowTestCase):
draw_bitmap = ImageDraw.Draw(im_bitmap) draw_bitmap = ImageDraw.Draw(im_bitmap)
draw_outline = ImageDraw.Draw(im_outline) draw_outline = ImageDraw.Draw(im_outline)
# Metrics are different on the bitmap and ttf fonts, # Metrics are different on the bitmap and TTF fonts,
# more so on some platforms and versions of freetype than others. # more so on some platforms and versions of FreeType than others.
# Mac has a 1px difference, linux doesn't. # Mac has a 1px difference, Linux doesn't.
draw_bitmap.text( draw_bitmap.text(
(0, size_final[1] - size_bitmap[1]), text, fill=(0, 0, 0), font=font_bitmap (0, size_final[1] - size_bitmap[1]), text, fill=(0, 0, 0), font=font_bitmap
) )
draw_outline.text( draw_outline.text(
(0, size_final[1] - size_outline[1]), (0, size_final[1] - size_outline[1]), text, fill=(0, 0, 0), font=font_outline,
text,
fill=(0, 0, 0),
font=font_outline,
) )
assert_image_similar(im_bitmap, im_outline, 20) assert_image_similar(im_bitmap, im_outline, 20)