Autotype tests (#7756)

* autotyping: --none-return
* autotyping: --scalar-return
* autotyping: --int-param
* autotyping: --float-param
* autotyping: --str-param
* autotyping: --annotate-named-param tmp_path:pathlib.Path
This commit is contained in:
Hugo van Kemenade 2024-01-31 11:12:58 +02:00 committed by GitHub
parent db437386eb
commit 4a4b90c365
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
108 changed files with 1866 additions and 1798 deletions

View File

@ -9,21 +9,21 @@ from .helper import hopper
# Not running this test by default. No DOS against CI. # Not running this test by default. No DOS against CI.
def iterate_get(size, access): def iterate_get(size, access) -> None:
(w, h) = size (w, h) = size
for x in range(w): for x in range(w):
for y in range(h): for y in range(h):
access[(x, y)] access[(x, y)]
def iterate_set(size, access): def iterate_set(size, access) -> None:
(w, h) = size (w, h) = size
for x in range(w): for x in range(w):
for y in range(h): for y in range(h):
access[(x, y)] = (x % 256, y % 256, 0) access[(x, y)] = (x % 256, y % 256, 0)
def timer(func, label, *args): def timer(func, label, *args) -> None:
iterations = 5000 iterations = 5000
starttime = time.time() starttime = time.time()
for x in range(iterations): for x in range(iterations):
@ -38,7 +38,7 @@ def timer(func, label, *args):
) )
def test_direct(): def test_direct() -> None:
im = hopper() im = hopper()
im.load() im.load()
# im = Image.new("RGB", (2000, 2000), (1, 3, 2)) # im = Image.new("RGB", (2000, 2000), (1, 3, 2))

View File

@ -10,13 +10,13 @@ from .helper import assert_image_similar
base = os.path.join("Tests", "images", "bmp") base = os.path.join("Tests", "images", "bmp")
def get_files(d, ext=".bmp"): def get_files(d, ext: str = ".bmp"):
return [ return [
os.path.join(base, d, f) for f in os.listdir(os.path.join(base, d)) if ext in f os.path.join(base, d, f) for f in os.listdir(os.path.join(base, d)) if ext in f
] ]
def test_bad(): def test_bad() -> None:
"""These shouldn't crash/dos, but they shouldn't return anything """These shouldn't crash/dos, but they shouldn't return anything
either""" either"""
for f in get_files("b"): for f in get_files("b"):
@ -56,7 +56,7 @@ def test_questionable():
raise raise
def test_good(): def test_good() -> None:
"""These should all work. There's a set of target files in the """These should all work. There's a set of target files in the
html directory that we can compare against.""" html directory that we can compare against."""

View File

@ -16,18 +16,18 @@ sample.putdata(sum([
# fmt: on # fmt: on
def test_imageops_box_blur(): def test_imageops_box_blur() -> None:
i = sample.filter(ImageFilter.BoxBlur(1)) i = sample.filter(ImageFilter.BoxBlur(1))
assert i.mode == sample.mode assert i.mode == sample.mode
assert i.size == sample.size assert i.size == sample.size
assert isinstance(i, Image.Image) assert isinstance(i, Image.Image)
def box_blur(image, radius=1, n=1): def box_blur(image, radius: int = 1, n: int = 1):
return image._new(image.im.box_blur((radius, radius), n)) return image._new(image.im.box_blur((radius, radius), n))
def assert_image(im, data, delta=0): def assert_image(im, data, delta: int = 0) -> None:
it = iter(im.getdata()) it = iter(im.getdata())
for data_row in data: for data_row in data:
im_row = [next(it) for _ in range(im.size[0])] im_row = [next(it) for _ in range(im.size[0])]
@ -37,7 +37,7 @@ def assert_image(im, data, delta=0):
next(it) next(it)
def assert_blur(im, radius, data, passes=1, delta=0): def assert_blur(im, radius, data, passes: int = 1, delta: int = 0) -> None:
# check grayscale image # check grayscale image
assert_image(box_blur(im, radius, passes), data, delta) assert_image(box_blur(im, radius, passes), data, delta)
rgba = Image.merge("RGBA", (im, im, im, im)) rgba = Image.merge("RGBA", (im, im, im, im))
@ -45,7 +45,7 @@ def assert_blur(im, radius, data, passes=1, delta=0):
assert_image(band, data, delta) assert_image(band, data, delta)
def test_color_modes(): def test_color_modes() -> None:
with pytest.raises(ValueError): with pytest.raises(ValueError):
box_blur(sample.convert("1")) box_blur(sample.convert("1"))
with pytest.raises(ValueError): with pytest.raises(ValueError):
@ -65,7 +65,7 @@ def test_color_modes():
box_blur(sample.convert("YCbCr")) box_blur(sample.convert("YCbCr"))
def test_radius_0(): def test_radius_0() -> None:
assert_blur( assert_blur(
sample, sample,
0, 0,
@ -81,7 +81,7 @@ def test_radius_0():
) )
def test_radius_0_02(): def test_radius_0_02() -> None:
assert_blur( assert_blur(
sample, sample,
0.02, 0.02,
@ -98,7 +98,7 @@ def test_radius_0_02():
) )
def test_radius_0_05(): def test_radius_0_05() -> None:
assert_blur( assert_blur(
sample, sample,
0.05, 0.05,
@ -115,7 +115,7 @@ def test_radius_0_05():
) )
def test_radius_0_1(): def test_radius_0_1() -> None:
assert_blur( assert_blur(
sample, sample,
0.1, 0.1,
@ -132,7 +132,7 @@ def test_radius_0_1():
) )
def test_radius_0_5(): def test_radius_0_5() -> None:
assert_blur( assert_blur(
sample, sample,
0.5, 0.5,
@ -149,7 +149,7 @@ def test_radius_0_5():
) )
def test_radius_1(): def test_radius_1() -> None:
assert_blur( assert_blur(
sample, sample,
1, 1,
@ -166,7 +166,7 @@ def test_radius_1():
) )
def test_radius_1_5(): def test_radius_1_5() -> None:
assert_blur( assert_blur(
sample, sample,
1.5, 1.5,
@ -183,7 +183,7 @@ def test_radius_1_5():
) )
def test_radius_bigger_then_half(): def test_radius_bigger_then_half() -> None:
assert_blur( assert_blur(
sample, sample,
3, 3,
@ -200,7 +200,7 @@ def test_radius_bigger_then_half():
) )
def test_radius_bigger_then_width(): def test_radius_bigger_then_width() -> None:
assert_blur( assert_blur(
sample, sample,
10, 10,
@ -215,7 +215,7 @@ def test_radius_bigger_then_width():
) )
def test_extreme_large_radius(): def test_extreme_large_radius() -> None:
assert_blur( assert_blur(
sample, sample,
600, 600,
@ -230,7 +230,7 @@ def test_extreme_large_radius():
) )
def test_two_passes(): def test_two_passes() -> None:
assert_blur( assert_blur(
sample, sample,
1, 1,
@ -248,7 +248,7 @@ def test_two_passes():
) )
def test_three_passes(): def test_three_passes() -> None:
assert_blur( assert_blur(
sample, sample,
1, 1,

View File

@ -41,7 +41,7 @@ class TestColorLut3DCoreAPI:
[item for sublist in table for item in sublist], [item for sublist in table for item in sublist],
) )
def test_wrong_args(self): def test_wrong_args(self) -> None:
im = Image.new("RGB", (10, 10), 0) im = Image.new("RGB", (10, 10), 0)
with pytest.raises(ValueError, match="filter"): with pytest.raises(ValueError, match="filter"):
@ -101,7 +101,7 @@ class TestColorLut3DCoreAPI:
with pytest.raises(TypeError): with pytest.raises(TypeError):
im.im.color_lut_3d("RGB", Image.Resampling.BILINEAR, 3, 2, 2, 2, 16) im.im.color_lut_3d("RGB", Image.Resampling.BILINEAR, 3, 2, 2, 2, 16)
def test_correct_args(self): def test_correct_args(self) -> None:
im = Image.new("RGB", (10, 10), 0) im = Image.new("RGB", (10, 10), 0)
im.im.color_lut_3d( im.im.color_lut_3d(
@ -136,7 +136,7 @@ class TestColorLut3DCoreAPI:
*self.generate_identity_table(3, (3, 3, 65)), *self.generate_identity_table(3, (3, 3, 65)),
) )
def test_wrong_mode(self): def test_wrong_mode(self) -> None:
with pytest.raises(ValueError, match="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( im.im.color_lut_3d(
@ -167,7 +167,7 @@ class TestColorLut3DCoreAPI:
"RGB", Image.Resampling.BILINEAR, *self.generate_identity_table(4, 3) "RGB", Image.Resampling.BILINEAR, *self.generate_identity_table(4, 3)
) )
def test_correct_mode(self): def test_correct_mode(self) -> None:
im = Image.new("RGBA", (10, 10), 0) im = Image.new("RGBA", (10, 10), 0)
im.im.color_lut_3d( im.im.color_lut_3d(
"RGBA", Image.Resampling.BILINEAR, *self.generate_identity_table(3, 3) "RGBA", Image.Resampling.BILINEAR, *self.generate_identity_table(3, 3)
@ -188,7 +188,7 @@ class TestColorLut3DCoreAPI:
"RGBA", Image.Resampling.BILINEAR, *self.generate_identity_table(4, 3) "RGBA", Image.Resampling.BILINEAR, *self.generate_identity_table(4, 3)
) )
def test_identities(self): def test_identities(self) -> None:
g = Image.linear_gradient("L") g = Image.linear_gradient("L")
im = Image.merge( im = Image.merge(
"RGB", "RGB",
@ -224,7 +224,7 @@ class TestColorLut3DCoreAPI:
), ),
) )
def test_identities_4_channels(self): def test_identities_4_channels(self) -> None:
g = Image.linear_gradient("L") g = Image.linear_gradient("L")
im = Image.merge( im = Image.merge(
"RGB", "RGB",
@ -247,7 +247,7 @@ class TestColorLut3DCoreAPI:
), ),
) )
def test_copy_alpha_channel(self): def test_copy_alpha_channel(self) -> None:
g = Image.linear_gradient("L") g = Image.linear_gradient("L")
im = Image.merge( im = Image.merge(
"RGBA", "RGBA",
@ -270,7 +270,7 @@ class TestColorLut3DCoreAPI:
), ),
) )
def test_channels_order(self): def test_channels_order(self) -> None:
g = Image.linear_gradient("L") g = Image.linear_gradient("L")
im = Image.merge( im = Image.merge(
"RGB", "RGB",
@ -295,7 +295,7 @@ class TestColorLut3DCoreAPI:
]))) ])))
# fmt: on # fmt: on
def test_overflow(self): def test_overflow(self) -> None:
g = Image.linear_gradient("L") g = Image.linear_gradient("L")
im = Image.merge( im = Image.merge(
"RGB", "RGB",
@ -348,7 +348,7 @@ class TestColorLut3DCoreAPI:
class TestColorLut3DFilter: class TestColorLut3DFilter:
def test_wrong_args(self): def test_wrong_args(self) -> None:
with pytest.raises(ValueError, match="should be either an integer"): with pytest.raises(ValueError, match="should be either an integer"):
ImageFilter.Color3DLUT("small", [1]) ImageFilter.Color3DLUT("small", [1])
@ -376,7 +376,7 @@ class TestColorLut3DFilter:
with pytest.raises(ValueError, match="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) -> None:
lut = ImageFilter.Color3DLUT(2, [0, 1, 2] * 8) lut = ImageFilter.Color3DLUT(2, [0, 1, 2] * 8)
assert tuple(lut.size) == (2, 2, 2) assert tuple(lut.size) == (2, 2, 2)
assert lut.name == "Color 3D LUT" assert lut.name == "Color 3D LUT"
@ -394,7 +394,7 @@ class TestColorLut3DFilter:
assert lut.table == list(range(4)) * 8 assert lut.table == list(range(4)) * 8
@pytest.mark.skipif(numpy is None, reason="NumPy not installed") @pytest.mark.skipif(numpy is None, reason="NumPy not installed")
def test_numpy_sources(self): def test_numpy_sources(self) -> None:
table = numpy.ones((5, 6, 7, 3), dtype=numpy.float16) table = numpy.ones((5, 6, 7, 3), dtype=numpy.float16)
with pytest.raises(ValueError, match="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)
@ -427,7 +427,7 @@ class TestColorLut3DFilter:
assert lut.table[0] == 33 assert lut.table[0] == 33
@pytest.mark.skipif(numpy is None, reason="NumPy not installed") @pytest.mark.skipif(numpy is None, reason="NumPy not installed")
def test_numpy_formats(self): def test_numpy_formats(self) -> None:
g = Image.linear_gradient("L") g = Image.linear_gradient("L")
im = Image.merge( im = Image.merge(
"RGB", "RGB",
@ -466,7 +466,7 @@ class TestColorLut3DFilter:
lut.table = numpy.array(lut.table, dtype=numpy.int8) lut.table = numpy.array(lut.table, dtype=numpy.int8)
im.filter(lut) im.filter(lut)
def test_repr(self): def test_repr(self) -> None:
lut = ImageFilter.Color3DLUT(2, [0, 1, 2] * 8) lut = ImageFilter.Color3DLUT(2, [0, 1, 2] * 8)
assert repr(lut) == "<Color3DLUT from list size=2x2x2 channels=3>" assert repr(lut) == "<Color3DLUT from list size=2x2x2 channels=3>"
@ -484,7 +484,7 @@ class TestColorLut3DFilter:
class TestGenerateColorLut3D: class TestGenerateColorLut3D:
def test_wrong_channels_count(self): def test_wrong_channels_count(self) -> None:
with pytest.raises(ValueError, match="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)
@ -498,7 +498,7 @@ class TestGenerateColorLut3D:
5, channels=4, callback=lambda r, g, b: (r, g, b) 5, channels=4, callback=lambda r, g, b: (r, g, b)
) )
def test_3_channels(self): def test_3_channels(self) -> None:
lut = ImageFilter.Color3DLUT.generate(5, lambda r, g, b: (r, g, b)) lut = ImageFilter.Color3DLUT.generate(5, lambda r, g, b: (r, g, b))
assert tuple(lut.size) == (5, 5, 5) assert tuple(lut.size) == (5, 5, 5)
assert lut.name == "Color 3D LUT" assert lut.name == "Color 3D LUT"
@ -508,7 +508,7 @@ class TestGenerateColorLut3D:
1.0, 0.0, 0.0, 0.0, 0.25, 0.0, 0.25, 0.25, 0.0, 0.5, 0.25, 0.0] 1.0, 0.0, 0.0, 0.0, 0.25, 0.0, 0.25, 0.25, 0.0, 0.5, 0.25, 0.0]
# fmt: on # fmt: on
def test_4_channels(self): def test_4_channels(self) -> None:
lut = ImageFilter.Color3DLUT.generate( lut = ImageFilter.Color3DLUT.generate(
5, channels=4, callback=lambda r, g, b: (b, r, g, (r + g + b) / 2) 5, channels=4, callback=lambda r, g, b: (b, r, g, (r + g + b) / 2)
) )
@ -521,7 +521,7 @@ class TestGenerateColorLut3D:
] ]
# fmt: on # fmt: on
def test_apply(self): def test_apply(self) -> None:
lut = ImageFilter.Color3DLUT.generate(5, lambda r, g, b: (r, g, b)) lut = ImageFilter.Color3DLUT.generate(5, lambda r, g, b: (r, g, b))
g = Image.linear_gradient("L") g = Image.linear_gradient("L")
@ -537,7 +537,7 @@ class TestGenerateColorLut3D:
class TestTransformColorLut3D: class TestTransformColorLut3D:
def test_wrong_args(self): def test_wrong_args(self) -> None:
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 pytest.raises(ValueError, match="Only 3 or 4 output"): with pytest.raises(ValueError, match="Only 3 or 4 output"):
@ -552,7 +552,7 @@ class TestTransformColorLut3D:
with pytest.raises(TypeError): with pytest.raises(TypeError):
source.transform(lambda r, g, b, a: (r, g, b)) source.transform(lambda r, g, b, a: (r, g, b))
def test_target_mode(self): def test_target_mode(self) -> None:
source = ImageFilter.Color3DLUT.generate( source = ImageFilter.Color3DLUT.generate(
2, lambda r, g, b: (r, g, b), target_mode="HSV" 2, lambda r, g, b: (r, g, b), target_mode="HSV"
) )
@ -563,7 +563,7 @@ class TestTransformColorLut3D:
lut = source.transform(lambda r, g, b: (r, g, b), target_mode="RGB") lut = source.transform(lambda r, g, b: (r, g, b), target_mode="RGB")
assert lut.mode == "RGB" assert lut.mode == "RGB"
def test_3_to_3_channels(self): def test_3_to_3_channels(self) -> None:
source = ImageFilter.Color3DLUT.generate((3, 4, 5), lambda r, g, b: (r, g, b)) source = ImageFilter.Color3DLUT.generate((3, 4, 5), lambda r, g, b: (r, g, b))
lut = source.transform(lambda r, g, b: (r * r, g * g, b * b)) lut = source.transform(lambda r, g, b: (r * r, g * g, b * b))
assert tuple(lut.size) == tuple(source.size) assert tuple(lut.size) == tuple(source.size)
@ -571,7 +571,7 @@ class TestTransformColorLut3D:
assert lut.table != source.table assert lut.table != source.table
assert lut.table[:10] == [0.0, 0.0, 0.0, 0.25, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0] assert lut.table[:10] == [0.0, 0.0, 0.0, 0.25, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0]
def test_3_to_4_channels(self): def test_3_to_4_channels(self) -> None:
source = ImageFilter.Color3DLUT.generate((6, 5, 4), lambda r, g, b: (r, g, b)) source = ImageFilter.Color3DLUT.generate((6, 5, 4), lambda r, g, b: (r, g, b))
lut = source.transform(lambda r, g, b: (r * r, g * g, b * b, 1), channels=4) lut = source.transform(lambda r, g, b: (r * r, g * g, b * b, 1), channels=4)
assert tuple(lut.size) == tuple(source.size) assert tuple(lut.size) == tuple(source.size)
@ -583,7 +583,7 @@ class TestTransformColorLut3D:
0.4**2, 0.0, 0.0, 1, 0.6**2, 0.0, 0.0, 1] 0.4**2, 0.0, 0.0, 1, 0.6**2, 0.0, 0.0, 1]
# fmt: on # fmt: on
def test_4_to_3_channels(self): def test_4_to_3_channels(self) -> None:
source = ImageFilter.Color3DLUT.generate( source = ImageFilter.Color3DLUT.generate(
(3, 6, 5), lambda r, g, b: (r, g, b, 1), channels=4 (3, 6, 5), lambda r, g, b: (r, g, b, 1), channels=4
) )
@ -599,7 +599,7 @@ class TestTransformColorLut3D:
1.0, 0.96, 1.0, 0.75, 0.96, 1.0, 0.0, 0.96, 1.0] 1.0, 0.96, 1.0, 0.75, 0.96, 1.0, 0.0, 0.96, 1.0]
# fmt: on # fmt: on
def test_4_to_4_channels(self): def test_4_to_4_channels(self) -> None:
source = ImageFilter.Color3DLUT.generate( source = ImageFilter.Color3DLUT.generate(
(6, 5, 4), lambda r, g, b: (r, g, b, 1), channels=4 (6, 5, 4), lambda r, g, b: (r, g, b, 1), channels=4
) )
@ -613,7 +613,7 @@ class TestTransformColorLut3D:
0.4**2, 0.0, 0.0, 0.5, 0.6**2, 0.0, 0.0, 0.5] 0.4**2, 0.0, 0.0, 0.5, 0.6**2, 0.0, 0.0, 0.5]
# fmt: on # fmt: on
def test_with_normals_3_channels(self): def test_with_normals_3_channels(self) -> None:
source = ImageFilter.Color3DLUT.generate( source = ImageFilter.Color3DLUT.generate(
(6, 5, 4), lambda r, g, b: (r * r, g * g, b * b) (6, 5, 4), lambda r, g, b: (r * r, g * g, b * b)
) )
@ -629,7 +629,7 @@ class TestTransformColorLut3D:
0.24, 0.0, 0.0, 0.8 - (0.8**2), 0, 0, 0, 0, 0] 0.24, 0.0, 0.0, 0.8 - (0.8**2), 0, 0, 0, 0, 0]
# fmt: on # fmt: on
def test_with_normals_4_channels(self): def test_with_normals_4_channels(self) -> None:
source = ImageFilter.Color3DLUT.generate( source = ImageFilter.Color3DLUT.generate(
(3, 6, 5), lambda r, g, b: (r * r, g * g, b * b, 1), channels=4 (3, 6, 5), lambda r, g, b: (r * r, g * g, b * b, 1), channels=4
) )

View File

@ -9,7 +9,7 @@ from PIL import Image
from .helper import is_pypy from .helper import is_pypy
def test_get_stats(): def test_get_stats() -> None:
# Create at least one image # Create at least one image
Image.new("RGB", (10, 10)) Image.new("RGB", (10, 10))
@ -22,7 +22,7 @@ def test_get_stats():
assert "blocks_cached" in stats assert "blocks_cached" in stats
def test_reset_stats(): def test_reset_stats() -> None:
Image.core.reset_stats() Image.core.reset_stats()
stats = Image.core.get_stats() stats = Image.core.get_stats()
@ -35,19 +35,19 @@ def test_reset_stats():
class TestCoreMemory: class TestCoreMemory:
def teardown_method(self): def teardown_method(self) -> None:
# Restore default values # Restore default values
Image.core.set_alignment(1) Image.core.set_alignment(1)
Image.core.set_block_size(1024 * 1024) Image.core.set_block_size(1024 * 1024)
Image.core.set_blocks_max(0) Image.core.set_blocks_max(0)
Image.core.clear_cache() Image.core.clear_cache()
def test_get_alignment(self): def test_get_alignment(self) -> None:
alignment = Image.core.get_alignment() alignment = Image.core.get_alignment()
assert alignment > 0 assert alignment > 0
def test_set_alignment(self): def test_set_alignment(self) -> None:
for i in [1, 2, 4, 8, 16, 32]: for i in [1, 2, 4, 8, 16, 32]:
Image.core.set_alignment(i) Image.core.set_alignment(i)
alignment = Image.core.get_alignment() alignment = Image.core.get_alignment()
@ -63,12 +63,12 @@ class TestCoreMemory:
with pytest.raises(ValueError): with pytest.raises(ValueError):
Image.core.set_alignment(3) Image.core.set_alignment(3)
def test_get_block_size(self): def test_get_block_size(self) -> None:
block_size = Image.core.get_block_size() block_size = Image.core.get_block_size()
assert block_size >= 4096 assert block_size >= 4096
def test_set_block_size(self): def test_set_block_size(self) -> None:
for i in [4096, 2 * 4096, 3 * 4096]: for i in [4096, 2 * 4096, 3 * 4096]:
Image.core.set_block_size(i) Image.core.set_block_size(i)
block_size = Image.core.get_block_size() block_size = Image.core.get_block_size()
@ -84,7 +84,7 @@ class TestCoreMemory:
with pytest.raises(ValueError): with pytest.raises(ValueError):
Image.core.set_block_size(4000) Image.core.set_block_size(4000)
def test_set_block_size_stats(self): def test_set_block_size_stats(self) -> None:
Image.core.reset_stats() Image.core.reset_stats()
Image.core.set_blocks_max(0) Image.core.set_blocks_max(0)
Image.core.set_block_size(4096) Image.core.set_block_size(4096)
@ -96,12 +96,12 @@ class TestCoreMemory:
if not is_pypy(): if not is_pypy():
assert stats["freed_blocks"] >= 64 assert stats["freed_blocks"] >= 64
def test_get_blocks_max(self): def test_get_blocks_max(self) -> None:
blocks_max = Image.core.get_blocks_max() blocks_max = Image.core.get_blocks_max()
assert blocks_max >= 0 assert blocks_max >= 0
def test_set_blocks_max(self): def test_set_blocks_max(self) -> None:
for i in [0, 1, 10]: for i in [0, 1, 10]:
Image.core.set_blocks_max(i) Image.core.set_blocks_max(i)
blocks_max = Image.core.get_blocks_max() blocks_max = Image.core.get_blocks_max()
@ -117,7 +117,7 @@ class TestCoreMemory:
Image.core.set_blocks_max(2**29) Image.core.set_blocks_max(2**29)
@pytest.mark.skipif(is_pypy(), reason="Images not collected") @pytest.mark.skipif(is_pypy(), reason="Images not collected")
def test_set_blocks_max_stats(self): def test_set_blocks_max_stats(self) -> None:
Image.core.reset_stats() Image.core.reset_stats()
Image.core.set_blocks_max(128) Image.core.set_blocks_max(128)
Image.core.set_block_size(4096) Image.core.set_block_size(4096)
@ -132,7 +132,7 @@ class TestCoreMemory:
assert stats["blocks_cached"] == 64 assert stats["blocks_cached"] == 64
@pytest.mark.skipif(is_pypy(), reason="Images not collected") @pytest.mark.skipif(is_pypy(), reason="Images not collected")
def test_clear_cache_stats(self): def test_clear_cache_stats(self) -> None:
Image.core.reset_stats() Image.core.reset_stats()
Image.core.clear_cache() Image.core.clear_cache()
Image.core.set_blocks_max(128) Image.core.set_blocks_max(128)
@ -149,7 +149,7 @@ class TestCoreMemory:
assert stats["freed_blocks"] >= 48 assert stats["freed_blocks"] >= 48
assert stats["blocks_cached"] == 16 assert stats["blocks_cached"] == 16
def test_large_images(self): def test_large_images(self) -> None:
Image.core.reset_stats() Image.core.reset_stats()
Image.core.set_blocks_max(0) Image.core.set_blocks_max(0)
Image.core.set_block_size(4096) Image.core.set_block_size(4096)
@ -166,14 +166,14 @@ class TestCoreMemory:
class TestEnvVars: class TestEnvVars:
def teardown_method(self): def teardown_method(self) -> None:
# Restore default values # Restore default values
Image.core.set_alignment(1) Image.core.set_alignment(1)
Image.core.set_block_size(1024 * 1024) Image.core.set_block_size(1024 * 1024)
Image.core.set_blocks_max(0) Image.core.set_blocks_max(0)
Image.core.clear_cache() Image.core.clear_cache()
def test_units(self): def test_units(self) -> None:
Image._apply_env_variables({"PILLOW_BLOCKS_MAX": "2K"}) Image._apply_env_variables({"PILLOW_BLOCKS_MAX": "2K"})
assert Image.core.get_blocks_max() == 2 * 1024 assert Image.core.get_blocks_max() == 2 * 1024
Image._apply_env_variables({"PILLOW_BLOCK_SIZE": "2m"}) Image._apply_env_variables({"PILLOW_BLOCK_SIZE": "2m"})
@ -187,6 +187,6 @@ class TestEnvVars:
{"PILLOW_BLOCKS_MAX": "wat"}, {"PILLOW_BLOCKS_MAX": "wat"},
), ),
) )
def test_warnings(self, var): def test_warnings(self, var) -> None:
with pytest.warns(UserWarning): with pytest.warns(UserWarning):
Image._apply_env_variables(var) Image._apply_env_variables(var)

View File

@ -12,16 +12,16 @@ ORIGINAL_LIMIT = Image.MAX_IMAGE_PIXELS
class TestDecompressionBomb: class TestDecompressionBomb:
def teardown_method(self, method): def teardown_method(self, method) -> None:
Image.MAX_IMAGE_PIXELS = ORIGINAL_LIMIT Image.MAX_IMAGE_PIXELS = ORIGINAL_LIMIT
def test_no_warning_small_file(self): def test_no_warning_small_file(self) -> None:
# Implicit assert: no warning. # Implicit assert: no warning.
# A warning would cause a failure. # A warning would cause a failure.
with Image.open(TEST_FILE): with Image.open(TEST_FILE):
pass pass
def test_no_warning_no_limit(self): def test_no_warning_no_limit(self) -> None:
# Arrange # Arrange
# Turn limit off # Turn limit off
Image.MAX_IMAGE_PIXELS = None Image.MAX_IMAGE_PIXELS = None
@ -33,7 +33,7 @@ class TestDecompressionBomb:
with Image.open(TEST_FILE): with Image.open(TEST_FILE):
pass pass
def test_warning(self): def test_warning(self) -> None:
# Set limit to trigger warning on the test file # Set limit to trigger warning on the test file
Image.MAX_IMAGE_PIXELS = 128 * 128 - 1 Image.MAX_IMAGE_PIXELS = 128 * 128 - 1
assert Image.MAX_IMAGE_PIXELS == 128 * 128 - 1 assert Image.MAX_IMAGE_PIXELS == 128 * 128 - 1
@ -42,7 +42,7 @@ class TestDecompressionBomb:
with Image.open(TEST_FILE): with Image.open(TEST_FILE):
pass pass
def test_exception(self): def test_exception(self) -> None:
# Set limit to trigger exception on the test file # Set limit to trigger exception on the test file
Image.MAX_IMAGE_PIXELS = 64 * 128 - 1 Image.MAX_IMAGE_PIXELS = 64 * 128 - 1
assert Image.MAX_IMAGE_PIXELS == 64 * 128 - 1 assert Image.MAX_IMAGE_PIXELS == 64 * 128 - 1
@ -51,22 +51,22 @@ class TestDecompressionBomb:
with Image.open(TEST_FILE): with Image.open(TEST_FILE):
pass pass
def test_exception_ico(self): def test_exception_ico(self) -> None:
with pytest.raises(Image.DecompressionBombError): with pytest.raises(Image.DecompressionBombError):
with Image.open("Tests/images/decompression_bomb.ico"): with Image.open("Tests/images/decompression_bomb.ico"):
pass pass
def test_exception_gif(self): def test_exception_gif(self) -> None:
with pytest.raises(Image.DecompressionBombError): with pytest.raises(Image.DecompressionBombError):
with Image.open("Tests/images/decompression_bomb.gif"): with Image.open("Tests/images/decompression_bomb.gif"):
pass pass
def test_exception_gif_extents(self): def test_exception_gif_extents(self) -> None:
with Image.open("Tests/images/decompression_bomb_extents.gif") as im: with Image.open("Tests/images/decompression_bomb_extents.gif") as im:
with pytest.raises(Image.DecompressionBombError): with pytest.raises(Image.DecompressionBombError):
im.seek(1) im.seek(1)
def test_exception_gif_zero_width(self): def test_exception_gif_zero_width(self) -> None:
# Set limit to trigger exception on the test file # Set limit to trigger exception on the test file
Image.MAX_IMAGE_PIXELS = 4 * 64 * 128 Image.MAX_IMAGE_PIXELS = 4 * 64 * 128
assert Image.MAX_IMAGE_PIXELS == 4 * 64 * 128 assert Image.MAX_IMAGE_PIXELS == 4 * 64 * 128
@ -75,7 +75,7 @@ class TestDecompressionBomb:
with Image.open("Tests/images/zero_width.gif"): with Image.open("Tests/images/zero_width.gif"):
pass pass
def test_exception_bmp(self): def test_exception_bmp(self) -> None:
with pytest.raises(Image.DecompressionBombError): with pytest.raises(Image.DecompressionBombError):
with Image.open("Tests/images/bmp/b/reallybig.bmp"): with Image.open("Tests/images/bmp/b/reallybig.bmp"):
pass pass
@ -83,15 +83,15 @@ class TestDecompressionBomb:
class TestDecompressionCrop: class TestDecompressionCrop:
@classmethod @classmethod
def setup_class(cls): def setup_class(cls) -> None:
width, height = 128, 128 width, height = 128, 128
Image.MAX_IMAGE_PIXELS = height * width * 4 - 1 Image.MAX_IMAGE_PIXELS = height * width * 4 - 1
@classmethod @classmethod
def teardown_class(cls): def teardown_class(cls) -> None:
Image.MAX_IMAGE_PIXELS = ORIGINAL_LIMIT Image.MAX_IMAGE_PIXELS = ORIGINAL_LIMIT
def test_enlarge_crop(self): def test_enlarge_crop(self) -> None:
# Crops can extend the extents, therefore we should have the # Crops can extend the extents, therefore we should have the
# same decompression bomb warnings on them. # same decompression bomb warnings on them.
with hopper() as src: with hopper() as src:
@ -99,7 +99,7 @@ class TestDecompressionCrop:
with pytest.warns(Image.DecompressionBombWarning): with pytest.warns(Image.DecompressionBombWarning):
src.crop(box) src.crop(box)
def test_crop_decompression_checks(self): def test_crop_decompression_checks(self) -> None:
im = Image.new("RGB", (100, 100)) im = Image.new("RGB", (100, 100))
for value in ((-9999, -9999, -9990, -9990), (-999, -999, -990, -990)): for value in ((-9999, -9999, -9990, -9990), (-999, -999, -990, -990)):

View File

@ -20,12 +20,12 @@ from PIL import _deprecate
), ),
], ],
) )
def test_version(version, expected): def test_version(version, expected) -> None:
with pytest.warns(DeprecationWarning, match=expected): with pytest.warns(DeprecationWarning, match=expected):
_deprecate.deprecate("Old thing", version, "new thing") _deprecate.deprecate("Old thing", version, "new thing")
def test_unknown_version(): def test_unknown_version() -> None:
expected = r"Unknown removal version: 12345. Update PIL\._deprecate\?" expected = r"Unknown removal version: 12345. Update PIL\._deprecate\?"
with pytest.raises(ValueError, match=expected): with pytest.raises(ValueError, match=expected):
_deprecate.deprecate("Old thing", 12345, "new thing") _deprecate.deprecate("Old thing", 12345, "new thing")
@ -46,13 +46,13 @@ def test_unknown_version():
), ),
], ],
) )
def test_old_version(deprecated, plural, expected): def test_old_version(deprecated, plural, expected) -> None:
expected = r"" expected = r""
with pytest.raises(RuntimeError, match=expected): with pytest.raises(RuntimeError, match=expected):
_deprecate.deprecate(deprecated, 1, plural=plural) _deprecate.deprecate(deprecated, 1, plural=plural)
def test_plural(): def test_plural() -> None:
expected = ( expected = (
r"Old things are deprecated and will be removed in Pillow 11 \(2024-10-15\)\. " r"Old things are deprecated and will be removed in Pillow 11 \(2024-10-15\)\. "
r"Use new thing instead\." r"Use new thing instead\."
@ -61,7 +61,7 @@ def test_plural():
_deprecate.deprecate("Old things", 11, "new thing", plural=True) _deprecate.deprecate("Old things", 11, "new thing", plural=True)
def test_replacement_and_action(): def test_replacement_and_action() -> None:
expected = "Use only one of 'replacement' and 'action'" expected = "Use only one of 'replacement' and 'action'"
with pytest.raises(ValueError, match=expected): with pytest.raises(ValueError, match=expected):
_deprecate.deprecate( _deprecate.deprecate(
@ -76,7 +76,7 @@ def test_replacement_and_action():
"Upgrade to new thing.", "Upgrade to new thing.",
], ],
) )
def test_action(action): def test_action(action) -> None:
expected = ( expected = (
r"Old thing is deprecated and will be removed in Pillow 11 \(2024-10-15\)\. " r"Old thing is deprecated and will be removed in Pillow 11 \(2024-10-15\)\. "
r"Upgrade to new thing\." r"Upgrade to new thing\."
@ -85,7 +85,7 @@ def test_action(action):
_deprecate.deprecate("Old thing", 11, action=action) _deprecate.deprecate("Old thing", 11, action=action)
def test_no_replacement_or_action(): def test_no_replacement_or_action() -> None:
expected = ( expected = (
r"Old thing is deprecated and will be removed in Pillow 11 \(2024-10-15\)" r"Old thing is deprecated and will be removed in Pillow 11 \(2024-10-15\)"
) )

View File

@ -15,7 +15,7 @@ except ImportError:
pass pass
def test_check(): def test_check() -> None:
# Check the correctness of the convenience function # Check the correctness of the convenience function
for module in features.modules: for module in features.modules:
assert features.check_module(module) == features.check(module) assert features.check_module(module) == features.check(module)
@ -25,11 +25,11 @@ def test_check():
assert features.check_feature(feature) == features.check(feature) assert features.check_feature(feature) == features.check(feature)
def test_version(): def test_version() -> None:
# Check the correctness of the convenience function # Check the correctness of the convenience function
# and the format of version numbers # and the format of version numbers
def test(name, function): def test(name, function) -> None:
version = features.version(name) version = features.version(name)
if not features.check(name): if not features.check(name):
assert version is None assert version is None
@ -47,56 +47,56 @@ def test_version():
@skip_unless_feature("webp") @skip_unless_feature("webp")
def test_webp_transparency(): def test_webp_transparency() -> None:
assert features.check("transp_webp") != _webp.WebPDecoderBuggyAlpha() assert features.check("transp_webp") != _webp.WebPDecoderBuggyAlpha()
assert features.check("transp_webp") == _webp.HAVE_TRANSPARENCY assert features.check("transp_webp") == _webp.HAVE_TRANSPARENCY
@skip_unless_feature("webp") @skip_unless_feature("webp")
def test_webp_mux(): def test_webp_mux() -> None:
assert features.check("webp_mux") == _webp.HAVE_WEBPMUX assert features.check("webp_mux") == _webp.HAVE_WEBPMUX
@skip_unless_feature("webp") @skip_unless_feature("webp")
def test_webp_anim(): def test_webp_anim() -> None:
assert features.check("webp_anim") == _webp.HAVE_WEBPANIM assert features.check("webp_anim") == _webp.HAVE_WEBPANIM
@skip_unless_feature("libjpeg_turbo") @skip_unless_feature("libjpeg_turbo")
def test_libjpeg_turbo_version(): def test_libjpeg_turbo_version() -> None:
assert re.search(r"\d+\.\d+\.\d+$", features.version("libjpeg_turbo")) assert re.search(r"\d+\.\d+\.\d+$", features.version("libjpeg_turbo"))
@skip_unless_feature("libimagequant") @skip_unless_feature("libimagequant")
def test_libimagequant_version(): def test_libimagequant_version() -> None:
assert re.search(r"\d+\.\d+\.\d+$", features.version("libimagequant")) assert re.search(r"\d+\.\d+\.\d+$", features.version("libimagequant"))
@pytest.mark.parametrize("feature", features.modules) @pytest.mark.parametrize("feature", features.modules)
def test_check_modules(feature): def test_check_modules(feature) -> None:
assert features.check_module(feature) in [True, False] assert features.check_module(feature) in [True, False]
@pytest.mark.parametrize("feature", features.codecs) @pytest.mark.parametrize("feature", features.codecs)
def test_check_codecs(feature): def test_check_codecs(feature) -> None:
assert features.check_codec(feature) in [True, False] assert features.check_codec(feature) in [True, False]
def test_check_warns_on_nonexistent(): def test_check_warns_on_nonexistent() -> None:
with pytest.warns(UserWarning) as cm: with pytest.warns(UserWarning) as cm:
has_feature = features.check("typo") has_feature = features.check("typo")
assert has_feature is False assert has_feature is False
assert str(cm[-1].message) == "Unknown feature 'typo'." assert str(cm[-1].message) == "Unknown feature 'typo'."
def test_supported_modules(): def test_supported_modules() -> None:
assert isinstance(features.get_supported_modules(), list) assert isinstance(features.get_supported_modules(), list)
assert isinstance(features.get_supported_codecs(), list) assert isinstance(features.get_supported_codecs(), list)
assert isinstance(features.get_supported_features(), list) assert isinstance(features.get_supported_features(), list)
assert isinstance(features.get_supported(), list) assert isinstance(features.get_supported(), list)
def test_unsupported_codec(): def test_unsupported_codec() -> None:
# Arrange # Arrange
codec = "unsupported_codec" codec = "unsupported_codec"
# Act / Assert # Act / Assert
@ -106,7 +106,7 @@ def test_unsupported_codec():
features.version_codec(codec) features.version_codec(codec)
def test_unsupported_module(): def test_unsupported_module() -> None:
# Arrange # Arrange
module = "unsupported_module" module = "unsupported_module"
# Act / Assert # Act / Assert
@ -116,7 +116,7 @@ def test_unsupported_module():
features.version_module(module) features.version_module(module)
def test_pilinfo(): def test_pilinfo() -> None:
buf = io.StringIO() buf = io.StringIO()
features.pilinfo(buf) features.pilinfo(buf)
out = buf.getvalue() out = buf.getvalue()

View File

@ -1,5 +1,7 @@
from __future__ import annotations from __future__ import annotations
from pathlib import Path
import pytest import pytest
from PIL import Image, ImageSequence, PngImagePlugin from PIL import Image, ImageSequence, PngImagePlugin
@ -8,7 +10,7 @@ from PIL import Image, ImageSequence, PngImagePlugin
# APNG browser support tests and fixtures via: # APNG browser support tests and fixtures via:
# https://philip.html5.org/tests/apng/tests.html # https://philip.html5.org/tests/apng/tests.html
# (referenced from https://wiki.mozilla.org/APNG_Specification) # (referenced from https://wiki.mozilla.org/APNG_Specification)
def test_apng_basic(): def test_apng_basic() -> None:
with Image.open("Tests/images/apng/single_frame.png") as im: with Image.open("Tests/images/apng/single_frame.png") as im:
assert not im.is_animated assert not im.is_animated
assert im.n_frames == 1 assert im.n_frames == 1
@ -45,14 +47,14 @@ def test_apng_basic():
"filename", "filename",
("Tests/images/apng/split_fdat.png", "Tests/images/apng/split_fdat_zero_chunk.png"), ("Tests/images/apng/split_fdat.png", "Tests/images/apng/split_fdat_zero_chunk.png"),
) )
def test_apng_fdat(filename): def test_apng_fdat(filename) -> None:
with Image.open(filename) as im: with Image.open(filename) as im:
im.seek(im.n_frames - 1) im.seek(im.n_frames - 1)
assert im.getpixel((0, 0)) == (0, 255, 0, 255) assert im.getpixel((0, 0)) == (0, 255, 0, 255)
assert im.getpixel((64, 32)) == (0, 255, 0, 255) assert im.getpixel((64, 32)) == (0, 255, 0, 255)
def test_apng_dispose(): def test_apng_dispose() -> None:
with Image.open("Tests/images/apng/dispose_op_none.png") as im: with Image.open("Tests/images/apng/dispose_op_none.png") as im:
im.seek(im.n_frames - 1) im.seek(im.n_frames - 1)
assert im.getpixel((0, 0)) == (0, 255, 0, 255) assert im.getpixel((0, 0)) == (0, 255, 0, 255)
@ -84,7 +86,7 @@ def test_apng_dispose():
assert im.getpixel((64, 32)) == (0, 0, 0, 0) assert im.getpixel((64, 32)) == (0, 0, 0, 0)
def test_apng_dispose_region(): def test_apng_dispose_region() -> None:
with Image.open("Tests/images/apng/dispose_op_none_region.png") as im: with Image.open("Tests/images/apng/dispose_op_none_region.png") as im:
im.seek(im.n_frames - 1) im.seek(im.n_frames - 1)
assert im.getpixel((0, 0)) == (0, 255, 0, 255) assert im.getpixel((0, 0)) == (0, 255, 0, 255)
@ -106,7 +108,7 @@ def test_apng_dispose_region():
assert im.getpixel((64, 32)) == (0, 255, 0, 255) assert im.getpixel((64, 32)) == (0, 255, 0, 255)
def test_apng_dispose_op_previous_frame(): def test_apng_dispose_op_previous_frame() -> None:
# Test that the dispose settings being used are from the previous frame # Test that the dispose settings being used are from the previous frame
# #
# Image created with: # Image created with:
@ -131,14 +133,14 @@ def test_apng_dispose_op_previous_frame():
assert im.getpixel((0, 0)) == (255, 0, 0, 255) assert im.getpixel((0, 0)) == (255, 0, 0, 255)
def test_apng_dispose_op_background_p_mode(): def test_apng_dispose_op_background_p_mode() -> None:
with Image.open("Tests/images/apng/dispose_op_background_p_mode.png") as im: with Image.open("Tests/images/apng/dispose_op_background_p_mode.png") as im:
im.seek(1) im.seek(1)
im.load() im.load()
assert im.size == (128, 64) assert im.size == (128, 64)
def test_apng_blend(): def test_apng_blend() -> None:
with Image.open("Tests/images/apng/blend_op_source_solid.png") as im: with Image.open("Tests/images/apng/blend_op_source_solid.png") as im:
im.seek(im.n_frames - 1) im.seek(im.n_frames - 1)
assert im.getpixel((0, 0)) == (0, 255, 0, 255) assert im.getpixel((0, 0)) == (0, 255, 0, 255)
@ -165,20 +167,20 @@ def test_apng_blend():
assert im.getpixel((64, 32)) == (0, 255, 0, 255) assert im.getpixel((64, 32)) == (0, 255, 0, 255)
def test_apng_blend_transparency(): def test_apng_blend_transparency() -> None:
with Image.open("Tests/images/blend_transparency.png") as im: with Image.open("Tests/images/blend_transparency.png") as im:
im.seek(1) im.seek(1)
assert im.getpixel((0, 0)) == (255, 0, 0) assert im.getpixel((0, 0)) == (255, 0, 0)
def test_apng_chunk_order(): def test_apng_chunk_order() -> None:
with Image.open("Tests/images/apng/fctl_actl.png") as im: with Image.open("Tests/images/apng/fctl_actl.png") as im:
im.seek(im.n_frames - 1) im.seek(im.n_frames - 1)
assert im.getpixel((0, 0)) == (0, 255, 0, 255) assert im.getpixel((0, 0)) == (0, 255, 0, 255)
assert im.getpixel((64, 32)) == (0, 255, 0, 255) assert im.getpixel((64, 32)) == (0, 255, 0, 255)
def test_apng_delay(): def test_apng_delay() -> None:
with Image.open("Tests/images/apng/delay.png") as im: with Image.open("Tests/images/apng/delay.png") as im:
im.seek(1) im.seek(1)
assert im.info.get("duration") == 500.0 assert im.info.get("duration") == 500.0
@ -218,7 +220,7 @@ def test_apng_delay():
assert im.info.get("duration") == 1000.0 assert im.info.get("duration") == 1000.0
def test_apng_num_plays(): def test_apng_num_plays() -> None:
with Image.open("Tests/images/apng/num_plays.png") as im: with Image.open("Tests/images/apng/num_plays.png") as im:
assert im.info.get("loop") == 0 assert im.info.get("loop") == 0
@ -226,7 +228,7 @@ def test_apng_num_plays():
assert im.info.get("loop") == 1 assert im.info.get("loop") == 1
def test_apng_mode(): def test_apng_mode() -> None:
with Image.open("Tests/images/apng/mode_16bit.png") as im: with Image.open("Tests/images/apng/mode_16bit.png") as im:
assert im.mode == "RGBA" assert im.mode == "RGBA"
im.seek(im.n_frames - 1) im.seek(im.n_frames - 1)
@ -267,7 +269,7 @@ def test_apng_mode():
assert im.getpixel((64, 32)) == (0, 0, 255, 128) assert im.getpixel((64, 32)) == (0, 0, 255, 128)
def test_apng_chunk_errors(): def test_apng_chunk_errors() -> None:
with Image.open("Tests/images/apng/chunk_no_actl.png") as im: with Image.open("Tests/images/apng/chunk_no_actl.png") as im:
assert not im.is_animated assert not im.is_animated
@ -292,7 +294,7 @@ def test_apng_chunk_errors():
im.seek(im.n_frames - 1) im.seek(im.n_frames - 1)
def test_apng_syntax_errors(): def test_apng_syntax_errors() -> None:
with pytest.warns(UserWarning): with pytest.warns(UserWarning):
with Image.open("Tests/images/apng/syntax_num_frames_zero.png") as im: with Image.open("Tests/images/apng/syntax_num_frames_zero.png") as im:
assert not im.is_animated assert not im.is_animated
@ -336,14 +338,14 @@ def test_apng_syntax_errors():
"sequence_fdat_fctl.png", "sequence_fdat_fctl.png",
), ),
) )
def test_apng_sequence_errors(test_file): def test_apng_sequence_errors(test_file) -> None:
with pytest.raises(SyntaxError): with pytest.raises(SyntaxError):
with Image.open(f"Tests/images/apng/{test_file}") as im: with Image.open(f"Tests/images/apng/{test_file}") as im:
im.seek(im.n_frames - 1) im.seek(im.n_frames - 1)
im.load() im.load()
def test_apng_save(tmp_path): def test_apng_save(tmp_path: Path) -> None:
with Image.open("Tests/images/apng/single_frame.png") as im: with Image.open("Tests/images/apng/single_frame.png") as im:
test_file = str(tmp_path / "temp.png") test_file = str(tmp_path / "temp.png")
im.save(test_file, save_all=True) im.save(test_file, save_all=True)
@ -374,7 +376,7 @@ def test_apng_save(tmp_path):
assert im.getpixel((64, 32)) == (0, 255, 0, 255) assert im.getpixel((64, 32)) == (0, 255, 0, 255)
def test_apng_save_alpha(tmp_path): def test_apng_save_alpha(tmp_path: Path) -> None:
test_file = str(tmp_path / "temp.png") test_file = str(tmp_path / "temp.png")
im = Image.new("RGBA", (1, 1), (255, 0, 0, 255)) im = Image.new("RGBA", (1, 1), (255, 0, 0, 255))
@ -388,7 +390,7 @@ def test_apng_save_alpha(tmp_path):
assert reloaded.getpixel((0, 0)) == (255, 0, 0, 127) assert reloaded.getpixel((0, 0)) == (255, 0, 0, 127)
def test_apng_save_split_fdat(tmp_path): def test_apng_save_split_fdat(tmp_path: Path) -> None:
# test to make sure we do not generate sequence errors when writing # test to make sure we do not generate sequence errors when writing
# frames with image data spanning multiple fdAT chunks (in this case # frames with image data spanning multiple fdAT chunks (in this case
# both the default image and first animation frame will span multiple # both the default image and first animation frame will span multiple
@ -412,7 +414,7 @@ def test_apng_save_split_fdat(tmp_path):
assert exception is None assert exception is None
def test_apng_save_duration_loop(tmp_path): def test_apng_save_duration_loop(tmp_path: Path) -> None:
test_file = str(tmp_path / "temp.png") test_file = str(tmp_path / "temp.png")
with Image.open("Tests/images/apng/delay.png") as im: with Image.open("Tests/images/apng/delay.png") as im:
frames = [] frames = []
@ -475,7 +477,7 @@ def test_apng_save_duration_loop(tmp_path):
assert im.info["duration"] == 600 assert im.info["duration"] == 600
def test_apng_save_disposal(tmp_path): def test_apng_save_disposal(tmp_path: Path) -> None:
test_file = str(tmp_path / "temp.png") test_file = str(tmp_path / "temp.png")
size = (128, 64) size = (128, 64)
red = Image.new("RGBA", size, (255, 0, 0, 255)) red = Image.new("RGBA", size, (255, 0, 0, 255))
@ -576,7 +578,7 @@ def test_apng_save_disposal(tmp_path):
assert im.getpixel((64, 32)) == (0, 0, 0, 0) assert im.getpixel((64, 32)) == (0, 0, 0, 0)
def test_apng_save_disposal_previous(tmp_path): def test_apng_save_disposal_previous(tmp_path: Path) -> None:
test_file = str(tmp_path / "temp.png") test_file = str(tmp_path / "temp.png")
size = (128, 64) size = (128, 64)
blue = Image.new("RGBA", size, (0, 0, 255, 255)) blue = Image.new("RGBA", size, (0, 0, 255, 255))
@ -598,7 +600,7 @@ def test_apng_save_disposal_previous(tmp_path):
assert im.getpixel((64, 32)) == (0, 255, 0, 255) assert im.getpixel((64, 32)) == (0, 255, 0, 255)
def test_apng_save_blend(tmp_path): def test_apng_save_blend(tmp_path: Path) -> None:
test_file = str(tmp_path / "temp.png") test_file = str(tmp_path / "temp.png")
size = (128, 64) size = (128, 64)
red = Image.new("RGBA", size, (255, 0, 0, 255)) red = Image.new("RGBA", size, (255, 0, 0, 255))
@ -666,7 +668,7 @@ def test_apng_save_blend(tmp_path):
assert im.getpixel((0, 0)) == (0, 255, 0, 255) assert im.getpixel((0, 0)) == (0, 255, 0, 255)
def test_seek_after_close(): def test_seek_after_close() -> None:
im = Image.open("Tests/images/apng/delay.png") im = Image.open("Tests/images/apng/delay.png")
im.seek(1) im.seek(1)
im.close() im.close()
@ -678,7 +680,9 @@ def test_seek_after_close():
@pytest.mark.parametrize("mode", ("RGBA", "RGB", "P")) @pytest.mark.parametrize("mode", ("RGBA", "RGB", "P"))
@pytest.mark.parametrize("default_image", (True, False)) @pytest.mark.parametrize("default_image", (True, False))
@pytest.mark.parametrize("duplicate", (True, False)) @pytest.mark.parametrize("duplicate", (True, False))
def test_different_modes_in_later_frames(mode, default_image, duplicate, tmp_path): def test_different_modes_in_later_frames(
mode, default_image, duplicate, tmp_path: Path
) -> None:
test_file = str(tmp_path / "temp.png") test_file = str(tmp_path / "temp.png")
im = Image.new("L", (1, 1)) im = Image.new("L", (1, 1))

View File

@ -1,5 +1,7 @@
from __future__ import annotations from __future__ import annotations
from pathlib import Path
import pytest import pytest
from PIL import Image from PIL import Image
@ -12,7 +14,7 @@ from .helper import (
) )
def test_load_blp1(): def test_load_blp1() -> None:
with Image.open("Tests/images/blp/blp1_jpeg.blp") as im: with Image.open("Tests/images/blp/blp1_jpeg.blp") as im:
assert_image_equal_tofile(im, "Tests/images/blp/blp1_jpeg.png") assert_image_equal_tofile(im, "Tests/images/blp/blp1_jpeg.png")
@ -20,22 +22,22 @@ def test_load_blp1():
im.load() im.load()
def test_load_blp2_raw(): def test_load_blp2_raw() -> None:
with Image.open("Tests/images/blp/blp2_raw.blp") as im: with Image.open("Tests/images/blp/blp2_raw.blp") as im:
assert_image_equal_tofile(im, "Tests/images/blp/blp2_raw.png") assert_image_equal_tofile(im, "Tests/images/blp/blp2_raw.png")
def test_load_blp2_dxt1(): def test_load_blp2_dxt1() -> None:
with Image.open("Tests/images/blp/blp2_dxt1.blp") as im: with Image.open("Tests/images/blp/blp2_dxt1.blp") as im:
assert_image_equal_tofile(im, "Tests/images/blp/blp2_dxt1.png") assert_image_equal_tofile(im, "Tests/images/blp/blp2_dxt1.png")
def test_load_blp2_dxt1a(): def test_load_blp2_dxt1a() -> None:
with Image.open("Tests/images/blp/blp2_dxt1a.blp") as im: with Image.open("Tests/images/blp/blp2_dxt1a.blp") as im:
assert_image_equal_tofile(im, "Tests/images/blp/blp2_dxt1a.png") assert_image_equal_tofile(im, "Tests/images/blp/blp2_dxt1a.png")
def test_save(tmp_path): def test_save(tmp_path: Path) -> None:
f = str(tmp_path / "temp.blp") f = str(tmp_path / "temp.blp")
for version in ("BLP1", "BLP2"): for version in ("BLP1", "BLP2"):
@ -69,7 +71,7 @@ def test_save(tmp_path):
"Tests/images/timeout-ef9112a065e7183fa7faa2e18929b03e44ee16bf.blp", "Tests/images/timeout-ef9112a065e7183fa7faa2e18929b03e44ee16bf.blp",
], ],
) )
def test_crashes(test_file): def test_crashes(test_file) -> None:
with open(test_file, "rb") as f: with open(test_file, "rb") as f:
with Image.open(f) as im: with Image.open(f) as im:
with pytest.raises(OSError): with pytest.raises(OSError):

View File

@ -1,6 +1,7 @@
from __future__ import annotations from __future__ import annotations
import io import io
from pathlib import Path
import pytest import pytest
@ -14,8 +15,8 @@ from .helper import (
) )
def test_sanity(tmp_path): def test_sanity(tmp_path: Path) -> None:
def roundtrip(im): def roundtrip(im) -> None:
outfile = str(tmp_path / "temp.bmp") outfile = str(tmp_path / "temp.bmp")
im.save(outfile, "BMP") im.save(outfile, "BMP")
@ -35,20 +36,20 @@ def test_sanity(tmp_path):
roundtrip(hopper("RGB")) roundtrip(hopper("RGB"))
def test_invalid_file(): def test_invalid_file() -> None:
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):
BmpImagePlugin.BmpImageFile(fp) BmpImagePlugin.BmpImageFile(fp)
def test_fallback_if_mmap_errors(): def test_fallback_if_mmap_errors() -> None:
# This image has been truncated, # This image has been truncated,
# so that the buffer is not large enough when using mmap # so that the buffer is not large enough when using mmap
with Image.open("Tests/images/mmap_error.bmp") as im: with Image.open("Tests/images/mmap_error.bmp") as im:
assert_image_equal_tofile(im, "Tests/images/pal8_offset.bmp") assert_image_equal_tofile(im, "Tests/images/pal8_offset.bmp")
def test_save_to_bytes(): def test_save_to_bytes() -> None:
output = io.BytesIO() output = io.BytesIO()
im = hopper() im = hopper()
im.save(output, "BMP") im.save(output, "BMP")
@ -60,7 +61,7 @@ def test_save_to_bytes():
assert reloaded.format == "BMP" assert reloaded.format == "BMP"
def test_small_palette(tmp_path): def test_small_palette(tmp_path: Path) -> None:
im = Image.new("P", (1, 1)) im = Image.new("P", (1, 1))
colors = [0, 0, 0, 125, 125, 125, 255, 255, 255] colors = [0, 0, 0, 125, 125, 125, 255, 255, 255]
im.putpalette(colors) im.putpalette(colors)
@ -72,7 +73,7 @@ def test_small_palette(tmp_path):
assert reloaded.getpalette() == colors assert reloaded.getpalette() == colors
def test_save_too_large(tmp_path): def test_save_too_large(tmp_path: Path) -> None:
outfile = str(tmp_path / "temp.bmp") outfile = str(tmp_path / "temp.bmp")
with Image.new("RGB", (1, 1)) as im: with Image.new("RGB", (1, 1)) as im:
im._size = (37838, 37838) im._size = (37838, 37838)
@ -80,7 +81,7 @@ def test_save_too_large(tmp_path):
im.save(outfile) im.save(outfile)
def test_dpi(): def test_dpi() -> None:
dpi = (72, 72) dpi = (72, 72)
output = io.BytesIO() output = io.BytesIO()
@ -92,7 +93,7 @@ def test_dpi():
assert reloaded.info["dpi"] == (72.008961115161, 72.008961115161) assert reloaded.info["dpi"] == (72.008961115161, 72.008961115161)
def test_save_bmp_with_dpi(tmp_path): def test_save_bmp_with_dpi(tmp_path: Path) -> None:
# Test for #1301 # Test for #1301
# Arrange # Arrange
outfile = str(tmp_path / "temp.jpg") outfile = str(tmp_path / "temp.jpg")
@ -110,7 +111,7 @@ def test_save_bmp_with_dpi(tmp_path):
assert reloaded.format == "JPEG" assert reloaded.format == "JPEG"
def test_save_float_dpi(tmp_path): def test_save_float_dpi(tmp_path: Path) -> None:
outfile = str(tmp_path / "temp.bmp") outfile = str(tmp_path / "temp.bmp")
with Image.open("Tests/images/hopper.bmp") as im: with Image.open("Tests/images/hopper.bmp") as im:
im.save(outfile, dpi=(72.21216100543306, 72.21216100543306)) im.save(outfile, dpi=(72.21216100543306, 72.21216100543306))
@ -118,7 +119,7 @@ def test_save_float_dpi(tmp_path):
assert reloaded.info["dpi"] == (72.21216100543306, 72.21216100543306) assert reloaded.info["dpi"] == (72.21216100543306, 72.21216100543306)
def test_load_dib(): def test_load_dib() -> None:
# test for #1293, Imagegrab returning Unsupported Bitfields Format # test for #1293, Imagegrab returning Unsupported Bitfields Format
with Image.open("Tests/images/clipboard.dib") as im: with Image.open("Tests/images/clipboard.dib") as im:
assert im.format == "DIB" assert im.format == "DIB"
@ -127,7 +128,7 @@ def test_load_dib():
assert_image_equal_tofile(im, "Tests/images/clipboard_target.png") assert_image_equal_tofile(im, "Tests/images/clipboard_target.png")
def test_save_dib(tmp_path): def test_save_dib(tmp_path: Path) -> None:
outfile = str(tmp_path / "temp.dib") outfile = str(tmp_path / "temp.dib")
with Image.open("Tests/images/clipboard.dib") as im: with Image.open("Tests/images/clipboard.dib") as im:
@ -139,7 +140,7 @@ def test_save_dib(tmp_path):
assert_image_equal(im, reloaded) assert_image_equal(im, reloaded)
def test_rgba_bitfields(): def test_rgba_bitfields() -> None:
# This test image has been manually hexedited # This test image has been manually hexedited
# to change the bitfield compression in the header from XBGR to RGBA # to change the bitfield compression in the header from XBGR to RGBA
with Image.open("Tests/images/rgb32bf-rgba.bmp") as im: with Image.open("Tests/images/rgb32bf-rgba.bmp") as im:
@ -157,7 +158,7 @@ def test_rgba_bitfields():
) )
def test_rle8(): def test_rle8() -> None:
with Image.open("Tests/images/hopper_rle8.bmp") as im: with Image.open("Tests/images/hopper_rle8.bmp") as im:
assert_image_similar_tofile(im.convert("RGB"), "Tests/images/hopper.bmp", 12) assert_image_similar_tofile(im.convert("RGB"), "Tests/images/hopper.bmp", 12)
@ -177,7 +178,7 @@ def test_rle8():
im.load() im.load()
def test_rle4(): def test_rle4() -> None:
with Image.open("Tests/images/bmp/g/pal4rle.bmp") as im: with Image.open("Tests/images/bmp/g/pal4rle.bmp") as im:
assert_image_similar_tofile(im, "Tests/images/bmp/g/pal4.bmp", 12) assert_image_similar_tofile(im, "Tests/images/bmp/g/pal4.bmp", 12)
@ -193,7 +194,7 @@ def test_rle4():
("Tests/images/bmp/g/pal8rle.bmp", 1064), ("Tests/images/bmp/g/pal8rle.bmp", 1064),
), ),
) )
def test_rle8_eof(file_name, length): def test_rle8_eof(file_name, length) -> None:
with open(file_name, "rb") as fp: with open(file_name, "rb") as fp:
data = fp.read(length) data = fp.read(length)
with Image.open(io.BytesIO(data)) as im: with Image.open(io.BytesIO(data)) as im:
@ -201,7 +202,7 @@ def test_rle8_eof(file_name, length):
im.load() im.load()
def test_offset(): def test_offset() -> None:
# This image has been hexedited # This image has been hexedited
# to exclude the palette size from the pixel data offset # to exclude the palette size from the pixel data offset
with Image.open("Tests/images/pal8_offset.bmp") as im: with Image.open("Tests/images/pal8_offset.bmp") as im:

View File

@ -1,5 +1,7 @@
from __future__ import annotations from __future__ import annotations
from pathlib import Path
import pytest import pytest
from PIL import BufrStubImagePlugin, Image from PIL import BufrStubImagePlugin, Image
@ -9,7 +11,7 @@ from .helper import hopper
TEST_FILE = "Tests/images/gfs.t06z.rassda.tm00.bufr_d" TEST_FILE = "Tests/images/gfs.t06z.rassda.tm00.bufr_d"
def test_open(): def test_open() -> None:
# Act # Act
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
# Assert # Assert
@ -20,7 +22,7 @@ def test_open():
assert im.size == (1, 1) assert im.size == (1, 1)
def test_invalid_file(): def test_invalid_file() -> None:
# Arrange # Arrange
invalid_file = "Tests/images/flower.jpg" invalid_file = "Tests/images/flower.jpg"
@ -29,7 +31,7 @@ def test_invalid_file():
BufrStubImagePlugin.BufrStubImageFile(invalid_file) BufrStubImagePlugin.BufrStubImageFile(invalid_file)
def test_load(): def test_load() -> None:
# Arrange # Arrange
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
# Act / Assert: stub cannot load without an implemented handler # Act / Assert: stub cannot load without an implemented handler
@ -37,7 +39,7 @@ def test_load():
im.load() im.load()
def test_save(tmp_path): def test_save(tmp_path: Path) -> None:
# Arrange # Arrange
im = hopper() im = hopper()
tmpfile = str(tmp_path / "temp.bufr") tmpfile = str(tmp_path / "temp.bufr")
@ -47,13 +49,13 @@ def test_save(tmp_path):
im.save(tmpfile) im.save(tmpfile)
def test_handler(tmp_path): def test_handler(tmp_path: Path) -> None:
class TestHandler: class TestHandler:
opened = False opened = False
loaded = False loaded = False
saved = False saved = False
def open(self, im): def open(self, im) -> None:
self.opened = True self.opened = True
def load(self, im): def load(self, im):
@ -61,7 +63,7 @@ def test_handler(tmp_path):
im.fp.close() im.fp.close()
return Image.new("RGB", (1, 1)) return Image.new("RGB", (1, 1))
def save(self, im, fp, filename): def save(self, im, fp, filename) -> None:
self.saved = True self.saved = True
handler = TestHandler() handler = TestHandler()

View File

@ -9,19 +9,19 @@ from .helper import hopper
TEST_FILE = "Tests/images/dummy.container" TEST_FILE = "Tests/images/dummy.container"
def test_sanity(): def test_sanity() -> None:
dir(Image) dir(Image)
dir(ContainerIO) dir(ContainerIO)
def test_isatty(): def test_isatty() -> None:
with hopper() as im: with hopper() as im:
container = ContainerIO.ContainerIO(im, 0, 0) container = ContainerIO.ContainerIO(im, 0, 0)
assert container.isatty() is False assert container.isatty() is False
def test_seek_mode_0(): def test_seek_mode_0() -> None:
# Arrange # Arrange
mode = 0 mode = 0
with open(TEST_FILE, "rb") as fh: with open(TEST_FILE, "rb") as fh:
@ -35,7 +35,7 @@ def test_seek_mode_0():
assert container.tell() == 33 assert container.tell() == 33
def test_seek_mode_1(): def test_seek_mode_1() -> None:
# Arrange # Arrange
mode = 1 mode = 1
with open(TEST_FILE, "rb") as fh: with open(TEST_FILE, "rb") as fh:
@ -49,7 +49,7 @@ def test_seek_mode_1():
assert container.tell() == 66 assert container.tell() == 66
def test_seek_mode_2(): def test_seek_mode_2() -> None:
# Arrange # Arrange
mode = 2 mode = 2
with open(TEST_FILE, "rb") as fh: with open(TEST_FILE, "rb") as fh:
@ -64,7 +64,7 @@ def test_seek_mode_2():
@pytest.mark.parametrize("bytesmode", (True, False)) @pytest.mark.parametrize("bytesmode", (True, False))
def test_read_n0(bytesmode): def test_read_n0(bytesmode) -> None:
# Arrange # Arrange
with open(TEST_FILE, "rb" if bytesmode else "r") as fh: with open(TEST_FILE, "rb" if bytesmode else "r") as fh:
container = ContainerIO.ContainerIO(fh, 22, 100) container = ContainerIO.ContainerIO(fh, 22, 100)
@ -80,7 +80,7 @@ def test_read_n0(bytesmode):
@pytest.mark.parametrize("bytesmode", (True, False)) @pytest.mark.parametrize("bytesmode", (True, False))
def test_read_n(bytesmode): def test_read_n(bytesmode) -> None:
# Arrange # Arrange
with open(TEST_FILE, "rb" if bytesmode else "r") as fh: with open(TEST_FILE, "rb" if bytesmode else "r") as fh:
container = ContainerIO.ContainerIO(fh, 22, 100) container = ContainerIO.ContainerIO(fh, 22, 100)
@ -96,7 +96,7 @@ def test_read_n(bytesmode):
@pytest.mark.parametrize("bytesmode", (True, False)) @pytest.mark.parametrize("bytesmode", (True, False))
def test_read_eof(bytesmode): def test_read_eof(bytesmode) -> None:
# Arrange # Arrange
with open(TEST_FILE, "rb" if bytesmode else "r") as fh: with open(TEST_FILE, "rb" if bytesmode else "r") as fh:
container = ContainerIO.ContainerIO(fh, 22, 100) container = ContainerIO.ContainerIO(fh, 22, 100)
@ -112,7 +112,7 @@ def test_read_eof(bytesmode):
@pytest.mark.parametrize("bytesmode", (True, False)) @pytest.mark.parametrize("bytesmode", (True, False))
def test_readline(bytesmode): def test_readline(bytesmode) -> None:
# Arrange # Arrange
with open(TEST_FILE, "rb" if bytesmode else "r") as fh: with open(TEST_FILE, "rb" if bytesmode else "r") as fh:
container = ContainerIO.ContainerIO(fh, 0, 120) container = ContainerIO.ContainerIO(fh, 0, 120)
@ -127,7 +127,7 @@ def test_readline(bytesmode):
@pytest.mark.parametrize("bytesmode", (True, False)) @pytest.mark.parametrize("bytesmode", (True, False))
def test_readlines(bytesmode): def test_readlines(bytesmode) -> None:
# Arrange # Arrange
expected = [ expected = [
"This is line 1\n", "This is line 1\n",

View File

@ -12,7 +12,7 @@ from .helper import assert_image_equal, hopper, is_pypy
TEST_FILE = "Tests/images/hopper.dcx" TEST_FILE = "Tests/images/hopper.dcx"
def test_sanity(): def test_sanity() -> None:
# Arrange # Arrange
# Act # Act
@ -25,8 +25,8 @@ def test_sanity():
@pytest.mark.skipif(is_pypy(), reason="Requires CPython") @pytest.mark.skipif(is_pypy(), reason="Requires CPython")
def test_unclosed_file(): def test_unclosed_file() -> None:
def open(): def open() -> None:
im = Image.open(TEST_FILE) im = Image.open(TEST_FILE)
im.load() im.load()
@ -34,26 +34,26 @@ def test_unclosed_file():
open() open()
def test_closed_file(): def test_closed_file() -> None:
with warnings.catch_warnings(): with warnings.catch_warnings():
im = Image.open(TEST_FILE) im = Image.open(TEST_FILE)
im.load() im.load()
im.close() im.close()
def test_context_manager(): def test_context_manager() -> None:
with warnings.catch_warnings(): with warnings.catch_warnings():
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
im.load() im.load()
def test_invalid_file(): def test_invalid_file() -> None:
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):
DcxImagePlugin.DcxImageFile(fp) DcxImagePlugin.DcxImageFile(fp)
def test_tell(): def test_tell() -> None:
# Arrange # Arrange
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
# Act # Act
@ -63,13 +63,13 @@ def test_tell():
assert frame == 0 assert frame == 0
def test_n_frames(): def test_n_frames() -> None:
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_eoferror(): def test_eoferror() -> None:
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
n_frames = im.n_frames n_frames = im.n_frames
@ -82,7 +82,7 @@ def test_eoferror():
im.seek(n_frames - 1) im.seek(n_frames - 1)
def test_seek_too_far(): def test_seek_too_far() -> None:
# Arrange # Arrange
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
frame = 999 # too big on purpose frame = 999 # too big on purpose

View File

@ -2,6 +2,7 @@
from __future__ import annotations from __future__ import annotations
from io import BytesIO from io import BytesIO
from pathlib import Path
import pytest import pytest
@ -46,7 +47,7 @@ TEST_FILE_UNCOMPRESSED_RGB_WITH_ALPHA = "Tests/images/uncompressed_rgb.dds"
TEST_FILE_DX10_BC1_TYPELESS, TEST_FILE_DX10_BC1_TYPELESS,
), ),
) )
def test_sanity_dxt1_bc1(image_path): def test_sanity_dxt1_bc1(image_path) -> None:
"""Check DXT1 and BC1 images can be opened""" """Check DXT1 and BC1 images can be opened"""
with Image.open(TEST_FILE_DXT1.replace(".dds", ".png")) as target: with Image.open(TEST_FILE_DXT1.replace(".dds", ".png")) as target:
target = target.convert("RGBA") target = target.convert("RGBA")
@ -60,7 +61,7 @@ def test_sanity_dxt1_bc1(image_path):
assert_image_equal(im, target) assert_image_equal(im, target)
def test_sanity_dxt3(): def test_sanity_dxt3() -> None:
"""Check DXT3 images can be opened""" """Check DXT3 images can be opened"""
with Image.open(TEST_FILE_DXT3) as im: with Image.open(TEST_FILE_DXT3) as im:
@ -73,7 +74,7 @@ def test_sanity_dxt3():
assert_image_equal_tofile(im, TEST_FILE_DXT3.replace(".dds", ".png")) assert_image_equal_tofile(im, TEST_FILE_DXT3.replace(".dds", ".png"))
def test_sanity_dxt5(): def test_sanity_dxt5() -> None:
"""Check DXT5 images can be opened""" """Check DXT5 images can be opened"""
with Image.open(TEST_FILE_DXT5) as im: with Image.open(TEST_FILE_DXT5) as im:
@ -94,7 +95,7 @@ def test_sanity_dxt5():
TEST_FILE_BC4U, TEST_FILE_BC4U,
), ),
) )
def test_sanity_ati1_bc4u(image_path): def test_sanity_ati1_bc4u(image_path) -> None:
"""Check ATI1 and BC4U images can be opened""" """Check ATI1 and BC4U images can be opened"""
with Image.open(image_path) as im: with Image.open(image_path) as im:
@ -115,7 +116,7 @@ def test_sanity_ati1_bc4u(image_path):
TEST_FILE_DX10_BC4_TYPELESS, TEST_FILE_DX10_BC4_TYPELESS,
), ),
) )
def test_dx10_bc4(image_path): def test_dx10_bc4(image_path) -> None:
"""Check DX10 BC4 images can be opened""" """Check DX10 BC4 images can be opened"""
with Image.open(image_path) as im: with Image.open(image_path) as im:
@ -136,7 +137,7 @@ def test_dx10_bc4(image_path):
TEST_FILE_BC5U, TEST_FILE_BC5U,
), ),
) )
def test_sanity_ati2_bc5u(image_path): def test_sanity_ati2_bc5u(image_path) -> None:
"""Check ATI2 and BC5U images can be opened""" """Check ATI2 and BC5U images can be opened"""
with Image.open(image_path) as im: with Image.open(image_path) as im:
@ -160,7 +161,7 @@ def test_sanity_ati2_bc5u(image_path):
(TEST_FILE_BC5S, TEST_FILE_BC5S), (TEST_FILE_BC5S, TEST_FILE_BC5S),
), ),
) )
def test_dx10_bc5(image_path, expected_path): def test_dx10_bc5(image_path, expected_path) -> None:
"""Check DX10 BC5 images can be opened""" """Check DX10 BC5 images can be opened"""
with Image.open(image_path) as im: with Image.open(image_path) as im:
@ -174,7 +175,7 @@ def test_dx10_bc5(image_path, expected_path):
@pytest.mark.parametrize("image_path", (TEST_FILE_BC6H, TEST_FILE_BC6HS)) @pytest.mark.parametrize("image_path", (TEST_FILE_BC6H, TEST_FILE_BC6HS))
def test_dx10_bc6h(image_path): def test_dx10_bc6h(image_path) -> None:
"""Check DX10 BC6H/BC6HS images can be opened""" """Check DX10 BC6H/BC6HS images can be opened"""
with Image.open(image_path) as im: with Image.open(image_path) as im:
@ -187,7 +188,7 @@ def test_dx10_bc6h(image_path):
assert_image_equal_tofile(im, image_path.replace(".dds", ".png")) assert_image_equal_tofile(im, image_path.replace(".dds", ".png"))
def test_dx10_bc7(): def test_dx10_bc7() -> None:
"""Check DX10 images can be opened""" """Check DX10 images can be opened"""
with Image.open(TEST_FILE_DX10_BC7) as im: with Image.open(TEST_FILE_DX10_BC7) as im:
@ -200,7 +201,7 @@ def test_dx10_bc7():
assert_image_equal_tofile(im, TEST_FILE_DX10_BC7.replace(".dds", ".png")) assert_image_equal_tofile(im, TEST_FILE_DX10_BC7.replace(".dds", ".png"))
def test_dx10_bc7_unorm_srgb(): def test_dx10_bc7_unorm_srgb() -> None:
"""Check DX10 unsigned normalized integer images can be opened""" """Check DX10 unsigned normalized integer images can be opened"""
with Image.open(TEST_FILE_DX10_BC7_UNORM_SRGB) as im: with Image.open(TEST_FILE_DX10_BC7_UNORM_SRGB) as im:
@ -216,7 +217,7 @@ def test_dx10_bc7_unorm_srgb():
) )
def test_dx10_r8g8b8a8(): def test_dx10_r8g8b8a8() -> None:
"""Check DX10 images can be opened""" """Check DX10 images can be opened"""
with Image.open(TEST_FILE_DX10_R8G8B8A8) as im: with Image.open(TEST_FILE_DX10_R8G8B8A8) as im:
@ -229,7 +230,7 @@ def test_dx10_r8g8b8a8():
assert_image_equal_tofile(im, TEST_FILE_DX10_R8G8B8A8.replace(".dds", ".png")) assert_image_equal_tofile(im, TEST_FILE_DX10_R8G8B8A8.replace(".dds", ".png"))
def test_dx10_r8g8b8a8_unorm_srgb(): def test_dx10_r8g8b8a8_unorm_srgb() -> None:
"""Check DX10 unsigned normalized integer images can be opened""" """Check DX10 unsigned normalized integer images can be opened"""
with Image.open(TEST_FILE_DX10_R8G8B8A8_UNORM_SRGB) as im: with Image.open(TEST_FILE_DX10_R8G8B8A8_UNORM_SRGB) as im:
@ -255,7 +256,7 @@ def test_dx10_r8g8b8a8_unorm_srgb():
("RGBA", (800, 600), TEST_FILE_UNCOMPRESSED_RGB_WITH_ALPHA), ("RGBA", (800, 600), TEST_FILE_UNCOMPRESSED_RGB_WITH_ALPHA),
], ],
) )
def test_uncompressed(mode, size, test_file): def test_uncompressed(mode, size, test_file) -> None:
"""Check uncompressed images can be opened""" """Check uncompressed images can be opened"""
with Image.open(test_file) as im: with Image.open(test_file) as im:
@ -266,7 +267,7 @@ def test_uncompressed(mode, size, test_file):
assert_image_equal_tofile(im, test_file.replace(".dds", ".png")) assert_image_equal_tofile(im, test_file.replace(".dds", ".png"))
def test__accept_true(): def test__accept_true() -> None:
"""Check valid prefix""" """Check valid prefix"""
# Arrange # Arrange
prefix = b"DDS etc" prefix = b"DDS etc"
@ -278,7 +279,7 @@ def test__accept_true():
assert output assert output
def test__accept_false(): def test__accept_false() -> None:
"""Check invalid prefix""" """Check invalid prefix"""
# Arrange # Arrange
prefix = b"something invalid" prefix = b"something invalid"
@ -290,19 +291,19 @@ def test__accept_false():
assert not output assert not output
def test_invalid_file(): def test_invalid_file() -> None:
invalid_file = "Tests/images/flower.jpg" invalid_file = "Tests/images/flower.jpg"
with pytest.raises(SyntaxError): with pytest.raises(SyntaxError):
DdsImagePlugin.DdsImageFile(invalid_file) DdsImagePlugin.DdsImageFile(invalid_file)
def test_short_header(): def test_short_header() -> None:
"""Check a short header""" """Check a short header"""
with open(TEST_FILE_DXT5, "rb") as f: with open(TEST_FILE_DXT5, "rb") as f:
img_file = f.read() img_file = f.read()
def short_header(): def short_header() -> None:
with Image.open(BytesIO(img_file[:119])): with Image.open(BytesIO(img_file[:119])):
pass # pragma: no cover pass # pragma: no cover
@ -310,13 +311,13 @@ def test_short_header():
short_header() short_header()
def test_short_file(): def test_short_file() -> None:
"""Check that the appropriate error is thrown for a short file""" """Check that the appropriate error is thrown for a short file"""
with open(TEST_FILE_DXT5, "rb") as f: with open(TEST_FILE_DXT5, "rb") as f:
img_file = f.read() img_file = f.read()
def short_file(): def short_file() -> None:
with Image.open(BytesIO(img_file[:-100])) as im: with Image.open(BytesIO(img_file[:-100])) as im:
im.load() im.load()
@ -324,7 +325,7 @@ def test_short_file():
short_file() short_file()
def test_dxt5_colorblock_alpha_issue_4142(): def test_dxt5_colorblock_alpha_issue_4142() -> None:
"""Check that colorblocks are decoded correctly in DXT5""" """Check that colorblocks are decoded correctly in DXT5"""
with Image.open("Tests/images/dxt5-colorblock-alpha-issue-4142.dds") as im: with Image.open("Tests/images/dxt5-colorblock-alpha-issue-4142.dds") as im:
@ -339,12 +340,12 @@ def test_dxt5_colorblock_alpha_issue_4142():
assert px[2] != 0 assert px[2] != 0
def test_palette(): def test_palette() -> None:
with Image.open("Tests/images/palette.dds") as im: with Image.open("Tests/images/palette.dds") as im:
assert_image_equal_tofile(im, "Tests/images/transparent.gif") assert_image_equal_tofile(im, "Tests/images/transparent.gif")
def test_unsupported_bitcount(): def test_unsupported_bitcount() -> None:
with pytest.raises(OSError): with pytest.raises(OSError):
with Image.open("Tests/images/unsupported_bitcount.dds"): with Image.open("Tests/images/unsupported_bitcount.dds"):
pass pass
@ -357,13 +358,13 @@ def test_unsupported_bitcount():
"Tests/images/unimplemented_pfflags.dds", "Tests/images/unimplemented_pfflags.dds",
), ),
) )
def test_not_implemented(test_file): def test_not_implemented(test_file) -> None:
with pytest.raises(NotImplementedError): with pytest.raises(NotImplementedError):
with Image.open(test_file): with Image.open(test_file):
pass pass
def test_save_unsupported_mode(tmp_path): def test_save_unsupported_mode(tmp_path: Path) -> None:
out = str(tmp_path / "temp.dds") out = str(tmp_path / "temp.dds")
im = hopper("HSV") im = hopper("HSV")
with pytest.raises(OSError): with pytest.raises(OSError):
@ -379,7 +380,7 @@ def test_save_unsupported_mode(tmp_path):
("RGBA", "Tests/images/pil123rgba.png"), ("RGBA", "Tests/images/pil123rgba.png"),
], ],
) )
def test_save(mode, test_file, tmp_path): def test_save(mode, test_file, tmp_path: Path) -> None:
out = str(tmp_path / "temp.dds") out = str(tmp_path / "temp.dds")
with Image.open(test_file) as im: with Image.open(test_file) as im:
assert im.mode == mode assert im.mode == mode

View File

@ -1,6 +1,7 @@
from __future__ import annotations from __future__ import annotations
import io import io
from pathlib import Path
import pytest import pytest
@ -83,7 +84,7 @@ simple_eps_file_with_long_binary_data = (
("filename", "size"), ((FILE1, (460, 352)), (FILE2, (360, 252))) ("filename", "size"), ((FILE1, (460, 352)), (FILE2, (360, 252)))
) )
@pytest.mark.parametrize("scale", (1, 2)) @pytest.mark.parametrize("scale", (1, 2))
def test_sanity(filename, size, scale): def test_sanity(filename, size, scale) -> None:
expected_size = tuple(s * scale for s in size) expected_size = tuple(s * scale for s in size)
with Image.open(filename) as image: with Image.open(filename) as image:
image.load(scale=scale) image.load(scale=scale)
@ -93,7 +94,7 @@ def test_sanity(filename, size, scale):
@pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available") @pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available")
def test_load(): def test_load() -> None:
with Image.open(FILE1) as im: with Image.open(FILE1) as im:
assert im.load()[0, 0] == (255, 255, 255) assert im.load()[0, 0] == (255, 255, 255)
@ -101,7 +102,7 @@ def test_load():
assert im.load()[0, 0] == (255, 255, 255) assert im.load()[0, 0] == (255, 255, 255)
def test_binary(): def test_binary() -> None:
if HAS_GHOSTSCRIPT: if HAS_GHOSTSCRIPT:
assert EpsImagePlugin.gs_binary is not None assert EpsImagePlugin.gs_binary is not None
else: else:
@ -115,41 +116,41 @@ def test_binary():
assert EpsImagePlugin.gs_windows_binary is not None assert EpsImagePlugin.gs_windows_binary is not None
def test_invalid_file(): def test_invalid_file() -> None:
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)
def test_binary_header_only(): def test_binary_header_only() -> None:
data = io.BytesIO(simple_binary_header) data = io.BytesIO(simple_binary_header)
with pytest.raises(SyntaxError, match='EPS header missing "%!PS-Adobe" comment'): with pytest.raises(SyntaxError, match='EPS header missing "%!PS-Adobe" comment'):
EpsImagePlugin.EpsImageFile(data) EpsImagePlugin.EpsImageFile(data)
@pytest.mark.parametrize("prefix", (b"", simple_binary_header)) @pytest.mark.parametrize("prefix", (b"", simple_binary_header))
def test_missing_version_comment(prefix): def test_missing_version_comment(prefix) -> None:
data = io.BytesIO(prefix + b"\n".join(simple_eps_file_without_version)) data = io.BytesIO(prefix + b"\n".join(simple_eps_file_without_version))
with pytest.raises(SyntaxError): with pytest.raises(SyntaxError):
EpsImagePlugin.EpsImageFile(data) EpsImagePlugin.EpsImageFile(data)
@pytest.mark.parametrize("prefix", (b"", simple_binary_header)) @pytest.mark.parametrize("prefix", (b"", simple_binary_header))
def test_missing_boundingbox_comment(prefix): def test_missing_boundingbox_comment(prefix) -> None:
data = io.BytesIO(prefix + b"\n".join(simple_eps_file_without_boundingbox)) data = io.BytesIO(prefix + b"\n".join(simple_eps_file_without_boundingbox))
with pytest.raises(SyntaxError, match='EPS header missing "%%BoundingBox" comment'): with pytest.raises(SyntaxError, match='EPS header missing "%%BoundingBox" comment'):
EpsImagePlugin.EpsImageFile(data) EpsImagePlugin.EpsImageFile(data)
@pytest.mark.parametrize("prefix", (b"", simple_binary_header)) @pytest.mark.parametrize("prefix", (b"", simple_binary_header))
def test_invalid_boundingbox_comment(prefix): def test_invalid_boundingbox_comment(prefix) -> None:
data = io.BytesIO(prefix + b"\n".join(simple_eps_file_with_invalid_boundingbox)) data = io.BytesIO(prefix + b"\n".join(simple_eps_file_with_invalid_boundingbox))
with pytest.raises(OSError, match="cannot determine EPS bounding box"): with pytest.raises(OSError, match="cannot determine EPS bounding box"):
EpsImagePlugin.EpsImageFile(data) EpsImagePlugin.EpsImageFile(data)
@pytest.mark.parametrize("prefix", (b"", simple_binary_header)) @pytest.mark.parametrize("prefix", (b"", simple_binary_header))
def test_invalid_boundingbox_comment_valid_imagedata_comment(prefix): def test_invalid_boundingbox_comment_valid_imagedata_comment(prefix) -> None:
data = io.BytesIO( data = io.BytesIO(
prefix + b"\n".join(simple_eps_file_with_invalid_boundingbox_valid_imagedata) prefix + b"\n".join(simple_eps_file_with_invalid_boundingbox_valid_imagedata)
) )
@ -160,21 +161,21 @@ def test_invalid_boundingbox_comment_valid_imagedata_comment(prefix):
@pytest.mark.parametrize("prefix", (b"", simple_binary_header)) @pytest.mark.parametrize("prefix", (b"", simple_binary_header))
def test_ascii_comment_too_long(prefix): def test_ascii_comment_too_long(prefix) -> None:
data = io.BytesIO(prefix + b"\n".join(simple_eps_file_with_long_ascii_comment)) data = io.BytesIO(prefix + b"\n".join(simple_eps_file_with_long_ascii_comment))
with pytest.raises(SyntaxError, match="not an EPS file"): with pytest.raises(SyntaxError, match="not an EPS file"):
EpsImagePlugin.EpsImageFile(data) EpsImagePlugin.EpsImageFile(data)
@pytest.mark.parametrize("prefix", (b"", simple_binary_header)) @pytest.mark.parametrize("prefix", (b"", simple_binary_header))
def test_long_binary_data(prefix): def test_long_binary_data(prefix) -> None:
data = io.BytesIO(prefix + b"\n".join(simple_eps_file_with_long_binary_data)) data = io.BytesIO(prefix + b"\n".join(simple_eps_file_with_long_binary_data))
EpsImagePlugin.EpsImageFile(data) EpsImagePlugin.EpsImageFile(data)
@pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available") @pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available")
@pytest.mark.parametrize("prefix", (b"", simple_binary_header)) @pytest.mark.parametrize("prefix", (b"", simple_binary_header))
def test_load_long_binary_data(prefix): def test_load_long_binary_data(prefix) -> None:
data = io.BytesIO(prefix + b"\n".join(simple_eps_file_with_long_binary_data)) data = io.BytesIO(prefix + b"\n".join(simple_eps_file_with_long_binary_data))
with Image.open(data) as img: with Image.open(data) as img:
img.load() img.load()
@ -187,7 +188,7 @@ def test_load_long_binary_data(prefix):
pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing"
) )
@pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available") @pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available")
def test_cmyk(): def test_cmyk() -> None:
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"
assert cmyk_image.size == (100, 100) assert cmyk_image.size == (100, 100)
@ -203,7 +204,7 @@ def test_cmyk():
@pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available") @pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available")
def test_showpage(): def test_showpage() -> None:
# 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:
@ -214,7 +215,7 @@ def test_showpage():
@pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available") @pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available")
def test_transparency(): def test_transparency() -> None:
with Image.open("Tests/images/reqd_showpage.eps") as plot_image: with Image.open("Tests/images/reqd_showpage.eps") as plot_image:
plot_image.load(transparency=True) plot_image.load(transparency=True)
assert plot_image.mode == "RGBA" assert plot_image.mode == "RGBA"
@ -225,7 +226,7 @@ def test_transparency():
@pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available") @pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available")
def test_file_object(tmp_path): def test_file_object(tmp_path: Path) -> None:
# issue 479 # issue 479
with Image.open(FILE1) as image1: with Image.open(FILE1) as image1:
with open(str(tmp_path / "temp.eps"), "wb") as fh: with open(str(tmp_path / "temp.eps"), "wb") as fh:
@ -233,7 +234,7 @@ def test_file_object(tmp_path):
@pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available") @pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available")
def test_bytesio_object(): def test_bytesio_object() -> None:
with open(FILE1, "rb") as f: with open(FILE1, "rb") as f:
img_bytes = io.BytesIO(f.read()) img_bytes = io.BytesIO(f.read())
@ -246,12 +247,12 @@ def test_bytesio_object():
assert_image_similar(img, image1_scale1_compare, 5) assert_image_similar(img, image1_scale1_compare, 5)
def test_1_mode(): def test_1_mode() -> None:
with Image.open("Tests/images/1.eps") as im: with Image.open("Tests/images/1.eps") as im:
assert im.mode == "1" assert im.mode == "1"
def test_image_mode_not_supported(tmp_path): def test_image_mode_not_supported(tmp_path: Path) -> None:
im = hopper("RGBA") im = hopper("RGBA")
tmpfile = str(tmp_path / "temp.eps") tmpfile = str(tmp_path / "temp.eps")
with pytest.raises(ValueError): with pytest.raises(ValueError):
@ -260,7 +261,7 @@ def test_image_mode_not_supported(tmp_path):
@pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available") @pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available")
@skip_unless_feature("zlib") @skip_unless_feature("zlib")
def test_render_scale1(): def test_render_scale1() -> None:
# We need png support for these render test # We need png support for these render test
# Zero bounding box # Zero bounding box
@ -282,7 +283,7 @@ def test_render_scale1():
@pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available") @pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available")
@skip_unless_feature("zlib") @skip_unless_feature("zlib")
def test_render_scale2(): def test_render_scale2() -> None:
# We need png support for these render test # We need png support for these render test
# Zero bounding box # Zero bounding box
@ -304,7 +305,7 @@ def test_render_scale2():
@pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available") @pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available")
@pytest.mark.parametrize("filename", (FILE1, FILE2, "Tests/images/illu10_preview.eps")) @pytest.mark.parametrize("filename", (FILE1, FILE2, "Tests/images/illu10_preview.eps"))
def test_resize(filename): def test_resize(filename) -> None:
with Image.open(filename) as im: with Image.open(filename) as im:
new_size = (100, 100) new_size = (100, 100)
im = im.resize(new_size) im = im.resize(new_size)
@ -313,7 +314,7 @@ def test_resize(filename):
@pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available") @pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available")
@pytest.mark.parametrize("filename", (FILE1, FILE2)) @pytest.mark.parametrize("filename", (FILE1, FILE2))
def test_thumbnail(filename): def test_thumbnail(filename) -> None:
# Issue #619 # Issue #619
with Image.open(filename) as im: with Image.open(filename) as im:
new_size = (100, 100) new_size = (100, 100)
@ -321,20 +322,20 @@ def test_thumbnail(filename):
assert max(im.size) == max(new_size) assert max(im.size) == max(new_size)
def test_read_binary_preview(): def test_read_binary_preview() -> None:
# 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_psfile(tmp_path): def test_readline_psfile(tmp_path: Path) -> None:
# check all the freaking line endings possible from the spec # check all the freaking line endings possible from the spec
# test_string = u'something\r\nelse\n\rbaz\rbif\n' # test_string = u'something\r\nelse\n\rbaz\rbif\n'
line_endings = ["\r\n", "\n", "\n\r", "\r"] line_endings = ["\r\n", "\n", "\n\r", "\r"]
strings = ["something", "else", "baz", "bif"] strings = ["something", "else", "baz", "bif"]
def _test_readline(t, ending): def _test_readline(t, ending) -> None:
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)
) )
@ -343,13 +344,13 @@ def test_readline_psfile(tmp_path):
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(test_string, ending): def _test_readline_io_psfile(test_string, ending) -> None:
f = io.BytesIO(test_string.encode("latin-1")) f = io.BytesIO(test_string.encode("latin-1"))
with pytest.warns(DeprecationWarning): with pytest.warns(DeprecationWarning):
t = EpsImagePlugin.PSFile(f) t = EpsImagePlugin.PSFile(f)
_test_readline(t, ending) _test_readline(t, ending)
def _test_readline_file_psfile(test_string, ending): def _test_readline_file_psfile(test_string, ending) -> None:
f = str(tmp_path / "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"))
@ -365,7 +366,7 @@ def test_readline_psfile(tmp_path):
_test_readline_file_psfile(s, ending) _test_readline_file_psfile(s, ending)
def test_psfile_deprecation(): def test_psfile_deprecation() -> None:
with pytest.warns(DeprecationWarning): with pytest.warns(DeprecationWarning):
EpsImagePlugin.PSFile(None) EpsImagePlugin.PSFile(None)
@ -375,7 +376,7 @@ def test_psfile_deprecation():
"line_ending", "line_ending",
(b"\r\n", b"\n", b"\n\r", b"\r"), (b"\r\n", b"\n", b"\n\r", b"\r"),
) )
def test_readline(prefix, line_ending): def test_readline(prefix, line_ending) -> None:
simple_file = prefix + line_ending.join(simple_eps_file_with_comments) simple_file = prefix + line_ending.join(simple_eps_file_with_comments)
data = io.BytesIO(simple_file) data = io.BytesIO(simple_file)
test_file = EpsImagePlugin.EpsImageFile(data) test_file = EpsImagePlugin.EpsImageFile(data)
@ -393,14 +394,14 @@ def test_readline(prefix, line_ending):
"Tests/images/illuCS6_preview.eps", "Tests/images/illuCS6_preview.eps",
), ),
) )
def test_open_eps(filename): def test_open_eps(filename) -> None:
# https://github.com/python-pillow/Pillow/issues/1104 # https://github.com/python-pillow/Pillow/issues/1104
with Image.open(filename) as img: with Image.open(filename) as img:
assert img.mode == "RGB" assert img.mode == "RGB"
@pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available") @pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available")
def test_emptyline(): def test_emptyline() -> None:
# 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"
@ -416,14 +417,14 @@ def test_emptyline():
"test_file", "test_file",
["Tests/images/timeout-d675703545fee17acab56e5fec644c19979175de.eps"], ["Tests/images/timeout-d675703545fee17acab56e5fec644c19979175de.eps"],
) )
def test_timeout(test_file): def test_timeout(test_file) -> None:
with open(test_file, "rb") as f: with open(test_file, "rb") as f:
with pytest.raises(Image.UnidentifiedImageError): with pytest.raises(Image.UnidentifiedImageError):
with Image.open(f): with Image.open(f):
pass pass
def test_bounding_box_in_trailer(): def test_bounding_box_in_trailer() -> None:
# Check bounding boxes are parsed in the same way # Check bounding boxes are parsed in the same way
# when specified in the header and the trailer # when specified in the header and the trailer
with Image.open("Tests/images/zero_bb_trailer.eps") as trailer_image, Image.open( with Image.open("Tests/images/zero_bb_trailer.eps") as trailer_image, Image.open(
@ -432,7 +433,7 @@ def test_bounding_box_in_trailer():
assert trailer_image.size == header_image.size assert trailer_image.size == header_image.size
def test_eof_before_bounding_box(): def test_eof_before_bounding_box() -> None:
with pytest.raises(OSError): with pytest.raises(OSError):
with Image.open("Tests/images/zero_bb_eof_before_boundingbox.eps"): with Image.open("Tests/images/zero_bb_eof_before_boundingbox.eps"):
pass pass

View File

@ -11,7 +11,7 @@ from .helper import assert_image_equal, hopper
TEST_FILE = "Tests/images/hopper.fits" TEST_FILE = "Tests/images/hopper.fits"
def test_open(): def test_open() -> None:
# Act # Act
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
# Assert # Assert
@ -22,7 +22,7 @@ def test_open():
assert_image_equal(im, hopper("L")) assert_image_equal(im, hopper("L"))
def test_invalid_file(): def test_invalid_file() -> None:
# Arrange # Arrange
invalid_file = "Tests/images/flower.jpg" invalid_file = "Tests/images/flower.jpg"
@ -31,14 +31,14 @@ def test_invalid_file():
FitsImagePlugin.FitsImageFile(invalid_file) FitsImagePlugin.FitsImageFile(invalid_file)
def test_truncated_fits(): def test_truncated_fits() -> None:
# No END to headers # No END to headers
image_data = b"SIMPLE = T" + b" " * 50 + b"TRUNCATE" image_data = b"SIMPLE = T" + b" " * 50 + b"TRUNCATE"
with pytest.raises(OSError): with pytest.raises(OSError):
FitsImagePlugin.FitsImageFile(BytesIO(image_data)) FitsImagePlugin.FitsImageFile(BytesIO(image_data))
def test_naxis_zero(): def test_naxis_zero() -> None:
# This test image has been manually hexedited # This test image has been manually hexedited
# to set the number of data axes to zero # to set the number of data axes to zero
with pytest.raises(ValueError): with pytest.raises(ValueError):
@ -46,7 +46,7 @@ def test_naxis_zero():
pass pass
def test_comment(): def test_comment() -> None:
image_data = b"SIMPLE = T / comment string" image_data = b"SIMPLE = T / comment string"
with pytest.raises(OSError): with pytest.raises(OSError):
FitsImagePlugin.FitsImageFile(BytesIO(image_data)) FitsImagePlugin.FitsImageFile(BytesIO(image_data))

View File

@ -16,7 +16,7 @@ static_test_file = "Tests/images/hopper.fli"
animated_test_file = "Tests/images/a.fli" animated_test_file = "Tests/images/a.fli"
def test_sanity(): def test_sanity() -> None:
with Image.open(static_test_file) as im: with Image.open(static_test_file) as im:
im.load() im.load()
assert im.mode == "P" assert im.mode == "P"
@ -33,8 +33,8 @@ def test_sanity():
@pytest.mark.skipif(is_pypy(), reason="Requires CPython") @pytest.mark.skipif(is_pypy(), reason="Requires CPython")
def test_unclosed_file(): def test_unclosed_file() -> None:
def open(): def open() -> None:
im = Image.open(static_test_file) im = Image.open(static_test_file)
im.load() im.load()
@ -42,14 +42,14 @@ def test_unclosed_file():
open() open()
def test_closed_file(): def test_closed_file() -> None:
with warnings.catch_warnings(): with warnings.catch_warnings():
im = Image.open(static_test_file) im = Image.open(static_test_file)
im.load() im.load()
im.close() im.close()
def test_seek_after_close(): def test_seek_after_close() -> None:
im = Image.open(animated_test_file) im = Image.open(animated_test_file)
im.seek(1) im.seek(1)
im.close() im.close()
@ -58,13 +58,13 @@ def test_seek_after_close():
im.seek(0) im.seek(0)
def test_context_manager(): def test_context_manager() -> None:
with warnings.catch_warnings(): with warnings.catch_warnings():
with Image.open(static_test_file) as im: with Image.open(static_test_file) as im:
im.load() im.load()
def test_tell(): def test_tell() -> None:
# Arrange # Arrange
with Image.open(static_test_file) as im: with Image.open(static_test_file) as im:
# Act # Act
@ -74,20 +74,20 @@ def test_tell():
assert frame == 0 assert frame == 0
def test_invalid_file(): def test_invalid_file() -> None:
invalid_file = "Tests/images/flower.jpg" invalid_file = "Tests/images/flower.jpg"
with pytest.raises(SyntaxError): with pytest.raises(SyntaxError):
FliImagePlugin.FliImageFile(invalid_file) FliImagePlugin.FliImageFile(invalid_file)
def test_palette_chunk_second(): def test_palette_chunk_second() -> None:
with Image.open("Tests/images/hopper_palette_chunk_second.fli") as im: with Image.open("Tests/images/hopper_palette_chunk_second.fli") as im:
with Image.open(static_test_file) as expected: with Image.open(static_test_file) as expected:
assert_image_equal(im.convert("RGB"), expected.convert("RGB")) assert_image_equal(im.convert("RGB"), expected.convert("RGB"))
def test_n_frames(): def test_n_frames() -> None:
with Image.open(static_test_file) as im: with Image.open(static_test_file) as im:
assert im.n_frames == 1 assert im.n_frames == 1
assert not im.is_animated assert not im.is_animated
@ -97,7 +97,7 @@ def test_n_frames():
assert im.is_animated assert im.is_animated
def test_eoferror(): def test_eoferror() -> None:
with Image.open(animated_test_file) as im: with Image.open(animated_test_file) as im:
n_frames = im.n_frames n_frames = im.n_frames
@ -110,7 +110,7 @@ def test_eoferror():
im.seek(n_frames - 1) im.seek(n_frames - 1)
def test_seek_tell(): def test_seek_tell() -> None:
with Image.open(animated_test_file) as im: with Image.open(animated_test_file) as im:
layer_number = im.tell() layer_number = im.tell()
assert layer_number == 0 assert layer_number == 0
@ -132,7 +132,7 @@ def test_seek_tell():
assert layer_number == 1 assert layer_number == 1
def test_seek(): def test_seek() -> None:
with Image.open(animated_test_file) as im: with Image.open(animated_test_file) as im:
im.seek(50) im.seek(50)
@ -147,7 +147,7 @@ def test_seek():
], ],
) )
@pytest.mark.timeout(timeout=3) @pytest.mark.timeout(timeout=3)
def test_timeouts(test_file): def test_timeouts(test_file) -> None:
with open(test_file, "rb") as f: with open(test_file, "rb") as f:
with Image.open(f) as im: with Image.open(f) as im:
with pytest.raises(OSError): with pytest.raises(OSError):
@ -160,7 +160,7 @@ def test_timeouts(test_file):
"Tests/images/crash-5762152299364352.fli", "Tests/images/crash-5762152299364352.fli",
], ],
) )
def test_crash(test_file): def test_crash(test_file) -> None:
with open(test_file, "rb") as f: with open(test_file, "rb") as f:
with Image.open(f) as im: with Image.open(f) as im:
with pytest.raises(OSError): with pytest.raises(OSError):

View File

@ -11,7 +11,7 @@ FpxImagePlugin = pytest.importorskip(
) )
def test_sanity(): def test_sanity() -> None:
with Image.open("Tests/images/input_bw_one_band.fpx") as im: with Image.open("Tests/images/input_bw_one_band.fpx") as im:
assert im.mode == "L" assert im.mode == "L"
assert im.size == (70, 46) assert im.size == (70, 46)
@ -20,7 +20,7 @@ def test_sanity():
assert_image_equal_tofile(im, "Tests/images/input_bw_one_band.png") assert_image_equal_tofile(im, "Tests/images/input_bw_one_band.png")
def test_close(): def test_close() -> None:
with Image.open("Tests/images/input_bw_one_band.fpx") as im: with Image.open("Tests/images/input_bw_one_band.fpx") as im:
pass pass
assert im.ole.fp.closed assert im.ole.fp.closed
@ -30,7 +30,7 @@ def test_close():
assert im.ole.fp.closed assert im.ole.fp.closed
def test_invalid_file(): def test_invalid_file() -> None:
# Test an invalid OLE file # Test an invalid OLE file
invalid_file = "Tests/images/flower.jpg" invalid_file = "Tests/images/flower.jpg"
with pytest.raises(SyntaxError): with pytest.raises(SyntaxError):
@ -42,7 +42,7 @@ def test_invalid_file():
FpxImagePlugin.FpxImageFile(ole_file) FpxImagePlugin.FpxImageFile(ole_file)
def test_fpx_invalid_number_of_bands(): def test_fpx_invalid_number_of_bands() -> None:
with pytest.raises(OSError, match="Invalid number of bands"): with pytest.raises(OSError, match="Invalid number of bands"):
with Image.open("Tests/images/input_bw_five_bands.fpx"): with Image.open("Tests/images/input_bw_five_bands.fpx"):
pass pass

View File

@ -2,6 +2,7 @@ from __future__ import annotations
import warnings import warnings
from io import BytesIO from io import BytesIO
from pathlib import Path
import pytest import pytest
@ -23,7 +24,7 @@ with open(TEST_GIF, "rb") as f:
data = f.read() data = f.read()
def test_sanity(): def test_sanity() -> None:
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"
@ -33,8 +34,8 @@ def test_sanity():
@pytest.mark.skipif(is_pypy(), reason="Requires CPython") @pytest.mark.skipif(is_pypy(), reason="Requires CPython")
def test_unclosed_file(): def test_unclosed_file() -> None:
def open(): def open() -> None:
im = Image.open(TEST_GIF) im = Image.open(TEST_GIF)
im.load() im.load()
@ -42,14 +43,14 @@ def test_unclosed_file():
open() open()
def test_closed_file(): def test_closed_file() -> None:
with warnings.catch_warnings(): with warnings.catch_warnings():
im = Image.open(TEST_GIF) im = Image.open(TEST_GIF)
im.load() im.load()
im.close() im.close()
def test_seek_after_close(): def test_seek_after_close() -> None:
im = Image.open("Tests/images/iss634.gif") im = Image.open("Tests/images/iss634.gif")
im.load() im.load()
im.close() im.close()
@ -62,20 +63,20 @@ def test_seek_after_close():
im.seek(1) im.seek(1)
def test_context_manager(): def test_context_manager() -> None:
with warnings.catch_warnings(): with warnings.catch_warnings():
with Image.open(TEST_GIF) as im: with Image.open(TEST_GIF) as im:
im.load() im.load()
def test_invalid_file(): def test_invalid_file() -> None:
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_l_mode_transparency(): def test_l_mode_transparency() -> None:
with Image.open("Tests/images/no_palette_with_transparency.gif") as im: with Image.open("Tests/images/no_palette_with_transparency.gif") as im:
assert im.mode == "L" assert im.mode == "L"
assert im.load()[0, 0] == 128 assert im.load()[0, 0] == 128
@ -86,7 +87,7 @@ def test_l_mode_transparency():
assert im.load()[0, 0] == 128 assert im.load()[0, 0] == 128
def test_l_mode_after_rgb(): def test_l_mode_after_rgb() -> None:
with Image.open("Tests/images/no_palette_after_rgb.gif") as im: with Image.open("Tests/images/no_palette_after_rgb.gif") as im:
im.seek(1) im.seek(1)
assert im.mode == "RGB" assert im.mode == "RGB"
@ -95,13 +96,13 @@ def test_l_mode_after_rgb():
assert im.mode == "RGB" assert im.mode == "RGB"
def test_palette_not_needed_for_second_frame(): def test_palette_not_needed_for_second_frame() -> None:
with Image.open("Tests/images/palette_not_needed_for_second_frame.gif") as im: with Image.open("Tests/images/palette_not_needed_for_second_frame.gif") as im:
im.seek(1) im.seek(1)
assert_image_similar(im, hopper("L").convert("RGB"), 8) assert_image_similar(im, hopper("L").convert("RGB"), 8)
def test_strategy(): def test_strategy() -> None:
with Image.open("Tests/images/iss634.gif") as im: with Image.open("Tests/images/iss634.gif") as im:
expected_rgb_always = im.convert("RGB") expected_rgb_always = im.convert("RGB")
@ -142,7 +143,7 @@ def test_strategy():
GifImagePlugin.LOADING_STRATEGY = GifImagePlugin.LoadingStrategy.RGB_AFTER_FIRST GifImagePlugin.LOADING_STRATEGY = GifImagePlugin.LoadingStrategy.RGB_AFTER_FIRST
def test_optimize(): def test_optimize() -> None:
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()
@ -177,7 +178,7 @@ def test_optimize():
(4, 513, 256), (4, 513, 256),
), ),
) )
def test_optimize_correctness(colors, size, expected_palette_length): def test_optimize_correctness(colors, size, expected_palette_length) -> None:
# 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.
@ -199,14 +200,14 @@ def test_optimize_correctness(colors, size, expected_palette_length):
assert_image_equal(im.convert("RGB"), reloaded.convert("RGB")) assert_image_equal(im.convert("RGB"), reloaded.convert("RGB"))
def test_optimize_full_l(): def test_optimize_full_l() -> None:
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_optimize_if_palette_can_be_reduced_by_half(): def test_optimize_if_palette_can_be_reduced_by_half() -> None:
im = Image.new("P", (8, 1)) im = Image.new("P", (8, 1))
im.palette = ImagePalette.raw("RGB", bytes((0, 0, 0) * 150)) im.palette = ImagePalette.raw("RGB", bytes((0, 0, 0) * 150))
for i in range(8): for i in range(8):
@ -219,7 +220,7 @@ def test_optimize_if_palette_can_be_reduced_by_half():
assert len(reloaded.palette.palette) // 3 == colors assert len(reloaded.palette.palette) // 3 == colors
def test_full_palette_second_frame(tmp_path): def test_full_palette_second_frame(tmp_path: Path) -> None:
out = str(tmp_path / "temp.gif") out = str(tmp_path / "temp.gif")
im = Image.new("P", (1, 256)) im = Image.new("P", (1, 256))
@ -240,7 +241,7 @@ def test_full_palette_second_frame(tmp_path):
reloaded.getpixel((0, i)) == i reloaded.getpixel((0, i)) == i
def test_roundtrip(tmp_path): def test_roundtrip(tmp_path: Path) -> None:
out = str(tmp_path / "temp.gif") out = str(tmp_path / "temp.gif")
im = hopper() im = hopper()
im.save(out) im.save(out)
@ -248,7 +249,7 @@ def test_roundtrip(tmp_path):
assert_image_similar(reread.convert("RGB"), im, 50) assert_image_similar(reread.convert("RGB"), im, 50)
def test_roundtrip2(tmp_path): def test_roundtrip2(tmp_path: Path) -> None:
# see https://github.com/python-pillow/Pillow/issues/403 # see https://github.com/python-pillow/Pillow/issues/403
out = str(tmp_path / "temp.gif") out = str(tmp_path / "temp.gif")
with Image.open(TEST_GIF) as im: with Image.open(TEST_GIF) as im:
@ -258,7 +259,7 @@ def test_roundtrip2(tmp_path):
assert_image_similar(reread.convert("RGB"), hopper(), 50) assert_image_similar(reread.convert("RGB"), hopper(), 50)
def test_roundtrip_save_all(tmp_path): def test_roundtrip_save_all(tmp_path: Path) -> None:
# Single frame image # Single frame image
out = str(tmp_path / "temp.gif") out = str(tmp_path / "temp.gif")
im = hopper() im = hopper()
@ -275,7 +276,7 @@ def test_roundtrip_save_all(tmp_path):
assert reread.n_frames == 5 assert reread.n_frames == 5
def test_roundtrip_save_all_1(tmp_path): def test_roundtrip_save_all_1(tmp_path: Path) -> None:
out = str(tmp_path / "temp.gif") out = str(tmp_path / "temp.gif")
im = Image.new("1", (1, 1)) im = Image.new("1", (1, 1))
im2 = Image.new("1", (1, 1), 1) im2 = Image.new("1", (1, 1), 1)
@ -296,7 +297,7 @@ def test_roundtrip_save_all_1(tmp_path):
("Tests/images/dispose_bgnd_rgba.gif", "RGBA"), ("Tests/images/dispose_bgnd_rgba.gif", "RGBA"),
), ),
) )
def test_loading_multiple_palettes(path, mode): def test_loading_multiple_palettes(path, mode) -> None:
with Image.open(path) as im: with Image.open(path) as im:
assert im.mode == "P" assert im.mode == "P"
first_frame_colors = im.palette.colors.keys() first_frame_colors = im.palette.colors.keys()
@ -314,7 +315,7 @@ def test_loading_multiple_palettes(path, mode):
assert im.load()[24, 24] not in first_frame_colors assert im.load()[24, 24] not in first_frame_colors
def test_headers_saving_for_animated_gifs(tmp_path): def test_headers_saving_for_animated_gifs(tmp_path: Path) -> None:
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:
@ -327,7 +328,7 @@ def test_headers_saving_for_animated_gifs(tmp_path):
assert info[header] == reread.info[header] assert info[header] == reread.info[header]
def test_palette_handling(tmp_path): def test_palette_handling(tmp_path: Path) -> None:
# 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:
@ -343,7 +344,7 @@ def test_palette_handling(tmp_path):
assert_image_similar(im, reloaded.convert("RGB"), 10) assert_image_similar(im, reloaded.convert("RGB"), 10)
def test_palette_434(tmp_path): def test_palette_434(tmp_path: Path) -> None:
# 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):
@ -368,7 +369,7 @@ def test_palette_434(tmp_path):
@pytest.mark.skipif(not netpbm_available(), reason="Netpbm not available") @pytest.mark.skipif(not netpbm_available(), reason="Netpbm not available")
def test_save_netpbm_bmp_mode(tmp_path): def test_save_netpbm_bmp_mode(tmp_path: Path) -> None:
with Image.open(TEST_GIF) as img: with Image.open(TEST_GIF) as img:
img = img.convert("RGB") img = img.convert("RGB")
@ -379,7 +380,7 @@ def test_save_netpbm_bmp_mode(tmp_path):
@pytest.mark.skipif(not netpbm_available(), reason="Netpbm not available") @pytest.mark.skipif(not netpbm_available(), reason="Netpbm not available")
def test_save_netpbm_l_mode(tmp_path): def test_save_netpbm_l_mode(tmp_path: Path) -> None:
with Image.open(TEST_GIF) as img: with Image.open(TEST_GIF) as img:
img = img.convert("L") img = img.convert("L")
@ -389,7 +390,7 @@ def test_save_netpbm_l_mode(tmp_path):
assert_image_similar(img, reloaded.convert("L"), 0) assert_image_similar(img, reloaded.convert("L"), 0)
def test_seek(): def test_seek() -> None:
with Image.open("Tests/images/dispose_none.gif") as img: with Image.open("Tests/images/dispose_none.gif") as img:
frame_count = 0 frame_count = 0
try: try:
@ -400,7 +401,7 @@ def test_seek():
assert frame_count == 5 assert frame_count == 5
def test_seek_info(): def test_seek_info() -> None:
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()
@ -410,7 +411,7 @@ def test_seek_info():
assert im.info == info assert im.info == info
def test_seek_rewind(): def test_seek_rewind() -> None:
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)
@ -428,7 +429,7 @@ def test_seek_rewind():
("Tests/images/iss634.gif", 42), ("Tests/images/iss634.gif", 42),
), ),
) )
def test_n_frames(path, n_frames): def test_n_frames(path, n_frames) -> None:
# Test is_animated before n_frames # Test is_animated before n_frames
with Image.open(path) as im: with Image.open(path) as im:
assert im.is_animated == (n_frames != 1) assert im.is_animated == (n_frames != 1)
@ -439,7 +440,7 @@ def test_n_frames(path, n_frames):
assert im.is_animated == (n_frames != 1) assert im.is_animated == (n_frames != 1)
def test_no_change(): def test_no_change() -> None:
# Test n_frames does not change the image # Test n_frames does not change the image
with Image.open("Tests/images/dispose_bgnd.gif") as im: with Image.open("Tests/images/dispose_bgnd.gif") as im:
im.seek(1) im.seek(1)
@ -460,7 +461,7 @@ def test_no_change():
assert_image_equal(im, expected) assert_image_equal(im, expected)
def test_eoferror(): def test_eoferror() -> None:
with Image.open(TEST_GIF) as im: with Image.open(TEST_GIF) as im:
n_frames = im.n_frames n_frames = im.n_frames
@ -473,13 +474,13 @@ def test_eoferror():
im.seek(n_frames - 1) im.seek(n_frames - 1)
def test_first_frame_transparency(): def test_first_frame_transparency() -> None:
with Image.open("Tests/images/first_frame_transparency.gif") as im: with Image.open("Tests/images/first_frame_transparency.gif") as im:
px = im.load() px = im.load()
assert px[0, 0] == im.info["transparency"] assert px[0, 0] == im.info["transparency"]
def test_dispose_none(): def test_dispose_none() -> 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:
@ -489,7 +490,7 @@ def test_dispose_none():
pass pass
def test_dispose_none_load_end(): def test_dispose_none_load_end() -> None:
# Test image created with: # Test image created with:
# #
# im = Image.open("transparent.gif") # im = Image.open("transparent.gif")
@ -502,7 +503,7 @@ def test_dispose_none_load_end():
assert_image_equal_tofile(img, "Tests/images/dispose_none_load_end_second.png") assert_image_equal_tofile(img, "Tests/images/dispose_none_load_end_second.png")
def test_dispose_background(): def test_dispose_background() -> None:
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:
@ -512,7 +513,7 @@ def test_dispose_background():
pass pass
def test_dispose_background_transparency(): def test_dispose_background_transparency() -> None:
with Image.open("Tests/images/dispose_bgnd_transparency.gif") as img: with Image.open("Tests/images/dispose_bgnd_transparency.gif") as img:
img.seek(2) img.seek(2)
px = img.load() px = img.load()
@ -540,7 +541,7 @@ def test_dispose_background_transparency():
), ),
), ),
) )
def test_transparent_dispose(loading_strategy, expected_colors): def test_transparent_dispose(loading_strategy, expected_colors) -> None:
GifImagePlugin.LOADING_STRATEGY = loading_strategy GifImagePlugin.LOADING_STRATEGY = loading_strategy
try: try:
with Image.open("Tests/images/transparent_dispose.gif") as img: with Image.open("Tests/images/transparent_dispose.gif") as img:
@ -553,7 +554,7 @@ def test_transparent_dispose(loading_strategy, expected_colors):
GifImagePlugin.LOADING_STRATEGY = GifImagePlugin.LoadingStrategy.RGB_AFTER_FIRST GifImagePlugin.LOADING_STRATEGY = GifImagePlugin.LoadingStrategy.RGB_AFTER_FIRST
def test_dispose_previous(): def test_dispose_previous() -> None:
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:
@ -563,7 +564,7 @@ def test_dispose_previous():
pass pass
def test_dispose_previous_first_frame(): def test_dispose_previous_first_frame() -> None:
with Image.open("Tests/images/dispose_prev_first_frame.gif") as im: with Image.open("Tests/images/dispose_prev_first_frame.gif") as im:
im.seek(1) im.seek(1)
assert_image_equal_tofile( assert_image_equal_tofile(
@ -571,7 +572,7 @@ def test_dispose_previous_first_frame():
) )
def test_previous_frame_loaded(): def test_previous_frame_loaded() -> None:
with Image.open("Tests/images/dispose_none.gif") as img: with Image.open("Tests/images/dispose_none.gif") as img:
img.load() img.load()
img.seek(1) img.seek(1)
@ -582,7 +583,7 @@ def test_previous_frame_loaded():
assert_image_equal(img_skipped, img) assert_image_equal(img_skipped, img)
def test_save_dispose(tmp_path): def test_save_dispose(tmp_path: Path) -> None:
out = str(tmp_path / "temp.gif") out = str(tmp_path / "temp.gif")
im_list = [ im_list = [
Image.new("L", (100, 100), "#000"), Image.new("L", (100, 100), "#000"),
@ -610,7 +611,7 @@ def test_save_dispose(tmp_path):
assert img.disposal_method == i + 1 assert img.disposal_method == i + 1
def test_dispose2_palette(tmp_path): def test_dispose2_palette(tmp_path: Path) -> None:
out = str(tmp_path / "temp.gif") out = str(tmp_path / "temp.gif")
# Four colors: white, gray, black, red # Four colors: white, gray, black, red
@ -641,7 +642,7 @@ def test_dispose2_palette(tmp_path):
assert rgb_img.getpixel((50, 50)) == circle assert rgb_img.getpixel((50, 50)) == circle
def test_dispose2_diff(tmp_path): def test_dispose2_diff(tmp_path: Path) -> None:
out = str(tmp_path / "temp.gif") 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
@ -683,7 +684,7 @@ def test_dispose2_diff(tmp_path):
assert rgb_img.getpixel((1, 1)) == (255, 255, 255, 0) assert rgb_img.getpixel((1, 1)) == (255, 255, 255, 0)
def test_dispose2_background(tmp_path): def test_dispose2_background(tmp_path: Path) -> None:
out = str(tmp_path / "temp.gif") out = str(tmp_path / "temp.gif")
im_list = [] im_list = []
@ -709,7 +710,7 @@ def test_dispose2_background(tmp_path):
assert im.getpixel((0, 0)) == (255, 0, 0) assert im.getpixel((0, 0)) == (255, 0, 0)
def test_dispose2_background_frame(tmp_path): def test_dispose2_background_frame(tmp_path: Path) -> None:
out = str(tmp_path / "temp.gif") out = str(tmp_path / "temp.gif")
im_list = [Image.new("RGBA", (1, 20))] im_list = [Image.new("RGBA", (1, 20))]
@ -727,7 +728,7 @@ def test_dispose2_background_frame(tmp_path):
assert im.n_frames == 3 assert im.n_frames == 3
def test_transparency_in_second_frame(tmp_path): def test_transparency_in_second_frame(tmp_path: Path) -> None:
out = str(tmp_path / "temp.gif") out = str(tmp_path / "temp.gif")
with Image.open("Tests/images/different_transparency.gif") as im: with Image.open("Tests/images/different_transparency.gif") as im:
assert im.info["transparency"] == 0 assert im.info["transparency"] == 0
@ -747,7 +748,7 @@ def test_transparency_in_second_frame(tmp_path):
) )
def test_no_transparency_in_second_frame(): def test_no_transparency_in_second_frame() -> None:
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)
@ -757,7 +758,7 @@ def test_no_transparency_in_second_frame():
assert img.histogram()[255] == 0 assert img.histogram()[255] == 0
def test_remapped_transparency(tmp_path): def test_remapped_transparency(tmp_path: Path) -> None:
out = str(tmp_path / "temp.gif") out = str(tmp_path / "temp.gif")
im = Image.new("P", (1, 2)) im = Image.new("P", (1, 2))
@ -773,7 +774,7 @@ def test_remapped_transparency(tmp_path):
assert reloaded.info["transparency"] == reloaded.getpixel((0, 1)) assert reloaded.info["transparency"] == reloaded.getpixel((0, 1))
def test_duration(tmp_path): def test_duration(tmp_path: Path) -> None:
duration = 1000 duration = 1000
out = str(tmp_path / "temp.gif") out = str(tmp_path / "temp.gif")
@ -787,7 +788,7 @@ def test_duration(tmp_path):
assert reread.info["duration"] == duration assert reread.info["duration"] == duration
def test_multiple_duration(tmp_path): def test_multiple_duration(tmp_path: Path) -> None:
duration_list = [1000, 2000, 3000] duration_list = [1000, 2000, 3000]
out = str(tmp_path / "temp.gif") out = str(tmp_path / "temp.gif")
@ -822,7 +823,7 @@ def test_multiple_duration(tmp_path):
pass pass
def test_roundtrip_info_duration(tmp_path): def test_roundtrip_info_duration(tmp_path: Path) -> None:
duration_list = [100, 500, 500] duration_list = [100, 500, 500]
out = str(tmp_path / "temp.gif") out = str(tmp_path / "temp.gif")
@ -839,7 +840,7 @@ def test_roundtrip_info_duration(tmp_path):
] == duration_list ] == duration_list
def test_roundtrip_info_duration_combined(tmp_path): def test_roundtrip_info_duration_combined(tmp_path: Path) -> None:
out = str(tmp_path / "temp.gif") out = str(tmp_path / "temp.gif")
with Image.open("Tests/images/duplicate_frame.gif") as im: with Image.open("Tests/images/duplicate_frame.gif") as im:
assert [frame.info["duration"] for frame in ImageSequence.Iterator(im)] == [ assert [frame.info["duration"] for frame in ImageSequence.Iterator(im)] == [
@ -855,7 +856,7 @@ def test_roundtrip_info_duration_combined(tmp_path):
] == [1000, 2000] ] == [1000, 2000]
def test_identical_frames(tmp_path): def test_identical_frames(tmp_path: Path) -> None:
duration_list = [1000, 1500, 2000, 4000] duration_list = [1000, 1500, 2000, 4000]
out = str(tmp_path / "temp.gif") out = str(tmp_path / "temp.gif")
@ -888,7 +889,7 @@ def test_identical_frames(tmp_path):
1500, 1500,
), ),
) )
def test_identical_frames_to_single_frame(duration, tmp_path): def test_identical_frames_to_single_frame(duration, tmp_path: Path) -> None:
out = str(tmp_path / "temp.gif") out = str(tmp_path / "temp.gif")
im_list = [ im_list = [
Image.new("L", (100, 100), "#000"), Image.new("L", (100, 100), "#000"),
@ -905,7 +906,7 @@ def test_identical_frames_to_single_frame(duration, tmp_path):
assert reread.info["duration"] == 4500 assert reread.info["duration"] == 4500
def test_loop_none(tmp_path): def test_loop_none(tmp_path: Path) -> None:
out = str(tmp_path / "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=None) im.save(out, loop=None)
@ -913,7 +914,7 @@ def test_loop_none(tmp_path):
assert "loop" not in reread.info assert "loop" not in reread.info
def test_number_of_loops(tmp_path): def test_number_of_loops(tmp_path: Path) -> None:
number_of_loops = 2 number_of_loops = 2
out = str(tmp_path / "temp.gif") out = str(tmp_path / "temp.gif")
@ -931,7 +932,7 @@ def test_number_of_loops(tmp_path):
assert im.info["loop"] == 2 assert im.info["loop"] == 2
def test_background(tmp_path): def test_background(tmp_path: Path) -> None:
out = str(tmp_path / "temp.gif") 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
@ -940,7 +941,7 @@ def test_background(tmp_path):
assert reread.info["background"] == im.info["background"] assert reread.info["background"] == im.info["background"]
def test_webp_background(tmp_path): def test_webp_background(tmp_path: Path) -> None:
out = str(tmp_path / "temp.gif") out = str(tmp_path / "temp.gif")
# Test opaque WebP background # Test opaque WebP background
@ -955,7 +956,7 @@ def test_webp_background(tmp_path):
im.save(out) im.save(out)
def test_comment(tmp_path): def test_comment(tmp_path: Path) -> None:
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"
@ -975,7 +976,7 @@ def test_comment(tmp_path):
assert reread.info["version"] == b"GIF89a" assert reread.info["version"] == b"GIF89a"
def test_comment_over_255(tmp_path): def test_comment_over_255(tmp_path: Path) -> None:
out = str(tmp_path / "temp.gif") 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"
@ -990,18 +991,18 @@ def test_comment_over_255(tmp_path):
assert reread.info["version"] == b"GIF89a" assert reread.info["version"] == b"GIF89a"
def test_zero_comment_subblocks(): def test_zero_comment_subblocks() -> None:
with Image.open("Tests/images/hopper_zero_comment_subblocks.gif") as im: with Image.open("Tests/images/hopper_zero_comment_subblocks.gif") as im:
assert_image_equal_tofile(im, TEST_GIF) assert_image_equal_tofile(im, TEST_GIF)
def test_read_multiple_comment_blocks(): def test_read_multiple_comment_blocks() -> None:
with Image.open("Tests/images/multiple_comments.gif") as im: with Image.open("Tests/images/multiple_comments.gif") as im:
# Multiple comment blocks in a frame are separated not concatenated # Multiple comment blocks in a frame are separated not concatenated
assert im.info["comment"] == b"Test comment 1\nTest comment 2" assert im.info["comment"] == b"Test comment 1\nTest comment 2"
def test_empty_string_comment(tmp_path): def test_empty_string_comment(tmp_path: Path) -> None:
out = str(tmp_path / "temp.gif") out = str(tmp_path / "temp.gif")
with Image.open("Tests/images/chi.gif") as im: with Image.open("Tests/images/chi.gif") as im:
assert "comment" in im.info assert "comment" in im.info
@ -1014,7 +1015,7 @@ def test_empty_string_comment(tmp_path):
assert "comment" not in frame.info assert "comment" not in frame.info
def test_retain_comment_in_subsequent_frames(tmp_path): def test_retain_comment_in_subsequent_frames(tmp_path: Path) -> None:
# Test that a comment block at the beginning is kept # Test that a comment block at the beginning is kept
with Image.open("Tests/images/chi.gif") as im: with Image.open("Tests/images/chi.gif") as im:
for frame in ImageSequence.Iterator(im): for frame in ImageSequence.Iterator(im):
@ -1045,10 +1046,10 @@ def test_retain_comment_in_subsequent_frames(tmp_path):
assert frame.info["comment"] == b"Test" assert frame.info["comment"] == b"Test"
def test_version(tmp_path): def test_version(tmp_path: Path) -> None:
out = str(tmp_path / "temp.gif") out = str(tmp_path / "temp.gif")
def assert_version_after_save(im, version): def assert_version_after_save(im, version) -> None:
im.save(out) im.save(out)
with Image.open(out) as reread: with Image.open(out) as reread:
assert reread.info["version"] == version assert reread.info["version"] == version
@ -1075,7 +1076,7 @@ def test_version(tmp_path):
assert_version_after_save(im, b"GIF87a") assert_version_after_save(im, b"GIF87a")
def test_append_images(tmp_path): def test_append_images(tmp_path: Path) -> None:
out = str(tmp_path / "temp.gif") out = str(tmp_path / "temp.gif")
# Test appending single frame images # Test appending single frame images
@ -1104,7 +1105,7 @@ def test_append_images(tmp_path):
assert reread.n_frames == 10 assert reread.n_frames == 10
def test_transparent_optimize(tmp_path): def test_transparent_optimize(tmp_path: Path) -> None:
# From issue #2195, if the transparent color is incorrectly optimized out, GIF loses # From issue #2195, if the transparent color is incorrectly optimized out, GIF loses
# transparency. # transparency.
# Need a palette that isn't using the 0 color, # Need a palette that isn't using the 0 color,
@ -1124,7 +1125,7 @@ def test_transparent_optimize(tmp_path):
assert reloaded.info["transparency"] == reloaded.getpixel((252, 0)) assert reloaded.info["transparency"] == reloaded.getpixel((252, 0))
def test_removed_transparency(tmp_path): def test_removed_transparency(tmp_path: Path) -> None:
out = str(tmp_path / "temp.gif") out = str(tmp_path / "temp.gif")
im = Image.new("RGB", (256, 1)) im = Image.new("RGB", (256, 1))
@ -1139,7 +1140,7 @@ def test_removed_transparency(tmp_path):
assert "transparency" not in reloaded.info assert "transparency" not in reloaded.info
def test_rgb_transparency(tmp_path): def test_rgb_transparency(tmp_path: Path) -> None:
out = str(tmp_path / "temp.gif") out = str(tmp_path / "temp.gif")
# Single frame # Single frame
@ -1161,7 +1162,7 @@ def test_rgb_transparency(tmp_path):
assert "transparency" not in reloaded.info assert "transparency" not in reloaded.info
def test_rgba_transparency(tmp_path): def test_rgba_transparency(tmp_path: Path) -> None:
out = str(tmp_path / "temp.gif") out = str(tmp_path / "temp.gif")
im = hopper("P") im = hopper("P")
@ -1172,13 +1173,13 @@ def test_rgba_transparency(tmp_path):
assert_image_equal(hopper("P").convert("RGB"), reloaded) assert_image_equal(hopper("P").convert("RGB"), reloaded)
def test_background_outside_palettte(tmp_path): def test_background_outside_palettte(tmp_path: Path) -> None:
with Image.open("Tests/images/background_outside_palette.gif") as im: with Image.open("Tests/images/background_outside_palette.gif") as im:
im.seek(1) im.seek(1)
assert im.info["background"] == 255 assert im.info["background"] == 255
def test_bbox(tmp_path): def test_bbox(tmp_path: Path) -> None:
out = str(tmp_path / "temp.gif") out = str(tmp_path / "temp.gif")
im = Image.new("RGB", (100, 100), "#fff") im = Image.new("RGB", (100, 100), "#fff")
@ -1189,7 +1190,7 @@ def test_bbox(tmp_path):
assert reread.n_frames == 2 assert reread.n_frames == 2
def test_bbox_alpha(tmp_path): def test_bbox_alpha(tmp_path: Path) -> None:
out = str(tmp_path / "temp.gif") out = str(tmp_path / "temp.gif")
im = Image.new("RGBA", (1, 2), (255, 0, 0, 255)) im = Image.new("RGBA", (1, 2), (255, 0, 0, 255))
@ -1201,7 +1202,7 @@ def test_bbox_alpha(tmp_path):
assert reread.n_frames == 2 assert reread.n_frames == 2
def test_palette_save_L(tmp_path): def test_palette_save_L(tmp_path: Path) -> None:
# Generate an L mode image with a separate palette # Generate an L mode image with a separate palette
im = hopper("P") im = hopper("P")
@ -1215,7 +1216,7 @@ def test_palette_save_L(tmp_path):
assert_image_equal(reloaded.convert("RGB"), im.convert("RGB")) assert_image_equal(reloaded.convert("RGB"), im.convert("RGB"))
def test_palette_save_P(tmp_path): def test_palette_save_P(tmp_path: Path) -> None:
im = Image.new("P", (1, 2)) im = Image.new("P", (1, 2))
im.putpixel((0, 1), 1) im.putpixel((0, 1), 1)
@ -1229,7 +1230,7 @@ def test_palette_save_P(tmp_path):
assert reloaded_rgb.getpixel((0, 1)) == (4, 5, 6) assert reloaded_rgb.getpixel((0, 1)) == (4, 5, 6)
def test_palette_save_duplicate_entries(tmp_path): def test_palette_save_duplicate_entries(tmp_path: Path) -> None:
im = Image.new("P", (1, 2)) im = Image.new("P", (1, 2))
im.putpixel((0, 1), 1) im.putpixel((0, 1), 1)
@ -1242,7 +1243,7 @@ def test_palette_save_duplicate_entries(tmp_path):
assert reloaded.convert("RGB").getpixel((0, 1)) == (0, 0, 0) assert reloaded.convert("RGB").getpixel((0, 1)) == (0, 0, 0)
def test_palette_save_all_P(tmp_path): def test_palette_save_all_P(tmp_path: Path) -> None:
frames = [] frames = []
colors = ((255, 0, 0), (0, 255, 0)) colors = ((255, 0, 0), (0, 255, 0))
for color in colors: for color in colors:
@ -1265,7 +1266,7 @@ def test_palette_save_all_P(tmp_path):
assert im.palette.palette == im.global_palette.palette assert im.palette.palette == im.global_palette.palette
def test_palette_save_ImagePalette(tmp_path): def test_palette_save_ImagePalette(tmp_path: Path) -> None:
# Pass in a different palette, as an ImagePalette.ImagePalette # 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
@ -1280,7 +1281,7 @@ def test_palette_save_ImagePalette(tmp_path):
assert_image_equal(reloaded.convert("RGB"), im.convert("RGB")) assert_image_equal(reloaded.convert("RGB"), im.convert("RGB"))
def test_save_I(tmp_path): def test_save_I(tmp_path: Path) -> None:
# 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")
@ -1292,7 +1293,7 @@ def test_save_I(tmp_path):
assert_image_equal(reloaded.convert("L"), im.convert("L")) assert_image_equal(reloaded.convert("L"), im.convert("L"))
def test_getdata(): def test_getdata() -> None:
# Test getheader/getdata against legacy values. # Test getheader/getdata against legacy values.
# Create a 'P' image with holes in the palette. # Create a 'P' image with holes in the palette.
im = Image._wedge().resize((16, 16), Image.Resampling.NEAREST) im = Image._wedge().resize((16, 16), Image.Resampling.NEAREST)
@ -1320,7 +1321,7 @@ def test_getdata():
GifImagePlugin._FORCE_OPTIMIZE = False GifImagePlugin._FORCE_OPTIMIZE = False
def test_lzw_bits(): def test_lzw_bits() -> None:
# 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
@ -1328,7 +1329,7 @@ def test_lzw_bits():
im.load() im.load()
def test_extents(): def test_extents() -> None:
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)
@ -1340,7 +1341,7 @@ def test_extents():
assert im.size == (150, 150) assert im.size == (150, 150)
def test_missing_background(): def test_missing_background() -> None:
# The Global Color Table Flag isn't set, so there is no background color index, # The Global Color Table Flag isn't set, so there is no background color index,
# but the disposal method is "Restore to background color" # but the disposal method is "Restore to background color"
with Image.open("Tests/images/missing_background.gif") as im: with Image.open("Tests/images/missing_background.gif") as im:
@ -1348,7 +1349,7 @@ def test_missing_background():
assert_image_equal_tofile(im, "Tests/images/missing_background_first_frame.png") assert_image_equal_tofile(im, "Tests/images/missing_background_first_frame.png")
def test_saving_rgba(tmp_path): def test_saving_rgba(tmp_path: Path) -> None:
out = str(tmp_path / "temp.gif") out = str(tmp_path / "temp.gif")
with Image.open("Tests/images/transparent.png") as im: with Image.open("Tests/images/transparent.png") as im:
im.save(out) im.save(out)

View File

@ -3,7 +3,7 @@ from __future__ import annotations
from PIL import GimpGradientFile, ImagePalette from PIL import GimpGradientFile, ImagePalette
def test_linear_pos_le_middle(): def test_linear_pos_le_middle() -> None:
# Arrange # Arrange
middle = 0.5 middle = 0.5
pos = 0.25 pos = 0.25
@ -15,7 +15,7 @@ def test_linear_pos_le_middle():
assert ret == 0.25 assert ret == 0.25
def test_linear_pos_le_small_middle(): def test_linear_pos_le_small_middle() -> None:
# Arrange # Arrange
middle = 1e-11 middle = 1e-11
pos = 1e-12 pos = 1e-12
@ -27,7 +27,7 @@ def test_linear_pos_le_small_middle():
assert ret == 0.0 assert ret == 0.0
def test_linear_pos_gt_middle(): def test_linear_pos_gt_middle() -> None:
# Arrange # Arrange
middle = 0.5 middle = 0.5
pos = 0.75 pos = 0.75
@ -39,7 +39,7 @@ def test_linear_pos_gt_middle():
assert ret == 0.75 assert ret == 0.75
def test_linear_pos_gt_small_middle(): def test_linear_pos_gt_small_middle() -> None:
# Arrange # Arrange
middle = 1 - 1e-11 middle = 1 - 1e-11
pos = 1 - 1e-12 pos = 1 - 1e-12
@ -51,7 +51,7 @@ def test_linear_pos_gt_small_middle():
assert ret == 1.0 assert ret == 1.0
def test_curved(): def test_curved() -> None:
# Arrange # Arrange
middle = 0.5 middle = 0.5
pos = 0.75 pos = 0.75
@ -63,7 +63,7 @@ def test_curved():
assert ret == 0.75 assert ret == 0.75
def test_sine(): def test_sine() -> None:
# Arrange # Arrange
middle = 0.5 middle = 0.5
pos = 0.75 pos = 0.75
@ -75,7 +75,7 @@ def test_sine():
assert ret == 0.8535533905932737 assert ret == 0.8535533905932737
def test_sphere_increasing(): def test_sphere_increasing() -> None:
# Arrange # Arrange
middle = 0.5 middle = 0.5
pos = 0.75 pos = 0.75
@ -87,7 +87,7 @@ def test_sphere_increasing():
assert round(abs(ret - 0.9682458365518543), 7) == 0 assert round(abs(ret - 0.9682458365518543), 7) == 0
def test_sphere_decreasing(): def test_sphere_decreasing() -> None:
# Arrange # Arrange
middle = 0.5 middle = 0.5
pos = 0.75 pos = 0.75
@ -99,7 +99,7 @@ def test_sphere_decreasing():
assert ret == 0.3385621722338523 assert ret == 0.3385621722338523
def test_load_via_imagepalette(): def test_load_via_imagepalette() -> None:
# Arrange # Arrange
test_file = "Tests/images/gimp_gradient.ggr" test_file = "Tests/images/gimp_gradient.ggr"
@ -112,7 +112,7 @@ def test_load_via_imagepalette():
assert palette[1] == "RGBA" assert palette[1] == "RGBA"
def test_load_1_3_via_imagepalette(): def test_load_1_3_via_imagepalette() -> None:
# Arrange # Arrange
# GIMP 1.3 gradient files contain a name field # GIMP 1.3 gradient files contain a name field
test_file = "Tests/images/gimp_gradient_with_name.ggr" test_file = "Tests/images/gimp_gradient_with_name.ggr"

View File

@ -1,5 +1,7 @@
from __future__ import annotations from __future__ import annotations
from pathlib import Path
import pytest import pytest
from PIL import GribStubImagePlugin, Image from PIL import GribStubImagePlugin, Image
@ -9,7 +11,7 @@ from .helper import hopper
TEST_FILE = "Tests/images/WAlaska.wind.7days.grb" TEST_FILE = "Tests/images/WAlaska.wind.7days.grb"
def test_open(): def test_open() -> None:
# Act # Act
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
# Assert # Assert
@ -20,7 +22,7 @@ def test_open():
assert im.size == (1, 1) assert im.size == (1, 1)
def test_invalid_file(): def test_invalid_file() -> None:
# Arrange # Arrange
invalid_file = "Tests/images/flower.jpg" invalid_file = "Tests/images/flower.jpg"
@ -29,7 +31,7 @@ def test_invalid_file():
GribStubImagePlugin.GribStubImageFile(invalid_file) GribStubImagePlugin.GribStubImageFile(invalid_file)
def test_load(): def test_load() -> None:
# Arrange # Arrange
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
# Act / Assert: stub cannot load without an implemented handler # Act / Assert: stub cannot load without an implemented handler
@ -37,7 +39,7 @@ def test_load():
im.load() im.load()
def test_save(tmp_path): def test_save(tmp_path: Path) -> None:
# Arrange # Arrange
im = hopper() im = hopper()
tmpfile = str(tmp_path / "temp.grib") tmpfile = str(tmp_path / "temp.grib")
@ -47,13 +49,13 @@ def test_save(tmp_path):
im.save(tmpfile) im.save(tmpfile)
def test_handler(tmp_path): def test_handler(tmp_path: Path) -> None:
class TestHandler: class TestHandler:
opened = False opened = False
loaded = False loaded = False
saved = False saved = False
def open(self, im): def open(self, im) -> None:
self.opened = True self.opened = True
def load(self, im): def load(self, im):
@ -61,7 +63,7 @@ def test_handler(tmp_path):
im.fp.close() im.fp.close()
return Image.new("RGB", (1, 1)) return Image.new("RGB", (1, 1))
def save(self, im, fp, filename): def save(self, im, fp, filename) -> None:
self.saved = True self.saved = True
handler = TestHandler() handler = TestHandler()

View File

@ -1,5 +1,7 @@
from __future__ import annotations from __future__ import annotations
from pathlib import Path
import pytest import pytest
from PIL import Hdf5StubImagePlugin, Image from PIL import Hdf5StubImagePlugin, Image
@ -7,7 +9,7 @@ from PIL import Hdf5StubImagePlugin, Image
TEST_FILE = "Tests/images/hdf5.h5" TEST_FILE = "Tests/images/hdf5.h5"
def test_open(): def test_open() -> None:
# Act # Act
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
# Assert # Assert
@ -18,7 +20,7 @@ def test_open():
assert im.size == (1, 1) assert im.size == (1, 1)
def test_invalid_file(): def test_invalid_file() -> None:
# Arrange # Arrange
invalid_file = "Tests/images/flower.jpg" invalid_file = "Tests/images/flower.jpg"
@ -27,7 +29,7 @@ def test_invalid_file():
Hdf5StubImagePlugin.HDF5StubImageFile(invalid_file) Hdf5StubImagePlugin.HDF5StubImageFile(invalid_file)
def test_load(): def test_load() -> None:
# Arrange # Arrange
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
# Act / Assert: stub cannot load without an implemented handler # Act / Assert: stub cannot load without an implemented handler
@ -35,7 +37,7 @@ def test_load():
im.load() im.load()
def test_save(): def test_save() -> None:
# Arrange # Arrange
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
dummy_fp = None dummy_fp = None
@ -48,13 +50,13 @@ def test_save():
Hdf5StubImagePlugin._save(im, dummy_fp, dummy_filename) Hdf5StubImagePlugin._save(im, dummy_fp, dummy_filename)
def test_handler(tmp_path): def test_handler(tmp_path: Path) -> None:
class TestHandler: class TestHandler:
opened = False opened = False
loaded = False loaded = False
saved = False saved = False
def open(self, im): def open(self, im) -> None:
self.opened = True self.opened = True
def load(self, im): def load(self, im):
@ -62,7 +64,7 @@ def test_handler(tmp_path):
im.fp.close() im.fp.close()
return Image.new("RGB", (1, 1)) return Image.new("RGB", (1, 1))
def save(self, im, fp, filename): def save(self, im, fp, filename) -> None:
self.saved = True self.saved = True
handler = TestHandler() handler = TestHandler()

View File

@ -3,6 +3,7 @@ from __future__ import annotations
import io import io
import os import os
import warnings import warnings
from pathlib import Path
import pytest import pytest
@ -14,7 +15,7 @@ from .helper import assert_image_equal, assert_image_similar_tofile, skip_unless
TEST_FILE = "Tests/images/pillow.icns" TEST_FILE = "Tests/images/pillow.icns"
def test_sanity(): def test_sanity() -> None:
# 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:
@ -27,7 +28,7 @@ def test_sanity():
assert im.format == "ICNS" assert im.format == "ICNS"
def test_load(): def test_load() -> None:
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
assert im.load()[0, 0] == (0, 0, 0, 0) assert im.load()[0, 0] == (0, 0, 0, 0)
@ -35,7 +36,7 @@ def test_load():
assert im.load()[0, 0] == (0, 0, 0, 0) assert im.load()[0, 0] == (0, 0, 0, 0)
def test_save(tmp_path): def test_save(tmp_path: Path) -> None:
temp_file = str(tmp_path / "temp.icns") temp_file = str(tmp_path / "temp.icns")
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
@ -52,7 +53,7 @@ def test_save(tmp_path):
assert _binary.i32be(fp.read(4)) == file_length assert _binary.i32be(fp.read(4)) == file_length
def test_save_append_images(tmp_path): def test_save_append_images(tmp_path: Path) -> None:
temp_file = str(tmp_path / "temp.icns") 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))
@ -67,7 +68,7 @@ def test_save_append_images(tmp_path):
assert_image_equal(reread, provided_im) assert_image_equal(reread, provided_im)
def test_save_fp(): def test_save_fp() -> None:
fp = io.BytesIO() fp = io.BytesIO()
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
@ -79,7 +80,7 @@ def test_save_fp():
assert reread.format == "ICNS" assert reread.format == "ICNS"
def test_sizes(): def test_sizes() -> None:
# 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:
@ -96,7 +97,7 @@ def test_sizes():
im.size = (1, 1) im.size = (1, 1)
def test_older_icon(): def test_older_icon() -> None:
# 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:
@ -111,7 +112,7 @@ def test_older_icon():
@skip_unless_feature("jpg_2000") @skip_unless_feature("jpg_2000")
def test_jp2_icon(): def test_jp2_icon() -> None:
# This icon uses JPEG 2000 images instead of the PNG images. # This icon uses JPEG 2000 images instead of the PNG images.
# The advantage of doing this is that OS X 10.5 supports JPEG 2000 # The advantage of doing this is that OS X 10.5 supports JPEG 2000
# but not PNG; some commercial software therefore does just this. # but not PNG; some commercial software therefore does just this.
@ -127,7 +128,7 @@ def test_jp2_icon():
assert im2.size == (wr, hr) assert im2.size == (wr, hr)
def test_getimage(): def test_getimage() -> None:
with open(TEST_FILE, "rb") as fp: with open(TEST_FILE, "rb") as fp:
icns_file = IcnsImagePlugin.IcnsFile(fp) icns_file = IcnsImagePlugin.IcnsFile(fp)
@ -140,14 +141,14 @@ def test_getimage():
assert im.size == (512, 512) assert im.size == (512, 512)
def test_not_an_icns_file(): def test_not_an_icns_file() -> None:
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)
@skip_unless_feature("jpg_2000") @skip_unless_feature("jpg_2000")
def test_icns_decompression_bomb(): def test_icns_decompression_bomb() -> None:
with Image.open( with Image.open(
"Tests/images/oom-8ed3316a4109213ca96fb8a256a0bfefdece1461.icns" "Tests/images/oom-8ed3316a4109213ca96fb8a256a0bfefdece1461.icns"
) as im: ) as im:

View File

@ -2,6 +2,7 @@ from __future__ import annotations
import io import io
import os import os
from pathlib import Path
import pytest import pytest
@ -12,7 +13,7 @@ from .helper import assert_image_equal, assert_image_equal_tofile, hopper
TEST_ICO_FILE = "Tests/images/hopper.ico" TEST_ICO_FILE = "Tests/images/hopper.ico"
def test_sanity(): def test_sanity() -> None:
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"
@ -21,29 +22,29 @@ def test_sanity():
assert im.get_format_mimetype() == "image/x-icon" assert im.get_format_mimetype() == "image/x-icon"
def test_load(): def test_load() -> None:
with Image.open(TEST_ICO_FILE) as im: with Image.open(TEST_ICO_FILE) as im:
assert im.load()[0, 0] == (1, 1, 9, 255) assert im.load()[0, 0] == (1, 1, 9, 255)
def test_mask(): def test_mask() -> None:
with Image.open("Tests/images/hopper_mask.ico") as im: with Image.open("Tests/images/hopper_mask.ico") as im:
assert_image_equal_tofile(im, "Tests/images/hopper_mask.png") assert_image_equal_tofile(im, "Tests/images/hopper_mask.png")
def test_black_and_white(): def test_black_and_white() -> None:
with Image.open("Tests/images/black_and_white.ico") as im: with Image.open("Tests/images/black_and_white.ico") as im:
assert im.mode == "RGBA" assert im.mode == "RGBA"
assert im.size == (16, 16) assert im.size == (16, 16)
def test_invalid_file(): def test_invalid_file() -> None:
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(): def test_save_to_bytes() -> None:
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)])
@ -73,7 +74,7 @@ def test_save_to_bytes():
) )
def test_getpixel(tmp_path): def test_getpixel(tmp_path: Path) -> None:
temp_file = str(tmp_path / "temp.ico") temp_file = str(tmp_path / "temp.ico")
im = hopper() im = hopper()
@ -86,7 +87,7 @@ def test_getpixel(tmp_path):
assert reloaded.getpixel((0, 0)) == (18, 20, 62) assert reloaded.getpixel((0, 0)) == (18, 20, 62)
def test_no_duplicates(tmp_path): def test_no_duplicates(tmp_path: Path) -> None:
temp_file = str(tmp_path / "temp.ico") temp_file = str(tmp_path / "temp.ico")
temp_file2 = str(tmp_path / "temp2.ico") temp_file2 = str(tmp_path / "temp2.ico")
@ -100,7 +101,7 @@ def test_no_duplicates(tmp_path):
assert os.path.getsize(temp_file) == os.path.getsize(temp_file2) assert os.path.getsize(temp_file) == os.path.getsize(temp_file2)
def test_different_bit_depths(tmp_path): def test_different_bit_depths(tmp_path: Path) -> None:
temp_file = str(tmp_path / "temp.ico") temp_file = str(tmp_path / "temp.ico")
temp_file2 = str(tmp_path / "temp2.ico") temp_file2 = str(tmp_path / "temp2.ico")
@ -134,7 +135,7 @@ def test_different_bit_depths(tmp_path):
@pytest.mark.parametrize("mode", ("1", "L", "P", "RGB", "RGBA")) @pytest.mark.parametrize("mode", ("1", "L", "P", "RGB", "RGBA"))
def test_save_to_bytes_bmp(mode): def test_save_to_bytes_bmp(mode) -> None:
output = io.BytesIO() output = io.BytesIO()
im = hopper(mode) im = hopper(mode)
im.save(output, "ico", bitmap_format="bmp", sizes=[(32, 32), (64, 64)]) im.save(output, "ico", bitmap_format="bmp", sizes=[(32, 32), (64, 64)])
@ -162,13 +163,13 @@ def test_save_to_bytes_bmp(mode):
assert_image_equal(reloaded, im) assert_image_equal(reloaded, im)
def test_incorrect_size(): def test_incorrect_size() -> None:
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(tmp_path): def test_save_256x256(tmp_path: Path) -> None:
"""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:
@ -181,7 +182,7 @@ def test_save_256x256(tmp_path):
assert im_saved.size == (256, 256) assert im_saved.size == (256, 256)
def test_only_save_relevant_sizes(tmp_path): def test_only_save_relevant_sizes(tmp_path: Path) -> None:
"""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
@ -197,7 +198,7 @@ def test_only_save_relevant_sizes(tmp_path):
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_save_append_images(tmp_path): def test_save_append_images(tmp_path: Path) -> None:
# append_images should be used for scaled down versions of the image # append_images should be used for scaled down versions of the image
im = hopper("RGBA") im = hopper("RGBA")
provided_im = Image.new("RGBA", (32, 32), (255, 0, 0)) provided_im = Image.new("RGBA", (32, 32), (255, 0, 0))
@ -211,7 +212,7 @@ def test_save_append_images(tmp_path):
assert_image_equal(reread, provided_im) assert_image_equal(reread, provided_im)
def test_unexpected_size(): def test_unexpected_size() -> None:
# 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
with pytest.warns(UserWarning): with pytest.warns(UserWarning):
@ -219,7 +220,7 @@ def test_unexpected_size():
assert im.size == (16, 16) assert im.size == (16, 16)
def test_draw_reloaded(tmp_path): def test_draw_reloaded(tmp_path: Path) -> None:
with Image.open(TEST_ICO_FILE) as im: with Image.open(TEST_ICO_FILE) as im:
outfile = str(tmp_path / "temp_saved_hopper_draw.ico") outfile = str(tmp_path / "temp_saved_hopper_draw.ico")

View File

@ -2,6 +2,7 @@ from __future__ import annotations
import filecmp import filecmp
import warnings import warnings
from pathlib import Path
import pytest import pytest
@ -13,7 +14,7 @@ from .helper import assert_image_equal_tofile, hopper, is_pypy
TEST_IM = "Tests/images/hopper.im" TEST_IM = "Tests/images/hopper.im"
def test_sanity(): def test_sanity() -> None:
with Image.open(TEST_IM) as im: with Image.open(TEST_IM) as im:
im.load() im.load()
assert im.mode == "RGB" assert im.mode == "RGB"
@ -21,7 +22,7 @@ def test_sanity():
assert im.format == "IM" assert im.format == "IM"
def test_name_limit(tmp_path): def test_name_limit(tmp_path: Path) -> None:
out = str(tmp_path / ("name_limit_test" * 7 + ".im")) out = str(tmp_path / ("name_limit_test" * 7 + ".im"))
with Image.open(TEST_IM) as im: with Image.open(TEST_IM) as im:
im.save(out) im.save(out)
@ -29,8 +30,8 @@ def test_name_limit(tmp_path):
@pytest.mark.skipif(is_pypy(), reason="Requires CPython") @pytest.mark.skipif(is_pypy(), reason="Requires CPython")
def test_unclosed_file(): def test_unclosed_file() -> None:
def open(): def open() -> None:
im = Image.open(TEST_IM) im = Image.open(TEST_IM)
im.load() im.load()
@ -38,20 +39,20 @@ def test_unclosed_file():
open() open()
def test_closed_file(): def test_closed_file() -> None:
with warnings.catch_warnings(): with warnings.catch_warnings():
im = Image.open(TEST_IM) im = Image.open(TEST_IM)
im.load() im.load()
im.close() im.close()
def test_context_manager(): def test_context_manager() -> None:
with warnings.catch_warnings(): with warnings.catch_warnings():
with Image.open(TEST_IM) as im: with Image.open(TEST_IM) as im:
im.load() im.load()
def test_tell(): def test_tell() -> None:
# Arrange # Arrange
with Image.open(TEST_IM) as im: with Image.open(TEST_IM) as im:
# Act # Act
@ -61,13 +62,13 @@ def test_tell():
assert frame == 0 assert frame == 0
def test_n_frames(): def test_n_frames() -> None:
with Image.open(TEST_IM) as im: with Image.open(TEST_IM) as im:
assert im.n_frames == 1 assert im.n_frames == 1
assert not im.is_animated assert not im.is_animated
def test_eoferror(): def test_eoferror() -> None:
with Image.open(TEST_IM) as im: with Image.open(TEST_IM) as im:
n_frames = im.n_frames n_frames = im.n_frames
@ -81,14 +82,14 @@ def test_eoferror():
@pytest.mark.parametrize("mode", ("RGB", "P", "PA")) @pytest.mark.parametrize("mode", ("RGB", "P", "PA"))
def test_roundtrip(mode, tmp_path): def test_roundtrip(mode, tmp_path: Path) -> None:
out = str(tmp_path / "temp.im") out = str(tmp_path / "temp.im")
im = hopper(mode) im = hopper(mode)
im.save(out) im.save(out)
assert_image_equal_tofile(im, out) assert_image_equal_tofile(im, out)
def test_small_palette(tmp_path): def test_small_palette(tmp_path: Path) -> None:
im = Image.new("P", (1, 1)) im = Image.new("P", (1, 1))
colors = [0, 1, 2] colors = [0, 1, 2]
im.putpalette(colors) im.putpalette(colors)
@ -100,19 +101,19 @@ def test_small_palette(tmp_path):
assert reloaded.getpalette() == colors + [0] * 765 assert reloaded.getpalette() == colors + [0] * 765
def test_save_unsupported_mode(tmp_path): def test_save_unsupported_mode(tmp_path: Path) -> None:
out = str(tmp_path / "temp.im") out = str(tmp_path / "temp.im")
im = hopper("HSV") im = hopper("HSV")
with pytest.raises(ValueError): with pytest.raises(ValueError):
im.save(out) im.save(out)
def test_invalid_file(): def test_invalid_file() -> None:
invalid_file = "Tests/images/flower.jpg" invalid_file = "Tests/images/flower.jpg"
with pytest.raises(SyntaxError): with pytest.raises(SyntaxError):
ImImagePlugin.ImImageFile(invalid_file) ImImagePlugin.ImImageFile(invalid_file)
def test_number(): def test_number() -> None:
assert ImImagePlugin.number("1.2") == 1.2 assert ImImagePlugin.number("1.2") == 1.2

View File

@ -12,7 +12,7 @@ from .helper import assert_image_equal, hopper
TEST_FILE = "Tests/images/iptc.jpg" TEST_FILE = "Tests/images/iptc.jpg"
def test_open(): def test_open() -> None:
expected = Image.new("L", (1, 1)) expected = Image.new("L", (1, 1))
f = BytesIO( f = BytesIO(
@ -24,7 +24,7 @@ def test_open():
assert_image_equal(im, expected) assert_image_equal(im, expected)
def test_getiptcinfo_jpg_none(): def test_getiptcinfo_jpg_none() -> None:
# Arrange # Arrange
with hopper() as im: with hopper() as im:
# Act # Act
@ -34,7 +34,7 @@ def test_getiptcinfo_jpg_none():
assert iptc is None assert iptc is None
def test_getiptcinfo_jpg_found(): def test_getiptcinfo_jpg_found() -> None:
# Arrange # Arrange
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
# Act # Act
@ -46,7 +46,7 @@ def test_getiptcinfo_jpg_found():
assert iptc[(2, 101)] == b"Hungary" assert iptc[(2, 101)] == b"Hungary"
def test_getiptcinfo_fotostation(): def test_getiptcinfo_fotostation() -> None:
# Arrange # Arrange
with open(TEST_FILE, "rb") as fp: with open(TEST_FILE, "rb") as fp:
data = bytearray(fp.read()) data = bytearray(fp.read())
@ -63,7 +63,7 @@ def test_getiptcinfo_fotostation():
pytest.fail("FotoStation tag not found") pytest.fail("FotoStation tag not found")
def test_getiptcinfo_zero_padding(): def test_getiptcinfo_zero_padding() -> None:
# Arrange # Arrange
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
im.info["photoshop"][0x0404] += b"\x00\x00\x00" im.info["photoshop"][0x0404] += b"\x00\x00\x00"
@ -76,7 +76,7 @@ def test_getiptcinfo_zero_padding():
assert len(iptc) == 3 assert len(iptc) == 3
def test_getiptcinfo_tiff_none(): def test_getiptcinfo_tiff_none() -> None:
# Arrange # Arrange
with Image.open("Tests/images/hopper.tif") as im: with Image.open("Tests/images/hopper.tif") as im:
# Act # Act
@ -86,7 +86,7 @@ def test_getiptcinfo_tiff_none():
assert iptc is None assert iptc is None
def test_i(): def test_i() -> None:
# Arrange # Arrange
c = b"a" c = b"a"
@ -98,7 +98,7 @@ def test_i():
assert ret == 97 assert ret == 97
def test_dump(monkeypatch): def test_dump(monkeypatch) -> None:
# Arrange # Arrange
c = b"abc" c = b"abc"
# Temporarily redirect stdout # Temporarily redirect stdout
@ -113,6 +113,6 @@ def test_dump(monkeypatch):
assert mystdout.getvalue() == "61 62 63 \n" assert mystdout.getvalue() == "61 62 63 \n"
def test_pad_deprecation(): def test_pad_deprecation() -> None:
with pytest.warns(DeprecationWarning): with pytest.warns(DeprecationWarning):
assert IptcImagePlugin.PAD == b"\0\0\0\0" assert IptcImagePlugin.PAD == b"\0\0\0\0"

View File

@ -4,6 +4,7 @@ import os
import re import re
import warnings import warnings
from io import BytesIO from io import BytesIO
from pathlib import Path
import pytest import pytest
@ -50,7 +51,7 @@ class TestFileJpeg:
im.bytes = test_bytes # for testing only im.bytes = test_bytes # for testing only
return im return im
def gen_random_image(self, size, mode="RGB"): def gen_random_image(self, size, mode: str = "RGB"):
"""Generates a very hard to compress file """Generates a very hard to compress file
:param size: tuple :param size: tuple
:param mode: optional image mode :param mode: optional image mode
@ -58,7 +59,7 @@ class TestFileJpeg:
""" """
return Image.frombytes(mode, size, os.urandom(size[0] * size[1] * len(mode))) return Image.frombytes(mode, size, os.urandom(size[0] * size[1] * len(mode)))
def test_sanity(self): def test_sanity(self) -> None:
# internal version number # internal version number
assert re.search(r"\d+\.\d+$", features.version_codec("jpg")) assert re.search(r"\d+\.\d+$", features.version_codec("jpg"))
@ -70,13 +71,13 @@ class TestFileJpeg:
assert im.get_format_mimetype() == "image/jpeg" assert im.get_format_mimetype() == "image/jpeg"
@pytest.mark.parametrize("size", ((1, 0), (0, 1), (0, 0))) @pytest.mark.parametrize("size", ((1, 0), (0, 1), (0, 0)))
def test_zero(self, size, tmp_path): def test_zero(self, size, tmp_path: Path) -> None:
f = str(tmp_path / "temp.jpg") f = str(tmp_path / "temp.jpg")
im = Image.new("RGB", size) im = Image.new("RGB", size)
with pytest.raises(ValueError): with pytest.raises(ValueError):
im.save(f) im.save(f)
def test_app(self): def test_app(self) -> None:
# Test APP/COM reader (@PIL135) # Test APP/COM reader (@PIL135)
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
assert im.applist[0] == ("APP0", b"JFIF\x00\x01\x01\x01\x00`\x00`\x00\x00") assert im.applist[0] == ("APP0", b"JFIF\x00\x01\x01\x01\x00`\x00`\x00\x00")
@ -89,7 +90,7 @@ class TestFileJpeg:
assert im.info["comment"] == b"File written by Adobe Photoshop\xa8 4.0\x00" assert im.info["comment"] == b"File written by Adobe Photoshop\xa8 4.0\x00"
assert im.app["COM"] == im.info["comment"] assert im.app["COM"] == im.info["comment"]
def test_comment_write(self): def test_comment_write(self) -> None:
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
assert im.info["comment"] == b"File written by Adobe Photoshop\xa8 4.0\x00" assert im.info["comment"] == b"File written by Adobe Photoshop\xa8 4.0\x00"
@ -115,7 +116,7 @@ class TestFileJpeg:
comment = comment.encode() comment = comment.encode()
assert reloaded.info["comment"] == comment assert reloaded.info["comment"] == comment
def test_cmyk(self): def test_cmyk(self) -> None:
# Test CMYK handling. Thanks to Tim and Charlie for test data, # Test CMYK handling. Thanks to Tim and Charlie for test data,
# Michael for getting me to look one more time. # Michael for getting me to look one more time.
f = "Tests/images/pil_sample_cmyk.jpg" f = "Tests/images/pil_sample_cmyk.jpg"
@ -143,7 +144,7 @@ class TestFileJpeg:
) )
assert k > 0.9 assert k > 0.9
def test_rgb(self): def test_rgb(self) -> None:
def getchannels(im): def getchannels(im):
return tuple(v[0] for v in im.layer) return tuple(v[0] for v in im.layer)
@ -160,7 +161,7 @@ class TestFileJpeg:
"test_image_path", "test_image_path",
[TEST_FILE, "Tests/images/pil_sample_cmyk.jpg"], [TEST_FILE, "Tests/images/pil_sample_cmyk.jpg"],
) )
def test_dpi(self, test_image_path): def test_dpi(self, test_image_path) -> None:
def test(xdpi, ydpi=None): def test(xdpi, ydpi=None):
with Image.open(test_image_path) as im: with Image.open(test_image_path) as im:
im = self.roundtrip(im, dpi=(xdpi, ydpi or xdpi)) im = self.roundtrip(im, dpi=(xdpi, ydpi or xdpi))
@ -174,7 +175,7 @@ class TestFileJpeg:
@mark_if_feature_version( @mark_if_feature_version(
pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing"
) )
def test_icc(self, tmp_path): def test_icc(self, tmp_path: Path) -> None:
# Test ICC support # Test ICC support
with Image.open("Tests/images/rgb.jpg") as im1: with Image.open("Tests/images/rgb.jpg") as im1:
icc_profile = im1.info["icc_profile"] icc_profile = im1.info["icc_profile"]
@ -206,7 +207,7 @@ class TestFileJpeg:
ImageFile.MAXBLOCK * 4 + 3, # large block ImageFile.MAXBLOCK * 4 + 3, # large block
), ),
) )
def test_icc_big(self, n): def test_icc_big(self, n) -> None:
# Make sure that the "extra" support handles large blocks # Make sure that the "extra" support handles large blocks
# The ICC APP marker can store 65519 bytes per marker, so # The ICC APP marker can store 65519 bytes per marker, so
# using a 4-byte test code should allow us to detect out of # using a 4-byte test code should allow us to detect out of
@ -219,7 +220,7 @@ class TestFileJpeg:
@mark_if_feature_version( @mark_if_feature_version(
pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing"
) )
def test_large_icc_meta(self, tmp_path): def test_large_icc_meta(self, tmp_path: Path) -> None:
# https://github.com/python-pillow/Pillow/issues/148 # https://github.com/python-pillow/Pillow/issues/148
# Sometimes the meta data on the icc_profile block is bigger than # Sometimes the meta data on the icc_profile block is bigger than
# Image.MAXBLOCK or the image size. # Image.MAXBLOCK or the image size.
@ -243,7 +244,7 @@ class TestFileJpeg:
f = str(tmp_path / "temp3.jpg") f = str(tmp_path / "temp3.jpg")
im.save(f, progressive=True, quality=94, exif=b" " * 43668) im.save(f, progressive=True, quality=94, exif=b" " * 43668)
def test_optimize(self): def test_optimize(self) -> None:
im1 = self.roundtrip(hopper()) im1 = self.roundtrip(hopper())
im2 = self.roundtrip(hopper(), optimize=0) im2 = self.roundtrip(hopper(), optimize=0)
im3 = self.roundtrip(hopper(), optimize=1) im3 = self.roundtrip(hopper(), optimize=1)
@ -252,14 +253,14 @@ class TestFileJpeg:
assert im1.bytes >= im2.bytes assert im1.bytes >= im2.bytes
assert im1.bytes >= im3.bytes assert im1.bytes >= im3.bytes
def test_optimize_large_buffer(self, tmp_path): def test_optimize_large_buffer(self, tmp_path: Path) -> None:
# https://github.com/python-pillow/Pillow/issues/148 # https://github.com/python-pillow/Pillow/issues/148
f = str(tmp_path / "temp.jpg") f = str(tmp_path / "temp.jpg")
# this requires ~ 1.5x Image.MAXBLOCK # this requires ~ 1.5x Image.MAXBLOCK
im = Image.new("RGB", (4096, 4096), 0xFF3333) im = Image.new("RGB", (4096, 4096), 0xFF3333)
im.save(f, format="JPEG", optimize=True) im.save(f, format="JPEG", optimize=True)
def test_progressive(self): def test_progressive(self) -> None:
im1 = self.roundtrip(hopper()) im1 = self.roundtrip(hopper())
im2 = self.roundtrip(hopper(), progressive=False) im2 = self.roundtrip(hopper(), progressive=False)
im3 = self.roundtrip(hopper(), progressive=True) im3 = self.roundtrip(hopper(), progressive=True)
@ -270,25 +271,25 @@ class TestFileJpeg:
assert_image_equal(im1, im3) assert_image_equal(im1, im3)
assert im1.bytes >= im3.bytes assert im1.bytes >= im3.bytes
def test_progressive_large_buffer(self, tmp_path): def test_progressive_large_buffer(self, tmp_path: Path) -> None:
f = str(tmp_path / "temp.jpg") f = str(tmp_path / "temp.jpg")
# this requires ~ 1.5x Image.MAXBLOCK # this requires ~ 1.5x Image.MAXBLOCK
im = Image.new("RGB", (4096, 4096), 0xFF3333) im = Image.new("RGB", (4096, 4096), 0xFF3333)
im.save(f, format="JPEG", progressive=True) im.save(f, format="JPEG", progressive=True)
def test_progressive_large_buffer_highest_quality(self, tmp_path): def test_progressive_large_buffer_highest_quality(self, tmp_path: Path) -> None:
f = str(tmp_path / "temp.jpg") f = str(tmp_path / "temp.jpg")
im = self.gen_random_image((255, 255)) im = self.gen_random_image((255, 255))
# this requires more bytes than pixels in the image # this requires more bytes than pixels in the image
im.save(f, format="JPEG", progressive=True, quality=100) im.save(f, format="JPEG", progressive=True, quality=100)
def test_progressive_cmyk_buffer(self): def test_progressive_cmyk_buffer(self) -> None:
# Issue 2272, quality 90 cmyk image is tripping the large buffer bug. # Issue 2272, quality 90 cmyk image is tripping the large buffer bug.
f = BytesIO() f = BytesIO()
im = self.gen_random_image((256, 256), "CMYK") im = self.gen_random_image((256, 256), "CMYK")
im.save(f, format="JPEG", progressive=True, quality=94) im.save(f, format="JPEG", progressive=True, quality=94)
def test_large_exif(self, tmp_path): def test_large_exif(self, tmp_path: Path) -> None:
# https://github.com/python-pillow/Pillow/issues/148 # https://github.com/python-pillow/Pillow/issues/148
f = str(tmp_path / "temp.jpg") f = str(tmp_path / "temp.jpg")
im = hopper() im = hopper()
@ -297,12 +298,12 @@ class TestFileJpeg:
with pytest.raises(ValueError): with pytest.raises(ValueError):
im.save(f, "JPEG", quality=90, exif=b"1" * 65534) im.save(f, "JPEG", quality=90, exif=b"1" * 65534)
def test_exif_typeerror(self): def test_exif_typeerror(self) -> None:
with Image.open("Tests/images/exif_typeerror.jpg") as im: with Image.open("Tests/images/exif_typeerror.jpg") as im:
# Should not raise a TypeError # Should not raise a TypeError
im._getexif() im._getexif()
def test_exif_gps(self, tmp_path): def test_exif_gps(self, tmp_path: Path) -> None:
expected_exif_gps = { expected_exif_gps = {
0: b"\x00\x00\x00\x01", 0: b"\x00\x00\x00\x01",
2: 4294967295, 2: 4294967295,
@ -327,7 +328,7 @@ class TestFileJpeg:
exif = reloaded._getexif() exif = reloaded._getexif()
assert exif[gps_index] == expected_exif_gps assert exif[gps_index] == expected_exif_gps
def test_empty_exif_gps(self): def test_empty_exif_gps(self) -> None:
with Image.open("Tests/images/empty_gps_ifd.jpg") as im: with Image.open("Tests/images/empty_gps_ifd.jpg") as im:
exif = im.getexif() exif = im.getexif()
del exif[0x8769] del exif[0x8769]
@ -345,7 +346,7 @@ class TestFileJpeg:
# Assert that it was transposed # Assert that it was transposed
assert 0x0112 not in exif assert 0x0112 not in exif
def test_exif_equality(self): def test_exif_equality(self) -> None:
# In 7.2.0, Exif rationals were changed to be read as # In 7.2.0, Exif rationals were changed to be read as
# TiffImagePlugin.IFDRational. This class had a bug in __eq__, # TiffImagePlugin.IFDRational. This class had a bug in __eq__,
# breaking the self-equality of Exif data # breaking the self-equality of Exif data
@ -355,7 +356,7 @@ class TestFileJpeg:
exifs.append(im._getexif()) exifs.append(im._getexif())
assert exifs[0] == exifs[1] assert exifs[0] == exifs[1]
def test_exif_rollback(self): def test_exif_rollback(self) -> None:
# rolling back exif support in 3.1 to pre-3.0 formatting. # rolling back exif support in 3.1 to pre-3.0 formatting.
# expected from 2.9, with b/u qualifiers switched for 3.2 compatibility # expected from 2.9, with b/u qualifiers switched for 3.2 compatibility
# this test passes on 2.9 and 3.1, but not 3.0 # this test passes on 2.9 and 3.1, but not 3.0
@ -390,12 +391,12 @@ class TestFileJpeg:
for tag, value in expected_exif.items(): for tag, value in expected_exif.items():
assert value == exif[tag] assert value == exif[tag]
def test_exif_gps_typeerror(self): def test_exif_gps_typeerror(self) -> None:
with Image.open("Tests/images/exif_gps_typeerror.jpg") as im: with Image.open("Tests/images/exif_gps_typeerror.jpg") as im:
# Should not raise a TypeError # Should not raise a TypeError
im._getexif() im._getexif()
def test_progressive_compat(self): def test_progressive_compat(self) -> None:
im1 = self.roundtrip(hopper()) im1 = self.roundtrip(hopper())
assert not im1.info.get("progressive") assert not im1.info.get("progressive")
assert not im1.info.get("progression") assert not im1.info.get("progression")
@ -416,7 +417,7 @@ class TestFileJpeg:
assert im3.info.get("progressive") assert im3.info.get("progressive")
assert im3.info.get("progression") assert im3.info.get("progression")
def test_quality(self): def test_quality(self) -> None:
im1 = self.roundtrip(hopper()) im1 = self.roundtrip(hopper())
im2 = self.roundtrip(hopper(), quality=50) im2 = self.roundtrip(hopper(), quality=50)
assert_image(im1, im2.mode, im2.size) assert_image(im1, im2.mode, im2.size)
@ -426,12 +427,12 @@ class TestFileJpeg:
assert_image(im1, im3.mode, im3.size) assert_image(im1, im3.mode, im3.size)
assert im2.bytes > im3.bytes assert im2.bytes > im3.bytes
def test_smooth(self): def test_smooth(self) -> None:
im1 = self.roundtrip(hopper()) im1 = self.roundtrip(hopper())
im2 = self.roundtrip(hopper(), smooth=100) im2 = self.roundtrip(hopper(), smooth=100)
assert_image(im1, im2.mode, im2.size) assert_image(im1, im2.mode, im2.size)
def test_subsampling(self): def test_subsampling(self) -> None:
def getsampling(im): def getsampling(im):
layer = im.layer layer = im.layer
return layer[0][1:3] + layer[1][1:3] + layer[2][1:3] return layer[0][1:3] + layer[1][1:3] + layer[2][1:3]
@ -463,23 +464,23 @@ class TestFileJpeg:
with pytest.raises(TypeError): with pytest.raises(TypeError):
self.roundtrip(hopper(), subsampling="1:1:1") self.roundtrip(hopper(), subsampling="1:1:1")
def test_exif(self): def test_exif(self) -> None:
with Image.open("Tests/images/pil_sample_rgb.jpg") as im: with Image.open("Tests/images/pil_sample_rgb.jpg") as im:
info = im._getexif() info = im._getexif()
assert info[305] == "Adobe Photoshop CS Macintosh" assert info[305] == "Adobe Photoshop CS Macintosh"
def test_get_child_images(self): def test_get_child_images(self) -> None:
with Image.open("Tests/images/flower.jpg") as im: with Image.open("Tests/images/flower.jpg") as im:
ims = im.get_child_images() ims = im.get_child_images()
assert len(ims) == 1 assert len(ims) == 1
assert_image_similar_tofile(ims[0], "Tests/images/flower_thumbnail.png", 2.1) assert_image_similar_tofile(ims[0], "Tests/images/flower_thumbnail.png", 2.1)
def test_mp(self): def test_mp(self) -> None:
with Image.open("Tests/images/pil_sample_rgb.jpg") as im: with Image.open("Tests/images/pil_sample_rgb.jpg") as im:
assert im._getmp() is None assert im._getmp() is None
def test_quality_keep(self, tmp_path): def test_quality_keep(self, tmp_path: Path) -> None:
# RGB # RGB
with Image.open("Tests/images/hopper.jpg") as im: with Image.open("Tests/images/hopper.jpg") as im:
f = str(tmp_path / "temp.jpg") f = str(tmp_path / "temp.jpg")
@ -493,13 +494,13 @@ class TestFileJpeg:
f = str(tmp_path / "temp.jpg") f = str(tmp_path / "temp.jpg")
im.save(f, quality="keep") im.save(f, quality="keep")
def test_junk_jpeg_header(self): def test_junk_jpeg_header(self) -> None:
# https://github.com/python-pillow/Pillow/issues/630 # https://github.com/python-pillow/Pillow/issues/630
filename = "Tests/images/junk_jpeg_header.jpg" filename = "Tests/images/junk_jpeg_header.jpg"
with Image.open(filename): with Image.open(filename):
pass pass
def test_ff00_jpeg_header(self): def test_ff00_jpeg_header(self) -> None:
filename = "Tests/images/jpeg_ff00_header.jpg" filename = "Tests/images/jpeg_ff00_header.jpg"
with Image.open(filename): with Image.open(filename):
pass pass
@ -507,7 +508,7 @@ class TestFileJpeg:
@mark_if_feature_version( @mark_if_feature_version(
pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing"
) )
def test_truncated_jpeg_should_read_all_the_data(self): def test_truncated_jpeg_should_read_all_the_data(self) -> None:
filename = "Tests/images/truncated_jpeg.jpg" filename = "Tests/images/truncated_jpeg.jpg"
ImageFile.LOAD_TRUNCATED_IMAGES = True ImageFile.LOAD_TRUNCATED_IMAGES = True
with Image.open(filename) as im: with Image.open(filename) as im:
@ -515,7 +516,7 @@ class TestFileJpeg:
ImageFile.LOAD_TRUNCATED_IMAGES = False ImageFile.LOAD_TRUNCATED_IMAGES = False
assert im.getbbox() is not None assert im.getbbox() is not None
def test_truncated_jpeg_throws_oserror(self): def test_truncated_jpeg_throws_oserror(self) -> None:
filename = "Tests/images/truncated_jpeg.jpg" filename = "Tests/images/truncated_jpeg.jpg"
with Image.open(filename) as im: with Image.open(filename) as im:
with pytest.raises(OSError): with pytest.raises(OSError):
@ -528,8 +529,8 @@ class TestFileJpeg:
@mark_if_feature_version( @mark_if_feature_version(
pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing"
) )
def test_qtables(self, tmp_path): def test_qtables(self, tmp_path: Path) -> None:
def _n_qtables_helper(n, test_file): def _n_qtables_helper(n, test_file) -> None:
with Image.open(test_file) as im: with Image.open(test_file) as im:
f = str(tmp_path / "temp.jpg") f = str(tmp_path / "temp.jpg")
im.save(f, qtables=[[n] * 64] * n) im.save(f, qtables=[[n] * 64] * n)
@ -637,24 +638,24 @@ class TestFileJpeg:
with pytest.raises(ValueError): with pytest.raises(ValueError):
self.roundtrip(im, qtables=[[1, 2, 3, 4]]) self.roundtrip(im, qtables=[[1, 2, 3, 4]])
def test_load_16bit_qtables(self): def test_load_16bit_qtables(self) -> None:
with Image.open("Tests/images/hopper_16bit_qtables.jpg") as im: with Image.open("Tests/images/hopper_16bit_qtables.jpg") as im:
assert len(im.quantization) == 2 assert len(im.quantization) == 2
assert len(im.quantization[0]) == 64 assert len(im.quantization[0]) == 64
assert max(im.quantization[0]) > 255 assert max(im.quantization[0]) > 255
def test_save_multiple_16bit_qtables(self): def test_save_multiple_16bit_qtables(self) -> None:
with Image.open("Tests/images/hopper_16bit_qtables.jpg") as im: with Image.open("Tests/images/hopper_16bit_qtables.jpg") as im:
im2 = self.roundtrip(im, qtables="keep") im2 = self.roundtrip(im, qtables="keep")
assert im.quantization == im2.quantization assert im.quantization == im2.quantization
def test_save_single_16bit_qtable(self): def test_save_single_16bit_qtable(self) -> None:
with Image.open("Tests/images/hopper_16bit_qtables.jpg") as im: with Image.open("Tests/images/hopper_16bit_qtables.jpg") as im:
im2 = self.roundtrip(im, qtables={0: im.quantization[0]}) im2 = self.roundtrip(im, qtables={0: im.quantization[0]})
assert len(im2.quantization) == 1 assert len(im2.quantization) == 1
assert im2.quantization[0] == im.quantization[0] assert im2.quantization[0] == im.quantization[0]
def test_save_low_quality_baseline_qtables(self): def test_save_low_quality_baseline_qtables(self) -> None:
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
im2 = self.roundtrip(im, quality=10) im2 = self.roundtrip(im, quality=10)
assert len(im2.quantization) == 2 assert len(im2.quantization) == 2
@ -665,7 +666,7 @@ class TestFileJpeg:
"blocks, rows, markers", "blocks, rows, markers",
((0, 0, 0), (1, 0, 15), (3, 0, 5), (8, 0, 1), (0, 1, 3), (0, 2, 1)), ((0, 0, 0), (1, 0, 15), (3, 0, 5), (8, 0, 1), (0, 1, 3), (0, 2, 1)),
) )
def test_restart_markers(self, blocks, rows, markers): def test_restart_markers(self, blocks, rows, markers) -> None:
im = Image.new("RGB", (32, 32)) # 16 MCUs im = Image.new("RGB", (32, 32)) # 16 MCUs
out = BytesIO() out = BytesIO()
im.save( im.save(
@ -679,20 +680,20 @@ class TestFileJpeg:
assert len(re.findall(b"\xff[\xd0-\xd7]", out.getvalue())) == markers assert len(re.findall(b"\xff[\xd0-\xd7]", out.getvalue())) == markers
@pytest.mark.skipif(not djpeg_available(), reason="djpeg not available") @pytest.mark.skipif(not djpeg_available(), reason="djpeg not available")
def test_load_djpeg(self): def test_load_djpeg(self) -> None:
with Image.open(TEST_FILE) as img: with Image.open(TEST_FILE) as img:
img.load_djpeg() img.load_djpeg()
assert_image_similar_tofile(img, TEST_FILE, 5) assert_image_similar_tofile(img, TEST_FILE, 5)
@pytest.mark.skipif(not cjpeg_available(), reason="cjpeg not available") @pytest.mark.skipif(not cjpeg_available(), reason="cjpeg not available")
def test_save_cjpeg(self, tmp_path): def test_save_cjpeg(self, tmp_path: Path) -> None:
with Image.open(TEST_FILE) as img: with Image.open(TEST_FILE) as img:
tempfile = str(tmp_path / "temp.jpg") tempfile = str(tmp_path / "temp.jpg")
JpegImagePlugin._save_cjpeg(img, 0, tempfile) JpegImagePlugin._save_cjpeg(img, 0, tempfile)
# Default save quality is 75%, so a tiny bit of difference is alright # Default save quality is 75%, so a tiny bit of difference is alright
assert_image_similar_tofile(img, tempfile, 17) assert_image_similar_tofile(img, tempfile, 17)
def test_no_duplicate_0x1001_tag(self): def test_no_duplicate_0x1001_tag(self) -> None:
# Arrange # Arrange
tag_ids = {v: k for k, v in ExifTags.TAGS.items()} tag_ids = {v: k for k, v in ExifTags.TAGS.items()}
@ -700,7 +701,7 @@ class TestFileJpeg:
assert tag_ids["RelatedImageWidth"] == 0x1001 assert tag_ids["RelatedImageWidth"] == 0x1001
assert tag_ids["RelatedImageLength"] == 0x1002 assert tag_ids["RelatedImageLength"] == 0x1002
def test_MAXBLOCK_scaling(self, tmp_path): def test_MAXBLOCK_scaling(self, tmp_path: Path) -> None:
im = self.gen_random_image((512, 512)) im = self.gen_random_image((512, 512))
f = str(tmp_path / "temp.jpeg") f = str(tmp_path / "temp.jpeg")
im.save(f, quality=100, optimize=True) im.save(f, quality=100, optimize=True)
@ -711,7 +712,7 @@ class TestFileJpeg:
reloaded.save(f, quality="keep", progressive=True) reloaded.save(f, quality="keep", progressive=True)
reloaded.save(f, quality="keep", optimize=True) reloaded.save(f, quality="keep", optimize=True)
def test_bad_mpo_header(self): def test_bad_mpo_header(self) -> None:
"""Treat unknown MPO as JPEG""" """Treat unknown MPO as JPEG"""
# Arrange # Arrange
@ -723,20 +724,20 @@ class TestFileJpeg:
assert im.format == "JPEG" assert im.format == "JPEG"
@pytest.mark.parametrize("mode", ("1", "L", "RGB", "RGBX", "CMYK", "YCbCr")) @pytest.mark.parametrize("mode", ("1", "L", "RGB", "RGBX", "CMYK", "YCbCr"))
def test_save_correct_modes(self, mode): def test_save_correct_modes(self, mode) -> None:
out = BytesIO() out = BytesIO()
img = Image.new(mode, (20, 20)) img = Image.new(mode, (20, 20))
img.save(out, "JPEG") img.save(out, "JPEG")
@pytest.mark.parametrize("mode", ("LA", "La", "RGBA", "RGBa", "P")) @pytest.mark.parametrize("mode", ("LA", "La", "RGBA", "RGBa", "P"))
def test_save_wrong_modes(self, mode): def test_save_wrong_modes(self, mode) -> None:
# ref https://github.com/python-pillow/Pillow/issues/2005 # ref https://github.com/python-pillow/Pillow/issues/2005
out = BytesIO() out = BytesIO()
img = Image.new(mode, (20, 20)) img = Image.new(mode, (20, 20))
with pytest.raises(OSError): with pytest.raises(OSError):
img.save(out, "JPEG") img.save(out, "JPEG")
def test_save_tiff_with_dpi(self, tmp_path): def test_save_tiff_with_dpi(self, tmp_path: Path) -> None:
# Arrange # Arrange
outfile = str(tmp_path / "temp.tif") outfile = str(tmp_path / "temp.tif")
with Image.open("Tests/images/hopper.tif") as im: with Image.open("Tests/images/hopper.tif") as im:
@ -748,7 +749,7 @@ class TestFileJpeg:
reloaded.load() reloaded.load()
assert im.info["dpi"] == reloaded.info["dpi"] assert im.info["dpi"] == reloaded.info["dpi"]
def test_save_dpi_rounding(self, tmp_path): def test_save_dpi_rounding(self, tmp_path: Path) -> None:
outfile = str(tmp_path / "temp.jpg") outfile = str(tmp_path / "temp.jpg")
with Image.open("Tests/images/hopper.jpg") as im: with Image.open("Tests/images/hopper.jpg") as im:
im.save(outfile, dpi=(72.2, 72.2)) im.save(outfile, dpi=(72.2, 72.2))
@ -761,7 +762,7 @@ class TestFileJpeg:
with Image.open(outfile) as reloaded: with Image.open(outfile) as reloaded:
assert reloaded.info["dpi"] == (73, 73) assert reloaded.info["dpi"] == (73, 73)
def test_dpi_tuple_from_exif(self): def test_dpi_tuple_from_exif(self) -> None:
# Arrange # Arrange
# This Photoshop CC 2017 image has DPI in EXIF not metadata # This Photoshop CC 2017 image has DPI in EXIF not metadata
# EXIF XResolution is (2000000, 10000) # EXIF XResolution is (2000000, 10000)
@ -769,7 +770,7 @@ class TestFileJpeg:
# Act / Assert # Act / Assert
assert im.info.get("dpi") == (200, 200) assert im.info.get("dpi") == (200, 200)
def test_dpi_int_from_exif(self): def test_dpi_int_from_exif(self) -> None:
# Arrange # Arrange
# This image has DPI in EXIF not metadata # This image has DPI in EXIF not metadata
# EXIF XResolution is 72 # EXIF XResolution is 72
@ -777,7 +778,7 @@ class TestFileJpeg:
# Act / Assert # Act / Assert
assert im.info.get("dpi") == (72, 72) assert im.info.get("dpi") == (72, 72)
def test_dpi_from_dpcm_exif(self): def test_dpi_from_dpcm_exif(self) -> None:
# Arrange # Arrange
# This is photoshop-200dpi.jpg with EXIF resolution unit set to cm: # This is photoshop-200dpi.jpg with EXIF resolution unit set to cm:
# exiftool -exif:ResolutionUnit=cm photoshop-200dpi.jpg # exiftool -exif:ResolutionUnit=cm photoshop-200dpi.jpg
@ -785,7 +786,7 @@ class TestFileJpeg:
# Act / Assert # Act / Assert
assert im.info.get("dpi") == (508, 508) assert im.info.get("dpi") == (508, 508)
def test_dpi_exif_zero_division(self): def test_dpi_exif_zero_division(self) -> None:
# Arrange # Arrange
# This is photoshop-200dpi.jpg with EXIF resolution set to 0/0: # This is photoshop-200dpi.jpg with EXIF resolution set to 0/0:
# exiftool -XResolution=0/0 -YResolution=0/0 photoshop-200dpi.jpg # exiftool -XResolution=0/0 -YResolution=0/0 photoshop-200dpi.jpg
@ -794,7 +795,7 @@ class TestFileJpeg:
# This should return the default, and not raise a ZeroDivisionError # This should return the default, and not raise a ZeroDivisionError
assert im.info.get("dpi") == (72, 72) assert im.info.get("dpi") == (72, 72)
def test_dpi_exif_string(self): def test_dpi_exif_string(self) -> None:
# Arrange # Arrange
# 0x011A tag in this exif contains string '300300\x02' # 0x011A tag in this exif contains string '300300\x02'
with Image.open("Tests/images/broken_exif_dpi.jpg") as im: with Image.open("Tests/images/broken_exif_dpi.jpg") as im:
@ -802,14 +803,14 @@ class TestFileJpeg:
# This should return the default # This should return the default
assert im.info.get("dpi") == (72, 72) assert im.info.get("dpi") == (72, 72)
def test_dpi_exif_truncated(self): def test_dpi_exif_truncated(self) -> None:
# Arrange # Arrange
with Image.open("Tests/images/truncated_exif_dpi.jpg") as im: with Image.open("Tests/images/truncated_exif_dpi.jpg") as im:
# Act / Assert # Act / Assert
# This should return the default # This should return the default
assert im.info.get("dpi") == (72, 72) assert im.info.get("dpi") == (72, 72)
def test_no_dpi_in_exif(self): def test_no_dpi_in_exif(self) -> None:
# Arrange # Arrange
# This is photoshop-200dpi.jpg with resolution removed from EXIF: # This is photoshop-200dpi.jpg with resolution removed from EXIF:
# exiftool "-*resolution*"= photoshop-200dpi.jpg # exiftool "-*resolution*"= photoshop-200dpi.jpg
@ -819,7 +820,7 @@ class TestFileJpeg:
# https://exiv2.org/tags.html # https://exiv2.org/tags.html
assert im.info.get("dpi") == (72, 72) assert im.info.get("dpi") == (72, 72)
def test_invalid_exif(self): def test_invalid_exif(self) -> None:
# This is no-dpi-in-exif with the tiff header of the exif block # This is no-dpi-in-exif with the tiff header of the exif block
# hexedited from MM * to FF FF FF FF # hexedited from MM * to FF FF FF FF
with Image.open("Tests/images/invalid-exif.jpg") as im: with Image.open("Tests/images/invalid-exif.jpg") as im:
@ -830,7 +831,7 @@ class TestFileJpeg:
@mark_if_feature_version( @mark_if_feature_version(
pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing"
) )
def test_exif_x_resolution(self, tmp_path): def test_exif_x_resolution(self, tmp_path: Path) -> None:
with Image.open("Tests/images/flower.jpg") as im: with Image.open("Tests/images/flower.jpg") as im:
exif = im.getexif() exif = im.getexif()
assert exif[282] == 180 assert exif[282] == 180
@ -842,14 +843,14 @@ class TestFileJpeg:
with Image.open(out) as reloaded: with Image.open(out) as reloaded:
assert reloaded.getexif()[282] == 180 assert reloaded.getexif()[282] == 180
def test_invalid_exif_x_resolution(self): def test_invalid_exif_x_resolution(self) -> None:
# When no x or y resolution is defined in EXIF # When no x or y resolution is defined in EXIF
with Image.open("Tests/images/invalid-exif-without-x-resolution.jpg") as im: with Image.open("Tests/images/invalid-exif-without-x-resolution.jpg") as im:
# This should return the default, and not a ValueError or # This should return the default, and not a ValueError or
# OSError for an unidentified image. # OSError for an unidentified image.
assert im.info.get("dpi") == (72, 72) assert im.info.get("dpi") == (72, 72)
def test_ifd_offset_exif(self): def test_ifd_offset_exif(self) -> None:
# Arrange # Arrange
# This image has been manually hexedited to have an IFD offset of 10, # This image has been manually hexedited to have an IFD offset of 10,
# in contrast to normal 8 # in contrast to normal 8
@ -857,14 +858,14 @@ class TestFileJpeg:
# Act / Assert # Act / Assert
assert im._getexif()[306] == "2017:03:13 23:03:09" assert im._getexif()[306] == "2017:03:13 23:03:09"
def test_multiple_exif(self): def test_multiple_exif(self) -> None:
with Image.open("Tests/images/multiple_exif.jpg") as im: with Image.open("Tests/images/multiple_exif.jpg") as im:
assert im.info["exif"] == b"Exif\x00\x00firstsecond" assert im.info["exif"] == b"Exif\x00\x00firstsecond"
@mark_if_feature_version( @mark_if_feature_version(
pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing"
) )
def test_photoshop(self): def test_photoshop(self) -> None:
with Image.open("Tests/images/photoshop-200dpi.jpg") as im: with Image.open("Tests/images/photoshop-200dpi.jpg") as im:
assert im.info["photoshop"][0x03ED] == { assert im.info["photoshop"][0x03ED] == {
"XResolution": 200.0, "XResolution": 200.0,
@ -881,14 +882,14 @@ class TestFileJpeg:
with Image.open("Tests/images/app13.jpg") as im: with Image.open("Tests/images/app13.jpg") as im:
assert "photoshop" not in im.info assert "photoshop" not in im.info
def test_photoshop_malformed_and_multiple(self): def test_photoshop_malformed_and_multiple(self) -> None:
with Image.open("Tests/images/app13-multiple.jpg") as im: with Image.open("Tests/images/app13-multiple.jpg") as im:
assert "photoshop" in im.info assert "photoshop" in im.info
assert 24 == len(im.info["photoshop"]) assert 24 == len(im.info["photoshop"])
apps_13_lengths = [len(v) for k, v in im.applist if k == "APP13"] apps_13_lengths = [len(v) for k, v in im.applist if k == "APP13"]
assert [65504, 24] == apps_13_lengths assert [65504, 24] == apps_13_lengths
def test_adobe_transform(self): def test_adobe_transform(self) -> None:
with Image.open("Tests/images/pil_sample_rgb.jpg") as im: with Image.open("Tests/images/pil_sample_rgb.jpg") as im:
assert im.info["adobe_transform"] == 1 assert im.info["adobe_transform"] == 1
@ -902,11 +903,11 @@ class TestFileJpeg:
assert "adobe" in im.info assert "adobe" in im.info
assert "adobe_transform" not in im.info assert "adobe_transform" not in im.info
def test_icc_after_SOF(self): def test_icc_after_SOF(self) -> None:
with Image.open("Tests/images/icc-after-SOF.jpg") as im: with Image.open("Tests/images/icc-after-SOF.jpg") as im:
assert im.info["icc_profile"] == b"profile" assert im.info["icc_profile"] == b"profile"
def test_jpeg_magic_number(self): def test_jpeg_magic_number(self) -> None:
size = 4097 size = 4097
buffer = BytesIO(b"\xFF" * size) # Many xFF bytes buffer = BytesIO(b"\xFF" * size) # Many xFF bytes
buffer.max_pos = 0 buffer.max_pos = 0
@ -925,7 +926,7 @@ class TestFileJpeg:
# Assert the entire file has not been read # Assert the entire file has not been read
assert 0 < buffer.max_pos < size assert 0 < buffer.max_pos < size
def test_getxmp(self): def test_getxmp(self) -> None:
with Image.open("Tests/images/xmp_test.jpg") as im: with Image.open("Tests/images/xmp_test.jpg") as im:
if ElementTree is None: if ElementTree is None:
with pytest.warns( with pytest.warns(
@ -954,7 +955,7 @@ class TestFileJpeg:
with Image.open("Tests/images/hopper.jpg") as im: with Image.open("Tests/images/hopper.jpg") as im:
assert im.getxmp() == {} assert im.getxmp() == {}
def test_getxmp_no_prefix(self): def test_getxmp_no_prefix(self) -> None:
with Image.open("Tests/images/xmp_no_prefix.jpg") as im: with Image.open("Tests/images/xmp_no_prefix.jpg") as im:
if ElementTree is None: if ElementTree is None:
with pytest.warns( with pytest.warns(
@ -965,7 +966,7 @@ class TestFileJpeg:
else: else:
assert im.getxmp() == {"xmpmeta": {"key": "value"}} assert im.getxmp() == {"xmpmeta": {"key": "value"}}
def test_getxmp_padded(self): def test_getxmp_padded(self) -> None:
with Image.open("Tests/images/xmp_padded.jpg") as im: with Image.open("Tests/images/xmp_padded.jpg") as im:
if ElementTree is None: if ElementTree is None:
with pytest.warns( with pytest.warns(
@ -977,7 +978,7 @@ class TestFileJpeg:
assert im.getxmp() == {"xmpmeta": None} assert im.getxmp() == {"xmpmeta": None}
@pytest.mark.timeout(timeout=1) @pytest.mark.timeout(timeout=1)
def test_eof(self): def test_eof(self) -> None:
# Even though this decoder never says that it is finished # Even though this decoder never says that it is finished
# the image should still end when there is no new data # the image should still end when there is no new data
class InfiniteMockPyDecoder(ImageFile.PyDecoder): class InfiniteMockPyDecoder(ImageFile.PyDecoder):
@ -1000,7 +1001,7 @@ class TestFileJpeg:
im.load() im.load()
ImageFile.LOAD_TRUNCATED_IMAGES = False ImageFile.LOAD_TRUNCATED_IMAGES = False
def test_separate_tables(self): def test_separate_tables(self) -> None:
im = hopper() im = hopper()
data = [] # [interchange, tables-only, image-only] data = [] # [interchange, tables-only, image-only]
for streamtype in range(3): for streamtype in range(3):
@ -1022,14 +1023,14 @@ class TestFileJpeg:
with Image.open(BytesIO(data[1] + data[2])) as combined_im: with Image.open(BytesIO(data[1] + data[2])) as combined_im:
assert_image_equal(interchange_im, combined_im) assert_image_equal(interchange_im, combined_im)
def test_repr_jpeg(self): def test_repr_jpeg(self) -> None:
im = hopper() im = hopper()
with Image.open(BytesIO(im._repr_jpeg_())) as repr_jpeg: with Image.open(BytesIO(im._repr_jpeg_())) as repr_jpeg:
assert repr_jpeg.format == "JPEG" assert repr_jpeg.format == "JPEG"
assert_image_similar(im, repr_jpeg, 17) assert_image_similar(im, repr_jpeg, 17)
def test_repr_jpeg_error_returns_none(self): def test_repr_jpeg_error_returns_none(self) -> None:
im = hopper("F") im = hopper("F")
assert im._repr_jpeg_() is None assert im._repr_jpeg_() is None
@ -1038,7 +1039,7 @@ class TestFileJpeg:
@pytest.mark.skipif(not is_win32(), reason="Windows only") @pytest.mark.skipif(not is_win32(), reason="Windows only")
@skip_unless_feature("jpg") @skip_unless_feature("jpg")
class TestFileCloseW32: class TestFileCloseW32:
def test_fd_leak(self, tmp_path): def test_fd_leak(self, tmp_path: Path) -> None:
tmpfile = str(tmp_path / "temp.jpg") tmpfile = str(tmp_path / "temp.jpg")
with Image.open("Tests/images/hopper.jpg") as im: with Image.open("Tests/images/hopper.jpg") as im:

View File

@ -3,6 +3,7 @@ from __future__ import annotations
import os import os
import re import re
from io import BytesIO from io import BytesIO
from pathlib import Path
import pytest import pytest
@ -46,7 +47,7 @@ def roundtrip(im, **options):
return im return im
def test_sanity(): def test_sanity() -> None:
# Internal version number # Internal version number
assert re.search(r"\d+\.\d+\.\d+$", features.version_codec("jpg_2000")) assert re.search(r"\d+\.\d+\.\d+$", features.version_codec("jpg_2000"))
@ -59,20 +60,20 @@ def test_sanity():
assert im.get_format_mimetype() == "image/jp2" assert im.get_format_mimetype() == "image/jp2"
def test_jpf(): def test_jpf() -> None:
with Image.open("Tests/images/balloon.jpf") as im: with Image.open("Tests/images/balloon.jpf") as im:
assert im.format == "JPEG2000" assert im.format == "JPEG2000"
assert im.get_format_mimetype() == "image/jpx" assert im.get_format_mimetype() == "image/jpx"
def test_invalid_file(): def test_invalid_file() -> None:
invalid_file = "Tests/images/flower.jpg" invalid_file = "Tests/images/flower.jpg"
with pytest.raises(SyntaxError): with pytest.raises(SyntaxError):
Jpeg2KImagePlugin.Jpeg2KImageFile(invalid_file) Jpeg2KImagePlugin.Jpeg2KImageFile(invalid_file)
def test_bytesio(): def test_bytesio() -> None:
with open("Tests/images/test-card-lossless.jp2", "rb") as f: with open("Tests/images/test-card-lossless.jp2", "rb") as f:
data = BytesIO(f.read()) data = BytesIO(f.read())
assert_image_similar_tofile(test_card, data, 1.0e-3) assert_image_similar_tofile(test_card, data, 1.0e-3)
@ -82,7 +83,7 @@ def test_bytesio():
# PIL (they were made using Adobe Photoshop) # PIL (they were made using Adobe Photoshop)
def test_lossless(tmp_path): def test_lossless(tmp_path: Path) -> None:
with Image.open("Tests/images/test-card-lossless.jp2") as im: with Image.open("Tests/images/test-card-lossless.jp2") as im:
im.load() im.load()
outfile = str(tmp_path / "temp_test-card.png") outfile = str(tmp_path / "temp_test-card.png")
@ -90,54 +91,54 @@ def test_lossless(tmp_path):
assert_image_similar(im, test_card, 1.0e-3) assert_image_similar(im, test_card, 1.0e-3)
def test_lossy_tiled(): def test_lossy_tiled() -> None:
assert_image_similar_tofile( assert_image_similar_tofile(
test_card, "Tests/images/test-card-lossy-tiled.jp2", 2.0 test_card, "Tests/images/test-card-lossy-tiled.jp2", 2.0
) )
def test_lossless_rt(): def test_lossless_rt() -> None:
im = roundtrip(test_card) im = roundtrip(test_card)
assert_image_equal(im, test_card) assert_image_equal(im, test_card)
def test_lossy_rt(): def test_lossy_rt() -> None:
im = roundtrip(test_card, quality_layers=[20]) im = roundtrip(test_card, quality_layers=[20])
assert_image_similar(im, test_card, 2.0) assert_image_similar(im, test_card, 2.0)
def test_tiled_rt(): def test_tiled_rt() -> None:
im = roundtrip(test_card, tile_size=(128, 128)) im = roundtrip(test_card, tile_size=(128, 128))
assert_image_equal(im, test_card) assert_image_equal(im, test_card)
def test_tiled_offset_rt(): def test_tiled_offset_rt() -> None:
im = roundtrip(test_card, tile_size=(128, 128), tile_offset=(0, 0), offset=(32, 32)) im = roundtrip(test_card, tile_size=(128, 128), tile_offset=(0, 0), offset=(32, 32))
assert_image_equal(im, test_card) assert_image_equal(im, test_card)
def test_tiled_offset_too_small(): def test_tiled_offset_too_small() -> None:
with pytest.raises(ValueError): with pytest.raises(ValueError):
roundtrip(test_card, tile_size=(128, 128), tile_offset=(0, 0), offset=(128, 32)) roundtrip(test_card, tile_size=(128, 128), tile_offset=(0, 0), offset=(128, 32))
def test_irreversible_rt(): def test_irreversible_rt() -> None:
im = roundtrip(test_card, irreversible=True, quality_layers=[20]) im = roundtrip(test_card, irreversible=True, quality_layers=[20])
assert_image_similar(im, test_card, 2.0) assert_image_similar(im, test_card, 2.0)
def test_prog_qual_rt(): def test_prog_qual_rt() -> None:
im = roundtrip(test_card, quality_layers=[60, 40, 20], progression="LRCP") im = roundtrip(test_card, quality_layers=[60, 40, 20], progression="LRCP")
assert_image_similar(im, test_card, 2.0) assert_image_similar(im, test_card, 2.0)
def test_prog_res_rt(): def test_prog_res_rt() -> None:
im = roundtrip(test_card, num_resolutions=8, progression="RLCP") im = roundtrip(test_card, num_resolutions=8, progression="RLCP")
assert_image_equal(im, test_card) assert_image_equal(im, test_card)
@pytest.mark.parametrize("num_resolutions", range(2, 6)) @pytest.mark.parametrize("num_resolutions", range(2, 6))
def test_default_num_resolutions(num_resolutions): def test_default_num_resolutions(num_resolutions) -> None:
d = 1 << (num_resolutions - 1) d = 1 << (num_resolutions - 1)
im = test_card.resize((d - 1, d - 1)) im = test_card.resize((d - 1, d - 1))
with pytest.raises(OSError): with pytest.raises(OSError):
@ -146,7 +147,7 @@ def test_default_num_resolutions(num_resolutions):
assert_image_equal(im, reloaded) assert_image_equal(im, reloaded)
def test_reduce(): def test_reduce() -> None:
with Image.open("Tests/images/test-card-lossless.jp2") as im: with Image.open("Tests/images/test-card-lossless.jp2") as im:
assert callable(im.reduce) assert callable(im.reduce)
@ -160,7 +161,7 @@ def test_reduce():
assert im.size == (40, 30) assert im.size == (40, 30)
def test_load_dpi(): def test_load_dpi() -> None:
with Image.open("Tests/images/test-card-lossless.jp2") as im: with Image.open("Tests/images/test-card-lossless.jp2") as im:
assert im.info["dpi"] == (71.9836, 71.9836) assert im.info["dpi"] == (71.9836, 71.9836)
@ -168,7 +169,7 @@ def test_load_dpi():
assert "dpi" not in im.info assert "dpi" not in im.info
def test_restricted_icc_profile(): def test_restricted_icc_profile() -> None:
ImageFile.LOAD_TRUNCATED_IMAGES = True ImageFile.LOAD_TRUNCATED_IMAGES = True
try: try:
# JPEG2000 image with a restricted ICC profile and a known colorspace # JPEG2000 image with a restricted ICC profile and a known colorspace
@ -178,7 +179,7 @@ def test_restricted_icc_profile():
ImageFile.LOAD_TRUNCATED_IMAGES = False ImageFile.LOAD_TRUNCATED_IMAGES = False
def test_header_errors(): def test_header_errors() -> None:
for path in ( for path in (
"Tests/images/invalid_header_length.jp2", "Tests/images/invalid_header_length.jp2",
"Tests/images/not_enough_data.jp2", "Tests/images/not_enough_data.jp2",
@ -192,7 +193,7 @@ def test_header_errors():
pass pass
def test_layers_type(tmp_path): def test_layers_type(tmp_path: Path) -> None:
outfile = str(tmp_path / "temp_layers.jp2") outfile = str(tmp_path / "temp_layers.jp2")
for quality_layers in [[100, 50, 10], (100, 50, 10), None]: for quality_layers in [[100, 50, 10], (100, 50, 10), None]:
test_card.save(outfile, quality_layers=quality_layers) test_card.save(outfile, quality_layers=quality_layers)
@ -202,7 +203,7 @@ def test_layers_type(tmp_path):
test_card.save(outfile, quality_layers=quality_layers) test_card.save(outfile, quality_layers=quality_layers)
def test_layers(): def test_layers() -> None:
out = BytesIO() out = BytesIO()
test_card.save(out, "JPEG2000", quality_layers=[100, 50, 10], progression="LRCP") test_card.save(out, "JPEG2000", quality_layers=[100, 50, 10], progression="LRCP")
out.seek(0) out.seek(0)
@ -232,7 +233,7 @@ def test_layers():
("foo.jp2", {"no_jp2": False}, 4, b"jP"), ("foo.jp2", {"no_jp2": False}, 4, b"jP"),
), ),
) )
def test_no_jp2(name, args, offset, data): def test_no_jp2(name, args, offset, data) -> None:
out = BytesIO() out = BytesIO()
if name: if name:
out.name = name out.name = name
@ -241,7 +242,7 @@ def test_no_jp2(name, args, offset, data):
assert out.read(2) == data assert out.read(2) == data
def test_mct(): def test_mct() -> None:
# Three component # Three component
for val in (0, 1): for val in (0, 1):
out = BytesIO() out = BytesIO()
@ -262,7 +263,7 @@ def test_mct():
assert_image_similar(im, jp2, 1.0e-3) assert_image_similar(im, jp2, 1.0e-3)
def test_sgnd(tmp_path): def test_sgnd(tmp_path: Path) -> None:
outfile = str(tmp_path / "temp.jp2") outfile = str(tmp_path / "temp.jp2")
im = Image.new("L", (1, 1)) im = Image.new("L", (1, 1))
@ -277,7 +278,7 @@ def test_sgnd(tmp_path):
@pytest.mark.parametrize("ext", (".j2k", ".jp2")) @pytest.mark.parametrize("ext", (".j2k", ".jp2"))
def test_rgba(ext): def test_rgba(ext) -> None:
# Arrange # Arrange
with Image.open("Tests/images/rgb_trns_ycbc" + ext) as im: with Image.open("Tests/images/rgb_trns_ycbc" + ext) as im:
# Act # Act
@ -288,47 +289,47 @@ def test_rgba(ext):
@pytest.mark.parametrize("ext", (".j2k", ".jp2")) @pytest.mark.parametrize("ext", (".j2k", ".jp2"))
def test_16bit_monochrome_has_correct_mode(ext): def test_16bit_monochrome_has_correct_mode(ext) -> None:
with Image.open("Tests/images/16bit.cropped" + ext) as im: with Image.open("Tests/images/16bit.cropped" + ext) as im:
im.load() im.load()
assert im.mode == "I;16" assert im.mode == "I;16"
def test_16bit_monochrome_jp2_like_tiff(): def test_16bit_monochrome_jp2_like_tiff() -> None:
with Image.open("Tests/images/16bit.cropped.tif") as tiff_16bit: with Image.open("Tests/images/16bit.cropped.tif") as tiff_16bit:
assert_image_similar_tofile(tiff_16bit, "Tests/images/16bit.cropped.jp2", 1e-3) assert_image_similar_tofile(tiff_16bit, "Tests/images/16bit.cropped.jp2", 1e-3)
def test_16bit_monochrome_j2k_like_tiff(): def test_16bit_monochrome_j2k_like_tiff() -> None:
with Image.open("Tests/images/16bit.cropped.tif") as tiff_16bit: with Image.open("Tests/images/16bit.cropped.tif") as tiff_16bit:
assert_image_similar_tofile(tiff_16bit, "Tests/images/16bit.cropped.j2k", 1e-3) assert_image_similar_tofile(tiff_16bit, "Tests/images/16bit.cropped.j2k", 1e-3)
def test_16bit_j2k_roundtrips(): def test_16bit_j2k_roundtrips() -> None:
with Image.open("Tests/images/16bit.cropped.j2k") as j2k: with Image.open("Tests/images/16bit.cropped.j2k") as j2k:
im = roundtrip(j2k) im = roundtrip(j2k)
assert_image_equal(im, j2k) assert_image_equal(im, j2k)
def test_16bit_jp2_roundtrips(): def test_16bit_jp2_roundtrips() -> None:
with Image.open("Tests/images/16bit.cropped.jp2") as jp2: with Image.open("Tests/images/16bit.cropped.jp2") as jp2:
im = roundtrip(jp2) im = roundtrip(jp2)
assert_image_equal(im, jp2) assert_image_equal(im, jp2)
def test_issue_6194(): def test_issue_6194() -> None:
with Image.open("Tests/images/issue_6194.j2k") as im: with Image.open("Tests/images/issue_6194.j2k") as im:
assert im.getpixel((5, 5)) == 31 assert im.getpixel((5, 5)) == 31
def test_unbound_local(): def test_unbound_local() -> None:
# prepatch, a malformed jp2 file could cause an UnboundLocalError exception. # prepatch, a malformed jp2 file could cause an UnboundLocalError exception.
with pytest.raises(OSError): with pytest.raises(OSError):
with Image.open("Tests/images/unbound_variable.jp2"): with Image.open("Tests/images/unbound_variable.jp2"):
pass pass
def test_parser_feed(): def test_parser_feed() -> None:
# Arrange # Arrange
with open("Tests/images/test-card-lossless.jp2", "rb") as f: with open("Tests/images/test-card-lossless.jp2", "rb") as f:
data = f.read() data = f.read()
@ -345,7 +346,7 @@ def test_parser_feed():
not os.path.exists(EXTRA_DIR), reason="Extra image files not installed" not os.path.exists(EXTRA_DIR), reason="Extra image files not installed"
) )
@pytest.mark.parametrize("name", ("subsampling_1", "subsampling_2", "zoo1", "zoo2")) @pytest.mark.parametrize("name", ("subsampling_1", "subsampling_2", "zoo1", "zoo2"))
def test_subsampling_decode(name): def test_subsampling_decode(name) -> None:
test = f"{EXTRA_DIR}/{name}.jp2" test = f"{EXTRA_DIR}/{name}.jp2"
reference = f"{EXTRA_DIR}/{name}.ppm" reference = f"{EXTRA_DIR}/{name}.ppm"
@ -361,7 +362,7 @@ def test_subsampling_decode(name):
assert_image_similar(im, expected, epsilon) assert_image_similar(im, expected, epsilon)
def test_comment(): def test_comment() -> None:
with Image.open("Tests/images/comment.jp2") as im: with Image.open("Tests/images/comment.jp2") as im:
assert im.info["comment"] == b"Created by OpenJPEG version 2.5.0" assert im.info["comment"] == b"Created by OpenJPEG version 2.5.0"
@ -372,7 +373,7 @@ def test_comment():
pass pass
def test_save_comment(): def test_save_comment() -> None:
for comment in ("Created by Pillow", b"Created by Pillow"): for comment in ("Created by Pillow", b"Created by Pillow"):
out = BytesIO() out = BytesIO()
test_card.save(out, "JPEG2000", comment=comment) test_card.save(out, "JPEG2000", comment=comment)
@ -399,7 +400,7 @@ def test_save_comment():
"Tests/images/crash-d2c93af851d3ab9a19e34503626368b2ecde9c03.j2k", "Tests/images/crash-d2c93af851d3ab9a19e34503626368b2ecde9c03.j2k",
], ],
) )
def test_crashes(test_file): def test_crashes(test_file) -> None:
with open(test_file, "rb") as f: with open(test_file, "rb") as f:
with Image.open(f) as im: with Image.open(f) as im:
# Valgrind should not complain here # Valgrind should not complain here
@ -410,7 +411,7 @@ def test_crashes(test_file):
@skip_unless_feature_version("jpg_2000", "2.4.0") @skip_unless_feature_version("jpg_2000", "2.4.0")
def test_plt_marker(): def test_plt_marker() -> None:
# Search the start of the codesteam for PLT # Search the start of the codesteam for PLT
out = BytesIO() out = BytesIO()
test_card.save(out, "JPEG2000", no_jp2=True, plt=True) test_card.save(out, "JPEG2000", no_jp2=True, plt=True)

View File

@ -7,6 +7,7 @@ import os
import re import re
import sys import sys
from collections import namedtuple from collections import namedtuple
from pathlib import Path
import pytest import pytest
@ -26,7 +27,7 @@ from .helper import (
@skip_unless_feature("libtiff") @skip_unless_feature("libtiff")
class LibTiffTestCase: class LibTiffTestCase:
def _assert_noerr(self, tmp_path, im): def _assert_noerr(self, tmp_path: Path, im) -> None:
"""Helper tests that assert basic sanity about the g4 tiff reading""" """Helper tests that assert basic sanity about the g4 tiff reading"""
# 1 bit # 1 bit
assert im.mode == "1" assert im.mode == "1"
@ -50,10 +51,10 @@ class LibTiffTestCase:
class TestFileLibTiff(LibTiffTestCase): class TestFileLibTiff(LibTiffTestCase):
def test_version(self): def test_version(self) -> None:
assert re.search(r"\d+\.\d+\.\d+$", features.version_codec("libtiff")) assert re.search(r"\d+\.\d+\.\d+$", features.version_codec("libtiff"))
def test_g4_tiff(self, tmp_path): def test_g4_tiff(self, tmp_path: Path) -> None:
"""Test the ordinary file path load path""" """Test the ordinary file path load path"""
test_file = "Tests/images/hopper_g4_500.tif" test_file = "Tests/images/hopper_g4_500.tif"
@ -61,12 +62,12 @@ class TestFileLibTiff(LibTiffTestCase):
assert im.size == (500, 500) assert im.size == (500, 500)
self._assert_noerr(tmp_path, im) self._assert_noerr(tmp_path, im)
def test_g4_large(self, tmp_path): def test_g4_large(self, tmp_path: Path) -> None:
test_file = "Tests/images/pport_g4.tif" test_file = "Tests/images/pport_g4.tif"
with Image.open(test_file) as im: with Image.open(test_file) as im:
self._assert_noerr(tmp_path, im) self._assert_noerr(tmp_path, im)
def test_g4_tiff_file(self, tmp_path): def test_g4_tiff_file(self, tmp_path: Path) -> None:
"""Testing the string load path""" """Testing the string load path"""
test_file = "Tests/images/hopper_g4_500.tif" test_file = "Tests/images/hopper_g4_500.tif"
@ -75,7 +76,7 @@ class TestFileLibTiff(LibTiffTestCase):
assert im.size == (500, 500) assert im.size == (500, 500)
self._assert_noerr(tmp_path, im) self._assert_noerr(tmp_path, im)
def test_g4_tiff_bytesio(self, tmp_path): def test_g4_tiff_bytesio(self, tmp_path: Path) -> None:
"""Testing the stringio loading code path""" """Testing the stringio loading code path"""
test_file = "Tests/images/hopper_g4_500.tif" test_file = "Tests/images/hopper_g4_500.tif"
s = io.BytesIO() s = io.BytesIO()
@ -86,7 +87,7 @@ class TestFileLibTiff(LibTiffTestCase):
assert im.size == (500, 500) assert im.size == (500, 500)
self._assert_noerr(tmp_path, im) self._assert_noerr(tmp_path, im)
def test_g4_non_disk_file_object(self, tmp_path): def test_g4_non_disk_file_object(self, tmp_path: Path) -> None:
"""Testing loading from non-disk non-BytesIO file object""" """Testing loading from non-disk non-BytesIO file object"""
test_file = "Tests/images/hopper_g4_500.tif" test_file = "Tests/images/hopper_g4_500.tif"
s = io.BytesIO() s = io.BytesIO()
@ -98,18 +99,18 @@ class TestFileLibTiff(LibTiffTestCase):
assert im.size == (500, 500) assert im.size == (500, 500)
self._assert_noerr(tmp_path, im) self._assert_noerr(tmp_path, im)
def test_g4_eq_png(self): def test_g4_eq_png(self) -> None:
"""Checking that we're actually getting the data that we expect""" """Checking that we're actually getting the data that we expect"""
with Image.open("Tests/images/hopper_bw_500.png") as png: with Image.open("Tests/images/hopper_bw_500.png") as png:
assert_image_equal_tofile(png, "Tests/images/hopper_g4_500.tif") assert_image_equal_tofile(png, "Tests/images/hopper_g4_500.tif")
# see https://github.com/python-pillow/Pillow/issues/279 # see https://github.com/python-pillow/Pillow/issues/279
def test_g4_fillorder_eq_png(self): def test_g4_fillorder_eq_png(self) -> None:
"""Checking that we're actually getting the data that we expect""" """Checking that we're actually getting the data that we expect"""
with Image.open("Tests/images/g4-fillorder-test.tif") as g4: with Image.open("Tests/images/g4-fillorder-test.tif") as g4:
assert_image_equal_tofile(g4, "Tests/images/g4-fillorder-test.png") assert_image_equal_tofile(g4, "Tests/images/g4-fillorder-test.png")
def test_g4_write(self, tmp_path): def test_g4_write(self, tmp_path: Path) -> None:
"""Checking to see that the saved image is the same as what we wrote""" """Checking to see that the saved image is the same as what we wrote"""
test_file = "Tests/images/hopper_g4_500.tif" test_file = "Tests/images/hopper_g4_500.tif"
with Image.open(test_file) as orig: with Image.open(test_file) as orig:
@ -128,7 +129,7 @@ class TestFileLibTiff(LibTiffTestCase):
assert orig.tobytes() != reread.tobytes() assert orig.tobytes() != reread.tobytes()
def test_adobe_deflate_tiff(self): def test_adobe_deflate_tiff(self) -> None:
test_file = "Tests/images/tiff_adobe_deflate.tif" test_file = "Tests/images/tiff_adobe_deflate.tif"
with Image.open(test_file) as im: with Image.open(test_file) as im:
assert im.mode == "RGB" assert im.mode == "RGB"
@ -139,7 +140,7 @@ class TestFileLibTiff(LibTiffTestCase):
assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png") assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png")
@pytest.mark.parametrize("legacy_api", (False, True)) @pytest.mark.parametrize("legacy_api", (False, True))
def test_write_metadata(self, legacy_api, tmp_path): def test_write_metadata(self, legacy_api, tmp_path: Path) -> None:
"""Test metadata writing through libtiff""" """Test metadata writing through libtiff"""
f = str(tmp_path / "temp.tiff") f = str(tmp_path / "temp.tiff")
with Image.open("Tests/images/hopper_g4.tif") as img: with Image.open("Tests/images/hopper_g4.tif") as img:
@ -184,7 +185,7 @@ class TestFileLibTiff(LibTiffTestCase):
assert field in reloaded, f"{field} not in metadata" assert field in reloaded, f"{field} not in metadata"
@pytest.mark.valgrind_known_error(reason="Known invalid metadata") @pytest.mark.valgrind_known_error(reason="Known invalid metadata")
def test_additional_metadata(self, tmp_path): def test_additional_metadata(self, tmp_path: Path) -> None:
# these should not crash. Seriously dummy data, most of it doesn't make # these should not crash. Seriously dummy data, most of it doesn't make
# any sense, so we're running up against limits where we're asking # any sense, so we're running up against limits where we're asking
# libtiff to do stupid things. # libtiff to do stupid things.
@ -241,7 +242,7 @@ class TestFileLibTiff(LibTiffTestCase):
TiffImagePlugin.WRITE_LIBTIFF = False TiffImagePlugin.WRITE_LIBTIFF = False
def test_custom_metadata(self, tmp_path): def test_custom_metadata(self, tmp_path: Path) -> None:
tc = namedtuple("test_case", "value,type,supported_by_default") tc = namedtuple("test_case", "value,type,supported_by_default")
custom = { custom = {
37000 + k: v 37000 + k: v
@ -283,7 +284,7 @@ class TestFileLibTiff(LibTiffTestCase):
for libtiff in libtiffs: for libtiff in libtiffs:
TiffImagePlugin.WRITE_LIBTIFF = libtiff TiffImagePlugin.WRITE_LIBTIFF = libtiff
def check_tags(tiffinfo): def check_tags(tiffinfo) -> None:
im = hopper() im = hopper()
out = str(tmp_path / "temp.tif") out = str(tmp_path / "temp.tif")
@ -322,7 +323,7 @@ class TestFileLibTiff(LibTiffTestCase):
) )
TiffImagePlugin.WRITE_LIBTIFF = False TiffImagePlugin.WRITE_LIBTIFF = False
def test_subifd(self, tmp_path): def test_subifd(self, tmp_path: Path) -> None:
outfile = str(tmp_path / "temp.tif") outfile = str(tmp_path / "temp.tif")
with Image.open("Tests/images/g4_orientation_6.tif") as im: with Image.open("Tests/images/g4_orientation_6.tif") as im:
im.tag_v2[SUBIFD] = 10000 im.tag_v2[SUBIFD] = 10000
@ -330,7 +331,7 @@ class TestFileLibTiff(LibTiffTestCase):
# Should not segfault # Should not segfault
im.save(outfile) im.save(outfile)
def test_xmlpacket_tag(self, tmp_path): def test_xmlpacket_tag(self, tmp_path: Path) -> None:
TiffImagePlugin.WRITE_LIBTIFF = True TiffImagePlugin.WRITE_LIBTIFF = True
out = str(tmp_path / "temp.tif") out = str(tmp_path / "temp.tif")
@ -341,7 +342,7 @@ class TestFileLibTiff(LibTiffTestCase):
if 700 in reloaded.tag_v2: if 700 in reloaded.tag_v2:
assert reloaded.tag_v2[700] == b"xmlpacket tag" assert reloaded.tag_v2[700] == b"xmlpacket tag"
def test_int_dpi(self, tmp_path): def test_int_dpi(self, tmp_path: Path) -> None:
# issue #1765 # issue #1765
im = hopper("RGB") im = hopper("RGB")
out = str(tmp_path / "temp.tif") out = str(tmp_path / "temp.tif")
@ -351,7 +352,7 @@ class TestFileLibTiff(LibTiffTestCase):
with Image.open(out) as reloaded: with Image.open(out) as reloaded:
assert reloaded.info["dpi"] == (72.0, 72.0) assert reloaded.info["dpi"] == (72.0, 72.0)
def test_g3_compression(self, tmp_path): def test_g3_compression(self, tmp_path: Path) -> None:
with Image.open("Tests/images/hopper_g4_500.tif") as i: with Image.open("Tests/images/hopper_g4_500.tif") as i:
out = str(tmp_path / "temp.tif") out = str(tmp_path / "temp.tif")
i.save(out, compression="group3") i.save(out, compression="group3")
@ -360,7 +361,7 @@ class TestFileLibTiff(LibTiffTestCase):
assert reread.info["compression"] == "group3" assert reread.info["compression"] == "group3"
assert_image_equal(reread, i) assert_image_equal(reread, i)
def test_little_endian(self, tmp_path): def test_little_endian(self, tmp_path: Path) -> None:
with Image.open("Tests/images/16bit.deflate.tif") as im: with Image.open("Tests/images/16bit.deflate.tif") as im:
assert im.getpixel((0, 0)) == 480 assert im.getpixel((0, 0)) == 480
assert im.mode == "I;16" assert im.mode == "I;16"
@ -379,7 +380,7 @@ class TestFileLibTiff(LibTiffTestCase):
# UNDONE - libtiff defaults to writing in native endian, so # UNDONE - libtiff defaults to writing in native endian, so
# on big endian, we'll get back mode = 'I;16B' here. # on big endian, we'll get back mode = 'I;16B' here.
def test_big_endian(self, tmp_path): def test_big_endian(self, tmp_path: Path) -> None:
with Image.open("Tests/images/16bit.MM.deflate.tif") as im: with Image.open("Tests/images/16bit.MM.deflate.tif") as im:
assert im.getpixel((0, 0)) == 480 assert im.getpixel((0, 0)) == 480
assert im.mode == "I;16B" assert im.mode == "I;16B"
@ -396,7 +397,7 @@ class TestFileLibTiff(LibTiffTestCase):
assert reread.info["compression"] == im.info["compression"] assert reread.info["compression"] == im.info["compression"]
assert reread.getpixel((0, 0)) == 480 assert reread.getpixel((0, 0)) == 480
def test_g4_string_info(self, tmp_path): def test_g4_string_info(self, tmp_path: Path) -> None:
"""Tests String data in info directory""" """Tests String data in info directory"""
test_file = "Tests/images/hopper_g4_500.tif" test_file = "Tests/images/hopper_g4_500.tif"
with Image.open(test_file) as orig: with Image.open(test_file) as orig:
@ -409,7 +410,7 @@ class TestFileLibTiff(LibTiffTestCase):
assert "temp.tif" == reread.tag_v2[269] assert "temp.tif" == reread.tag_v2[269]
assert "temp.tif" == reread.tag[269][0] assert "temp.tif" == reread.tag[269][0]
def test_12bit_rawmode(self): def test_12bit_rawmode(self) -> None:
"""Are we generating the same interpretation """Are we generating the same interpretation
of the image as Imagemagick is?""" of the image as Imagemagick is?"""
TiffImagePlugin.READ_LIBTIFF = True TiffImagePlugin.READ_LIBTIFF = True
@ -424,7 +425,7 @@ class TestFileLibTiff(LibTiffTestCase):
assert_image_equal_tofile(im, "Tests/images/12in16bit.tif") assert_image_equal_tofile(im, "Tests/images/12in16bit.tif")
def test_blur(self, tmp_path): def test_blur(self, tmp_path: Path) -> None:
# test case from irc, how to do blur on b/w image # test case from irc, how to do blur on b/w image
# and save to compressed tif. # and save to compressed tif.
out = str(tmp_path / "temp.tif") out = str(tmp_path / "temp.tif")
@ -436,7 +437,7 @@ class TestFileLibTiff(LibTiffTestCase):
assert_image_equal_tofile(im, out) assert_image_equal_tofile(im, out)
def test_compressions(self, tmp_path): def test_compressions(self, tmp_path: Path) -> None:
# Test various tiff compressions and assert similar image content but reduced # Test various tiff compressions and assert similar image content but reduced
# file sizes. # file sizes.
im = hopper("RGB") im = hopper("RGB")
@ -462,7 +463,7 @@ class TestFileLibTiff(LibTiffTestCase):
assert size_compressed > size_jpeg assert size_compressed > size_jpeg
assert size_jpeg > size_jpeg_30 assert size_jpeg > size_jpeg_30
def test_tiff_jpeg_compression(self, tmp_path): def test_tiff_jpeg_compression(self, tmp_path: Path) -> None:
im = hopper("RGB") im = hopper("RGB")
out = str(tmp_path / "temp.tif") out = str(tmp_path / "temp.tif")
im.save(out, compression="tiff_jpeg") im.save(out, compression="tiff_jpeg")
@ -470,7 +471,7 @@ class TestFileLibTiff(LibTiffTestCase):
with Image.open(out) as reloaded: with Image.open(out) as reloaded:
assert reloaded.info["compression"] == "jpeg" assert reloaded.info["compression"] == "jpeg"
def test_tiff_deflate_compression(self, tmp_path): def test_tiff_deflate_compression(self, tmp_path: Path) -> None:
im = hopper("RGB") im = hopper("RGB")
out = str(tmp_path / "temp.tif") out = str(tmp_path / "temp.tif")
im.save(out, compression="tiff_deflate") im.save(out, compression="tiff_deflate")
@ -478,7 +479,7 @@ class TestFileLibTiff(LibTiffTestCase):
with Image.open(out) as reloaded: with Image.open(out) as reloaded:
assert reloaded.info["compression"] == "tiff_adobe_deflate" assert reloaded.info["compression"] == "tiff_adobe_deflate"
def test_quality(self, tmp_path): def test_quality(self, tmp_path: Path) -> None:
im = hopper("RGB") im = hopper("RGB")
out = str(tmp_path / "temp.tif") out = str(tmp_path / "temp.tif")
@ -493,7 +494,7 @@ class TestFileLibTiff(LibTiffTestCase):
im.save(out, compression="jpeg", quality=0) im.save(out, compression="jpeg", quality=0)
im.save(out, compression="jpeg", quality=100) im.save(out, compression="jpeg", quality=100)
def test_cmyk_save(self, tmp_path): def test_cmyk_save(self, tmp_path: Path) -> None:
im = hopper("CMYK") im = hopper("CMYK")
out = str(tmp_path / "temp.tif") out = str(tmp_path / "temp.tif")
@ -501,7 +502,7 @@ class TestFileLibTiff(LibTiffTestCase):
assert_image_equal_tofile(im, out) assert_image_equal_tofile(im, out)
@pytest.mark.parametrize("im", (hopper("P"), Image.new("P", (1, 1), "#000"))) @pytest.mark.parametrize("im", (hopper("P"), Image.new("P", (1, 1), "#000")))
def test_palette_save(self, im, tmp_path): def test_palette_save(self, im, tmp_path: Path) -> None:
out = str(tmp_path / "temp.tif") out = str(tmp_path / "temp.tif")
TiffImagePlugin.WRITE_LIBTIFF = True TiffImagePlugin.WRITE_LIBTIFF = True
@ -513,14 +514,14 @@ class TestFileLibTiff(LibTiffTestCase):
assert len(reloaded.tag_v2[320]) == 768 assert len(reloaded.tag_v2[320]) == 768
@pytest.mark.parametrize("compression", ("tiff_ccitt", "group3", "group4")) @pytest.mark.parametrize("compression", ("tiff_ccitt", "group3", "group4"))
def test_bw_compression_w_rgb(self, compression, tmp_path): def test_bw_compression_w_rgb(self, compression, tmp_path: Path) -> None:
im = hopper("RGB") im = hopper("RGB")
out = str(tmp_path / "temp.tif") out = str(tmp_path / "temp.tif")
with pytest.raises(OSError): with pytest.raises(OSError):
im.save(out, compression=compression) im.save(out, compression=compression)
def test_fp_leak(self): def test_fp_leak(self) -> None:
im = Image.open("Tests/images/hopper_g4_500.tif") im = Image.open("Tests/images/hopper_g4_500.tif")
fn = im.fp.fileno() fn = im.fp.fileno()
@ -534,7 +535,7 @@ class TestFileLibTiff(LibTiffTestCase):
with pytest.raises(OSError): with pytest.raises(OSError):
os.close(fn) os.close(fn)
def test_multipage(self): def test_multipage(self) -> None:
# issue #862 # issue #862
TiffImagePlugin.READ_LIBTIFF = True TiffImagePlugin.READ_LIBTIFF = True
with Image.open("Tests/images/multipage.tiff") as im: with Image.open("Tests/images/multipage.tiff") as im:
@ -557,7 +558,7 @@ class TestFileLibTiff(LibTiffTestCase):
TiffImagePlugin.READ_LIBTIFF = False TiffImagePlugin.READ_LIBTIFF = False
def test_multipage_nframes(self): def test_multipage_nframes(self) -> None:
# issue #862 # issue #862
TiffImagePlugin.READ_LIBTIFF = True TiffImagePlugin.READ_LIBTIFF = True
with Image.open("Tests/images/multipage.tiff") as im: with Image.open("Tests/images/multipage.tiff") as im:
@ -570,7 +571,7 @@ class TestFileLibTiff(LibTiffTestCase):
TiffImagePlugin.READ_LIBTIFF = False TiffImagePlugin.READ_LIBTIFF = False
def test_multipage_seek_backwards(self): def test_multipage_seek_backwards(self) -> None:
TiffImagePlugin.READ_LIBTIFF = True TiffImagePlugin.READ_LIBTIFF = True
with Image.open("Tests/images/multipage.tiff") as im: with Image.open("Tests/images/multipage.tiff") as im:
im.seek(1) im.seek(1)
@ -581,14 +582,14 @@ class TestFileLibTiff(LibTiffTestCase):
TiffImagePlugin.READ_LIBTIFF = False TiffImagePlugin.READ_LIBTIFF = False
def test__next(self): def test__next(self) -> None:
TiffImagePlugin.READ_LIBTIFF = True TiffImagePlugin.READ_LIBTIFF = True
with Image.open("Tests/images/hopper.tif") as im: with Image.open("Tests/images/hopper.tif") as im:
assert not im.tag.next assert not im.tag.next
im.load() im.load()
assert not im.tag.next assert not im.tag.next
def test_4bit(self): def test_4bit(self) -> None:
# Arrange # Arrange
test_file = "Tests/images/hopper_gray_4bpp.tif" test_file = "Tests/images/hopper_gray_4bpp.tif"
original = hopper("L") original = hopper("L")
@ -603,7 +604,7 @@ class TestFileLibTiff(LibTiffTestCase):
assert im.mode == "L" assert im.mode == "L"
assert_image_similar(im, original, 7.3) assert_image_similar(im, original, 7.3)
def test_gray_semibyte_per_pixel(self): def test_gray_semibyte_per_pixel(self) -> None:
test_files = ( test_files = (
( (
24.8, # epsilon 24.8, # epsilon
@ -636,7 +637,7 @@ class TestFileLibTiff(LibTiffTestCase):
assert im2.mode == "L" assert im2.mode == "L"
assert_image_equal(im, im2) assert_image_equal(im, im2)
def test_save_bytesio(self): def test_save_bytesio(self) -> None:
# PR 1011 # PR 1011
# Test TIFF saving to io.BytesIO() object. # Test TIFF saving to io.BytesIO() object.
@ -646,7 +647,7 @@ class TestFileLibTiff(LibTiffTestCase):
# Generate test image # Generate test image
pilim = hopper() pilim = hopper()
def save_bytesio(compression=None): def save_bytesio(compression=None) -> None:
buffer_io = io.BytesIO() buffer_io = io.BytesIO()
pilim.save(buffer_io, format="tiff", compression=compression) pilim.save(buffer_io, format="tiff", compression=compression)
buffer_io.seek(0) buffer_io.seek(0)
@ -661,7 +662,7 @@ class TestFileLibTiff(LibTiffTestCase):
TiffImagePlugin.WRITE_LIBTIFF = False TiffImagePlugin.WRITE_LIBTIFF = False
TiffImagePlugin.READ_LIBTIFF = False TiffImagePlugin.READ_LIBTIFF = False
def test_save_ycbcr(self, tmp_path): def test_save_ycbcr(self, tmp_path: Path) -> None:
im = hopper("YCbCr") im = hopper("YCbCr")
outfile = str(tmp_path / "temp.tif") outfile = str(tmp_path / "temp.tif")
im.save(outfile, compression="jpeg") im.save(outfile, compression="jpeg")
@ -670,7 +671,7 @@ class TestFileLibTiff(LibTiffTestCase):
assert reloaded.tag_v2[530] == (1, 1) assert reloaded.tag_v2[530] == (1, 1)
assert reloaded.tag_v2[532] == (0, 255, 128, 255, 128, 255) assert reloaded.tag_v2[532] == (0, 255, 128, 255, 128, 255)
def test_exif_ifd(self, tmp_path): def test_exif_ifd(self, tmp_path: Path) -> None:
outfile = str(tmp_path / "temp.tif") outfile = str(tmp_path / "temp.tif")
with Image.open("Tests/images/tiff_adobe_deflate.tif") as im: with Image.open("Tests/images/tiff_adobe_deflate.tif") as im:
assert im.tag_v2[34665] == 125456 assert im.tag_v2[34665] == 125456
@ -680,7 +681,7 @@ class TestFileLibTiff(LibTiffTestCase):
if Image.core.libtiff_support_custom_tags: if Image.core.libtiff_support_custom_tags:
assert reloaded.tag_v2[34665] == 125456 assert reloaded.tag_v2[34665] == 125456
def test_crashing_metadata(self, tmp_path): def test_crashing_metadata(self, tmp_path: Path) -> None:
# issue 1597 # issue 1597
with Image.open("Tests/images/rdf.tif") as im: with Image.open("Tests/images/rdf.tif") as im:
out = str(tmp_path / "temp.tif") out = str(tmp_path / "temp.tif")
@ -690,7 +691,7 @@ class TestFileLibTiff(LibTiffTestCase):
im.save(out, format="TIFF") im.save(out, format="TIFF")
TiffImagePlugin.WRITE_LIBTIFF = False TiffImagePlugin.WRITE_LIBTIFF = False
def test_page_number_x_0(self, tmp_path): def test_page_number_x_0(self, tmp_path: Path) -> None:
# Issue 973 # Issue 973
# Test TIFF with tag 297 (Page Number) having value of 0 0. # Test TIFF with tag 297 (Page Number) having value of 0 0.
# The first number is the current page number. # The first number is the current page number.
@ -704,7 +705,7 @@ class TestFileLibTiff(LibTiffTestCase):
# Should not divide by zero # Should not divide by zero
im.save(outfile) im.save(outfile)
def test_fd_duplication(self, tmp_path): def test_fd_duplication(self, tmp_path: Path) -> None:
# https://github.com/python-pillow/Pillow/issues/1651 # https://github.com/python-pillow/Pillow/issues/1651
tmpfile = str(tmp_path / "temp.tif") tmpfile = str(tmp_path / "temp.tif")
@ -718,7 +719,7 @@ class TestFileLibTiff(LibTiffTestCase):
# Should not raise PermissionError. # Should not raise PermissionError.
os.remove(tmpfile) os.remove(tmpfile)
def test_read_icc(self): def test_read_icc(self) -> None:
with Image.open("Tests/images/hopper.iccprofile.tif") as img: with Image.open("Tests/images/hopper.iccprofile.tif") as img:
icc = img.info.get("icc_profile") icc = img.info.get("icc_profile")
assert icc is not None assert icc is not None
@ -729,8 +730,8 @@ class TestFileLibTiff(LibTiffTestCase):
TiffImagePlugin.READ_LIBTIFF = False TiffImagePlugin.READ_LIBTIFF = False
assert icc == icc_libtiff assert icc == icc_libtiff
def test_write_icc(self, tmp_path): def test_write_icc(self, tmp_path: Path) -> None:
def check_write(libtiff): def check_write(libtiff) -> None:
TiffImagePlugin.WRITE_LIBTIFF = libtiff TiffImagePlugin.WRITE_LIBTIFF = libtiff
with Image.open("Tests/images/hopper.iccprofile.tif") as img: with Image.open("Tests/images/hopper.iccprofile.tif") as img:
@ -749,7 +750,7 @@ class TestFileLibTiff(LibTiffTestCase):
for libtiff in libtiffs: for libtiff in libtiffs:
check_write(libtiff) check_write(libtiff)
def test_multipage_compression(self): def test_multipage_compression(self) -> None:
with Image.open("Tests/images/compression.tif") as im: with Image.open("Tests/images/compression.tif") as im:
im.seek(0) im.seek(0)
assert im._compression == "tiff_ccitt" assert im._compression == "tiff_ccitt"
@ -765,7 +766,7 @@ class TestFileLibTiff(LibTiffTestCase):
assert im.size == (10, 10) assert im.size == (10, 10)
im.load() im.load()
def test_save_tiff_with_jpegtables(self, tmp_path): def test_save_tiff_with_jpegtables(self, tmp_path: Path) -> None:
# Arrange # Arrange
outfile = str(tmp_path / "temp.tif") outfile = str(tmp_path / "temp.tif")
@ -777,7 +778,7 @@ class TestFileLibTiff(LibTiffTestCase):
# Should not raise UnicodeDecodeError or anything else # Should not raise UnicodeDecodeError or anything else
im.save(outfile) im.save(outfile)
def test_16bit_RGB_tiff(self): def test_16bit_RGB_tiff(self) -> None:
with Image.open("Tests/images/tiff_16bit_RGB.tiff") as im: with Image.open("Tests/images/tiff_16bit_RGB.tiff") as im:
assert im.mode == "RGB" assert im.mode == "RGB"
assert im.size == (100, 40) assert im.size == (100, 40)
@ -793,7 +794,7 @@ class TestFileLibTiff(LibTiffTestCase):
assert_image_equal_tofile(im, "Tests/images/tiff_16bit_RGB_target.png") assert_image_equal_tofile(im, "Tests/images/tiff_16bit_RGB_target.png")
def test_16bit_RGBa_tiff(self): def test_16bit_RGBa_tiff(self) -> None:
with Image.open("Tests/images/tiff_16bit_RGBa.tiff") as im: with Image.open("Tests/images/tiff_16bit_RGBa.tiff") as im:
assert im.mode == "RGBA" assert im.mode == "RGBA"
assert im.size == (100, 40) assert im.size == (100, 40)
@ -805,7 +806,7 @@ class TestFileLibTiff(LibTiffTestCase):
assert_image_equal_tofile(im, "Tests/images/tiff_16bit_RGBa_target.png") assert_image_equal_tofile(im, "Tests/images/tiff_16bit_RGBa_target.png")
@skip_unless_feature("jpg") @skip_unless_feature("jpg")
def test_gimp_tiff(self): def test_gimp_tiff(self) -> None:
# Read TIFF JPEG images from GIMP [@PIL168] # Read TIFF JPEG images from GIMP [@PIL168]
filename = "Tests/images/pil168.tif" filename = "Tests/images/pil168.tif"
with Image.open(filename) as im: with Image.open(filename) as im:
@ -818,14 +819,14 @@ class TestFileLibTiff(LibTiffTestCase):
assert_image_equal_tofile(im, "Tests/images/pil168.png") assert_image_equal_tofile(im, "Tests/images/pil168.png")
def test_sampleformat(self): def test_sampleformat(self) -> None:
# https://github.com/python-pillow/Pillow/issues/1466 # https://github.com/python-pillow/Pillow/issues/1466
with Image.open("Tests/images/copyleft.tiff") as im: with Image.open("Tests/images/copyleft.tiff") as im:
assert im.mode == "RGB" assert im.mode == "RGB"
assert_image_equal_tofile(im, "Tests/images/copyleft.png", mode="RGB") assert_image_equal_tofile(im, "Tests/images/copyleft.png", mode="RGB")
def test_sampleformat_write(self, tmp_path): def test_sampleformat_write(self, tmp_path: Path) -> None:
im = Image.new("F", (1, 1)) im = Image.new("F", (1, 1))
out = str(tmp_path / "temp.tif") out = str(tmp_path / "temp.tif")
TiffImagePlugin.WRITE_LIBTIFF = True TiffImagePlugin.WRITE_LIBTIFF = True
@ -874,7 +875,7 @@ class TestFileLibTiff(LibTiffTestCase):
sys.stderr.write(captured.err) sys.stderr.write(captured.err)
raise raise
def test_lzw(self): def test_lzw(self) -> None:
with Image.open("Tests/images/hopper_lzw.tif") as im: with Image.open("Tests/images/hopper_lzw.tif") as im:
assert im.mode == "RGB" assert im.mode == "RGB"
assert im.size == (128, 128) assert im.size == (128, 128)
@ -882,12 +883,12 @@ class TestFileLibTiff(LibTiffTestCase):
im2 = hopper() im2 = hopper()
assert_image_similar(im, im2, 5) assert_image_similar(im, im2, 5)
def test_strip_cmyk_jpeg(self): def test_strip_cmyk_jpeg(self) -> None:
infile = "Tests/images/tiff_strip_cmyk_jpeg.tif" infile = "Tests/images/tiff_strip_cmyk_jpeg.tif"
with Image.open(infile) as im: with Image.open(infile) as im:
assert_image_similar_tofile(im, "Tests/images/pil_sample_cmyk.jpg", 0.5) assert_image_similar_tofile(im, "Tests/images/pil_sample_cmyk.jpg", 0.5)
def test_strip_cmyk_16l_jpeg(self): def test_strip_cmyk_16l_jpeg(self) -> None:
infile = "Tests/images/tiff_strip_cmyk_16l_jpeg.tif" infile = "Tests/images/tiff_strip_cmyk_16l_jpeg.tif"
with Image.open(infile) as im: with Image.open(infile) as im:
assert_image_similar_tofile(im, "Tests/images/pil_sample_cmyk.jpg", 0.5) assert_image_similar_tofile(im, "Tests/images/pil_sample_cmyk.jpg", 0.5)
@ -895,7 +896,7 @@ class TestFileLibTiff(LibTiffTestCase):
@mark_if_feature_version( @mark_if_feature_version(
pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing"
) )
def test_strip_ycbcr_jpeg_2x2_sampling(self): def test_strip_ycbcr_jpeg_2x2_sampling(self) -> None:
infile = "Tests/images/tiff_strip_ycbcr_jpeg_2x2_sampling.tif" infile = "Tests/images/tiff_strip_ycbcr_jpeg_2x2_sampling.tif"
with Image.open(infile) as im: with Image.open(infile) as im:
assert_image_similar_tofile(im, "Tests/images/flower.jpg", 1.2) assert_image_similar_tofile(im, "Tests/images/flower.jpg", 1.2)
@ -903,12 +904,12 @@ class TestFileLibTiff(LibTiffTestCase):
@mark_if_feature_version( @mark_if_feature_version(
pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing"
) )
def test_strip_ycbcr_jpeg_1x1_sampling(self): def test_strip_ycbcr_jpeg_1x1_sampling(self) -> None:
infile = "Tests/images/tiff_strip_ycbcr_jpeg_1x1_sampling.tif" infile = "Tests/images/tiff_strip_ycbcr_jpeg_1x1_sampling.tif"
with Image.open(infile) as im: with Image.open(infile) as im:
assert_image_similar_tofile(im, "Tests/images/flower2.jpg", 0.01) assert_image_similar_tofile(im, "Tests/images/flower2.jpg", 0.01)
def test_tiled_cmyk_jpeg(self): def test_tiled_cmyk_jpeg(self) -> None:
infile = "Tests/images/tiff_tiled_cmyk_jpeg.tif" infile = "Tests/images/tiff_tiled_cmyk_jpeg.tif"
with Image.open(infile) as im: with Image.open(infile) as im:
assert_image_similar_tofile(im, "Tests/images/pil_sample_cmyk.jpg", 0.5) assert_image_similar_tofile(im, "Tests/images/pil_sample_cmyk.jpg", 0.5)
@ -916,7 +917,7 @@ class TestFileLibTiff(LibTiffTestCase):
@mark_if_feature_version( @mark_if_feature_version(
pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing"
) )
def test_tiled_ycbcr_jpeg_1x1_sampling(self): def test_tiled_ycbcr_jpeg_1x1_sampling(self) -> None:
infile = "Tests/images/tiff_tiled_ycbcr_jpeg_1x1_sampling.tif" infile = "Tests/images/tiff_tiled_ycbcr_jpeg_1x1_sampling.tif"
with Image.open(infile) as im: with Image.open(infile) as im:
assert_image_similar_tofile(im, "Tests/images/flower2.jpg", 0.01) assert_image_similar_tofile(im, "Tests/images/flower2.jpg", 0.01)
@ -924,45 +925,45 @@ class TestFileLibTiff(LibTiffTestCase):
@mark_if_feature_version( @mark_if_feature_version(
pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing"
) )
def test_tiled_ycbcr_jpeg_2x2_sampling(self): def test_tiled_ycbcr_jpeg_2x2_sampling(self) -> None:
infile = "Tests/images/tiff_tiled_ycbcr_jpeg_2x2_sampling.tif" infile = "Tests/images/tiff_tiled_ycbcr_jpeg_2x2_sampling.tif"
with Image.open(infile) as im: with Image.open(infile) as im:
assert_image_similar_tofile(im, "Tests/images/flower.jpg", 1.5) assert_image_similar_tofile(im, "Tests/images/flower.jpg", 1.5)
def test_strip_planar_rgb(self): def test_strip_planar_rgb(self) -> None:
# gdal_translate -co TILED=no -co INTERLEAVE=BAND -co COMPRESS=LZW \ # gdal_translate -co TILED=no -co INTERLEAVE=BAND -co COMPRESS=LZW \
# tiff_strip_raw.tif tiff_strip_planar_lzw.tiff # tiff_strip_raw.tif tiff_strip_planar_lzw.tiff
infile = "Tests/images/tiff_strip_planar_lzw.tiff" infile = "Tests/images/tiff_strip_planar_lzw.tiff"
with Image.open(infile) as im: with Image.open(infile) as im:
assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png") assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png")
def test_tiled_planar_rgb(self): def test_tiled_planar_rgb(self) -> None:
# gdal_translate -co TILED=yes -co INTERLEAVE=BAND -co COMPRESS=LZW \ # gdal_translate -co TILED=yes -co INTERLEAVE=BAND -co COMPRESS=LZW \
# tiff_tiled_raw.tif tiff_tiled_planar_lzw.tiff # tiff_tiled_raw.tif tiff_tiled_planar_lzw.tiff
infile = "Tests/images/tiff_tiled_planar_lzw.tiff" infile = "Tests/images/tiff_tiled_planar_lzw.tiff"
with Image.open(infile) as im: with Image.open(infile) as im:
assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png") assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png")
def test_tiled_planar_16bit_RGB(self): def test_tiled_planar_16bit_RGB(self) -> None:
# gdal_translate -co TILED=yes -co INTERLEAVE=BAND -co COMPRESS=LZW \ # gdal_translate -co TILED=yes -co INTERLEAVE=BAND -co COMPRESS=LZW \
# tiff_16bit_RGB.tiff tiff_tiled_planar_16bit_RGB.tiff # tiff_16bit_RGB.tiff tiff_tiled_planar_16bit_RGB.tiff
with Image.open("Tests/images/tiff_tiled_planar_16bit_RGB.tiff") as im: with Image.open("Tests/images/tiff_tiled_planar_16bit_RGB.tiff") as im:
assert_image_equal_tofile(im, "Tests/images/tiff_16bit_RGB_target.png") assert_image_equal_tofile(im, "Tests/images/tiff_16bit_RGB_target.png")
def test_strip_planar_16bit_RGB(self): def test_strip_planar_16bit_RGB(self) -> None:
# gdal_translate -co TILED=no -co INTERLEAVE=BAND -co COMPRESS=LZW \ # gdal_translate -co TILED=no -co INTERLEAVE=BAND -co COMPRESS=LZW \
# tiff_16bit_RGB.tiff tiff_strip_planar_16bit_RGB.tiff # tiff_16bit_RGB.tiff tiff_strip_planar_16bit_RGB.tiff
with Image.open("Tests/images/tiff_strip_planar_16bit_RGB.tiff") as im: with Image.open("Tests/images/tiff_strip_planar_16bit_RGB.tiff") as im:
assert_image_equal_tofile(im, "Tests/images/tiff_16bit_RGB_target.png") assert_image_equal_tofile(im, "Tests/images/tiff_16bit_RGB_target.png")
def test_tiled_planar_16bit_RGBa(self): def test_tiled_planar_16bit_RGBa(self) -> None:
# gdal_translate -co TILED=yes \ # gdal_translate -co TILED=yes \
# -co INTERLEAVE=BAND -co COMPRESS=LZW -co ALPHA=PREMULTIPLIED \ # -co INTERLEAVE=BAND -co COMPRESS=LZW -co ALPHA=PREMULTIPLIED \
# tiff_16bit_RGBa.tiff tiff_tiled_planar_16bit_RGBa.tiff # tiff_16bit_RGBa.tiff tiff_tiled_planar_16bit_RGBa.tiff
with Image.open("Tests/images/tiff_tiled_planar_16bit_RGBa.tiff") as im: with Image.open("Tests/images/tiff_tiled_planar_16bit_RGBa.tiff") as im:
assert_image_equal_tofile(im, "Tests/images/tiff_16bit_RGBa_target.png") assert_image_equal_tofile(im, "Tests/images/tiff_16bit_RGBa_target.png")
def test_strip_planar_16bit_RGBa(self): def test_strip_planar_16bit_RGBa(self) -> None:
# gdal_translate -co TILED=no \ # gdal_translate -co TILED=no \
# -co INTERLEAVE=BAND -co COMPRESS=LZW -co ALPHA=PREMULTIPLIED \ # -co INTERLEAVE=BAND -co COMPRESS=LZW -co ALPHA=PREMULTIPLIED \
# tiff_16bit_RGBa.tiff tiff_strip_planar_16bit_RGBa.tiff # tiff_16bit_RGBa.tiff tiff_strip_planar_16bit_RGBa.tiff
@ -970,7 +971,7 @@ class TestFileLibTiff(LibTiffTestCase):
assert_image_equal_tofile(im, "Tests/images/tiff_16bit_RGBa_target.png") assert_image_equal_tofile(im, "Tests/images/tiff_16bit_RGBa_target.png")
@pytest.mark.parametrize("compression", (None, "jpeg")) @pytest.mark.parametrize("compression", (None, "jpeg"))
def test_block_tile_tags(self, compression, tmp_path): def test_block_tile_tags(self, compression, tmp_path: Path) -> None:
im = hopper() im = hopper()
out = str(tmp_path / "temp.tif") out = str(tmp_path / "temp.tif")
@ -986,11 +987,11 @@ class TestFileLibTiff(LibTiffTestCase):
for tag in tags: for tag in tags:
assert tag not in reloaded.getexif() assert tag not in reloaded.getexif()
def test_old_style_jpeg(self): def test_old_style_jpeg(self) -> None:
with Image.open("Tests/images/old-style-jpeg-compression.tif") as im: with Image.open("Tests/images/old-style-jpeg-compression.tif") as im:
assert_image_equal_tofile(im, "Tests/images/old-style-jpeg-compression.png") assert_image_equal_tofile(im, "Tests/images/old-style-jpeg-compression.png")
def test_open_missing_samplesperpixel(self): def test_open_missing_samplesperpixel(self) -> None:
with Image.open( with Image.open(
"Tests/images/old-style-jpeg-compression-no-samplesperpixel.tif" "Tests/images/old-style-jpeg-compression-no-samplesperpixel.tif"
) as im: ) as im:
@ -1019,21 +1020,21 @@ class TestFileLibTiff(LibTiffTestCase):
), ),
], ],
) )
def test_wrong_bits_per_sample(self, file_name, mode, size, tile): def test_wrong_bits_per_sample(self, file_name, mode, size, tile) -> None:
with Image.open("Tests/images/" + file_name) as im: with Image.open("Tests/images/" + file_name) as im:
assert im.mode == mode assert im.mode == mode
assert im.size == size assert im.size == size
assert im.tile == tile assert im.tile == tile
im.load() im.load()
def test_no_rows_per_strip(self): def test_no_rows_per_strip(self) -> None:
# This image does not have a RowsPerStrip TIFF tag # This image does not have a RowsPerStrip TIFF tag
infile = "Tests/images/no_rows_per_strip.tif" infile = "Tests/images/no_rows_per_strip.tif"
with Image.open(infile) as im: with Image.open(infile) as im:
im.load() im.load()
assert im.size == (950, 975) assert im.size == (950, 975)
def test_orientation(self): def test_orientation(self) -> None:
with Image.open("Tests/images/g4_orientation_1.tif") as base_im: with Image.open("Tests/images/g4_orientation_1.tif") as base_im:
for i in range(2, 9): for i in range(2, 9):
with Image.open("Tests/images/g4_orientation_" + str(i) + ".tif") as im: with Image.open("Tests/images/g4_orientation_" + str(i) + ".tif") as im:
@ -1044,7 +1045,7 @@ class TestFileLibTiff(LibTiffTestCase):
assert_image_similar(base_im, im, 0.7) assert_image_similar(base_im, im, 0.7)
def test_exif_transpose(self): def test_exif_transpose(self) -> None:
with Image.open("Tests/images/g4_orientation_1.tif") as base_im: with Image.open("Tests/images/g4_orientation_1.tif") as base_im:
for i in range(2, 9): for i in range(2, 9):
with Image.open("Tests/images/g4_orientation_" + str(i) + ".tif") as im: with Image.open("Tests/images/g4_orientation_" + str(i) + ".tif") as im:
@ -1053,7 +1054,7 @@ class TestFileLibTiff(LibTiffTestCase):
assert_image_similar(base_im, im, 0.7) assert_image_similar(base_im, im, 0.7)
@pytest.mark.valgrind_known_error(reason="Backtrace in Python Core") @pytest.mark.valgrind_known_error(reason="Backtrace in Python Core")
def test_sampleformat_not_corrupted(self): def test_sampleformat_not_corrupted(self) -> None:
# Assert that a TIFF image with SampleFormat=UINT tag is not corrupted # Assert that a TIFF image with SampleFormat=UINT tag is not corrupted
# when saving to a new file. # when saving to a new file.
# Pillow 6.0 fails with "OSError: cannot identify image file". # Pillow 6.0 fails with "OSError: cannot identify image file".
@ -1074,7 +1075,7 @@ class TestFileLibTiff(LibTiffTestCase):
with Image.open(out) as im: with Image.open(out) as im:
im.load() im.load()
def test_realloc_overflow(self): def test_realloc_overflow(self) -> None:
TiffImagePlugin.READ_LIBTIFF = True TiffImagePlugin.READ_LIBTIFF = True
with Image.open("Tests/images/tiff_overflow_rows_per_strip.tif") as im: with Image.open("Tests/images/tiff_overflow_rows_per_strip.tif") as im:
with pytest.raises(OSError) as e: with pytest.raises(OSError) as e:
@ -1085,7 +1086,7 @@ class TestFileLibTiff(LibTiffTestCase):
TiffImagePlugin.READ_LIBTIFF = False TiffImagePlugin.READ_LIBTIFF = False
@pytest.mark.parametrize("compression", ("tiff_adobe_deflate", "jpeg")) @pytest.mark.parametrize("compression", ("tiff_adobe_deflate", "jpeg"))
def test_save_multistrip(self, compression, tmp_path): def test_save_multistrip(self, compression, tmp_path: Path) -> None:
im = hopper("RGB").resize((256, 256)) im = hopper("RGB").resize((256, 256))
out = str(tmp_path / "temp.tif") out = str(tmp_path / "temp.tif")
im.save(out, compression=compression) im.save(out, compression=compression)
@ -1095,7 +1096,7 @@ class TestFileLibTiff(LibTiffTestCase):
assert len(im.tag_v2[STRIPOFFSETS]) > 1 assert len(im.tag_v2[STRIPOFFSETS]) > 1
@pytest.mark.parametrize("argument", (True, False)) @pytest.mark.parametrize("argument", (True, False))
def test_save_single_strip(self, argument, tmp_path): def test_save_single_strip(self, argument, tmp_path: Path) -> None:
im = hopper("RGB").resize((256, 256)) im = hopper("RGB").resize((256, 256))
out = str(tmp_path / "temp.tif") out = str(tmp_path / "temp.tif")
@ -1113,13 +1114,13 @@ class TestFileLibTiff(LibTiffTestCase):
TiffImagePlugin.STRIP_SIZE = 65536 TiffImagePlugin.STRIP_SIZE = 65536
@pytest.mark.parametrize("compression", ("tiff_adobe_deflate", None)) @pytest.mark.parametrize("compression", ("tiff_adobe_deflate", None))
def test_save_zero(self, compression, tmp_path): def test_save_zero(self, compression, tmp_path: Path) -> None:
im = Image.new("RGB", (0, 0)) im = Image.new("RGB", (0, 0))
out = str(tmp_path / "temp.tif") out = str(tmp_path / "temp.tif")
with pytest.raises(SystemError): with pytest.raises(SystemError):
im.save(out, compression=compression) im.save(out, compression=compression)
def test_save_many_compressed(self, tmp_path): def test_save_many_compressed(self, tmp_path: Path) -> None:
im = hopper() im = hopper()
out = str(tmp_path / "temp.tif") out = str(tmp_path / "temp.tif")
for _ in range(10000): for _ in range(10000):
@ -1133,7 +1134,7 @@ class TestFileLibTiff(LibTiffTestCase):
("Tests/images/child_ifd_jpeg.tiff", (20,)), ("Tests/images/child_ifd_jpeg.tiff", (20,)),
), ),
) )
def test_get_child_images(self, path, sizes): def test_get_child_images(self, path, sizes) -> None:
with Image.open(path) as im: with Image.open(path) as im:
ims = im.get_child_images() ims = im.get_child_images()

View File

@ -1,6 +1,7 @@
from __future__ import annotations from __future__ import annotations
from io import BytesIO from io import BytesIO
from pathlib import Path
from PIL import Image from PIL import Image
@ -17,7 +18,7 @@ class TestFileLibTiffSmall(LibTiffTestCase):
file just before reading in libtiff. These tests remain file just before reading in libtiff. These tests remain
to ensure that it stays fixed.""" to ensure that it stays fixed."""
def test_g4_hopper_file(self, tmp_path): def test_g4_hopper_file(self, tmp_path: Path) -> None:
"""Testing the open file load path""" """Testing the open file load path"""
test_file = "Tests/images/hopper_g4.tif" test_file = "Tests/images/hopper_g4.tif"
@ -26,7 +27,7 @@ class TestFileLibTiffSmall(LibTiffTestCase):
assert im.size == (128, 128) assert im.size == (128, 128)
self._assert_noerr(tmp_path, im) self._assert_noerr(tmp_path, im)
def test_g4_hopper_bytesio(self, tmp_path): def test_g4_hopper_bytesio(self, tmp_path: Path) -> None:
"""Testing the bytesio loading code path""" """Testing the bytesio loading code path"""
test_file = "Tests/images/hopper_g4.tif" test_file = "Tests/images/hopper_g4.tif"
s = BytesIO() s = BytesIO()
@ -37,7 +38,7 @@ class TestFileLibTiffSmall(LibTiffTestCase):
assert im.size == (128, 128) assert im.size == (128, 128)
self._assert_noerr(tmp_path, im) self._assert_noerr(tmp_path, im)
def test_g4_hopper(self, tmp_path): def test_g4_hopper(self, tmp_path: Path) -> None:
"""The 128x128 lena image failed for some reason.""" """The 128x128 lena image failed for some reason."""
test_file = "Tests/images/hopper_g4.tif" test_file = "Tests/images/hopper_g4.tif"

View File

@ -13,7 +13,7 @@ pytestmark = skip_unless_feature("libtiff")
TEST_FILE = "Tests/images/hopper.mic" TEST_FILE = "Tests/images/hopper.mic"
def test_sanity(): def test_sanity() -> None:
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
im.load() im.load()
assert im.mode == "RGBA" assert im.mode == "RGBA"
@ -28,22 +28,22 @@ def test_sanity():
assert_image_similar(im, im2, 10) assert_image_similar(im, im2, 10)
def test_n_frames(): def test_n_frames() -> None:
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
assert im.n_frames == 1 assert im.n_frames == 1
def test_is_animated(): def test_is_animated() -> None:
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
assert not im.is_animated assert not im.is_animated
def test_tell(): def test_tell() -> None:
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
assert im.tell() == 0 assert im.tell() == 0
def test_seek(): def test_seek() -> None:
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
im.seek(0) im.seek(0)
assert im.tell() == 0 assert im.tell() == 0
@ -53,7 +53,7 @@ def test_seek():
assert im.tell() == 0 assert im.tell() == 0
def test_close(): def test_close() -> None:
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
pass pass
assert im.ole.fp.closed assert im.ole.fp.closed
@ -63,7 +63,7 @@ def test_close():
assert im.ole.fp.closed assert im.ole.fp.closed
def test_invalid_file(): def test_invalid_file() -> None:
# Test an invalid OLE file # Test an invalid OLE file
invalid_file = "Tests/images/flower.jpg" invalid_file = "Tests/images/flower.jpg"
with pytest.raises(SyntaxError): with pytest.raises(SyntaxError):

View File

@ -30,7 +30,7 @@ def roundtrip(im, **options):
@pytest.mark.parametrize("test_file", test_files) @pytest.mark.parametrize("test_file", test_files)
def test_sanity(test_file): def test_sanity(test_file) -> None:
with Image.open(test_file) as im: with Image.open(test_file) as im:
im.load() im.load()
assert im.mode == "RGB" assert im.mode == "RGB"
@ -39,8 +39,8 @@ def test_sanity(test_file):
@pytest.mark.skipif(is_pypy(), reason="Requires CPython") @pytest.mark.skipif(is_pypy(), reason="Requires CPython")
def test_unclosed_file(): def test_unclosed_file() -> None:
def open(): def open() -> None:
im = Image.open(test_files[0]) im = Image.open(test_files[0])
im.load() im.load()
@ -48,14 +48,14 @@ def test_unclosed_file():
open() open()
def test_closed_file(): def test_closed_file() -> None:
with warnings.catch_warnings(): with warnings.catch_warnings():
im = Image.open(test_files[0]) im = Image.open(test_files[0])
im.load() im.load()
im.close() im.close()
def test_seek_after_close(): def test_seek_after_close() -> None:
im = Image.open(test_files[0]) im = Image.open(test_files[0])
im.close() im.close()
@ -63,14 +63,14 @@ def test_seek_after_close():
im.seek(1) im.seek(1)
def test_context_manager(): def test_context_manager() -> None:
with warnings.catch_warnings(): with warnings.catch_warnings():
with Image.open(test_files[0]) as im: with Image.open(test_files[0]) as im:
im.load() im.load()
@pytest.mark.parametrize("test_file", test_files) @pytest.mark.parametrize("test_file", test_files)
def test_app(test_file): def test_app(test_file) -> None:
# Test APP/COM reader (@PIL135) # Test APP/COM reader (@PIL135)
with Image.open(test_file) as im: with Image.open(test_file) as im:
assert im.applist[0][0] == "APP1" assert im.applist[0][0] == "APP1"
@ -82,7 +82,7 @@ def test_app(test_file):
@pytest.mark.parametrize("test_file", test_files) @pytest.mark.parametrize("test_file", test_files)
def test_exif(test_file): def test_exif(test_file) -> None:
with Image.open(test_file) as im_original: with Image.open(test_file) as im_original:
im_reloaded = roundtrip(im_original, save_all=True, exif=im_original.getexif()) im_reloaded = roundtrip(im_original, save_all=True, exif=im_original.getexif())
@ -93,7 +93,7 @@ def test_exif(test_file):
assert info[34665] == 188 assert info[34665] == 188
def test_frame_size(): def test_frame_size() -> None:
# This image has been hexedited to contain a different size # This image has been hexedited to contain a different size
# in the EXIF data of the second frame # in the EXIF data of the second frame
with Image.open("Tests/images/sugarshack_frame_size.mpo") as im: with Image.open("Tests/images/sugarshack_frame_size.mpo") as im:
@ -106,7 +106,7 @@ def test_frame_size():
assert im.size == (640, 480) assert im.size == (640, 480)
def test_ignore_frame_size(): def test_ignore_frame_size() -> None:
# Ignore the different size of the second frame # Ignore the different size of the second frame
# since this is not a "Large Thumbnail" image # since this is not a "Large Thumbnail" image
with Image.open("Tests/images/ignore_frame_size.mpo") as im: with Image.open("Tests/images/ignore_frame_size.mpo") as im:
@ -120,7 +120,7 @@ def test_ignore_frame_size():
assert im.size == (64, 64) assert im.size == (64, 64)
def test_parallax(): def test_parallax() -> None:
# Nintendo # Nintendo
with Image.open("Tests/images/sugarshack.mpo") as im: with Image.open("Tests/images/sugarshack.mpo") as im:
exif = im.getexif() exif = im.getexif()
@ -133,7 +133,7 @@ def test_parallax():
assert exif.get_ifd(0x927C)[0xB211] == -3.125 assert exif.get_ifd(0x927C)[0xB211] == -3.125
def test_reload_exif_after_seek(): def test_reload_exif_after_seek() -> None:
with Image.open("Tests/images/sugarshack.mpo") as im: with Image.open("Tests/images/sugarshack.mpo") as im:
exif = im.getexif() exif = im.getexif()
del exif[296] del exif[296]
@ -143,14 +143,14 @@ def test_reload_exif_after_seek():
@pytest.mark.parametrize("test_file", test_files) @pytest.mark.parametrize("test_file", test_files)
def test_mp(test_file): def test_mp(test_file) -> None:
with Image.open(test_file) as im: with Image.open(test_file) as im:
mpinfo = im._getmp() mpinfo = im._getmp()
assert mpinfo[45056] == b"0100" assert mpinfo[45056] == b"0100"
assert mpinfo[45057] == 2 assert mpinfo[45057] == 2
def test_mp_offset(): def test_mp_offset() -> None:
# This image has been manually hexedited to have an IFD offset of 10 # This image has been manually hexedited to have an IFD offset of 10
# in APP2 data, in contrast to normal 8 # in APP2 data, in contrast to normal 8
with Image.open("Tests/images/sugarshack_ifd_offset.mpo") as im: with Image.open("Tests/images/sugarshack_ifd_offset.mpo") as im:
@ -159,7 +159,7 @@ def test_mp_offset():
assert mpinfo[45057] == 2 assert mpinfo[45057] == 2
def test_mp_no_data(): def test_mp_no_data() -> None:
# This image has been manually hexedited to have the second frame # This image has been manually hexedited to have the second frame
# beyond the end of the file # beyond the end of the file
with Image.open("Tests/images/sugarshack_no_data.mpo") as im: with Image.open("Tests/images/sugarshack_no_data.mpo") as im:
@ -168,7 +168,7 @@ def test_mp_no_data():
@pytest.mark.parametrize("test_file", test_files) @pytest.mark.parametrize("test_file", test_files)
def test_mp_attribute(test_file): def test_mp_attribute(test_file) -> None:
with Image.open(test_file) as im: with Image.open(test_file) as im:
mpinfo = im._getmp() mpinfo = im._getmp()
for frame_number, mpentry in enumerate(mpinfo[0xB002]): for frame_number, mpentry in enumerate(mpinfo[0xB002]):
@ -185,7 +185,7 @@ def test_mp_attribute(test_file):
@pytest.mark.parametrize("test_file", test_files) @pytest.mark.parametrize("test_file", test_files)
def test_seek(test_file): def test_seek(test_file) -> None:
with Image.open(test_file) as im: with Image.open(test_file) as im:
assert im.tell() == 0 assert im.tell() == 0
# prior to first image raises an error, both blatant and borderline # prior to first image raises an error, both blatant and borderline
@ -209,13 +209,13 @@ def test_seek(test_file):
assert im.tell() == 0 assert im.tell() == 0
def test_n_frames(): def test_n_frames() -> None:
with Image.open("Tests/images/sugarshack.mpo") as im: with Image.open("Tests/images/sugarshack.mpo") as im:
assert im.n_frames == 2 assert im.n_frames == 2
assert im.is_animated assert im.is_animated
def test_eoferror(): def test_eoferror() -> None:
with Image.open("Tests/images/sugarshack.mpo") as im: with Image.open("Tests/images/sugarshack.mpo") as im:
n_frames = im.n_frames n_frames = im.n_frames
@ -229,7 +229,7 @@ def test_eoferror():
@pytest.mark.parametrize("test_file", test_files) @pytest.mark.parametrize("test_file", test_files)
def test_image_grab(test_file): def test_image_grab(test_file) -> None:
with Image.open(test_file) as im: with Image.open(test_file) as im:
assert im.tell() == 0 assert im.tell() == 0
im0 = im.tobytes() im0 = im.tobytes()
@ -244,7 +244,7 @@ def test_image_grab(test_file):
@pytest.mark.parametrize("test_file", test_files) @pytest.mark.parametrize("test_file", test_files)
def test_save(test_file): def test_save(test_file) -> None:
with Image.open(test_file) as im: with Image.open(test_file) as im:
assert im.tell() == 0 assert im.tell() == 0
jpg0 = roundtrip(im) jpg0 = roundtrip(im)
@ -255,7 +255,7 @@ def test_save(test_file):
assert_image_similar(im, jpg1, 30) assert_image_similar(im, jpg1, 30)
def test_save_all(): def test_save_all() -> None:
for test_file in test_files: for test_file in test_files:
with Image.open(test_file) as im: with Image.open(test_file) as im:
im_reloaded = roundtrip(im, save_all=True) im_reloaded = roundtrip(im, save_all=True)

View File

@ -1,6 +1,7 @@
from __future__ import annotations from __future__ import annotations
import os import os
from pathlib import Path
import pytest import pytest
@ -13,7 +14,7 @@ EXTRA_DIR = "Tests/images/picins"
YA_EXTRA_DIR = "Tests/images/msp" YA_EXTRA_DIR = "Tests/images/msp"
def test_sanity(tmp_path): def test_sanity(tmp_path: Path) -> None:
test_file = str(tmp_path / "temp.msp") test_file = str(tmp_path / "temp.msp")
hopper("1").save(test_file) hopper("1").save(test_file)
@ -25,14 +26,14 @@ def test_sanity(tmp_path):
assert im.format == "MSP" assert im.format == "MSP"
def test_invalid_file(): def test_invalid_file() -> None:
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(): def test_bad_checksum() -> None:
# 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"
@ -42,7 +43,7 @@ def test_bad_checksum():
MspImagePlugin.MspImageFile(bad_checksum) MspImagePlugin.MspImageFile(bad_checksum)
def test_open_windows_v1(): def test_open_windows_v1() -> None:
# Arrange # Arrange
# Act # Act
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
@ -51,7 +52,7 @@ def test_open_windows_v1():
assert isinstance(im, MspImagePlugin.MspImageFile) assert isinstance(im, MspImagePlugin.MspImageFile)
def _assert_file_image_equal(source_path, target_path): def _assert_file_image_equal(source_path, target_path) -> None:
with Image.open(source_path) as im: with Image.open(source_path) as im:
assert_image_equal_tofile(im, target_path) assert_image_equal_tofile(im, target_path)
@ -59,7 +60,7 @@ def _assert_file_image_equal(source_path, target_path):
@pytest.mark.skipif( @pytest.mark.skipif(
not os.path.exists(EXTRA_DIR), reason="Extra image files not installed" not os.path.exists(EXTRA_DIR), reason="Extra image files not installed"
) )
def test_open_windows_v2(): def test_open_windows_v2() -> None:
files = ( files = (
os.path.join(EXTRA_DIR, f) os.path.join(EXTRA_DIR, f)
for f in os.listdir(EXTRA_DIR) for f in os.listdir(EXTRA_DIR)
@ -72,7 +73,7 @@ def test_open_windows_v2():
@pytest.mark.skipif( @pytest.mark.skipif(
not os.path.exists(YA_EXTRA_DIR), reason="Even More Extra image files not installed" not os.path.exists(YA_EXTRA_DIR), reason="Even More Extra image files not installed"
) )
def test_msp_v2(): def test_msp_v2() -> None:
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
@ -80,7 +81,7 @@ def test_msp_v2():
_assert_file_image_equal(path, path.replace(".MSP", ".png")) _assert_file_image_equal(path, path.replace(".MSP", ".png"))
def test_cannot_save_wrong_mode(tmp_path): def test_cannot_save_wrong_mode(tmp_path: Path) -> None:
# Arrange # Arrange
im = hopper() im = hopper()
filename = str(tmp_path / "temp.msp") filename = str(tmp_path / "temp.msp")

View File

@ -2,6 +2,7 @@ from __future__ import annotations
import os.path import os.path
import subprocess import subprocess
from pathlib import Path
import pytest import pytest
@ -10,7 +11,7 @@ from PIL import Image
from .helper import assert_image_equal, hopper, magick_command from .helper import assert_image_equal, hopper, magick_command
def helper_save_as_palm(tmp_path, mode): def helper_save_as_palm(tmp_path: Path, mode) -> None:
# Arrange # Arrange
im = hopper(mode) im = hopper(mode)
outfile = str(tmp_path / ("temp_" + mode + ".palm")) outfile = str(tmp_path / ("temp_" + mode + ".palm"))
@ -23,7 +24,7 @@ def helper_save_as_palm(tmp_path, mode):
assert os.path.getsize(outfile) > 0 assert os.path.getsize(outfile) > 0
def open_with_magick(magick, tmp_path, f): def open_with_magick(magick, tmp_path: Path, f):
outfile = str(tmp_path / "temp.png") outfile = str(tmp_path / "temp.png")
rc = subprocess.call( rc = subprocess.call(
magick + [f, outfile], stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT magick + [f, outfile], stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT
@ -32,7 +33,7 @@ def open_with_magick(magick, tmp_path, f):
return Image.open(outfile) return Image.open(outfile)
def roundtrip(tmp_path, mode): def roundtrip(tmp_path: Path, mode) -> None:
magick = magick_command() magick = magick_command()
if not magick: if not magick:
return return
@ -45,7 +46,7 @@ def roundtrip(tmp_path, mode):
assert_image_equal(converted, im) assert_image_equal(converted, im)
def test_monochrome(tmp_path): def test_monochrome(tmp_path: Path) -> None:
# Arrange # Arrange
mode = "1" mode = "1"
@ -55,7 +56,7 @@ def test_monochrome(tmp_path):
@pytest.mark.xfail(reason="Palm P image is wrong") @pytest.mark.xfail(reason="Palm P image is wrong")
def test_p_mode(tmp_path): def test_p_mode(tmp_path: Path) -> None:
# Arrange # Arrange
mode = "P" mode = "P"
@ -65,6 +66,6 @@ def test_p_mode(tmp_path):
@pytest.mark.parametrize("mode", ("L", "RGB")) @pytest.mark.parametrize("mode", ("L", "RGB"))
def test_oserror(tmp_path, mode): def test_oserror(tmp_path: Path, mode) -> None:
with pytest.raises(OSError): with pytest.raises(OSError):
helper_save_as_palm(tmp_path, mode) helper_save_as_palm(tmp_path, mode)

View File

@ -1,5 +1,7 @@
from __future__ import annotations from __future__ import annotations
from pathlib import Path
import pytest import pytest
from PIL import Image, ImageFile, PcxImagePlugin from PIL import Image, ImageFile, PcxImagePlugin
@ -7,7 +9,7 @@ from PIL import Image, ImageFile, PcxImagePlugin
from .helper import assert_image_equal, hopper from .helper import assert_image_equal, hopper
def _roundtrip(tmp_path, im): def _roundtrip(tmp_path: Path, im) -> None:
f = str(tmp_path / "temp.pcx") f = str(tmp_path / "temp.pcx")
im.save(f) im.save(f)
with Image.open(f) as im2: with Image.open(f) as im2:
@ -18,7 +20,7 @@ def _roundtrip(tmp_path, im):
assert_image_equal(im2, im) assert_image_equal(im2, im)
def test_sanity(tmp_path): def test_sanity(tmp_path: Path) -> None:
for mode in ("1", "L", "P", "RGB"): for mode in ("1", "L", "P", "RGB"):
_roundtrip(tmp_path, hopper(mode)) _roundtrip(tmp_path, hopper(mode))
@ -34,7 +36,7 @@ def test_sanity(tmp_path):
im.save(f) im.save(f)
def test_invalid_file(): def test_invalid_file() -> None:
invalid_file = "Tests/images/flower.jpg" invalid_file = "Tests/images/flower.jpg"
with pytest.raises(SyntaxError): with pytest.raises(SyntaxError):
@ -42,7 +44,7 @@ def test_invalid_file():
@pytest.mark.parametrize("mode", ("1", "L", "P", "RGB")) @pytest.mark.parametrize("mode", ("1", "L", "P", "RGB"))
def test_odd(tmp_path, mode): def test_odd(tmp_path: Path, mode) -> None:
# See issue #523, odd sized images should have a stride that's even. # See issue #523, odd sized images should have a stride that's even.
# Not that ImageMagick or GIMP write PCX that way. # Not that ImageMagick or GIMP write PCX that way.
# We were not handling properly. # We were not handling properly.
@ -51,7 +53,7 @@ def test_odd(tmp_path, mode):
_roundtrip(tmp_path, hopper(mode).resize((511, 511))) _roundtrip(tmp_path, hopper(mode).resize((511, 511)))
def test_odd_read(): def test_odd_read() -> None:
# Reading an image with an odd stride, making it malformed # Reading an image with an odd stride, making it malformed
with Image.open("Tests/images/odd_stride.pcx") as im: with Image.open("Tests/images/odd_stride.pcx") as im:
im.load() im.load()
@ -59,7 +61,7 @@ def test_odd_read():
assert im.size == (371, 150) assert im.size == (371, 150)
def test_pil184(): def test_pil184() -> None:
# Check reading of files where xmin/xmax is not zero. # Check reading of files where xmin/xmax is not zero.
test_file = "Tests/images/pil184.pcx" test_file = "Tests/images/pil184.pcx"
@ -71,7 +73,7 @@ def test_pil184():
assert im.histogram()[0] + im.histogram()[255] == 447 * 144 assert im.histogram()[0] + im.histogram()[255] == 447 * 144
def test_1px_width(tmp_path): def test_1px_width(tmp_path: Path) -> None:
im = Image.new("L", (1, 256)) im = Image.new("L", (1, 256))
px = im.load() px = im.load()
for y in range(256): for y in range(256):
@ -79,7 +81,7 @@ def test_1px_width(tmp_path):
_roundtrip(tmp_path, im) _roundtrip(tmp_path, im)
def test_large_count(tmp_path): def test_large_count(tmp_path: Path) -> None:
im = Image.new("L", (256, 1)) im = Image.new("L", (256, 1))
px = im.load() px = im.load()
for x in range(256): for x in range(256):
@ -87,7 +89,7 @@ def test_large_count(tmp_path):
_roundtrip(tmp_path, im) _roundtrip(tmp_path, im)
def _test_buffer_overflow(tmp_path, im, size=1024): def _test_buffer_overflow(tmp_path: Path, im, size: int = 1024) -> None:
_last = ImageFile.MAXBLOCK _last = ImageFile.MAXBLOCK
ImageFile.MAXBLOCK = size ImageFile.MAXBLOCK = size
try: try:
@ -96,7 +98,7 @@ def _test_buffer_overflow(tmp_path, im, size=1024):
ImageFile.MAXBLOCK = _last ImageFile.MAXBLOCK = _last
def test_break_in_count_overflow(tmp_path): def test_break_in_count_overflow(tmp_path: Path) -> None:
im = Image.new("L", (256, 5)) im = Image.new("L", (256, 5))
px = im.load() px = im.load()
for y in range(4): for y in range(4):
@ -105,7 +107,7 @@ def test_break_in_count_overflow(tmp_path):
_test_buffer_overflow(tmp_path, im) _test_buffer_overflow(tmp_path, im)
def test_break_one_in_loop(tmp_path): def test_break_one_in_loop(tmp_path: Path) -> None:
im = Image.new("L", (256, 5)) im = Image.new("L", (256, 5))
px = im.load() px = im.load()
for y in range(5): for y in range(5):
@ -114,7 +116,7 @@ def test_break_one_in_loop(tmp_path):
_test_buffer_overflow(tmp_path, im) _test_buffer_overflow(tmp_path, im)
def test_break_many_in_loop(tmp_path): def test_break_many_in_loop(tmp_path: Path) -> None:
im = Image.new("L", (256, 5)) im = Image.new("L", (256, 5))
px = im.load() px = im.load()
for y in range(4): for y in range(4):
@ -125,7 +127,7 @@ def test_break_many_in_loop(tmp_path):
_test_buffer_overflow(tmp_path, im) _test_buffer_overflow(tmp_path, im)
def test_break_one_at_end(tmp_path): def test_break_one_at_end(tmp_path: Path) -> None:
im = Image.new("L", (256, 5)) im = Image.new("L", (256, 5))
px = im.load() px = im.load()
for y in range(5): for y in range(5):
@ -135,7 +137,7 @@ def test_break_one_at_end(tmp_path):
_test_buffer_overflow(tmp_path, im) _test_buffer_overflow(tmp_path, im)
def test_break_many_at_end(tmp_path): def test_break_many_at_end(tmp_path: Path) -> None:
im = Image.new("L", (256, 5)) im = Image.new("L", (256, 5))
px = im.load() px = im.load()
for y in range(5): for y in range(5):
@ -147,7 +149,7 @@ def test_break_many_at_end(tmp_path):
_test_buffer_overflow(tmp_path, im) _test_buffer_overflow(tmp_path, im)
def test_break_padding(tmp_path): def test_break_padding(tmp_path: Path) -> None:
im = Image.new("L", (257, 5)) im = Image.new("L", (257, 5))
px = im.load() px = im.load()
for y in range(5): for y in range(5):

View File

@ -5,6 +5,7 @@ import os
import os.path import os.path
import tempfile import tempfile
import time import time
from pathlib import Path
import pytest import pytest
@ -13,7 +14,7 @@ from PIL import Image, PdfParser, features
from .helper import hopper, mark_if_feature_version, skip_unless_feature from .helper import hopper, mark_if_feature_version, skip_unless_feature
def helper_save_as_pdf(tmp_path, mode, **kwargs): def helper_save_as_pdf(tmp_path: Path, mode, **kwargs):
# Arrange # Arrange
im = hopper(mode) im = hopper(mode)
outfile = str(tmp_path / ("temp_" + mode + ".pdf")) outfile = str(tmp_path / ("temp_" + mode + ".pdf"))
@ -40,17 +41,17 @@ def helper_save_as_pdf(tmp_path, mode, **kwargs):
@pytest.mark.parametrize("mode", ("L", "P", "RGB", "CMYK")) @pytest.mark.parametrize("mode", ("L", "P", "RGB", "CMYK"))
def test_save(tmp_path, mode): def test_save(tmp_path: Path, mode) -> None:
helper_save_as_pdf(tmp_path, mode) helper_save_as_pdf(tmp_path, mode)
@skip_unless_feature("jpg_2000") @skip_unless_feature("jpg_2000")
@pytest.mark.parametrize("mode", ("LA", "RGBA")) @pytest.mark.parametrize("mode", ("LA", "RGBA"))
def test_save_alpha(tmp_path, mode): def test_save_alpha(tmp_path: Path, mode) -> None:
helper_save_as_pdf(tmp_path, mode) helper_save_as_pdf(tmp_path, mode)
def test_p_alpha(tmp_path): def test_p_alpha(tmp_path: Path) -> None:
# Arrange # Arrange
outfile = str(tmp_path / "temp.pdf") outfile = str(tmp_path / "temp.pdf")
with Image.open("Tests/images/pil123p.png") as im: with Image.open("Tests/images/pil123p.png") as im:
@ -66,7 +67,7 @@ def test_p_alpha(tmp_path):
assert b"\n/SMask " in contents assert b"\n/SMask " in contents
def test_monochrome(tmp_path): def test_monochrome(tmp_path: Path) -> None:
# Arrange # Arrange
mode = "1" mode = "1"
@ -75,7 +76,7 @@ def test_monochrome(tmp_path):
assert os.path.getsize(outfile) < (5000 if features.check("libtiff") else 15000) assert os.path.getsize(outfile) < (5000 if features.check("libtiff") else 15000)
def test_unsupported_mode(tmp_path): def test_unsupported_mode(tmp_path: Path) -> None:
im = hopper("PA") im = hopper("PA")
outfile = str(tmp_path / "temp_PA.pdf") outfile = str(tmp_path / "temp_PA.pdf")
@ -83,7 +84,7 @@ def test_unsupported_mode(tmp_path):
im.save(outfile) im.save(outfile)
def test_resolution(tmp_path): def test_resolution(tmp_path: Path) -> None:
im = hopper() im = hopper()
outfile = str(tmp_path / "temp.pdf") outfile = str(tmp_path / "temp.pdf")
@ -111,7 +112,7 @@ def test_resolution(tmp_path):
{"dpi": (75, 150), "resolution": 200}, {"dpi": (75, 150), "resolution": 200},
), ),
) )
def test_dpi(params, tmp_path): def test_dpi(params, tmp_path: Path) -> None:
im = hopper() im = hopper()
outfile = str(tmp_path / "temp.pdf") outfile = str(tmp_path / "temp.pdf")
@ -135,7 +136,7 @@ def test_dpi(params, tmp_path):
@mark_if_feature_version( @mark_if_feature_version(
pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing"
) )
def test_save_all(tmp_path): def test_save_all(tmp_path: Path) -> None:
# Single frame image # Single frame image
helper_save_as_pdf(tmp_path, "RGB", save_all=True) helper_save_as_pdf(tmp_path, "RGB", save_all=True)
@ -171,7 +172,7 @@ def test_save_all(tmp_path):
assert os.path.getsize(outfile) > 0 assert os.path.getsize(outfile) > 0
def test_multiframe_normal_save(tmp_path): def test_multiframe_normal_save(tmp_path: Path) -> None:
# Test saving a multiframe image without save_all # Test saving a multiframe image without save_all
with Image.open("Tests/images/dispose_bgnd.gif") as im: with Image.open("Tests/images/dispose_bgnd.gif") as im:
outfile = str(tmp_path / "temp.pdf") outfile = str(tmp_path / "temp.pdf")
@ -181,7 +182,7 @@ def test_multiframe_normal_save(tmp_path):
assert os.path.getsize(outfile) > 0 assert os.path.getsize(outfile) > 0
def test_pdf_open(tmp_path): def test_pdf_open(tmp_path: Path) -> None:
# fail on a buffer full of null bytes # fail on a buffer full of null bytes
with pytest.raises(PdfParser.PdfFormatError): with pytest.raises(PdfParser.PdfFormatError):
PdfParser.PdfParser(buf=bytearray(65536)) PdfParser.PdfParser(buf=bytearray(65536))
@ -218,14 +219,14 @@ def test_pdf_open(tmp_path):
assert not hopper_pdf.should_close_file assert not hopper_pdf.should_close_file
def test_pdf_append_fails_on_nonexistent_file(): def test_pdf_append_fails_on_nonexistent_file() -> None:
im = hopper("RGB") im = hopper("RGB")
with tempfile.TemporaryDirectory() as temp_dir: with tempfile.TemporaryDirectory() as temp_dir:
with pytest.raises(OSError): with pytest.raises(OSError):
im.save(os.path.join(temp_dir, "nonexistent.pdf"), append=True) im.save(os.path.join(temp_dir, "nonexistent.pdf"), append=True)
def check_pdf_pages_consistency(pdf): def check_pdf_pages_consistency(pdf) -> None:
pages_info = pdf.read_indirect(pdf.pages_ref) pages_info = pdf.read_indirect(pdf.pages_ref)
assert b"Parent" not in pages_info assert b"Parent" not in pages_info
assert b"Kids" in pages_info assert b"Kids" in pages_info
@ -243,7 +244,7 @@ def check_pdf_pages_consistency(pdf):
assert kids_not_used == [] assert kids_not_used == []
def test_pdf_append(tmp_path): def test_pdf_append(tmp_path: Path) -> None:
# make a PDF file # make a PDF file
pdf_filename = helper_save_as_pdf(tmp_path, "RGB", producer="PdfParser") pdf_filename = helper_save_as_pdf(tmp_path, "RGB", producer="PdfParser")
@ -294,7 +295,7 @@ def test_pdf_append(tmp_path):
check_pdf_pages_consistency(pdf) check_pdf_pages_consistency(pdf)
def test_pdf_info(tmp_path): def test_pdf_info(tmp_path: Path) -> None:
# make a PDF file # make a PDF file
pdf_filename = helper_save_as_pdf( pdf_filename = helper_save_as_pdf(
tmp_path, tmp_path,
@ -323,7 +324,7 @@ def test_pdf_info(tmp_path):
check_pdf_pages_consistency(pdf) check_pdf_pages_consistency(pdf)
def test_pdf_append_to_bytesio(): def test_pdf_append_to_bytesio() -> None:
im = hopper("RGB") im = hopper("RGB")
f = io.BytesIO() f = io.BytesIO()
im.save(f, format="PDF") im.save(f, format="PDF")
@ -338,7 +339,7 @@ def test_pdf_append_to_bytesio():
@pytest.mark.timeout(1) @pytest.mark.timeout(1)
@pytest.mark.skipif("PILLOW_VALGRIND_TEST" in os.environ, reason="Valgrind is slower") @pytest.mark.skipif("PILLOW_VALGRIND_TEST" in os.environ, reason="Valgrind is slower")
@pytest.mark.parametrize("newline", (b"\r", b"\n")) @pytest.mark.parametrize("newline", (b"\r", b"\n"))
def test_redos(newline): def test_redos(newline) -> None:
malicious = b" trailer<<>>" + newline * 3456 malicious = b" trailer<<>>" + newline * 3456
# This particular exception isn't relevant here. # This particular exception isn't relevant here.

View File

@ -5,6 +5,7 @@ import sys
import warnings import warnings
import zlib import zlib
from io import BytesIO from io import BytesIO
from pathlib import Path
import pytest import pytest
@ -79,7 +80,7 @@ class TestFilePng:
png.crc(cid, s) png.crc(cid, s)
return chunks return chunks
def test_sanity(self, tmp_path): def test_sanity(self, tmp_path: Path) -> None:
# internal version number # internal version number
assert re.search(r"\d+(\.\d+){1,3}$", features.version_codec("zlib")) assert re.search(r"\d+(\.\d+){1,3}$", features.version_codec("zlib"))
@ -102,13 +103,13 @@ class TestFilePng:
reloaded = reloaded.convert(mode) reloaded = reloaded.convert(mode)
assert_image_equal(reloaded, im) assert_image_equal(reloaded, im)
def test_invalid_file(self): def test_invalid_file(self) -> None:
invalid_file = "Tests/images/flower.jpg" invalid_file = "Tests/images/flower.jpg"
with pytest.raises(SyntaxError): with pytest.raises(SyntaxError):
PngImagePlugin.PngImageFile(invalid_file) PngImagePlugin.PngImageFile(invalid_file)
def test_broken(self): def test_broken(self) -> None:
# Check reading of totally broken files. In this case, the test # Check reading of totally broken files. In this case, the test
# file was checked into Subversion as a text file. # file was checked into Subversion as a text file.
@ -117,7 +118,7 @@ class TestFilePng:
with Image.open(test_file): with Image.open(test_file):
pass pass
def test_bad_text(self): def test_bad_text(self) -> None:
# Make sure PIL can read malformed tEXt chunks (@PIL152) # Make sure PIL can read malformed tEXt chunks (@PIL152)
im = load(HEAD + chunk(b"tEXt") + TAIL) im = load(HEAD + chunk(b"tEXt") + TAIL)
@ -135,7 +136,7 @@ class TestFilePng:
im = load(HEAD + chunk(b"tEXt", b"spam\0egg\0") + TAIL) im = load(HEAD + chunk(b"tEXt", b"spam\0egg\0") + TAIL)
assert im.info == {"spam": "egg\x00"} assert im.info == {"spam": "egg\x00"}
def test_bad_ztxt(self): def test_bad_ztxt(self) -> None:
# Test reading malformed zTXt chunks (python-pillow/Pillow#318) # Test reading malformed zTXt chunks (python-pillow/Pillow#318)
im = load(HEAD + chunk(b"zTXt") + TAIL) im = load(HEAD + chunk(b"zTXt") + TAIL)
@ -156,7 +157,7 @@ class TestFilePng:
im = load(HEAD + chunk(b"zTXt", b"spam\0\0" + zlib.compress(b"egg")) + TAIL) im = load(HEAD + chunk(b"zTXt", b"spam\0\0" + zlib.compress(b"egg")) + TAIL)
assert im.info == {"spam": "egg"} assert im.info == {"spam": "egg"}
def test_bad_itxt(self): def test_bad_itxt(self) -> None:
im = load(HEAD + chunk(b"iTXt") + TAIL) im = load(HEAD + chunk(b"iTXt") + TAIL)
assert im.info == {} assert im.info == {}
@ -200,7 +201,7 @@ class TestFilePng:
assert im.info["spam"].lang == "en" assert im.info["spam"].lang == "en"
assert im.info["spam"].tkey == "Spam" assert im.info["spam"].tkey == "Spam"
def test_interlace(self): def test_interlace(self) -> None:
test_file = "Tests/images/pil123p.png" test_file = "Tests/images/pil123p.png"
with Image.open(test_file) as im: with Image.open(test_file) as im:
assert_image(im, "P", (162, 150)) assert_image(im, "P", (162, 150))
@ -215,7 +216,7 @@ class TestFilePng:
im.load() im.load()
def test_load_transparent_p(self): def test_load_transparent_p(self) -> None:
test_file = "Tests/images/pil123p.png" test_file = "Tests/images/pil123p.png"
with Image.open(test_file) as im: with Image.open(test_file) as im:
assert_image(im, "P", (162, 150)) assert_image(im, "P", (162, 150))
@ -225,7 +226,7 @@ class TestFilePng:
# image has 124 unique alpha values # image has 124 unique alpha values
assert len(im.getchannel("A").getcolors()) == 124 assert len(im.getchannel("A").getcolors()) == 124
def test_load_transparent_rgb(self): def test_load_transparent_rgb(self) -> None:
test_file = "Tests/images/rgb_trns.png" test_file = "Tests/images/rgb_trns.png"
with Image.open(test_file) as im: with Image.open(test_file) as im:
assert im.info["transparency"] == (0, 255, 52) assert im.info["transparency"] == (0, 255, 52)
@ -237,7 +238,7 @@ class TestFilePng:
# image has 876 transparent pixels # image has 876 transparent pixels
assert im.getchannel("A").getcolors()[0][0] == 876 assert im.getchannel("A").getcolors()[0][0] == 876
def test_save_p_transparent_palette(self, tmp_path): def test_save_p_transparent_palette(self, tmp_path: Path) -> None:
in_file = "Tests/images/pil123p.png" in_file = "Tests/images/pil123p.png"
with Image.open(in_file) as im: with Image.open(in_file) as im:
# 'transparency' contains a byte string with the opacity for # 'transparency' contains a byte string with the opacity for
@ -258,7 +259,7 @@ class TestFilePng:
# image has 124 unique alpha values # image has 124 unique alpha values
assert len(im.getchannel("A").getcolors()) == 124 assert len(im.getchannel("A").getcolors()) == 124
def test_save_p_single_transparency(self, tmp_path): def test_save_p_single_transparency(self, tmp_path: Path) -> None:
in_file = "Tests/images/p_trns_single.png" in_file = "Tests/images/p_trns_single.png"
with Image.open(in_file) as im: with Image.open(in_file) as im:
# pixel value 164 is full transparent # pixel value 164 is full transparent
@ -281,7 +282,7 @@ class TestFilePng:
# image has 876 transparent pixels # image has 876 transparent pixels
assert im.getchannel("A").getcolors()[0][0] == 876 assert im.getchannel("A").getcolors()[0][0] == 876
def test_save_p_transparent_black(self, tmp_path): def test_save_p_transparent_black(self, tmp_path: Path) -> None:
# check if solid black image with full transparency # check if solid black image with full transparency
# is supported (check for #1838) # is supported (check for #1838)
im = Image.new("RGBA", (10, 10), (0, 0, 0, 0)) im = Image.new("RGBA", (10, 10), (0, 0, 0, 0))
@ -299,7 +300,7 @@ class TestFilePng:
assert_image(im, "RGBA", (10, 10)) assert_image(im, "RGBA", (10, 10))
assert im.getcolors() == [(100, (0, 0, 0, 0))] assert im.getcolors() == [(100, (0, 0, 0, 0))]
def test_save_grayscale_transparency(self, tmp_path): def test_save_grayscale_transparency(self, tmp_path: Path) -> None:
for mode, num_transparent in {"1": 1994, "L": 559, "I": 559}.items(): for mode, num_transparent in {"1": 1994, "L": 559, "I": 559}.items():
in_file = "Tests/images/" + mode.lower() + "_trns.png" in_file = "Tests/images/" + mode.lower() + "_trns.png"
with Image.open(in_file) as im: with Image.open(in_file) as im:
@ -320,13 +321,13 @@ class TestFilePng:
test_im_rgba = test_im.convert("RGBA") test_im_rgba = test_im.convert("RGBA")
assert test_im_rgba.getchannel("A").getcolors()[0][0] == num_transparent assert test_im_rgba.getchannel("A").getcolors()[0][0] == num_transparent
def test_save_rgb_single_transparency(self, tmp_path): def test_save_rgb_single_transparency(self, tmp_path: Path) -> None:
in_file = "Tests/images/caption_6_33_22.png" in_file = "Tests/images/caption_6_33_22.png"
with Image.open(in_file) as im: with Image.open(in_file) as im:
test_file = str(tmp_path / "temp.png") test_file = str(tmp_path / "temp.png")
im.save(test_file) im.save(test_file)
def test_load_verify(self): def test_load_verify(self) -> None:
# Check open/load/verify exception (@PIL150) # Check open/load/verify exception (@PIL150)
with Image.open(TEST_PNG_FILE) as im: with Image.open(TEST_PNG_FILE) as im:
@ -339,7 +340,7 @@ class TestFilePng:
with pytest.raises(RuntimeError): with pytest.raises(RuntimeError):
im.verify() im.verify()
def test_verify_struct_error(self): def test_verify_struct_error(self) -> None:
# Check open/load/verify exception (#1755) # Check open/load/verify exception (#1755)
# offsets to test, -10: breaks in i32() in read. (OSError) # offsets to test, -10: breaks in i32() in read. (OSError)
@ -355,7 +356,7 @@ class TestFilePng:
with pytest.raises((OSError, SyntaxError)): with pytest.raises((OSError, SyntaxError)):
im.verify() im.verify()
def test_verify_ignores_crc_error(self): def test_verify_ignores_crc_error(self) -> None:
# check ignores crc errors in ancillary chunks # check ignores crc errors in ancillary chunks
chunk_data = chunk(b"tEXt", b"spam") chunk_data = chunk(b"tEXt", b"spam")
@ -372,7 +373,7 @@ class TestFilePng:
finally: finally:
ImageFile.LOAD_TRUNCATED_IMAGES = False ImageFile.LOAD_TRUNCATED_IMAGES = False
def test_verify_not_ignores_crc_error_in_required_chunk(self): def test_verify_not_ignores_crc_error_in_required_chunk(self) -> None:
# check does not ignore crc errors in required chunks # check does not ignore crc errors in required chunks
image_data = MAGIC + IHDR[:-1] + b"q" + TAIL image_data = MAGIC + IHDR[:-1] + b"q" + TAIL
@ -384,18 +385,18 @@ class TestFilePng:
finally: finally:
ImageFile.LOAD_TRUNCATED_IMAGES = False ImageFile.LOAD_TRUNCATED_IMAGES = False
def test_roundtrip_dpi(self): def test_roundtrip_dpi(self) -> None:
# Check dpi roundtripping # Check dpi roundtripping
with Image.open(TEST_PNG_FILE) as im: with Image.open(TEST_PNG_FILE) as im:
im = roundtrip(im, dpi=(100.33, 100.33)) im = roundtrip(im, dpi=(100.33, 100.33))
assert im.info["dpi"] == (100.33, 100.33) assert im.info["dpi"] == (100.33, 100.33)
def test_load_float_dpi(self): def test_load_float_dpi(self) -> None:
with Image.open(TEST_PNG_FILE) as im: with Image.open(TEST_PNG_FILE) as im:
assert im.info["dpi"] == (95.9866, 95.9866) assert im.info["dpi"] == (95.9866, 95.9866)
def test_roundtrip_text(self): def test_roundtrip_text(self) -> None:
# Check text roundtripping # Check text roundtripping
with Image.open(TEST_PNG_FILE) as im: with Image.open(TEST_PNG_FILE) as im:
@ -407,7 +408,7 @@ class TestFilePng:
assert im.info == {"TXT": "VALUE", "ZIP": "VALUE"} assert im.info == {"TXT": "VALUE", "ZIP": "VALUE"}
assert im.text == {"TXT": "VALUE", "ZIP": "VALUE"} assert im.text == {"TXT": "VALUE", "ZIP": "VALUE"}
def test_roundtrip_itxt(self): def test_roundtrip_itxt(self) -> None:
# Check iTXt roundtripping # Check iTXt roundtripping
im = Image.new("RGB", (32, 32)) im = Image.new("RGB", (32, 32))
@ -423,7 +424,7 @@ class TestFilePng:
assert im.text["eggs"].lang == "en" assert im.text["eggs"].lang == "en"
assert im.text["eggs"].tkey == "Eggs" assert im.text["eggs"].tkey == "Eggs"
def test_nonunicode_text(self): def test_nonunicode_text(self) -> None:
# Check so that non-Unicode text is saved as a tEXt rather than iTXt # Check so that non-Unicode text is saved as a tEXt rather than iTXt
im = Image.new("RGB", (32, 32)) im = Image.new("RGB", (32, 32))
@ -432,10 +433,10 @@ class TestFilePng:
im = roundtrip(im, pnginfo=info) im = roundtrip(im, pnginfo=info)
assert isinstance(im.info["Text"], str) assert isinstance(im.info["Text"], str)
def test_unicode_text(self): def test_unicode_text(self) -> None:
# Check preservation of non-ASCII characters # Check preservation of non-ASCII characters
def rt_text(value): def rt_text(value) -> None:
im = Image.new("RGB", (32, 32)) im = Image.new("RGB", (32, 32))
info = PngImagePlugin.PngInfo() info = PngImagePlugin.PngInfo()
info.add_text("Text", value) info.add_text("Text", value)
@ -448,7 +449,7 @@ class TestFilePng:
rt_text(chr(0x4E00) + chr(0x66F0) + chr(0x9FBA) + chr(0x3042) + chr(0xAC00)) rt_text(chr(0x4E00) + chr(0x66F0) + chr(0x9FBA) + chr(0x3042) + chr(0xAC00))
rt_text("A" + chr(0xC4) + chr(0x472) + chr(0x3042)) # Combined rt_text("A" + chr(0xC4) + chr(0x472) + chr(0x3042)) # Combined
def test_scary(self): def test_scary(self) -> None:
# Check reading of evil PNG file. For information, see: # Check reading of evil PNG file. For information, see:
# http://scary.beasts.org/security/CESA-2004-001.txt # http://scary.beasts.org/security/CESA-2004-001.txt
# The first byte is removed from pngtest_bad.png # The first byte is removed from pngtest_bad.png
@ -462,7 +463,7 @@ class TestFilePng:
with Image.open(pngfile): with Image.open(pngfile):
pass pass
def test_trns_rgb(self): def test_trns_rgb(self) -> None:
# Check writing and reading of tRNS chunks for RGB images. # Check writing and reading of tRNS chunks for RGB images.
# Independent file sample provided by Sebastian Spaeth. # Independent file sample provided by Sebastian Spaeth.
@ -477,7 +478,7 @@ class TestFilePng:
im = roundtrip(im, transparency=(0, 1, 2)) im = roundtrip(im, transparency=(0, 1, 2))
assert im.info["transparency"] == (0, 1, 2) assert im.info["transparency"] == (0, 1, 2)
def test_trns_p(self, tmp_path): def test_trns_p(self, tmp_path: Path) -> None:
# Check writing a transparency of 0, issue #528 # Check writing a transparency of 0, issue #528
im = hopper("P") im = hopper("P")
im.info["transparency"] = 0 im.info["transparency"] = 0
@ -490,13 +491,13 @@ class TestFilePng:
assert_image_equal(im2.convert("RGBA"), im.convert("RGBA")) assert_image_equal(im2.convert("RGBA"), im.convert("RGBA"))
def test_trns_null(self): def test_trns_null(self) -> None:
# Check reading images with null tRNS value, issue #1239 # Check reading images with null tRNS value, issue #1239
test_file = "Tests/images/tRNS_null_1x1.png" test_file = "Tests/images/tRNS_null_1x1.png"
with Image.open(test_file) as im: with Image.open(test_file) as im:
assert im.info["transparency"] == 0 assert im.info["transparency"] == 0
def test_save_icc_profile(self): def test_save_icc_profile(self) -> None:
with Image.open("Tests/images/icc_profile_none.png") as im: with Image.open("Tests/images/icc_profile_none.png") as im:
assert im.info["icc_profile"] is None assert im.info["icc_profile"] is None
@ -506,40 +507,40 @@ class TestFilePng:
im = roundtrip(im, icc_profile=expected_icc) im = roundtrip(im, icc_profile=expected_icc)
assert im.info["icc_profile"] == expected_icc assert im.info["icc_profile"] == expected_icc
def test_discard_icc_profile(self): def test_discard_icc_profile(self) -> None:
with Image.open("Tests/images/icc_profile.png") as im: with Image.open("Tests/images/icc_profile.png") as im:
assert "icc_profile" in im.info assert "icc_profile" in im.info
im = roundtrip(im, icc_profile=None) im = roundtrip(im, icc_profile=None)
assert "icc_profile" not in im.info assert "icc_profile" not in im.info
def test_roundtrip_icc_profile(self): def test_roundtrip_icc_profile(self) -> None:
with Image.open("Tests/images/icc_profile.png") as im: with Image.open("Tests/images/icc_profile.png") as im:
expected_icc = im.info["icc_profile"] expected_icc = im.info["icc_profile"]
im = roundtrip(im) im = roundtrip(im)
assert im.info["icc_profile"] == expected_icc assert im.info["icc_profile"] == expected_icc
def test_roundtrip_no_icc_profile(self): def test_roundtrip_no_icc_profile(self) -> None:
with Image.open("Tests/images/icc_profile_none.png") as im: with Image.open("Tests/images/icc_profile_none.png") as im:
assert im.info["icc_profile"] is None assert im.info["icc_profile"] is None
im = roundtrip(im) im = roundtrip(im)
assert "icc_profile" not in im.info assert "icc_profile" not in im.info
def test_repr_png(self): def test_repr_png(self) -> None:
im = hopper() im = hopper()
with Image.open(BytesIO(im._repr_png_())) as repr_png: with Image.open(BytesIO(im._repr_png_())) as repr_png:
assert repr_png.format == "PNG" assert repr_png.format == "PNG"
assert_image_equal(im, repr_png) assert_image_equal(im, repr_png)
def test_repr_png_error_returns_none(self): def test_repr_png_error_returns_none(self) -> None:
im = hopper("F") im = hopper("F")
assert im._repr_png_() is None assert im._repr_png_() is None
def test_chunk_order(self, tmp_path): def test_chunk_order(self, tmp_path: Path) -> None:
with Image.open("Tests/images/icc_profile.png") as im: with Image.open("Tests/images/icc_profile.png") as im:
test_file = str(tmp_path / "temp.png") test_file = str(tmp_path / "temp.png")
im.convert("P").save(test_file, dpi=(100, 100)) im.convert("P").save(test_file, dpi=(100, 100))
@ -560,17 +561,17 @@ class TestFilePng:
# pHYs - before IDAT # pHYs - before IDAT
assert chunks.index(b"pHYs") < chunks.index(b"IDAT") assert chunks.index(b"pHYs") < chunks.index(b"IDAT")
def test_getchunks(self): def test_getchunks(self) -> None:
im = hopper() im = hopper()
chunks = PngImagePlugin.getchunks(im) chunks = PngImagePlugin.getchunks(im)
assert len(chunks) == 3 assert len(chunks) == 3
def test_read_private_chunks(self): def test_read_private_chunks(self) -> None:
with Image.open("Tests/images/exif.png") as im: with Image.open("Tests/images/exif.png") as im:
assert im.private_chunks == [(b"orNT", b"\x01")] assert im.private_chunks == [(b"orNT", b"\x01")]
def test_roundtrip_private_chunk(self): def test_roundtrip_private_chunk(self) -> None:
# Check private chunk roundtripping # Check private chunk roundtripping
with Image.open(TEST_PNG_FILE) as im: with Image.open(TEST_PNG_FILE) as im:
@ -588,7 +589,7 @@ class TestFilePng:
(b"prIV", b"VALUE3", True), (b"prIV", b"VALUE3", True),
] ]
def test_textual_chunks_after_idat(self): def test_textual_chunks_after_idat(self) -> None:
with Image.open("Tests/images/hopper.png") as im: with Image.open("Tests/images/hopper.png") as im:
assert "comment" in im.text assert "comment" in im.text
for k, v in { for k, v in {
@ -615,7 +616,7 @@ class TestFilePng:
with Image.open("Tests/images/hopper_idat_after_image_end.png") as im: with Image.open("Tests/images/hopper_idat_after_image_end.png") as im:
assert im.text == {"TXT": "VALUE", "ZIP": "VALUE"} assert im.text == {"TXT": "VALUE", "ZIP": "VALUE"}
def test_padded_idat(self): def test_padded_idat(self) -> None:
# This image has been manually hexedited # This image has been manually hexedited
# so that the IDAT chunk has padding at the end # so that the IDAT chunk has padding at the end
# Set MAXBLOCK to the length of the actual data # Set MAXBLOCK to the length of the actual data
@ -635,7 +636,7 @@ class TestFilePng:
@pytest.mark.parametrize( @pytest.mark.parametrize(
"cid", (b"IHDR", b"sRGB", b"pHYs", b"acTL", b"fcTL", b"fdAT") "cid", (b"IHDR", b"sRGB", b"pHYs", b"acTL", b"fcTL", b"fdAT")
) )
def test_truncated_chunks(self, cid): def test_truncated_chunks(self, cid) -> None:
fp = BytesIO() fp = BytesIO()
with PngImagePlugin.PngStream(fp) as png: with PngImagePlugin.PngStream(fp) as png:
with pytest.raises(ValueError): with pytest.raises(ValueError):
@ -645,7 +646,7 @@ class TestFilePng:
png.call(cid, 0, 0) png.call(cid, 0, 0)
ImageFile.LOAD_TRUNCATED_IMAGES = False ImageFile.LOAD_TRUNCATED_IMAGES = False
def test_specify_bits(self, tmp_path): def test_specify_bits(self, tmp_path: Path) -> None:
im = hopper("P") im = hopper("P")
out = str(tmp_path / "temp.png") out = str(tmp_path / "temp.png")
@ -654,7 +655,7 @@ class TestFilePng:
with Image.open(out) as reloaded: with Image.open(out) as reloaded:
assert len(reloaded.png.im_palette[1]) == 48 assert len(reloaded.png.im_palette[1]) == 48
def test_plte_length(self, tmp_path): def test_plte_length(self, tmp_path: Path) -> None:
im = Image.new("P", (1, 1)) im = Image.new("P", (1, 1))
im.putpalette((1, 1, 1)) im.putpalette((1, 1, 1))
@ -664,7 +665,7 @@ class TestFilePng:
with Image.open(out) as reloaded: with Image.open(out) as reloaded:
assert len(reloaded.png.im_palette[1]) == 3 assert len(reloaded.png.im_palette[1]) == 3
def test_getxmp(self): def test_getxmp(self) -> None:
with Image.open("Tests/images/color_snakes.png") as im: with Image.open("Tests/images/color_snakes.png") as im:
if ElementTree is None: if ElementTree is None:
with pytest.warns( with pytest.warns(
@ -679,7 +680,7 @@ class TestFilePng:
assert description["PixelXDimension"] == "10" assert description["PixelXDimension"] == "10"
assert description["subject"]["Seq"] is None assert description["subject"]["Seq"] is None
def test_exif(self): def test_exif(self) -> None:
# With an EXIF chunk # With an EXIF chunk
with Image.open("Tests/images/exif.png") as im: with Image.open("Tests/images/exif.png") as im:
exif = im._getexif() exif = im._getexif()
@ -705,7 +706,7 @@ class TestFilePng:
exif = im.getexif() exif = im.getexif()
assert exif[274] == 3 assert exif[274] == 3
def test_exif_save(self, tmp_path): def test_exif_save(self, tmp_path: Path) -> None:
# Test exif is not saved from info # Test exif is not saved from info
test_file = str(tmp_path / "temp.png") test_file = str(tmp_path / "temp.png")
with Image.open("Tests/images/exif.png") as im: with Image.open("Tests/images/exif.png") as im:
@ -725,7 +726,7 @@ class TestFilePng:
@mark_if_feature_version( @mark_if_feature_version(
pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing"
) )
def test_exif_from_jpg(self, tmp_path): def test_exif_from_jpg(self, tmp_path: Path) -> None:
with Image.open("Tests/images/pil_sample_rgb.jpg") as im: with Image.open("Tests/images/pil_sample_rgb.jpg") as im:
test_file = str(tmp_path / "temp.png") test_file = str(tmp_path / "temp.png")
im.save(test_file, exif=im.getexif()) im.save(test_file, exif=im.getexif())
@ -734,7 +735,7 @@ class TestFilePng:
exif = reloaded._getexif() exif = reloaded._getexif()
assert exif[305] == "Adobe Photoshop CS Macintosh" assert exif[305] == "Adobe Photoshop CS Macintosh"
def test_exif_argument(self, tmp_path): def test_exif_argument(self, tmp_path: Path) -> None:
with Image.open(TEST_PNG_FILE) as im: with Image.open(TEST_PNG_FILE) as im:
test_file = str(tmp_path / "temp.png") test_file = str(tmp_path / "temp.png")
im.save(test_file, exif=b"exifstring") im.save(test_file, exif=b"exifstring")
@ -742,11 +743,11 @@ class TestFilePng:
with Image.open(test_file) as reloaded: with Image.open(test_file) as reloaded:
assert reloaded.info["exif"] == b"Exif\x00\x00exifstring" assert reloaded.info["exif"] == b"Exif\x00\x00exifstring"
def test_tell(self): def test_tell(self) -> None:
with Image.open(TEST_PNG_FILE) as im: with Image.open(TEST_PNG_FILE) as im:
assert im.tell() == 0 assert im.tell() == 0
def test_seek(self): def test_seek(self) -> None:
with Image.open(TEST_PNG_FILE) as im: with Image.open(TEST_PNG_FILE) as im:
im.seek(0) im.seek(0)
@ -754,7 +755,7 @@ class TestFilePng:
im.seek(1) im.seek(1)
@pytest.mark.parametrize("buffer", (True, False)) @pytest.mark.parametrize("buffer", (True, False))
def test_save_stdout(self, buffer): def test_save_stdout(self, buffer) -> None:
old_stdout = sys.stdout old_stdout = sys.stdout
if buffer: if buffer:
@ -786,7 +787,7 @@ class TestTruncatedPngPLeaks(PillowLeakTestCase):
mem_limit = 2 * 1024 # max increase in K mem_limit = 2 * 1024 # max increase in K
iterations = 100 # Leak is 56k/iteration, this will leak 5.6megs iterations = 100 # Leak is 56k/iteration, this will leak 5.6megs
def test_leak_load(self): def test_leak_load(self) -> None:
with open("Tests/images/hopper.png", "rb") as f: with open("Tests/images/hopper.png", "rb") as f:
DATA = BytesIO(f.read(16 * 1024)) DATA = BytesIO(f.read(16 * 1024))
@ -794,7 +795,7 @@ class TestTruncatedPngPLeaks(PillowLeakTestCase):
with Image.open(DATA) as im: with Image.open(DATA) as im:
im.load() im.load()
def core(): def core() -> None:
with Image.open(DATA) as im: with Image.open(DATA) as im:
im.load() im.load()

View File

@ -2,6 +2,7 @@ from __future__ import annotations
import sys import sys
from io import BytesIO from io import BytesIO
from pathlib import Path
import pytest import pytest
@ -18,7 +19,7 @@ from .helper import (
TEST_FILE = "Tests/images/hopper.ppm" TEST_FILE = "Tests/images/hopper.ppm"
def test_sanity(): def test_sanity() -> None:
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
assert im.mode == "RGB" assert im.mode == "RGB"
assert im.size == (128, 128) assert im.size == (128, 128)
@ -69,7 +70,7 @@ def test_sanity():
), ),
), ),
) )
def test_arbitrary_maxval(data, mode, pixels): def test_arbitrary_maxval(data, mode, pixels) -> None:
fp = BytesIO(data) fp = BytesIO(data)
with Image.open(fp) as im: with Image.open(fp) as im:
assert im.size == (3, 1) assert im.size == (3, 1)
@ -79,7 +80,7 @@ def test_arbitrary_maxval(data, mode, pixels):
assert tuple(px[x, 0] for x in range(3)) == pixels assert tuple(px[x, 0] for x in range(3)) == pixels
def test_16bit_pgm(): def test_16bit_pgm() -> None:
with Image.open("Tests/images/16_bit_binary.pgm") as im: with Image.open("Tests/images/16_bit_binary.pgm") as im:
assert im.mode == "I" assert im.mode == "I"
assert im.size == (20, 100) assert im.size == (20, 100)
@ -88,7 +89,7 @@ def test_16bit_pgm():
assert_image_equal_tofile(im, "Tests/images/16_bit_binary_pgm.png") assert_image_equal_tofile(im, "Tests/images/16_bit_binary_pgm.png")
def test_16bit_pgm_write(tmp_path): def test_16bit_pgm_write(tmp_path: Path) -> None:
with Image.open("Tests/images/16_bit_binary.pgm") as im: with Image.open("Tests/images/16_bit_binary.pgm") as im:
filename = str(tmp_path / "temp.pgm") filename = str(tmp_path / "temp.pgm")
im.save(filename, "PPM") im.save(filename, "PPM")
@ -96,7 +97,7 @@ def test_16bit_pgm_write(tmp_path):
assert_image_equal_tofile(im, filename) assert_image_equal_tofile(im, filename)
def test_pnm(tmp_path): def test_pnm(tmp_path: Path) -> None:
with Image.open("Tests/images/hopper.pnm") as im: with Image.open("Tests/images/hopper.pnm") as im:
assert_image_similar(im, hopper(), 0.0001) assert_image_similar(im, hopper(), 0.0001)
@ -106,7 +107,7 @@ def test_pnm(tmp_path):
assert_image_equal_tofile(im, filename) assert_image_equal_tofile(im, filename)
def test_pfm(tmp_path): def test_pfm(tmp_path: Path) -> None:
with Image.open("Tests/images/hopper.pfm") as im: with Image.open("Tests/images/hopper.pfm") as im:
assert im.info["scale"] == 1.0 assert im.info["scale"] == 1.0
assert_image_equal(im, hopper("F")) assert_image_equal(im, hopper("F"))
@ -117,7 +118,7 @@ def test_pfm(tmp_path):
assert_image_equal_tofile(im, filename) assert_image_equal_tofile(im, filename)
def test_pfm_big_endian(tmp_path): def test_pfm_big_endian(tmp_path: Path) -> None:
with Image.open("Tests/images/hopper_be.pfm") as im: with Image.open("Tests/images/hopper_be.pfm") as im:
assert im.info["scale"] == 2.5 assert im.info["scale"] == 2.5
assert_image_equal(im, hopper("F")) assert_image_equal(im, hopper("F"))
@ -138,7 +139,7 @@ def test_pfm_big_endian(tmp_path):
b"Pf 1 1 -0.0 \0\0\0\0", b"Pf 1 1 -0.0 \0\0\0\0",
], ],
) )
def test_pfm_invalid(data): def test_pfm_invalid(data) -> None:
with pytest.raises(ValueError): with pytest.raises(ValueError):
with Image.open(BytesIO(data)): with Image.open(BytesIO(data)):
pass pass
@ -161,12 +162,12 @@ def test_pfm_invalid(data):
), ),
), ),
) )
def test_plain(plain_path, raw_path): def test_plain(plain_path, raw_path) -> None:
with Image.open(plain_path) as im: with Image.open(plain_path) as im:
assert_image_equal_tofile(im, raw_path) assert_image_equal_tofile(im, raw_path)
def test_16bit_plain_pgm(): def test_16bit_plain_pgm() -> None:
# P2 with maxval 2 ** 16 - 1 # P2 with maxval 2 ** 16 - 1
with Image.open("Tests/images/hopper_16bit_plain.pgm") as im: with Image.open("Tests/images/hopper_16bit_plain.pgm") as im:
assert im.mode == "I" assert im.mode == "I"
@ -185,7 +186,7 @@ def test_16bit_plain_pgm():
(b"P3\n2 2\n255", b"0 0 0 001 1 1 2 2 2 255 255 255", 10**6), (b"P3\n2 2\n255", b"0 0 0 001 1 1 2 2 2 255 255 255", 10**6),
), ),
) )
def test_plain_data_with_comment(tmp_path, header, data, comment_count): def test_plain_data_with_comment(tmp_path: Path, header, data, comment_count) -> None:
path1 = str(tmp_path / "temp1.ppm") path1 = str(tmp_path / "temp1.ppm")
path2 = str(tmp_path / "temp2.ppm") path2 = str(tmp_path / "temp2.ppm")
comment = b"# comment" * comment_count comment = b"# comment" * comment_count
@ -198,7 +199,7 @@ def test_plain_data_with_comment(tmp_path, header, data, comment_count):
@pytest.mark.parametrize("data", (b"P1\n128 128\n", b"P3\n128 128\n255\n")) @pytest.mark.parametrize("data", (b"P1\n128 128\n", b"P3\n128 128\n255\n"))
def test_plain_truncated_data(tmp_path, data): def test_plain_truncated_data(tmp_path: Path, data) -> None:
path = str(tmp_path / "temp.ppm") path = str(tmp_path / "temp.ppm")
with open(path, "wb") as f: with open(path, "wb") as f:
f.write(data) f.write(data)
@ -209,7 +210,7 @@ def test_plain_truncated_data(tmp_path, data):
@pytest.mark.parametrize("data", (b"P1\n128 128\n1009", b"P3\n128 128\n255\n100A")) @pytest.mark.parametrize("data", (b"P1\n128 128\n1009", b"P3\n128 128\n255\n100A"))
def test_plain_invalid_data(tmp_path, data): def test_plain_invalid_data(tmp_path: Path, data) -> None:
path = str(tmp_path / "temp.ppm") path = str(tmp_path / "temp.ppm")
with open(path, "wb") as f: with open(path, "wb") as f:
f.write(data) f.write(data)
@ -226,7 +227,7 @@ def test_plain_invalid_data(tmp_path, data):
b"P3\n128 128\n255\n012345678910 0", # token too long b"P3\n128 128\n255\n012345678910 0", # token too long
), ),
) )
def test_plain_ppm_token_too_long(tmp_path, data): def test_plain_ppm_token_too_long(tmp_path: Path, data) -> None:
path = str(tmp_path / "temp.ppm") path = str(tmp_path / "temp.ppm")
with open(path, "wb") as f: with open(path, "wb") as f:
f.write(data) f.write(data)
@ -236,7 +237,7 @@ def test_plain_ppm_token_too_long(tmp_path, data):
im.load() im.load()
def test_plain_ppm_value_too_large(tmp_path): def test_plain_ppm_value_too_large(tmp_path: Path) -> None:
path = str(tmp_path / "temp.ppm") path = str(tmp_path / "temp.ppm")
with open(path, "wb") as f: with open(path, "wb") as f:
f.write(b"P3\n128 128\n255\n256") f.write(b"P3\n128 128\n255\n256")
@ -246,12 +247,12 @@ def test_plain_ppm_value_too_large(tmp_path):
im.load() im.load()
def test_magic(): def test_magic() -> None:
with pytest.raises(SyntaxError): with pytest.raises(SyntaxError):
PpmImagePlugin.PpmImageFile(fp=BytesIO(b"PyInvalid")) PpmImagePlugin.PpmImageFile(fp=BytesIO(b"PyInvalid"))
def test_header_with_comments(tmp_path): def test_header_with_comments(tmp_path: Path) -> None:
path = str(tmp_path / "temp.ppm") path = str(tmp_path / "temp.ppm")
with open(path, "wb") as f: with open(path, "wb") as f:
f.write(b"P6 #comment\n#comment\r12#comment\r8\n128 #comment\n255\n") f.write(b"P6 #comment\n#comment\r12#comment\r8\n128 #comment\n255\n")
@ -260,7 +261,7 @@ def test_header_with_comments(tmp_path):
assert im.size == (128, 128) assert im.size == (128, 128)
def test_non_integer_token(tmp_path): def test_non_integer_token(tmp_path: Path) -> None:
path = str(tmp_path / "temp.ppm") path = str(tmp_path / "temp.ppm")
with open(path, "wb") as f: with open(path, "wb") as f:
f.write(b"P6\nTEST") f.write(b"P6\nTEST")
@ -270,7 +271,7 @@ def test_non_integer_token(tmp_path):
pass pass
def test_header_token_too_long(tmp_path): def test_header_token_too_long(tmp_path: Path) -> None:
path = str(tmp_path / "temp.ppm") path = str(tmp_path / "temp.ppm")
with open(path, "wb") as f: with open(path, "wb") as f:
f.write(b"P6\n 01234567890") f.write(b"P6\n 01234567890")
@ -282,7 +283,7 @@ def test_header_token_too_long(tmp_path):
assert str(e.value) == "Token too long in file header: 01234567890" assert str(e.value) == "Token too long in file header: 01234567890"
def test_truncated_file(tmp_path): def test_truncated_file(tmp_path: Path) -> None:
# Test EOF in header # Test EOF in header
path = str(tmp_path / "temp.pgm") path = str(tmp_path / "temp.pgm")
with open(path, "wb") as f: with open(path, "wb") as f:
@ -301,7 +302,7 @@ def test_truncated_file(tmp_path):
im.load() im.load()
def test_not_enough_image_data(tmp_path): def test_not_enough_image_data(tmp_path: Path) -> None:
path = str(tmp_path / "temp.ppm") path = str(tmp_path / "temp.ppm")
with open(path, "wb") as f: with open(path, "wb") as f:
f.write(b"P2 1 2 255 255") f.write(b"P2 1 2 255 255")
@ -312,7 +313,7 @@ def test_not_enough_image_data(tmp_path):
@pytest.mark.parametrize("maxval", (b"0", b"65536")) @pytest.mark.parametrize("maxval", (b"0", b"65536"))
def test_invalid_maxval(maxval, tmp_path): def test_invalid_maxval(maxval, tmp_path: Path) -> None:
path = str(tmp_path / "temp.ppm") path = str(tmp_path / "temp.ppm")
with open(path, "wb") as f: with open(path, "wb") as f:
f.write(b"P6\n3 1 " + maxval) f.write(b"P6\n3 1 " + maxval)
@ -324,7 +325,7 @@ def test_invalid_maxval(maxval, tmp_path):
assert str(e.value) == "maxval must be greater than 0 and less than 65536" assert str(e.value) == "maxval must be greater than 0 and less than 65536"
def test_neg_ppm(): def test_neg_ppm() -> None:
# Storage.c accepted negative values for xsize, ysize. the # Storage.c accepted negative values for xsize, ysize. the
# internal open_ppm function didn't check for sanity but it # internal open_ppm function didn't check for sanity but it
# has been removed. The default opener doesn't accept negative # has been removed. The default opener doesn't accept negative
@ -335,7 +336,7 @@ def test_neg_ppm():
pass pass
def test_mimetypes(tmp_path): def test_mimetypes(tmp_path: Path) -> None:
path = str(tmp_path / "temp.pgm") path = str(tmp_path / "temp.pgm")
with open(path, "wb") as f: with open(path, "wb") as f:
@ -350,7 +351,7 @@ def test_mimetypes(tmp_path):
@pytest.mark.parametrize("buffer", (True, False)) @pytest.mark.parametrize("buffer", (True, False))
def test_save_stdout(buffer): def test_save_stdout(buffer) -> None:
old_stdout = sys.stdout old_stdout = sys.stdout
if buffer: if buffer:

View File

@ -11,7 +11,7 @@ from .helper import assert_image_equal_tofile, assert_image_similar, hopper, is_
test_file = "Tests/images/hopper.psd" test_file = "Tests/images/hopper.psd"
def test_sanity(): def test_sanity() -> None:
with Image.open(test_file) as im: with Image.open(test_file) as im:
im.load() im.load()
assert im.mode == "RGB" assert im.mode == "RGB"
@ -24,8 +24,8 @@ def test_sanity():
@pytest.mark.skipif(is_pypy(), reason="Requires CPython") @pytest.mark.skipif(is_pypy(), reason="Requires CPython")
def test_unclosed_file(): def test_unclosed_file() -> None:
def open(): def open() -> None:
im = Image.open(test_file) im = Image.open(test_file)
im.load() im.load()
@ -33,27 +33,27 @@ def test_unclosed_file():
open() open()
def test_closed_file(): def test_closed_file() -> None:
with warnings.catch_warnings(): with warnings.catch_warnings():
im = Image.open(test_file) im = Image.open(test_file)
im.load() im.load()
im.close() im.close()
def test_context_manager(): def test_context_manager() -> None:
with warnings.catch_warnings(): with warnings.catch_warnings():
with Image.open(test_file) as im: with Image.open(test_file) as im:
im.load() im.load()
def test_invalid_file(): def test_invalid_file() -> None:
invalid_file = "Tests/images/flower.jpg" invalid_file = "Tests/images/flower.jpg"
with pytest.raises(SyntaxError): with pytest.raises(SyntaxError):
PsdImagePlugin.PsdImageFile(invalid_file) PsdImagePlugin.PsdImageFile(invalid_file)
def test_n_frames(): def test_n_frames() -> None:
with Image.open("Tests/images/hopper_merged.psd") as im: with Image.open("Tests/images/hopper_merged.psd") as im:
assert im.n_frames == 1 assert im.n_frames == 1
assert not im.is_animated assert not im.is_animated
@ -64,7 +64,7 @@ def test_n_frames():
assert im.is_animated assert im.is_animated
def test_eoferror(): def test_eoferror() -> None:
with Image.open(test_file) as im: with Image.open(test_file) as im:
# PSD seek index starts at 1 rather than 0 # PSD seek index starts at 1 rather than 0
n_frames = im.n_frames + 1 n_frames = im.n_frames + 1
@ -78,7 +78,7 @@ def test_eoferror():
im.seek(n_frames - 1) im.seek(n_frames - 1)
def test_seek_tell(): def test_seek_tell() -> None:
with Image.open(test_file) as im: with Image.open(test_file) as im:
layer_number = im.tell() layer_number = im.tell()
assert layer_number == 1 assert layer_number == 1
@ -95,30 +95,30 @@ def test_seek_tell():
assert layer_number == 2 assert layer_number == 2
def test_seek_eoferror(): def test_seek_eoferror() -> None:
with Image.open(test_file) as im: with Image.open(test_file) as im:
with pytest.raises(EOFError): with pytest.raises(EOFError):
im.seek(-1) im.seek(-1)
def test_open_after_exclusive_load(): def test_open_after_exclusive_load() -> None:
with Image.open(test_file) as im: with Image.open(test_file) as im:
im.load() im.load()
im.seek(im.tell() + 1) im.seek(im.tell() + 1)
im.load() im.load()
def test_rgba(): def test_rgba() -> None:
with Image.open("Tests/images/rgba.psd") as im: with Image.open("Tests/images/rgba.psd") as im:
assert_image_equal_tofile(im, "Tests/images/imagedraw_square.png") assert_image_equal_tofile(im, "Tests/images/imagedraw_square.png")
def test_layer_skip(): def test_layer_skip() -> None:
with Image.open("Tests/images/five_channels.psd") as im: with Image.open("Tests/images/five_channels.psd") as im:
assert im.n_frames == 1 assert im.n_frames == 1
def test_icc_profile(): def test_icc_profile() -> None:
with Image.open(test_file) as im: with Image.open(test_file) as im:
assert "icc_profile" in im.info assert "icc_profile" in im.info
@ -126,12 +126,12 @@ def test_icc_profile():
assert len(icc_profile) == 3144 assert len(icc_profile) == 3144
def test_no_icc_profile(): def test_no_icc_profile() -> None:
with Image.open("Tests/images/hopper_merged.psd") as im: with Image.open("Tests/images/hopper_merged.psd") as im:
assert "icc_profile" not in im.info assert "icc_profile" not in im.info
def test_combined_larger_than_size(): def test_combined_larger_than_size() -> None:
# The combined size of the individual parts is larger than the # The combined size of the individual parts is larger than the
# declared 'size' of the extra data field, resulting in a backwards seek. # declared 'size' of the extra data field, resulting in a backwards seek.
@ -157,7 +157,7 @@ def test_combined_larger_than_size():
("Tests/images/timeout-dedc7a4ebd856d79b4359bbcc79e8ef231ce38f6.psd", OSError), ("Tests/images/timeout-dedc7a4ebd856d79b4359bbcc79e8ef231ce38f6.psd", OSError),
], ],
) )
def test_crashes(test_file, raises): def test_crashes(test_file, raises) -> None:
with open(test_file, "rb") as f: with open(test_file, "rb") as f:
with pytest.raises(raises): with pytest.raises(raises):
with Image.open(f): with Image.open(f):

View File

@ -1,5 +1,7 @@
from __future__ import annotations from __future__ import annotations
from pathlib import Path
import pytest import pytest
from PIL import Image, SgiImagePlugin from PIL import Image, SgiImagePlugin
@ -12,7 +14,7 @@ from .helper import (
) )
def test_rgb(): def test_rgb() -> None:
# Created with ImageMagick then renamed: # Created with ImageMagick then renamed:
# convert hopper.ppm -compress None sgi:hopper.rgb # convert hopper.ppm -compress None sgi:hopper.rgb
test_file = "Tests/images/hopper.rgb" test_file = "Tests/images/hopper.rgb"
@ -22,11 +24,11 @@ def test_rgb():
assert im.get_format_mimetype() == "image/rgb" assert im.get_format_mimetype() == "image/rgb"
def test_rgb16(): def test_rgb16() -> None:
assert_image_equal_tofile(hopper(), "Tests/images/hopper16.rgb") assert_image_equal_tofile(hopper(), "Tests/images/hopper16.rgb")
def test_l(): def test_l() -> None:
# Created with ImageMagick # Created with ImageMagick
# convert hopper.ppm -monochrome -compress None sgi:hopper.bw # convert hopper.ppm -monochrome -compress None sgi:hopper.bw
test_file = "Tests/images/hopper.bw" test_file = "Tests/images/hopper.bw"
@ -36,7 +38,7 @@ def test_l():
assert im.get_format_mimetype() == "image/sgi" assert im.get_format_mimetype() == "image/sgi"
def test_rgba(): def test_rgba() -> None:
# Created with ImageMagick: # Created with ImageMagick:
# convert transparent.png -compress None transparent.sgi # convert transparent.png -compress None transparent.sgi
test_file = "Tests/images/transparent.sgi" test_file = "Tests/images/transparent.sgi"
@ -46,7 +48,7 @@ def test_rgba():
assert im.get_format_mimetype() == "image/sgi" assert im.get_format_mimetype() == "image/sgi"
def test_rle(): def test_rle() -> None:
# Created with ImageMagick: # Created with ImageMagick:
# convert hopper.ppm hopper.sgi # convert hopper.ppm hopper.sgi
test_file = "Tests/images/hopper.sgi" test_file = "Tests/images/hopper.sgi"
@ -55,22 +57,22 @@ def test_rle():
assert_image_equal_tofile(im, "Tests/images/hopper.rgb") assert_image_equal_tofile(im, "Tests/images/hopper.rgb")
def test_rle16(): def test_rle16() -> None:
test_file = "Tests/images/tv16.sgi" test_file = "Tests/images/tv16.sgi"
with Image.open(test_file) as im: with Image.open(test_file) as im:
assert_image_equal_tofile(im, "Tests/images/tv.rgb") assert_image_equal_tofile(im, "Tests/images/tv.rgb")
def test_invalid_file(): def test_invalid_file() -> None:
invalid_file = "Tests/images/flower.jpg" invalid_file = "Tests/images/flower.jpg"
with pytest.raises(ValueError): with pytest.raises(ValueError):
SgiImagePlugin.SgiImageFile(invalid_file) SgiImagePlugin.SgiImageFile(invalid_file)
def test_write(tmp_path): def test_write(tmp_path: Path) -> None:
def roundtrip(img): def roundtrip(img) -> None:
out = str(tmp_path / "temp.sgi") out = str(tmp_path / "temp.sgi")
img.save(out, format="sgi") img.save(out, format="sgi")
assert_image_equal_tofile(img, out) assert_image_equal_tofile(img, out)
@ -89,7 +91,7 @@ def test_write(tmp_path):
roundtrip(Image.new("L", (10, 1))) roundtrip(Image.new("L", (10, 1)))
def test_write16(tmp_path): def test_write16(tmp_path: Path) -> None:
test_file = "Tests/images/hopper16.rgb" test_file = "Tests/images/hopper16.rgb"
with Image.open(test_file) as im: with Image.open(test_file) as im:
@ -99,7 +101,7 @@ def test_write16(tmp_path):
assert_image_equal_tofile(im, out) assert_image_equal_tofile(im, out)
def test_unsupported_mode(tmp_path): def test_unsupported_mode(tmp_path: Path) -> None:
im = hopper("LA") im = hopper("LA")
out = str(tmp_path / "temp.sgi") out = str(tmp_path / "temp.sgi")

View File

@ -3,6 +3,7 @@ from __future__ import annotations
import tempfile import tempfile
import warnings import warnings
from io import BytesIO from io import BytesIO
from pathlib import Path
import pytest import pytest
@ -13,7 +14,7 @@ from .helper import assert_image_equal_tofile, hopper, is_pypy
TEST_FILE = "Tests/images/hopper.spider" TEST_FILE = "Tests/images/hopper.spider"
def test_sanity(): def test_sanity() -> None:
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"
@ -22,8 +23,8 @@ def test_sanity():
@pytest.mark.skipif(is_pypy(), reason="Requires CPython") @pytest.mark.skipif(is_pypy(), reason="Requires CPython")
def test_unclosed_file(): def test_unclosed_file() -> None:
def open(): def open() -> None:
im = Image.open(TEST_FILE) im = Image.open(TEST_FILE)
im.load() im.load()
@ -31,20 +32,20 @@ def test_unclosed_file():
open() open()
def test_closed_file(): def test_closed_file() -> None:
with warnings.catch_warnings(): with warnings.catch_warnings():
im = Image.open(TEST_FILE) im = Image.open(TEST_FILE)
im.load() im.load()
im.close() im.close()
def test_context_manager(): def test_context_manager() -> None:
with warnings.catch_warnings(): with warnings.catch_warnings():
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
im.load() im.load()
def test_save(tmp_path): def test_save(tmp_path: Path) -> None:
# Arrange # Arrange
temp = str(tmp_path / "temp.spider") temp = str(tmp_path / "temp.spider")
im = hopper() im = hopper()
@ -59,7 +60,7 @@ def test_save(tmp_path):
assert im2.format == "SPIDER" assert im2.format == "SPIDER"
def test_tempfile(): def test_tempfile() -> None:
# Arrange # Arrange
im = hopper() im = hopper()
@ -75,11 +76,11 @@ def test_tempfile():
assert reloaded.format == "SPIDER" assert reloaded.format == "SPIDER"
def test_is_spider_image(): def test_is_spider_image() -> None:
assert SpiderImagePlugin.isSpiderImage(TEST_FILE) assert SpiderImagePlugin.isSpiderImage(TEST_FILE)
def test_tell(): def test_tell() -> None:
# Arrange # Arrange
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
# Act # Act
@ -89,13 +90,13 @@ def test_tell():
assert index == 0 assert index == 0
def test_n_frames(): def test_n_frames() -> None:
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_load_image_series(): def test_load_image_series() -> None:
# 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"]
@ -109,7 +110,7 @@ def test_load_image_series():
assert img_list[0].size == (128, 128) assert img_list[0].size == (128, 128)
def test_load_image_series_no_input(): def test_load_image_series_no_input() -> None:
# Arrange # Arrange
file_list = None file_list = None
@ -120,7 +121,7 @@ def test_load_image_series_no_input():
assert img_list is None assert img_list is None
def test_is_int_not_a_number(): def test_is_int_not_a_number() -> None:
# Arrange # Arrange
not_a_number = "a" not_a_number = "a"
@ -131,7 +132,7 @@ def test_is_int_not_a_number():
assert ret == 0 assert ret == 0
def test_invalid_file(): def test_invalid_file() -> None:
invalid_file = "Tests/images/invalid.spider" invalid_file = "Tests/images/invalid.spider"
with pytest.raises(OSError): with pytest.raises(OSError):
@ -139,20 +140,20 @@ def test_invalid_file():
pass pass
def test_nonstack_file(): def test_nonstack_file() -> None:
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(): def test_nonstack_dos() -> None:
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 # for issue #4093
def test_odd_size(): def test_odd_size() -> None:
data = BytesIO() data = BytesIO()
width = 100 width = 100
im = Image.new("F", (width, 64)) im = Image.new("F", (width, 64))

View File

@ -11,7 +11,7 @@ from .helper import assert_image_equal_tofile, assert_image_similar, hopper
EXTRA_DIR = "Tests/images/sunraster" EXTRA_DIR = "Tests/images/sunraster"
def test_sanity(): def test_sanity() -> None:
# Arrange # Arrange
# Created with ImageMagick: convert hopper.jpg hopper.ras # Created with ImageMagick: convert hopper.jpg hopper.ras
test_file = "Tests/images/hopper.ras" test_file = "Tests/images/hopper.ras"
@ -28,7 +28,7 @@ def test_sanity():
SunImagePlugin.SunImageFile(invalid_file) SunImagePlugin.SunImageFile(invalid_file)
def test_im1(): def test_im1() -> None:
with Image.open("Tests/images/sunraster.im1") as im: with Image.open("Tests/images/sunraster.im1") as im:
assert_image_equal_tofile(im, "Tests/images/sunraster.im1.png") assert_image_equal_tofile(im, "Tests/images/sunraster.im1.png")
@ -36,7 +36,7 @@ def test_im1():
@pytest.mark.skipif( @pytest.mark.skipif(
not os.path.exists(EXTRA_DIR), reason="Extra image files not installed" not os.path.exists(EXTRA_DIR), reason="Extra image files not installed"
) )
def test_others(): def test_others() -> None:
files = ( files = (
os.path.join(EXTRA_DIR, f) os.path.join(EXTRA_DIR, f)
for f in os.listdir(EXTRA_DIR) for f in os.listdir(EXTRA_DIR)

View File

@ -19,7 +19,7 @@ TEST_TAR_FILE = "Tests/images/hopper.tar"
("jpg", "hopper.jpg", "JPEG"), ("jpg", "hopper.jpg", "JPEG"),
), ),
) )
def test_sanity(codec, test_path, format): def test_sanity(codec, test_path, format) -> None:
if features.check(codec): if features.check(codec):
with TarIO.TarIO(TEST_TAR_FILE, test_path) as tar: with TarIO.TarIO(TEST_TAR_FILE, test_path) as tar:
with Image.open(tar) as im: with Image.open(tar) as im:
@ -30,18 +30,18 @@ def test_sanity(codec, test_path, format):
@pytest.mark.skipif(is_pypy(), reason="Requires CPython") @pytest.mark.skipif(is_pypy(), reason="Requires CPython")
def test_unclosed_file(): def test_unclosed_file() -> None:
with pytest.warns(ResourceWarning): with pytest.warns(ResourceWarning):
TarIO.TarIO(TEST_TAR_FILE, "hopper.jpg") TarIO.TarIO(TEST_TAR_FILE, "hopper.jpg")
def test_close(): def test_close() -> None:
with warnings.catch_warnings(): with warnings.catch_warnings():
tar = TarIO.TarIO(TEST_TAR_FILE, "hopper.jpg") tar = TarIO.TarIO(TEST_TAR_FILE, "hopper.jpg")
tar.close() tar.close()
def test_contextmanager(): def test_contextmanager() -> None:
with warnings.catch_warnings(): with warnings.catch_warnings():
with TarIO.TarIO(TEST_TAR_FILE, "hopper.jpg"): with TarIO.TarIO(TEST_TAR_FILE, "hopper.jpg"):
pass pass

View File

@ -3,6 +3,7 @@ from __future__ import annotations
import os import os
from glob import glob from glob import glob
from itertools import product from itertools import product
from pathlib import Path
import pytest import pytest
@ -21,8 +22,8 @@ _ORIGIN_TO_ORIENTATION = {"tl": 1, "bl": -1}
@pytest.mark.parametrize("mode", _MODES) @pytest.mark.parametrize("mode", _MODES)
def test_sanity(mode, tmp_path): def test_sanity(mode, tmp_path: Path) -> None:
def roundtrip(original_im): def roundtrip(original_im) -> None:
out = str(tmp_path / "temp.tga") out = str(tmp_path / "temp.tga")
original_im.save(out, rle=rle) original_im.save(out, rle=rle)
@ -64,7 +65,7 @@ def test_sanity(mode, tmp_path):
roundtrip(original_im) roundtrip(original_im)
def test_palette_depth_16(tmp_path): def test_palette_depth_16(tmp_path: Path) -> None:
with Image.open("Tests/images/p_16.tga") as im: with Image.open("Tests/images/p_16.tga") as im:
assert_image_equal_tofile(im.convert("RGB"), "Tests/images/p_16.png") assert_image_equal_tofile(im.convert("RGB"), "Tests/images/p_16.png")
@ -74,7 +75,7 @@ def test_palette_depth_16(tmp_path):
assert_image_equal_tofile(reloaded.convert("RGB"), "Tests/images/p_16.png") assert_image_equal_tofile(reloaded.convert("RGB"), "Tests/images/p_16.png")
def test_id_field(): def test_id_field() -> None:
# tga file with id field # tga file with id field
test_file = "Tests/images/tga_id_field.tga" test_file = "Tests/images/tga_id_field.tga"
@ -84,7 +85,7 @@ def test_id_field():
assert im.size == (100, 100) assert im.size == (100, 100)
def test_id_field_rle(): def test_id_field_rle() -> None:
# tga file with id field # tga file with id field
test_file = "Tests/images/rgb32rle.tga" test_file = "Tests/images/rgb32rle.tga"
@ -94,7 +95,7 @@ def test_id_field_rle():
assert im.size == (199, 199) assert im.size == (199, 199)
def test_cross_scan_line(): def test_cross_scan_line() -> None:
with Image.open("Tests/images/cross_scan_line.tga") as im: with Image.open("Tests/images/cross_scan_line.tga") as im:
assert_image_equal_tofile(im, "Tests/images/cross_scan_line.png") assert_image_equal_tofile(im, "Tests/images/cross_scan_line.png")
@ -103,7 +104,7 @@ def test_cross_scan_line():
im.load() im.load()
def test_save(tmp_path): def test_save(tmp_path: Path) -> None:
test_file = "Tests/images/tga_id_field.tga" test_file = "Tests/images/tga_id_field.tga"
with Image.open(test_file) as im: with Image.open(test_file) as im:
out = str(tmp_path / "temp.tga") out = str(tmp_path / "temp.tga")
@ -120,7 +121,7 @@ def test_save(tmp_path):
assert test_im.size == (100, 100) assert test_im.size == (100, 100)
def test_small_palette(tmp_path): def test_small_palette(tmp_path: Path) -> None:
im = Image.new("P", (1, 1)) im = Image.new("P", (1, 1))
colors = [0, 0, 0] colors = [0, 0, 0]
im.putpalette(colors) im.putpalette(colors)
@ -132,7 +133,7 @@ def test_small_palette(tmp_path):
assert reloaded.getpalette() == colors assert reloaded.getpalette() == colors
def test_save_wrong_mode(tmp_path): def test_save_wrong_mode(tmp_path: Path) -> None:
im = hopper("PA") im = hopper("PA")
out = str(tmp_path / "temp.tga") out = str(tmp_path / "temp.tga")
@ -140,7 +141,7 @@ def test_save_wrong_mode(tmp_path):
im.save(out) im.save(out)
def test_save_mapdepth(): def test_save_mapdepth() -> None:
# This image has been manually hexedited from 200x32_p_bl_raw.tga # This image has been manually hexedited from 200x32_p_bl_raw.tga
# to include an origin # to include an origin
test_file = "Tests/images/200x32_p_bl_raw_origin.tga" test_file = "Tests/images/200x32_p_bl_raw_origin.tga"
@ -148,7 +149,7 @@ def test_save_mapdepth():
assert_image_equal_tofile(im, "Tests/images/tga/common/200x32_p.png") assert_image_equal_tofile(im, "Tests/images/tga/common/200x32_p.png")
def test_save_id_section(tmp_path): def test_save_id_section(tmp_path: Path) -> None:
test_file = "Tests/images/rgb32rle.tga" test_file = "Tests/images/rgb32rle.tga"
with Image.open(test_file) as im: with Image.open(test_file) as im:
out = str(tmp_path / "temp.tga") out = str(tmp_path / "temp.tga")
@ -179,7 +180,7 @@ def test_save_id_section(tmp_path):
assert "id_section" not in test_im.info assert "id_section" not in test_im.info
def test_save_orientation(tmp_path): def test_save_orientation(tmp_path: Path) -> None:
test_file = "Tests/images/rgb32rle.tga" test_file = "Tests/images/rgb32rle.tga"
out = str(tmp_path / "temp.tga") out = str(tmp_path / "temp.tga")
with Image.open(test_file) as im: with Image.open(test_file) as im:
@ -190,7 +191,7 @@ def test_save_orientation(tmp_path):
assert test_im.info["orientation"] == 1 assert test_im.info["orientation"] == 1
def test_horizontal_orientations(): def test_horizontal_orientations() -> None:
# These images have been manually hexedited to have the relevant orientations # These images have been manually hexedited to have the relevant orientations
with Image.open("Tests/images/rgb32rle_top_right.tga") as im: with Image.open("Tests/images/rgb32rle_top_right.tga") as im:
assert im.load()[90, 90][:3] == (0, 0, 0) assert im.load()[90, 90][:3] == (0, 0, 0)
@ -199,7 +200,7 @@ def test_horizontal_orientations():
assert im.load()[90, 90][:3] == (0, 255, 0) assert im.load()[90, 90][:3] == (0, 255, 0)
def test_save_rle(tmp_path): def test_save_rle(tmp_path: Path) -> None:
test_file = "Tests/images/rgb32rle.tga" test_file = "Tests/images/rgb32rle.tga"
with Image.open(test_file) as im: with Image.open(test_file) as im:
assert im.info["compression"] == "tga_rle" assert im.info["compression"] == "tga_rle"
@ -232,7 +233,7 @@ def test_save_rle(tmp_path):
assert test_im.info["compression"] == "tga_rle" assert test_im.info["compression"] == "tga_rle"
def test_save_l_transparency(tmp_path): def test_save_l_transparency(tmp_path: Path) -> None:
# There are 559 transparent pixels in la.tga. # There are 559 transparent pixels in la.tga.
num_transparent = 559 num_transparent = 559

View File

@ -3,6 +3,7 @@ from __future__ import annotations
import os import os
import warnings import warnings
from io import BytesIO from io import BytesIO
from pathlib import Path
import pytest import pytest
@ -26,7 +27,7 @@ except ImportError:
class TestFileTiff: class TestFileTiff:
def test_sanity(self, tmp_path): def test_sanity(self, tmp_path: Path) -> None:
filename = str(tmp_path / "temp.tif") filename = str(tmp_path / "temp.tif")
hopper("RGB").save(filename) hopper("RGB").save(filename)
@ -58,21 +59,21 @@ class TestFileTiff:
pass pass
@pytest.mark.skipif(is_pypy(), reason="Requires CPython") @pytest.mark.skipif(is_pypy(), reason="Requires CPython")
def test_unclosed_file(self): def test_unclosed_file(self) -> None:
def open(): def open() -> None:
im = Image.open("Tests/images/multipage.tiff") im = Image.open("Tests/images/multipage.tiff")
im.load() im.load()
with pytest.warns(ResourceWarning): with pytest.warns(ResourceWarning):
open() open()
def test_closed_file(self): def test_closed_file(self) -> None:
with warnings.catch_warnings(): with warnings.catch_warnings():
im = Image.open("Tests/images/multipage.tiff") im = Image.open("Tests/images/multipage.tiff")
im.load() im.load()
im.close() im.close()
def test_seek_after_close(self): def test_seek_after_close(self) -> None:
im = Image.open("Tests/images/multipage.tiff") im = Image.open("Tests/images/multipage.tiff")
im.close() im.close()
@ -81,12 +82,12 @@ class TestFileTiff:
with pytest.raises(ValueError): with pytest.raises(ValueError):
im.seek(1) im.seek(1)
def test_context_manager(self): def test_context_manager(self) -> None:
with warnings.catch_warnings(): with warnings.catch_warnings():
with Image.open("Tests/images/multipage.tiff") as im: with Image.open("Tests/images/multipage.tiff") as im:
im.load() im.load()
def test_mac_tiff(self): def test_mac_tiff(self) -> None:
# Read RGBa images from macOS [@PIL136] # Read RGBa images from macOS [@PIL136]
filename = "Tests/images/pil136.tiff" filename = "Tests/images/pil136.tiff"
@ -98,7 +99,7 @@ class TestFileTiff:
assert_image_similar_tofile(im, "Tests/images/pil136.png", 1) assert_image_similar_tofile(im, "Tests/images/pil136.png", 1)
def test_bigtiff(self, tmp_path): def test_bigtiff(self, tmp_path: Path) -> None:
with Image.open("Tests/images/hopper_bigtiff.tif") as im: with Image.open("Tests/images/hopper_bigtiff.tif") as im:
assert_image_equal_tofile(im, "Tests/images/hopper.tif") assert_image_equal_tofile(im, "Tests/images/hopper.tif")
@ -109,13 +110,13 @@ class TestFileTiff:
outfile = str(tmp_path / "temp.tif") outfile = str(tmp_path / "temp.tif")
im.save(outfile, save_all=True, append_images=[im], tiffinfo=im.tag_v2) im.save(outfile, save_all=True, append_images=[im], tiffinfo=im.tag_v2)
def test_set_legacy_api(self): def test_set_legacy_api(self) -> None:
ifd = TiffImagePlugin.ImageFileDirectory_v2() ifd = TiffImagePlugin.ImageFileDirectory_v2()
with pytest.raises(Exception) as e: with pytest.raises(Exception) as e:
ifd.legacy_api = None ifd.legacy_api = None
assert str(e.value) == "Not allowing setting of legacy api" assert str(e.value) == "Not allowing setting of legacy api"
def test_xyres_tiff(self): def test_xyres_tiff(self) -> None:
filename = "Tests/images/pil168.tif" filename = "Tests/images/pil168.tif"
with Image.open(filename) as im: with Image.open(filename) as im:
# legacy api # legacy api
@ -128,7 +129,7 @@ class TestFileTiff:
assert im.info["dpi"] == (72.0, 72.0) assert im.info["dpi"] == (72.0, 72.0)
def test_xyres_fallback_tiff(self): def test_xyres_fallback_tiff(self) -> None:
filename = "Tests/images/compression.tif" filename = "Tests/images/compression.tif"
with Image.open(filename) as im: with Image.open(filename) as im:
# v2 api # v2 api
@ -142,7 +143,7 @@ class TestFileTiff:
# Fallback "inch". # Fallback "inch".
assert im.info["dpi"] == (100.0, 100.0) assert im.info["dpi"] == (100.0, 100.0)
def test_int_resolution(self): def test_int_resolution(self) -> None:
filename = "Tests/images/pil168.tif" filename = "Tests/images/pil168.tif"
with Image.open(filename) as im: with Image.open(filename) as im:
# Try to read a file where X,Y_RESOLUTION are ints # Try to read a file where X,Y_RESOLUTION are ints
@ -155,14 +156,14 @@ class TestFileTiff:
"resolution_unit, dpi", "resolution_unit, dpi",
[(None, 72.8), (2, 72.8), (3, 184.912)], [(None, 72.8), (2, 72.8), (3, 184.912)],
) )
def test_load_float_dpi(self, resolution_unit, dpi): def test_load_float_dpi(self, resolution_unit, dpi) -> None:
with Image.open( with Image.open(
"Tests/images/hopper_float_dpi_" + str(resolution_unit) + ".tif" "Tests/images/hopper_float_dpi_" + str(resolution_unit) + ".tif"
) as im: ) as im:
assert im.tag_v2.get(RESOLUTION_UNIT) == resolution_unit assert im.tag_v2.get(RESOLUTION_UNIT) == resolution_unit
assert im.info["dpi"] == (dpi, dpi) assert im.info["dpi"] == (dpi, dpi)
def test_save_float_dpi(self, tmp_path): def test_save_float_dpi(self, tmp_path: Path) -> None:
outfile = str(tmp_path / "temp.tif") outfile = str(tmp_path / "temp.tif")
with Image.open("Tests/images/hopper.tif") as im: with Image.open("Tests/images/hopper.tif") as im:
dpi = (72.2, 72.2) dpi = (72.2, 72.2)
@ -171,7 +172,7 @@ class TestFileTiff:
with Image.open(outfile) as reloaded: with Image.open(outfile) as reloaded:
assert reloaded.info["dpi"] == dpi assert reloaded.info["dpi"] == dpi
def test_save_setting_missing_resolution(self): def test_save_setting_missing_resolution(self) -> None:
b = BytesIO() b = BytesIO()
with Image.open("Tests/images/10ct_32bit_128.tiff") as im: with Image.open("Tests/images/10ct_32bit_128.tiff") as im:
im.save(b, format="tiff", resolution=123.45) im.save(b, format="tiff", resolution=123.45)
@ -179,7 +180,7 @@ class TestFileTiff:
assert im.tag_v2[X_RESOLUTION] == 123.45 assert im.tag_v2[X_RESOLUTION] == 123.45
assert im.tag_v2[Y_RESOLUTION] == 123.45 assert im.tag_v2[Y_RESOLUTION] == 123.45
def test_invalid_file(self): def test_invalid_file(self) -> None:
invalid_file = "Tests/images/flower.jpg" invalid_file = "Tests/images/flower.jpg"
with pytest.raises(SyntaxError): with pytest.raises(SyntaxError):
@ -190,30 +191,30 @@ class TestFileTiff:
TiffImagePlugin.TiffImageFile(invalid_file) TiffImagePlugin.TiffImageFile(invalid_file)
TiffImagePlugin.PREFIXES.pop() TiffImagePlugin.PREFIXES.pop()
def test_bad_exif(self): def test_bad_exif(self) -> None:
with Image.open("Tests/images/hopper_bad_exif.jpg") as i: with Image.open("Tests/images/hopper_bad_exif.jpg") as i:
# Should not raise struct.error. # Should not raise struct.error.
with pytest.warns(UserWarning): with pytest.warns(UserWarning):
i._getexif() i._getexif()
def test_save_rgba(self, tmp_path): def test_save_rgba(self, tmp_path: Path) -> None:
im = hopper("RGBA") im = hopper("RGBA")
outfile = str(tmp_path / "temp.tif") outfile = str(tmp_path / "temp.tif")
im.save(outfile) im.save(outfile)
def test_save_unsupported_mode(self, tmp_path): def test_save_unsupported_mode(self, tmp_path: Path) -> None:
im = hopper("HSV") im = hopper("HSV")
outfile = str(tmp_path / "temp.tif") outfile = str(tmp_path / "temp.tif")
with pytest.raises(OSError): with pytest.raises(OSError):
im.save(outfile) im.save(outfile)
def test_8bit_s(self): def test_8bit_s(self) -> None:
with Image.open("Tests/images/8bit.s.tif") as im: with Image.open("Tests/images/8bit.s.tif") as im:
im.load() im.load()
assert im.mode == "L" assert im.mode == "L"
assert im.getpixel((50, 50)) == 184 assert im.getpixel((50, 50)) == 184
def test_little_endian(self): def test_little_endian(self) -> None:
with Image.open("Tests/images/16bit.cropped.tif") as im: with Image.open("Tests/images/16bit.cropped.tif") as im:
assert im.getpixel((0, 0)) == 480 assert im.getpixel((0, 0)) == 480
assert im.mode == "I;16" assert im.mode == "I;16"
@ -223,7 +224,7 @@ class TestFileTiff:
assert b[0] == ord(b"\xe0") assert b[0] == ord(b"\xe0")
assert b[1] == ord(b"\x01") assert b[1] == ord(b"\x01")
def test_big_endian(self): def test_big_endian(self) -> None:
with Image.open("Tests/images/16bit.MM.cropped.tif") as im: with Image.open("Tests/images/16bit.MM.cropped.tif") as im:
assert im.getpixel((0, 0)) == 480 assert im.getpixel((0, 0)) == 480
assert im.mode == "I;16B" assert im.mode == "I;16B"
@ -233,7 +234,7 @@ class TestFileTiff:
assert b[0] == ord(b"\x01") assert b[0] == ord(b"\x01")
assert b[1] == ord(b"\xe0") assert b[1] == ord(b"\xe0")
def test_16bit_r(self): def test_16bit_r(self) -> None:
with Image.open("Tests/images/16bit.r.tif") as im: with Image.open("Tests/images/16bit.r.tif") as im:
assert im.getpixel((0, 0)) == 480 assert im.getpixel((0, 0)) == 480
assert im.mode == "I;16" assert im.mode == "I;16"
@ -242,14 +243,14 @@ class TestFileTiff:
assert b[0] == ord(b"\xe0") assert b[0] == ord(b"\xe0")
assert b[1] == ord(b"\x01") assert b[1] == ord(b"\x01")
def test_16bit_s(self): def test_16bit_s(self) -> None:
with Image.open("Tests/images/16bit.s.tif") as im: with Image.open("Tests/images/16bit.s.tif") as im:
im.load() im.load()
assert im.mode == "I" assert im.mode == "I"
assert im.getpixel((0, 0)) == 32767 assert im.getpixel((0, 0)) == 32767
assert im.getpixel((0, 1)) == 0 assert im.getpixel((0, 1)) == 0
def test_12bit_rawmode(self): def test_12bit_rawmode(self) -> None:
"""Are we generating the same interpretation """Are we generating the same interpretation
of the image as Imagemagick is?""" of the image as Imagemagick is?"""
@ -262,7 +263,7 @@ class TestFileTiff:
assert_image_equal_tofile(im, "Tests/images/12in16bit.tif") assert_image_equal_tofile(im, "Tests/images/12in16bit.tif")
def test_32bit_float(self): def test_32bit_float(self) -> None:
# Issue 614, specific 32-bit float format # Issue 614, specific 32-bit float format
path = "Tests/images/10ct_32bit_128.tiff" path = "Tests/images/10ct_32bit_128.tiff"
with Image.open(path) as im: with Image.open(path) as im:
@ -271,7 +272,7 @@ class TestFileTiff:
assert im.getpixel((0, 0)) == -0.4526388943195343 assert im.getpixel((0, 0)) == -0.4526388943195343
assert im.getextrema() == (-3.140936851501465, 3.140684127807617) assert im.getextrema() == (-3.140936851501465, 3.140684127807617)
def test_unknown_pixel_mode(self): def test_unknown_pixel_mode(self) -> None:
with pytest.raises(OSError): with pytest.raises(OSError):
with Image.open("Tests/images/hopper_unknown_pixel_mode.tif"): with Image.open("Tests/images/hopper_unknown_pixel_mode.tif"):
pass pass
@ -283,12 +284,12 @@ class TestFileTiff:
("Tests/images/multipage.tiff", 3), ("Tests/images/multipage.tiff", 3),
), ),
) )
def test_n_frames(self, path, n_frames): def test_n_frames(self, path, n_frames) -> None:
with Image.open(path) as im: with Image.open(path) as im:
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(self) -> None:
with Image.open("Tests/images/multipage-lastframe.tif") as im: with Image.open("Tests/images/multipage-lastframe.tif") as im:
n_frames = im.n_frames n_frames = im.n_frames
@ -300,7 +301,7 @@ class TestFileTiff:
# 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_multipage(self): def test_multipage(self) -> None:
# issue #862 # issue #862
with Image.open("Tests/images/multipage.tiff") as im: with Image.open("Tests/images/multipage.tiff") as im:
# file is a multipage tiff: 10x10 green, 10x10 red, 20x20 blue # file is a multipage tiff: 10x10 green, 10x10 red, 20x20 blue
@ -324,13 +325,13 @@ class TestFileTiff:
assert im.size == (20, 20) assert im.size == (20, 20)
assert im.convert("RGB").getpixel((0, 0)) == (0, 0, 255) assert im.convert("RGB").getpixel((0, 0)) == (0, 0, 255)
def test_multipage_last_frame(self): def test_multipage_last_frame(self) -> None:
with Image.open("Tests/images/multipage-lastframe.tif") as im: with Image.open("Tests/images/multipage-lastframe.tif") as im:
im.load() im.load()
assert im.size == (20, 20) assert im.size == (20, 20)
assert im.convert("RGB").getpixel((0, 0)) == (0, 0, 255) assert im.convert("RGB").getpixel((0, 0)) == (0, 0, 255)
def test_frame_order(self): def test_frame_order(self) -> None:
# A frame can't progress to itself after reading # A frame can't progress to itself after reading
with Image.open("Tests/images/multipage_single_frame_loop.tiff") as im: with Image.open("Tests/images/multipage_single_frame_loop.tiff") as im:
assert im.n_frames == 1 assert im.n_frames == 1
@ -343,7 +344,7 @@ class TestFileTiff:
with Image.open("Tests/images/multipage_out_of_order.tiff") as im: with Image.open("Tests/images/multipage_out_of_order.tiff") as im:
assert im.n_frames == 3 assert im.n_frames == 3
def test___str__(self): def test___str__(self) -> None:
filename = "Tests/images/pil136.tiff" filename = "Tests/images/pil136.tiff"
with Image.open(filename) as im: with Image.open(filename) as im:
# Act # Act
@ -352,7 +353,7 @@ class TestFileTiff:
# Assert # Assert
assert isinstance(ret, str) assert isinstance(ret, str)
def test_dict(self): def test_dict(self) -> None:
# Arrange # Arrange
filename = "Tests/images/pil136.tiff" filename = "Tests/images/pil136.tiff"
with Image.open(filename) as im: with Image.open(filename) as im:
@ -392,7 +393,7 @@ class TestFileTiff:
} }
assert dict(im.tag) == legacy_tags assert dict(im.tag) == legacy_tags
def test__delitem__(self): def test__delitem__(self) -> None:
filename = "Tests/images/pil136.tiff" filename = "Tests/images/pil136.tiff"
with Image.open(filename) as im: with Image.open(filename) as im:
len_before = len(dict(im.ifd)) len_before = len(dict(im.ifd))
@ -401,36 +402,36 @@ class TestFileTiff:
assert len_before == len_after + 1 assert len_before == len_after + 1
@pytest.mark.parametrize("legacy_api", (False, True)) @pytest.mark.parametrize("legacy_api", (False, True))
def test_load_byte(self, legacy_api): def test_load_byte(self, legacy_api) -> None:
ifd = TiffImagePlugin.ImageFileDirectory_v2() ifd = TiffImagePlugin.ImageFileDirectory_v2()
data = b"abc" data = b"abc"
ret = ifd.load_byte(data, legacy_api) ret = ifd.load_byte(data, legacy_api)
assert ret == b"abc" assert ret == b"abc"
def test_load_string(self): def test_load_string(self) -> None:
ifd = TiffImagePlugin.ImageFileDirectory_v2() ifd = TiffImagePlugin.ImageFileDirectory_v2()
data = b"abc\0" data = b"abc\0"
ret = ifd.load_string(data, False) ret = ifd.load_string(data, False)
assert ret == "abc" assert ret == "abc"
def test_load_float(self): def test_load_float(self) -> None:
ifd = TiffImagePlugin.ImageFileDirectory_v2() ifd = TiffImagePlugin.ImageFileDirectory_v2()
data = b"abcdabcd" data = b"abcdabcd"
ret = ifd.load_float(data, False) ret = ifd.load_float(data, False)
assert ret == (1.6777999408082104e22, 1.6777999408082104e22) assert ret == (1.6777999408082104e22, 1.6777999408082104e22)
def test_load_double(self): def test_load_double(self) -> None:
ifd = TiffImagePlugin.ImageFileDirectory_v2() ifd = TiffImagePlugin.ImageFileDirectory_v2()
data = b"abcdefghabcdefgh" data = b"abcdefghabcdefgh"
ret = ifd.load_double(data, False) ret = ifd.load_double(data, False)
assert ret == (8.540883223036124e194, 8.540883223036124e194) assert ret == (8.540883223036124e194, 8.540883223036124e194)
def test_ifd_tag_type(self): def test_ifd_tag_type(self) -> None:
with Image.open("Tests/images/ifd_tag_type.tiff") as im: with Image.open("Tests/images/ifd_tag_type.tiff") as im:
assert 0x8825 in im.tag_v2 assert 0x8825 in im.tag_v2
def test_exif(self, tmp_path): def test_exif(self, tmp_path: Path) -> None:
def check_exif(exif): def check_exif(exif) -> None:
assert sorted(exif.keys()) == [ assert sorted(exif.keys()) == [
256, 256,
257, 257,
@ -481,7 +482,7 @@ class TestFileTiff:
exif = im.getexif() exif = im.getexif()
check_exif(exif) check_exif(exif)
def test_modify_exif(self, tmp_path): def test_modify_exif(self, tmp_path: Path) -> None:
outfile = str(tmp_path / "temp.tif") outfile = str(tmp_path / "temp.tif")
with Image.open("Tests/images/ifd_tag_type.tiff") as im: with Image.open("Tests/images/ifd_tag_type.tiff") as im:
exif = im.getexif() exif = im.getexif()
@ -493,7 +494,7 @@ class TestFileTiff:
exif = im.getexif() exif = im.getexif()
assert exif[264] == 100 assert exif[264] == 100
def test_reload_exif_after_seek(self): def test_reload_exif_after_seek(self) -> None:
with Image.open("Tests/images/multipage.tiff") as im: with Image.open("Tests/images/multipage.tiff") as im:
exif = im.getexif() exif = im.getexif()
del exif[256] del exif[256]
@ -501,7 +502,7 @@ class TestFileTiff:
assert 256 in exif assert 256 in exif
def test_exif_frames(self): def test_exif_frames(self) -> None:
# Test that EXIF data can change across frames # Test that EXIF data can change across frames
with Image.open("Tests/images/g4-multi.tiff") as im: with Image.open("Tests/images/g4-multi.tiff") as im:
assert im.getexif()[273] == (328, 815) assert im.getexif()[273] == (328, 815)
@ -510,7 +511,7 @@ class TestFileTiff:
assert im.getexif()[273] == (1408, 1907) assert im.getexif()[273] == (1408, 1907)
@pytest.mark.parametrize("mode", ("1", "L")) @pytest.mark.parametrize("mode", ("1", "L"))
def test_photometric(self, mode, tmp_path): def test_photometric(self, mode, tmp_path: Path) -> None:
filename = str(tmp_path / "temp.tif") filename = str(tmp_path / "temp.tif")
im = hopper(mode) im = hopper(mode)
im.save(filename, tiffinfo={262: 0}) im.save(filename, tiffinfo={262: 0})
@ -518,13 +519,13 @@ class TestFileTiff:
assert reloaded.tag_v2[262] == 0 assert reloaded.tag_v2[262] == 0
assert_image_equal(im, reloaded) assert_image_equal(im, reloaded)
def test_seek(self): def test_seek(self) -> None:
filename = "Tests/images/pil136.tiff" filename = "Tests/images/pil136.tiff"
with Image.open(filename) as im: with Image.open(filename) as im:
im.seek(0) im.seek(0)
assert im.tell() == 0 assert im.tell() == 0
def test_seek_eof(self): def test_seek_eof(self) -> None:
filename = "Tests/images/pil136.tiff" filename = "Tests/images/pil136.tiff"
with Image.open(filename) as im: with Image.open(filename) as im:
assert im.tell() == 0 assert im.tell() == 0
@ -533,21 +534,21 @@ class TestFileTiff:
with pytest.raises(EOFError): with pytest.raises(EOFError):
im.seek(1) im.seek(1)
def test__limit_rational_int(self): def test__limit_rational_int(self) -> None:
from PIL.TiffImagePlugin import _limit_rational from PIL.TiffImagePlugin import _limit_rational
value = 34 value = 34
ret = _limit_rational(value, 65536) ret = _limit_rational(value, 65536)
assert ret == (34, 1) assert ret == (34, 1)
def test__limit_rational_float(self): def test__limit_rational_float(self) -> None:
from PIL.TiffImagePlugin import _limit_rational from PIL.TiffImagePlugin import _limit_rational
value = 22.3 value = 22.3
ret = _limit_rational(value, 65536) ret = _limit_rational(value, 65536)
assert ret == (223, 10) assert ret == (223, 10)
def test_4bit(self): def test_4bit(self) -> None:
test_file = "Tests/images/hopper_gray_4bpp.tif" test_file = "Tests/images/hopper_gray_4bpp.tif"
original = hopper("L") original = hopper("L")
with Image.open(test_file) as im: with Image.open(test_file) as im:
@ -555,7 +556,7 @@ class TestFileTiff:
assert im.mode == "L" assert im.mode == "L"
assert_image_similar(im, original, 7.3) assert_image_similar(im, original, 7.3)
def test_gray_semibyte_per_pixel(self): def test_gray_semibyte_per_pixel(self) -> None:
test_files = ( test_files = (
( (
24.8, # epsilon 24.8, # epsilon
@ -588,7 +589,7 @@ class TestFileTiff:
assert im2.mode == "L" assert im2.mode == "L"
assert_image_equal(im, im2) assert_image_equal(im, im2)
def test_with_underscores(self, tmp_path): def test_with_underscores(self, tmp_path: Path) -> None:
kwargs = {"resolution_unit": "inch", "x_resolution": 72, "y_resolution": 36} kwargs = {"resolution_unit": "inch", "x_resolution": 72, "y_resolution": 36}
filename = str(tmp_path / "temp.tif") filename = str(tmp_path / "temp.tif")
hopper("RGB").save(filename, **kwargs) hopper("RGB").save(filename, **kwargs)
@ -601,7 +602,7 @@ class TestFileTiff:
assert im.tag_v2[X_RESOLUTION] == 72 assert im.tag_v2[X_RESOLUTION] == 72
assert im.tag_v2[Y_RESOLUTION] == 36 assert im.tag_v2[Y_RESOLUTION] == 36
def test_roundtrip_tiff_uint16(self, tmp_path): def test_roundtrip_tiff_uint16(self, tmp_path: Path) -> None:
# Test an image of all '0' values # Test an image of all '0' values
pixel_value = 0x1234 pixel_value = 0x1234
infile = "Tests/images/uint16_1_4660.tif" infile = "Tests/images/uint16_1_4660.tif"
@ -613,7 +614,7 @@ class TestFileTiff:
assert_image_equal_tofile(im, tmpfile) assert_image_equal_tofile(im, tmpfile)
def test_rowsperstrip(self, tmp_path): def test_rowsperstrip(self, tmp_path: Path) -> None:
outfile = str(tmp_path / "temp.tif") outfile = str(tmp_path / "temp.tif")
im = hopper() im = hopper()
im.save(outfile, tiffinfo={278: 256}) im.save(outfile, tiffinfo={278: 256})
@ -621,25 +622,25 @@ class TestFileTiff:
with Image.open(outfile) as im: with Image.open(outfile) as im:
assert im.tag_v2[278] == 256 assert im.tag_v2[278] == 256
def test_strip_raw(self): def test_strip_raw(self) -> None:
infile = "Tests/images/tiff_strip_raw.tif" infile = "Tests/images/tiff_strip_raw.tif"
with Image.open(infile) as im: with Image.open(infile) as im:
assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png") assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png")
def test_strip_planar_raw(self): def test_strip_planar_raw(self) -> None:
# gdal_translate -of GTiff -co INTERLEAVE=BAND \ # gdal_translate -of GTiff -co INTERLEAVE=BAND \
# tiff_strip_raw.tif tiff_strip_planar_raw.tiff # tiff_strip_raw.tif tiff_strip_planar_raw.tiff
infile = "Tests/images/tiff_strip_planar_raw.tif" infile = "Tests/images/tiff_strip_planar_raw.tif"
with Image.open(infile) as im: with Image.open(infile) as im:
assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png") assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png")
def test_strip_planar_raw_with_overviews(self): def test_strip_planar_raw_with_overviews(self) -> None:
# gdaladdo tiff_strip_planar_raw2.tif 2 4 8 16 # gdaladdo tiff_strip_planar_raw2.tif 2 4 8 16
infile = "Tests/images/tiff_strip_planar_raw_with_overviews.tif" infile = "Tests/images/tiff_strip_planar_raw_with_overviews.tif"
with Image.open(infile) as im: with Image.open(infile) as im:
assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png") assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png")
def test_tiled_planar_raw(self): def test_tiled_planar_raw(self) -> None:
# gdal_translate -of GTiff -co TILED=YES -co BLOCKXSIZE=32 \ # gdal_translate -of GTiff -co TILED=YES -co BLOCKXSIZE=32 \
# -co BLOCKYSIZE=32 -co INTERLEAVE=BAND \ # -co BLOCKYSIZE=32 -co INTERLEAVE=BAND \
# tiff_tiled_raw.tif tiff_tiled_planar_raw.tiff # tiff_tiled_raw.tif tiff_tiled_planar_raw.tiff
@ -647,7 +648,7 @@ class TestFileTiff:
with Image.open(infile) as im: with Image.open(infile) as im:
assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png") assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png")
def test_planar_configuration_save(self, tmp_path): def test_planar_configuration_save(self, tmp_path: Path) -> None:
infile = "Tests/images/tiff_tiled_planar_raw.tif" infile = "Tests/images/tiff_tiled_planar_raw.tif"
with Image.open(infile) as im: with Image.open(infile) as im:
assert im._planar_configuration == 2 assert im._planar_configuration == 2
@ -659,7 +660,7 @@ class TestFileTiff:
assert_image_equal_tofile(reloaded, infile) assert_image_equal_tofile(reloaded, infile)
@pytest.mark.parametrize("mode", ("P", "PA")) @pytest.mark.parametrize("mode", ("P", "PA"))
def test_palette(self, mode, tmp_path): def test_palette(self, mode, tmp_path: Path) -> None:
outfile = str(tmp_path / "temp.tif") outfile = str(tmp_path / "temp.tif")
im = hopper(mode) im = hopper(mode)
@ -668,7 +669,7 @@ class TestFileTiff:
with Image.open(outfile) as reloaded: with Image.open(outfile) as reloaded:
assert_image_equal(im.convert("RGB"), reloaded.convert("RGB")) assert_image_equal(im.convert("RGB"), reloaded.convert("RGB"))
def test_tiff_save_all(self): def test_tiff_save_all(self) -> None:
mp = BytesIO() mp = BytesIO()
with Image.open("Tests/images/multipage.tiff") as im: with Image.open("Tests/images/multipage.tiff") as im:
im.save(mp, format="tiff", save_all=True) im.save(mp, format="tiff", save_all=True)
@ -698,7 +699,7 @@ class TestFileTiff:
with Image.open(mp) as reread: with Image.open(mp) as reread:
assert reread.n_frames == 3 assert reread.n_frames == 3
def test_saving_icc_profile(self, tmp_path): def test_saving_icc_profile(self, tmp_path: Path) -> None:
# Tests saving TIFF with icc_profile set. # Tests saving TIFF with icc_profile set.
# At the time of writing this will only work for non-compressed tiffs # At the time of writing this will only work for non-compressed tiffs
# as libtiff does not support embedded ICC profiles, # as libtiff does not support embedded ICC profiles,
@ -712,7 +713,7 @@ class TestFileTiff:
with Image.open(tmpfile) as reloaded: with Image.open(tmpfile) as reloaded:
assert b"Dummy value" == reloaded.info["icc_profile"] assert b"Dummy value" == reloaded.info["icc_profile"]
def test_save_icc_profile(self, tmp_path): def test_save_icc_profile(self, tmp_path: Path) -> None:
im = hopper() im = hopper()
assert "icc_profile" not in im.info assert "icc_profile" not in im.info
@ -723,14 +724,14 @@ class TestFileTiff:
with Image.open(outfile) as reloaded: with Image.open(outfile) as reloaded:
assert reloaded.info["icc_profile"] == icc_profile assert reloaded.info["icc_profile"] == icc_profile
def test_save_bmp_compression(self, tmp_path): def test_save_bmp_compression(self, tmp_path: Path) -> None:
with Image.open("Tests/images/hopper.bmp") as im: with Image.open("Tests/images/hopper.bmp") as im:
assert im.info["compression"] == 0 assert im.info["compression"] == 0
outfile = str(tmp_path / "temp.tif") outfile = str(tmp_path / "temp.tif")
im.save(outfile) im.save(outfile)
def test_discard_icc_profile(self, tmp_path): def test_discard_icc_profile(self, tmp_path: Path) -> None:
outfile = str(tmp_path / "temp.tif") outfile = str(tmp_path / "temp.tif")
with Image.open("Tests/images/icc_profile.png") as im: with Image.open("Tests/images/icc_profile.png") as im:
@ -741,7 +742,7 @@ class TestFileTiff:
with Image.open(outfile) as reloaded: with Image.open(outfile) as reloaded:
assert "icc_profile" not in reloaded.info assert "icc_profile" not in reloaded.info
def test_getxmp(self): def test_getxmp(self) -> None:
with Image.open("Tests/images/lab.tif") as im: with Image.open("Tests/images/lab.tif") as im:
if ElementTree is None: if ElementTree is None:
with pytest.warns( with pytest.warns(
@ -756,7 +757,7 @@ class TestFileTiff:
assert description[0]["format"] == "image/tiff" assert description[0]["format"] == "image/tiff"
assert description[3]["BitsPerSample"]["Seq"]["li"] == ["8", "8", "8"] assert description[3]["BitsPerSample"]["Seq"]["li"] == ["8", "8", "8"]
def test_get_photoshop_blocks(self): def test_get_photoshop_blocks(self) -> None:
with Image.open("Tests/images/lab.tif") as im: with Image.open("Tests/images/lab.tif") as im:
assert list(im.get_photoshop_blocks().keys()) == [ assert list(im.get_photoshop_blocks().keys()) == [
1061, 1061,
@ -782,7 +783,7 @@ class TestFileTiff:
4001, 4001,
] ]
def test_tiff_chunks(self, tmp_path): def test_tiff_chunks(self, tmp_path: Path) -> None:
tmpfile = str(tmp_path / "temp.tif") tmpfile = str(tmp_path / "temp.tif")
im = hopper() im = hopper()
@ -803,7 +804,7 @@ class TestFileTiff:
assert_image_equal_tofile(im, tmpfile) assert_image_equal_tofile(im, tmpfile)
def test_close_on_load_exclusive(self, tmp_path): def test_close_on_load_exclusive(self, tmp_path: Path) -> None:
# similar to test_fd_leak, but runs on unixlike os # similar to test_fd_leak, but runs on unixlike os
tmpfile = str(tmp_path / "temp.tif") tmpfile = str(tmp_path / "temp.tif")
@ -816,7 +817,7 @@ class TestFileTiff:
im.load() im.load()
assert fp.closed assert fp.closed
def test_close_on_load_nonexclusive(self, tmp_path): def test_close_on_load_nonexclusive(self, tmp_path: Path) -> None:
tmpfile = str(tmp_path / "temp.tif") tmpfile = str(tmp_path / "temp.tif")
with Image.open("Tests/images/uint16_1_4660.tif") as im: with Image.open("Tests/images/uint16_1_4660.tif") as im:
@ -838,7 +839,7 @@ class TestFileTiff:
not os.path.exists("Tests/images/string_dimension.tiff"), not os.path.exists("Tests/images/string_dimension.tiff"),
reason="Extra image files not installed", reason="Extra image files not installed",
) )
def test_string_dimension(self): def test_string_dimension(self) -> None:
# Assert that an error is raised if one of the dimensions is a string # Assert that an error is raised if one of the dimensions is a string
with Image.open("Tests/images/string_dimension.tiff") as im: with Image.open("Tests/images/string_dimension.tiff") as im:
with pytest.raises(OSError): with pytest.raises(OSError):
@ -846,7 +847,7 @@ class TestFileTiff:
@pytest.mark.timeout(6) @pytest.mark.timeout(6)
@pytest.mark.filterwarnings("ignore:Truncated File Read") @pytest.mark.filterwarnings("ignore:Truncated File Read")
def test_timeout(self): def test_timeout(self) -> None:
with Image.open("Tests/images/timeout-6646305047838720") as im: with Image.open("Tests/images/timeout-6646305047838720") as im:
ImageFile.LOAD_TRUNCATED_IMAGES = True ImageFile.LOAD_TRUNCATED_IMAGES = True
im.load() im.load()
@ -859,7 +860,7 @@ class TestFileTiff:
], ],
) )
@pytest.mark.timeout(2) @pytest.mark.timeout(2)
def test_oom(self, test_file): def test_oom(self, test_file) -> None:
with pytest.raises(UnidentifiedImageError): with pytest.raises(UnidentifiedImageError):
with pytest.warns(UserWarning): with pytest.warns(UserWarning):
with Image.open(test_file): with Image.open(test_file):
@ -868,7 +869,7 @@ class TestFileTiff:
@pytest.mark.skipif(not is_win32(), reason="Windows only") @pytest.mark.skipif(not is_win32(), reason="Windows only")
class TestFileTiffW32: class TestFileTiffW32:
def test_fd_leak(self, tmp_path): def test_fd_leak(self, tmp_path: Path) -> None:
tmpfile = str(tmp_path / "temp.tif") tmpfile = str(tmp_path / "temp.tif")
# this is an mmaped file. # this is an mmaped file.

View File

@ -2,6 +2,7 @@ from __future__ import annotations
import io import io
import struct import struct
from pathlib import Path
import pytest import pytest
@ -13,7 +14,7 @@ from .helper import assert_deep_equal, hopper
TAG_IDS = {info.name: info.value for info in TiffTags.TAGS_V2.values()} TAG_IDS = {info.name: info.value for info in TiffTags.TAGS_V2.values()}
def test_rt_metadata(tmp_path): def test_rt_metadata(tmp_path: Path) -> None:
"""Test writing arbitrary metadata into the tiff image directory """Test writing arbitrary metadata into the tiff image directory
Use case is ImageJ private tags, one numeric, one arbitrary Use case is ImageJ private tags, one numeric, one arbitrary
data. https://github.com/python-pillow/Pillow/issues/291 data. https://github.com/python-pillow/Pillow/issues/291
@ -79,7 +80,7 @@ def test_rt_metadata(tmp_path):
assert loaded.tag_v2[ImageJMetaDataByteCounts] == (8, len(bin_data) - 8) assert loaded.tag_v2[ImageJMetaDataByteCounts] == (8, len(bin_data) - 8)
def test_read_metadata(): def test_read_metadata() -> None:
with Image.open("Tests/images/hopper_g4.tif") as img: with Image.open("Tests/images/hopper_g4.tif") as img:
assert { assert {
"YResolution": IFDRational(4294967295, 113653537), "YResolution": IFDRational(4294967295, 113653537),
@ -120,7 +121,7 @@ def test_read_metadata():
} == img.tag.named() } == img.tag.named()
def test_write_metadata(tmp_path): def test_write_metadata(tmp_path: Path) -> None:
"""Test metadata writing through the python code""" """Test metadata writing through the python code"""
with Image.open("Tests/images/hopper.tif") as img: with Image.open("Tests/images/hopper.tif") as img:
f = str(tmp_path / "temp.tiff") f = str(tmp_path / "temp.tiff")
@ -157,7 +158,7 @@ def test_write_metadata(tmp_path):
assert value == reloaded[tag], f"{tag} didn't roundtrip" assert value == reloaded[tag], f"{tag} didn't roundtrip"
def test_change_stripbytecounts_tag_type(tmp_path): def test_change_stripbytecounts_tag_type(tmp_path: Path) -> None:
out = str(tmp_path / "temp.tiff") out = str(tmp_path / "temp.tiff")
with Image.open("Tests/images/hopper.tif") as im: with Image.open("Tests/images/hopper.tif") as im:
info = im.tag_v2 info = im.tag_v2
@ -176,19 +177,19 @@ def test_change_stripbytecounts_tag_type(tmp_path):
assert reloaded.tag_v2.tagtype[TiffImagePlugin.STRIPBYTECOUNTS] == TiffTags.LONG assert reloaded.tag_v2.tagtype[TiffImagePlugin.STRIPBYTECOUNTS] == TiffTags.LONG
def test_no_duplicate_50741_tag(): def test_no_duplicate_50741_tag() -> None:
assert TAG_IDS["MakerNoteSafety"] == 50741 assert TAG_IDS["MakerNoteSafety"] == 50741
assert TAG_IDS["BestQualityScale"] == 50780 assert TAG_IDS["BestQualityScale"] == 50780
def test_iptc(tmp_path): def test_iptc(tmp_path: Path) -> None:
out = str(tmp_path / "temp.tiff") out = str(tmp_path / "temp.tiff")
with Image.open("Tests/images/hopper.Lab.tif") as im: with Image.open("Tests/images/hopper.Lab.tif") as im:
im.save(out) im.save(out)
@pytest.mark.parametrize("value, expected", ((b"test", "test"), (1, "1"))) @pytest.mark.parametrize("value, expected", ((b"test", "test"), (1, "1")))
def test_writing_other_types_to_ascii(value, expected, tmp_path): def test_writing_other_types_to_ascii(value, expected, tmp_path: Path) -> None:
info = TiffImagePlugin.ImageFileDirectory_v2() info = TiffImagePlugin.ImageFileDirectory_v2()
tag = TiffTags.TAGS_V2[271] tag = TiffTags.TAGS_V2[271]
@ -205,7 +206,7 @@ def test_writing_other_types_to_ascii(value, expected, tmp_path):
@pytest.mark.parametrize("value", (1, IFDRational(1))) @pytest.mark.parametrize("value", (1, IFDRational(1)))
def test_writing_other_types_to_bytes(value, tmp_path): def test_writing_other_types_to_bytes(value, tmp_path: Path) -> None:
im = hopper() im = hopper()
info = TiffImagePlugin.ImageFileDirectory_v2() info = TiffImagePlugin.ImageFileDirectory_v2()
@ -221,7 +222,7 @@ def test_writing_other_types_to_bytes(value, tmp_path):
assert reloaded.tag_v2[700] == b"\x01" assert reloaded.tag_v2[700] == b"\x01"
def test_writing_other_types_to_undefined(tmp_path): def test_writing_other_types_to_undefined(tmp_path: Path) -> None:
im = hopper() im = hopper()
info = TiffImagePlugin.ImageFileDirectory_v2() info = TiffImagePlugin.ImageFileDirectory_v2()
@ -237,7 +238,7 @@ def test_writing_other_types_to_undefined(tmp_path):
assert reloaded.tag_v2[33723] == b"1" assert reloaded.tag_v2[33723] == b"1"
def test_undefined_zero(tmp_path): def test_undefined_zero(tmp_path: Path) -> None:
# Check that the tag has not been changed since this test was created # Check that the tag has not been changed since this test was created
tag = TiffTags.TAGS_V2[45059] tag = TiffTags.TAGS_V2[45059]
assert tag.type == TiffTags.UNDEFINED assert tag.type == TiffTags.UNDEFINED
@ -252,7 +253,7 @@ def test_undefined_zero(tmp_path):
assert info[45059] == original assert info[45059] == original
def test_empty_metadata(): def test_empty_metadata() -> None:
f = io.BytesIO(b"II*\x00\x08\x00\x00\x00") f = io.BytesIO(b"II*\x00\x08\x00\x00\x00")
head = f.read(8) head = f.read(8)
info = TiffImagePlugin.ImageFileDirectory(head) info = TiffImagePlugin.ImageFileDirectory(head)
@ -261,7 +262,7 @@ def test_empty_metadata():
info.load(f) info.load(f)
def test_iccprofile(tmp_path): def test_iccprofile(tmp_path: Path) -> None:
# https://github.com/python-pillow/Pillow/issues/1462 # https://github.com/python-pillow/Pillow/issues/1462
out = str(tmp_path / "temp.tiff") out = str(tmp_path / "temp.tiff")
with Image.open("Tests/images/hopper.iccprofile.tif") as im: with Image.open("Tests/images/hopper.iccprofile.tif") as im:
@ -272,7 +273,7 @@ def test_iccprofile(tmp_path):
assert im.info["icc_profile"] == reloaded.info["icc_profile"] assert im.info["icc_profile"] == reloaded.info["icc_profile"]
def test_iccprofile_binary(): def test_iccprofile_binary() -> None:
# https://github.com/python-pillow/Pillow/issues/1526 # https://github.com/python-pillow/Pillow/issues/1526
# We should be able to load this, # We should be able to load this,
# but probably won't be able to save it. # but probably won't be able to save it.
@ -282,19 +283,19 @@ def test_iccprofile_binary():
assert im.info["icc_profile"] assert im.info["icc_profile"]
def test_iccprofile_save_png(tmp_path): def test_iccprofile_save_png(tmp_path: Path) -> None:
with Image.open("Tests/images/hopper.iccprofile.tif") as im: with Image.open("Tests/images/hopper.iccprofile.tif") as im:
outfile = str(tmp_path / "temp.png") outfile = str(tmp_path / "temp.png")
im.save(outfile) im.save(outfile)
def test_iccprofile_binary_save_png(tmp_path): def test_iccprofile_binary_save_png(tmp_path: Path) -> None:
with Image.open("Tests/images/hopper.iccprofile_binary.tif") as im: with Image.open("Tests/images/hopper.iccprofile_binary.tif") as im:
outfile = str(tmp_path / "temp.png") outfile = str(tmp_path / "temp.png")
im.save(outfile) im.save(outfile)
def test_exif_div_zero(tmp_path): def test_exif_div_zero(tmp_path: Path) -> None:
im = hopper() im = hopper()
info = TiffImagePlugin.ImageFileDirectory_v2() info = TiffImagePlugin.ImageFileDirectory_v2()
info[41988] = TiffImagePlugin.IFDRational(0, 0) info[41988] = TiffImagePlugin.IFDRational(0, 0)
@ -307,7 +308,7 @@ def test_exif_div_zero(tmp_path):
assert 0 == reloaded.tag_v2[41988].denominator assert 0 == reloaded.tag_v2[41988].denominator
def test_ifd_unsigned_rational(tmp_path): def test_ifd_unsigned_rational(tmp_path: Path) -> None:
im = hopper() im = hopper()
info = TiffImagePlugin.ImageFileDirectory_v2() info = TiffImagePlugin.ImageFileDirectory_v2()
@ -338,7 +339,7 @@ def test_ifd_unsigned_rational(tmp_path):
assert 1 == reloaded.tag_v2[41493].denominator assert 1 == reloaded.tag_v2[41493].denominator
def test_ifd_signed_rational(tmp_path): def test_ifd_signed_rational(tmp_path: Path) -> None:
im = hopper() im = hopper()
info = TiffImagePlugin.ImageFileDirectory_v2() info = TiffImagePlugin.ImageFileDirectory_v2()
@ -381,7 +382,7 @@ def test_ifd_signed_rational(tmp_path):
assert -1 == reloaded.tag_v2[37380].denominator assert -1 == reloaded.tag_v2[37380].denominator
def test_ifd_signed_long(tmp_path): def test_ifd_signed_long(tmp_path: Path) -> None:
im = hopper() im = hopper()
info = TiffImagePlugin.ImageFileDirectory_v2() info = TiffImagePlugin.ImageFileDirectory_v2()
@ -394,7 +395,7 @@ def test_ifd_signed_long(tmp_path):
assert reloaded.tag_v2[37000] == -60000 assert reloaded.tag_v2[37000] == -60000
def test_empty_values(): def test_empty_values() -> None:
data = io.BytesIO( data = io.BytesIO(
b"II*\x00\x08\x00\x00\x00\x03\x00\x1a\x01\x05\x00\x00\x00\x00\x00" b"II*\x00\x08\x00\x00\x00\x03\x00\x1a\x01\x05\x00\x00\x00\x00\x00"
b"\x00\x00\x00\x00\x1b\x01\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00" b"\x00\x00\x00\x00\x1b\x01\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00"
@ -409,7 +410,7 @@ def test_empty_values():
assert 33432 in info assert 33432 in info
def test_photoshop_info(tmp_path): def test_photoshop_info(tmp_path: Path) -> None:
with Image.open("Tests/images/issue_2278.tif") as im: with Image.open("Tests/images/issue_2278.tif") as im:
assert len(im.tag_v2[34377]) == 70 assert len(im.tag_v2[34377]) == 70
assert isinstance(im.tag_v2[34377], bytes) assert isinstance(im.tag_v2[34377], bytes)
@ -420,7 +421,7 @@ def test_photoshop_info(tmp_path):
assert isinstance(reloaded.tag_v2[34377], bytes) assert isinstance(reloaded.tag_v2[34377], bytes)
def test_too_many_entries(): def test_too_many_entries() -> None:
ifd = TiffImagePlugin.ImageFileDirectory_v2() ifd = TiffImagePlugin.ImageFileDirectory_v2()
# 277: ("SamplesPerPixel", SHORT, 1), # 277: ("SamplesPerPixel", SHORT, 1),
@ -432,7 +433,7 @@ def test_too_many_entries():
assert ifd[277] == 4 assert ifd[277] == 4
def test_tag_group_data(): def test_tag_group_data() -> None:
base_ifd = TiffImagePlugin.ImageFileDirectory_v2() base_ifd = TiffImagePlugin.ImageFileDirectory_v2()
interop_ifd = TiffImagePlugin.ImageFileDirectory_v2(group=40965) interop_ifd = TiffImagePlugin.ImageFileDirectory_v2(group=40965)
for ifd in (base_ifd, interop_ifd): for ifd in (base_ifd, interop_ifd):
@ -446,7 +447,7 @@ def test_tag_group_data():
assert base_ifd.tagtype[2] != interop_ifd.tagtype[256] assert base_ifd.tagtype[2] != interop_ifd.tagtype[256]
def test_empty_subifd(tmp_path): def test_empty_subifd(tmp_path: Path) -> None:
out = str(tmp_path / "temp.jpg") out = str(tmp_path / "temp.jpg")
im = hopper() im = hopper()

View File

@ -4,6 +4,7 @@ import io
import re import re
import sys import sys
import warnings import warnings
from pathlib import Path
import pytest import pytest
@ -26,7 +27,7 @@ except ImportError:
class TestUnsupportedWebp: class TestUnsupportedWebp:
def test_unsupported(self): def test_unsupported(self) -> None:
if HAVE_WEBP: if HAVE_WEBP:
WebPImagePlugin.SUPPORTED = False WebPImagePlugin.SUPPORTED = False
@ -42,15 +43,15 @@ class TestUnsupportedWebp:
@skip_unless_feature("webp") @skip_unless_feature("webp")
class TestFileWebp: class TestFileWebp:
def setup_method(self): def setup_method(self) -> None:
self.rgb_mode = "RGB" self.rgb_mode = "RGB"
def test_version(self): def test_version(self) -> None:
_webp.WebPDecoderVersion() _webp.WebPDecoderVersion()
_webp.WebPDecoderBuggyAlpha() _webp.WebPDecoderBuggyAlpha()
assert re.search(r"\d+\.\d+\.\d+$", features.version_module("webp")) assert re.search(r"\d+\.\d+\.\d+$", features.version_module("webp"))
def test_read_rgb(self): def test_read_rgb(self) -> None:
""" """
Can we read a RGB mode WebP file without error? Can we read a RGB mode WebP file without error?
Does it have the bits we expect? Does it have the bits we expect?
@ -67,7 +68,7 @@ class TestFileWebp:
# dwebp -ppm ../../Tests/images/hopper.webp -o hopper_webp_bits.ppm # dwebp -ppm ../../Tests/images/hopper.webp -o hopper_webp_bits.ppm
assert_image_similar_tofile(image, "Tests/images/hopper_webp_bits.ppm", 1.0) assert_image_similar_tofile(image, "Tests/images/hopper_webp_bits.ppm", 1.0)
def _roundtrip(self, tmp_path, mode, epsilon, args={}): def _roundtrip(self, tmp_path: Path, mode, epsilon, args={}) -> None:
temp_file = str(tmp_path / "temp.webp") temp_file = str(tmp_path / "temp.webp")
hopper(mode).save(temp_file, **args) hopper(mode).save(temp_file, **args)
@ -93,7 +94,7 @@ class TestFileWebp:
target = target.convert(self.rgb_mode) target = target.convert(self.rgb_mode)
assert_image_similar(image, target, epsilon) assert_image_similar(image, target, epsilon)
def test_write_rgb(self, tmp_path): def test_write_rgb(self, tmp_path: Path) -> None:
""" """
Can we write a RGB mode file to webp without error? Can we write a RGB mode file to webp without error?
Does it have the bits we expect? Does it have the bits we expect?
@ -101,7 +102,7 @@ class TestFileWebp:
self._roundtrip(tmp_path, self.rgb_mode, 12.5) self._roundtrip(tmp_path, self.rgb_mode, 12.5)
def test_write_method(self, tmp_path): def test_write_method(self, tmp_path: Path) -> None:
self._roundtrip(tmp_path, self.rgb_mode, 12.0, {"method": 6}) self._roundtrip(tmp_path, self.rgb_mode, 12.0, {"method": 6})
buffer_no_args = io.BytesIO() buffer_no_args = io.BytesIO()
@ -112,7 +113,7 @@ class TestFileWebp:
assert buffer_no_args.getbuffer() != buffer_method.getbuffer() assert buffer_no_args.getbuffer() != buffer_method.getbuffer()
@skip_unless_feature("webp_anim") @skip_unless_feature("webp_anim")
def test_save_all(self, tmp_path): def test_save_all(self, tmp_path: Path) -> None:
temp_file = str(tmp_path / "temp.webp") temp_file = str(tmp_path / "temp.webp")
im = Image.new("RGB", (1, 1)) im = Image.new("RGB", (1, 1))
im2 = Image.new("RGB", (1, 1), "#f00") im2 = Image.new("RGB", (1, 1), "#f00")
@ -124,14 +125,14 @@ class TestFileWebp:
reloaded.seek(1) reloaded.seek(1)
assert_image_similar(im2, reloaded, 1) assert_image_similar(im2, reloaded, 1)
def test_icc_profile(self, tmp_path): def test_icc_profile(self, tmp_path: Path) -> None:
self._roundtrip(tmp_path, self.rgb_mode, 12.5, {"icc_profile": None}) self._roundtrip(tmp_path, self.rgb_mode, 12.5, {"icc_profile": None})
if _webp.HAVE_WEBPANIM: if _webp.HAVE_WEBPANIM:
self._roundtrip( self._roundtrip(
tmp_path, self.rgb_mode, 12.5, {"icc_profile": None, "save_all": True} tmp_path, self.rgb_mode, 12.5, {"icc_profile": None, "save_all": True}
) )
def test_write_unsupported_mode_L(self, tmp_path): def test_write_unsupported_mode_L(self, tmp_path: Path) -> None:
""" """
Saving a black-and-white file to WebP format should work, and be Saving a black-and-white file to WebP format should work, and be
similar to the original file. similar to the original file.
@ -139,7 +140,7 @@ class TestFileWebp:
self._roundtrip(tmp_path, "L", 10.0) self._roundtrip(tmp_path, "L", 10.0)
def test_write_unsupported_mode_P(self, tmp_path): def test_write_unsupported_mode_P(self, tmp_path: Path) -> None:
""" """
Saving a palette-based file to WebP format should work, and be Saving a palette-based file to WebP format should work, and be
similar to the original file. similar to the original file.
@ -148,14 +149,14 @@ class TestFileWebp:
self._roundtrip(tmp_path, "P", 50.0) self._roundtrip(tmp_path, "P", 50.0)
@pytest.mark.skipif(sys.maxsize <= 2**32, reason="Requires 64-bit system") @pytest.mark.skipif(sys.maxsize <= 2**32, reason="Requires 64-bit system")
def test_write_encoding_error_message(self, tmp_path): def test_write_encoding_error_message(self, tmp_path: Path) -> None:
temp_file = str(tmp_path / "temp.webp") temp_file = str(tmp_path / "temp.webp")
im = Image.new("RGB", (15000, 15000)) im = Image.new("RGB", (15000, 15000))
with pytest.raises(ValueError) as e: with pytest.raises(ValueError) as e:
im.save(temp_file, method=0) im.save(temp_file, method=0)
assert str(e.value) == "encoding error 6" assert str(e.value) == "encoding error 6"
def test_WebPEncode_with_invalid_args(self): def test_WebPEncode_with_invalid_args(self) -> None:
""" """
Calling encoder functions with no arguments should result in an error. Calling encoder functions with no arguments should result in an error.
""" """
@ -166,7 +167,7 @@ class TestFileWebp:
with pytest.raises(TypeError): with pytest.raises(TypeError):
_webp.WebPEncode() _webp.WebPEncode()
def test_WebPDecode_with_invalid_args(self): def test_WebPDecode_with_invalid_args(self) -> None:
""" """
Calling decoder functions with no arguments should result in an error. Calling decoder functions with no arguments should result in an error.
""" """
@ -177,14 +178,14 @@ class TestFileWebp:
with pytest.raises(TypeError): with pytest.raises(TypeError):
_webp.WebPDecode() _webp.WebPDecode()
def test_no_resource_warning(self, tmp_path): def test_no_resource_warning(self, tmp_path: Path) -> None:
file_path = "Tests/images/hopper.webp" file_path = "Tests/images/hopper.webp"
with Image.open(file_path) as image: with Image.open(file_path) as image:
temp_file = str(tmp_path / "temp.webp") temp_file = str(tmp_path / "temp.webp")
with warnings.catch_warnings(): with warnings.catch_warnings():
image.save(temp_file) image.save(temp_file)
def test_file_pointer_could_be_reused(self): def test_file_pointer_could_be_reused(self) -> None:
file_path = "Tests/images/hopper.webp" file_path = "Tests/images/hopper.webp"
with open(file_path, "rb") as blob: with open(file_path, "rb") as blob:
Image.open(blob).load() Image.open(blob).load()
@ -195,14 +196,14 @@ class TestFileWebp:
(0, (0,), (-1, 0, 1, 2), (253, 254, 255, 256)), (0, (0,), (-1, 0, 1, 2), (253, 254, 255, 256)),
) )
@skip_unless_feature("webp_anim") @skip_unless_feature("webp_anim")
def test_invalid_background(self, background, tmp_path): def test_invalid_background(self, background, tmp_path: Path) -> None:
temp_file = str(tmp_path / "temp.webp") temp_file = str(tmp_path / "temp.webp")
im = hopper() im = hopper()
with pytest.raises(OSError): with pytest.raises(OSError):
im.save(temp_file, save_all=True, append_images=[im], background=background) im.save(temp_file, save_all=True, append_images=[im], background=background)
@skip_unless_feature("webp_anim") @skip_unless_feature("webp_anim")
def test_background_from_gif(self, tmp_path): def test_background_from_gif(self, tmp_path: Path) -> None:
# Save L mode GIF with background # Save L mode GIF with background
with Image.open("Tests/images/no_palette_with_background.gif") as im: with Image.open("Tests/images/no_palette_with_background.gif") as im:
out_webp = str(tmp_path / "temp.webp") out_webp = str(tmp_path / "temp.webp")
@ -227,7 +228,7 @@ class TestFileWebp:
assert difference < 5 assert difference < 5
@skip_unless_feature("webp_anim") @skip_unless_feature("webp_anim")
def test_duration(self, tmp_path): def test_duration(self, tmp_path: Path) -> None:
with Image.open("Tests/images/dispose_bgnd.gif") as im: with Image.open("Tests/images/dispose_bgnd.gif") as im:
assert im.info["duration"] == 1000 assert im.info["duration"] == 1000
@ -238,7 +239,7 @@ class TestFileWebp:
reloaded.load() reloaded.load()
assert reloaded.info["duration"] == 1000 assert reloaded.info["duration"] == 1000
def test_roundtrip_rgba_palette(self, tmp_path): def test_roundtrip_rgba_palette(self, tmp_path: Path) -> None:
temp_file = str(tmp_path / "temp.webp") temp_file = str(tmp_path / "temp.webp")
im = Image.new("RGBA", (1, 1)).convert("P") im = Image.new("RGBA", (1, 1)).convert("P")
assert im.mode == "P" assert im.mode == "P"

View File

@ -1,5 +1,7 @@
from __future__ import annotations from __future__ import annotations
from pathlib import Path
import pytest import pytest
from PIL import Image from PIL import Image
@ -14,12 +16,12 @@ from .helper import (
_webp = pytest.importorskip("PIL._webp", reason="WebP support not installed") _webp = pytest.importorskip("PIL._webp", reason="WebP support not installed")
def setup_module(): def setup_module() -> None:
if _webp.WebPDecoderBuggyAlpha(): if _webp.WebPDecoderBuggyAlpha():
pytest.skip("Buggy early version of WebP installed, not testing transparency") pytest.skip("Buggy early version of WebP installed, not testing transparency")
def test_read_rgba(): def test_read_rgba() -> None:
""" """
Can we read an RGBA mode file without error? Can we read an RGBA mode file without error?
Does it have the bits we expect? Does it have the bits we expect?
@ -39,7 +41,7 @@ def test_read_rgba():
assert_image_similar_tofile(image, "Tests/images/transparent.png", 20.0) assert_image_similar_tofile(image, "Tests/images/transparent.png", 20.0)
def test_write_lossless_rgb(tmp_path): def test_write_lossless_rgb(tmp_path: Path) -> None:
""" """
Can we write an RGBA mode file with lossless compression without error? Can we write an RGBA mode file with lossless compression without error?
Does it have the bits we expect? Does it have the bits we expect?
@ -68,7 +70,7 @@ def test_write_lossless_rgb(tmp_path):
assert_image_equal(image, pil_image) assert_image_equal(image, pil_image)
def test_write_rgba(tmp_path): def test_write_rgba(tmp_path: Path) -> None:
""" """
Can we write a RGBA mode file to WebP without error. Can we write a RGBA mode file to WebP without error.
Does it have the bits we expect? Does it have the bits we expect?
@ -99,7 +101,7 @@ def test_write_rgba(tmp_path):
assert_image_similar(image, pil_image, 1.0) assert_image_similar(image, pil_image, 1.0)
def test_keep_rgb_values_when_transparent(tmp_path): def test_keep_rgb_values_when_transparent(tmp_path: Path) -> None:
""" """
Saving transparent pixels should retain their original RGB values Saving transparent pixels should retain their original RGB values
when using the "exact" parameter. when using the "exact" parameter.
@ -128,7 +130,7 @@ def test_keep_rgb_values_when_transparent(tmp_path):
assert_image_equal(reloaded.convert("RGB"), image) assert_image_equal(reloaded.convert("RGB"), image)
def test_write_unsupported_mode_PA(tmp_path): def test_write_unsupported_mode_PA(tmp_path: Path) -> None:
""" """
Saving a palette-based file with transparency to WebP format Saving a palette-based file with transparency to WebP format
should work, and be similar to the original file. should work, and be similar to the original file.

View File

@ -1,5 +1,7 @@
from __future__ import annotations from __future__ import annotations
from pathlib import Path
import pytest import pytest
from packaging.version import parse as parse_version from packaging.version import parse as parse_version
@ -18,7 +20,7 @@ pytestmark = [
] ]
def test_n_frames(): def test_n_frames() -> None:
"""Ensure that WebP format sets n_frames and is_animated attributes correctly.""" """Ensure that WebP format sets n_frames and is_animated attributes correctly."""
with Image.open("Tests/images/hopper.webp") as im: with Image.open("Tests/images/hopper.webp") as im:
@ -30,7 +32,7 @@ def test_n_frames():
assert im.is_animated assert im.is_animated
def test_write_animation_L(tmp_path): def test_write_animation_L(tmp_path: Path) -> None:
""" """
Convert an animated GIF to animated WebP, then compare the frame count, and first Convert an animated GIF to animated WebP, then compare the frame count, and first
and last frames to ensure they're visually similar. and last frames to ensure they're visually similar.
@ -60,13 +62,13 @@ def test_write_animation_L(tmp_path):
assert_image_similar(im, orig.convert("RGBA"), 32.9) assert_image_similar(im, orig.convert("RGBA"), 32.9)
def test_write_animation_RGB(tmp_path): def test_write_animation_RGB(tmp_path: Path) -> None:
""" """
Write an animated WebP from RGB frames, and ensure the frames Write an animated WebP from RGB frames, and ensure the frames
are visually similar to the originals. are visually similar to the originals.
""" """
def check(temp_file): def check(temp_file) -> None:
with Image.open(temp_file) as im: with Image.open(temp_file) as im:
assert im.n_frames == 2 assert im.n_frames == 2
@ -105,7 +107,7 @@ def test_write_animation_RGB(tmp_path):
check(temp_file2) check(temp_file2)
def test_timestamp_and_duration(tmp_path): def test_timestamp_and_duration(tmp_path: Path) -> None:
""" """
Try passing a list of durations, and make sure the encoded Try passing a list of durations, and make sure the encoded
timestamps and durations are correct. timestamps and durations are correct.
@ -136,7 +138,7 @@ def test_timestamp_and_duration(tmp_path):
ts += durations[frame] ts += durations[frame]
def test_float_duration(tmp_path): def test_float_duration(tmp_path: Path) -> None:
temp_file = str(tmp_path / "temp.webp") temp_file = str(tmp_path / "temp.webp")
with Image.open("Tests/images/iss634.apng") as im: with Image.open("Tests/images/iss634.apng") as im:
assert im.info["duration"] == 70.0 assert im.info["duration"] == 70.0
@ -148,7 +150,7 @@ def test_float_duration(tmp_path):
assert reloaded.info["duration"] == 70 assert reloaded.info["duration"] == 70
def test_seeking(tmp_path): def test_seeking(tmp_path: Path) -> None:
""" """
Create an animated WebP file, and then try seeking through frames in reverse-order, Create an animated WebP file, and then try seeking through frames in reverse-order,
verifying the timestamps and durations are correct. verifying the timestamps and durations are correct.
@ -179,7 +181,7 @@ def test_seeking(tmp_path):
ts -= dur ts -= dur
def test_seek_errors(): def test_seek_errors() -> None:
with Image.open("Tests/images/iss634.webp") as im: with Image.open("Tests/images/iss634.webp") as im:
with pytest.raises(EOFError): with pytest.raises(EOFError):
im.seek(-1) im.seek(-1)

View File

@ -1,6 +1,7 @@
from __future__ import annotations from __future__ import annotations
from io import BytesIO from io import BytesIO
from pathlib import Path
import pytest import pytest
@ -19,7 +20,7 @@ except ImportError:
ElementTree = None ElementTree = None
def test_read_exif_metadata(): def test_read_exif_metadata() -> None:
file_path = "Tests/images/flower.webp" file_path = "Tests/images/flower.webp"
with Image.open(file_path) as image: with Image.open(file_path) as image:
assert image.format == "WEBP" assert image.format == "WEBP"
@ -37,7 +38,7 @@ def test_read_exif_metadata():
assert exif_data == expected_exif assert exif_data == expected_exif
def test_read_exif_metadata_without_prefix(): def test_read_exif_metadata_without_prefix() -> None:
with Image.open("Tests/images/flower2.webp") as im: with Image.open("Tests/images/flower2.webp") as im:
# Assert prefix is not present # Assert prefix is not present
assert im.info["exif"][:6] != b"Exif\x00\x00" assert im.info["exif"][:6] != b"Exif\x00\x00"
@ -49,7 +50,7 @@ def test_read_exif_metadata_without_prefix():
@mark_if_feature_version( @mark_if_feature_version(
pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing"
) )
def test_write_exif_metadata(): def test_write_exif_metadata() -> None:
file_path = "Tests/images/flower.jpg" file_path = "Tests/images/flower.jpg"
test_buffer = BytesIO() test_buffer = BytesIO()
with Image.open(file_path) as image: with Image.open(file_path) as image:
@ -63,7 +64,7 @@ def test_write_exif_metadata():
assert webp_exif == expected_exif[6:], "WebP EXIF didn't match" assert webp_exif == expected_exif[6:], "WebP EXIF didn't match"
def test_read_icc_profile(): def test_read_icc_profile() -> None:
file_path = "Tests/images/flower2.webp" file_path = "Tests/images/flower2.webp"
with Image.open(file_path) as image: with Image.open(file_path) as image:
assert image.format == "WEBP" assert image.format == "WEBP"
@ -80,7 +81,7 @@ def test_read_icc_profile():
@mark_if_feature_version( @mark_if_feature_version(
pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing"
) )
def test_write_icc_metadata(): def test_write_icc_metadata() -> None:
file_path = "Tests/images/flower2.jpg" file_path = "Tests/images/flower2.jpg"
test_buffer = BytesIO() test_buffer = BytesIO()
with Image.open(file_path) as image: with Image.open(file_path) as image:
@ -100,7 +101,7 @@ def test_write_icc_metadata():
@mark_if_feature_version( @mark_if_feature_version(
pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing"
) )
def test_read_no_exif(): def test_read_no_exif() -> None:
file_path = "Tests/images/flower.jpg" file_path = "Tests/images/flower.jpg"
test_buffer = BytesIO() test_buffer = BytesIO()
with Image.open(file_path) as image: with Image.open(file_path) as image:
@ -113,7 +114,7 @@ def test_read_no_exif():
assert not webp_image._getexif() assert not webp_image._getexif()
def test_getxmp(): def test_getxmp() -> None:
with Image.open("Tests/images/flower.webp") as im: with Image.open("Tests/images/flower.webp") as im:
assert "xmp" not in im.info assert "xmp" not in im.info
assert im.getxmp() == {} assert im.getxmp() == {}
@ -133,7 +134,7 @@ def test_getxmp():
@skip_unless_feature("webp_anim") @skip_unless_feature("webp_anim")
def test_write_animated_metadata(tmp_path): def test_write_animated_metadata(tmp_path: Path) -> None:
iccp_data = b"<iccp_data>" iccp_data = b"<iccp_data>"
exif_data = b"<exif_data>" exif_data = b"<exif_data>"
xmp_data = b"<xmp_data>" xmp_data = b"<xmp_data>"

View File

@ -1,5 +1,7 @@
from __future__ import annotations from __future__ import annotations
from pathlib import Path
import pytest import pytest
from PIL import Image, WmfImagePlugin from PIL import Image, WmfImagePlugin
@ -7,7 +9,7 @@ from PIL import Image, WmfImagePlugin
from .helper import assert_image_similar_tofile, hopper from .helper import assert_image_similar_tofile, hopper
def test_load_raw(): def test_load_raw() -> None:
# Test basic EMF open and rendering # Test basic EMF open and rendering
with Image.open("Tests/images/drawing.emf") as im: with Image.open("Tests/images/drawing.emf") as im:
if hasattr(Image.core, "drawwmf"): if hasattr(Image.core, "drawwmf"):
@ -25,17 +27,17 @@ def test_load_raw():
assert_image_similar_tofile(im, "Tests/images/drawing_wmf_ref.png", 2.0) assert_image_similar_tofile(im, "Tests/images/drawing_wmf_ref.png", 2.0)
def test_load(): def test_load() -> None:
with Image.open("Tests/images/drawing.emf") as im: with Image.open("Tests/images/drawing.emf") as im:
if hasattr(Image.core, "drawwmf"): if hasattr(Image.core, "drawwmf"):
assert im.load()[0, 0] == (255, 255, 255) assert im.load()[0, 0] == (255, 255, 255)
def test_register_handler(tmp_path): def test_register_handler(tmp_path: Path) -> None:
class TestHandler: class TestHandler:
methodCalled = False methodCalled = False
def save(self, im, fp, filename): def save(self, im, fp, filename) -> None:
self.methodCalled = True self.methodCalled = True
handler = TestHandler() handler = TestHandler()
@ -51,12 +53,12 @@ def test_register_handler(tmp_path):
WmfImagePlugin.register_handler(original_handler) WmfImagePlugin.register_handler(original_handler)
def test_load_float_dpi(): def test_load_float_dpi() -> None:
with Image.open("Tests/images/drawing.emf") as im: with Image.open("Tests/images/drawing.emf") as im:
assert im.info["dpi"] == 1423.7668161434979 assert im.info["dpi"] == 1423.7668161434979
def test_load_set_dpi(): def test_load_set_dpi() -> None:
with Image.open("Tests/images/drawing.wmf") as im: with Image.open("Tests/images/drawing.wmf") as im:
assert im.size == (82, 82) assert im.size == (82, 82)
@ -68,7 +70,7 @@ def test_load_set_dpi():
@pytest.mark.parametrize("ext", (".wmf", ".emf")) @pytest.mark.parametrize("ext", (".wmf", ".emf"))
def test_save(ext, tmp_path): def test_save(ext, tmp_path: Path) -> None:
im = hopper() im = hopper()
tmpfile = str(tmp_path / ("temp" + ext)) tmpfile = str(tmp_path / ("temp" + ext))

View File

@ -1,6 +1,7 @@
from __future__ import annotations from __future__ import annotations
from io import BytesIO from io import BytesIO
from pathlib import Path
import pytest import pytest
@ -32,14 +33,14 @@ static char basic_bits[] = {
""" """
def test_pil151(): def test_pil151() -> None:
with Image.open(BytesIO(PIL151)) as im: with Image.open(BytesIO(PIL151)) as im:
im.load() im.load()
assert im.mode == "1" assert im.mode == "1"
assert im.size == (32, 32) assert im.size == (32, 32)
def test_open(): def test_open() -> None:
# Arrange # Arrange
# Created with `convert hopper.png hopper.xbm` # Created with `convert hopper.png hopper.xbm`
filename = "Tests/images/hopper.xbm" filename = "Tests/images/hopper.xbm"
@ -51,7 +52,7 @@ def test_open():
assert im.size == (128, 128) assert im.size == (128, 128)
def test_open_filename_with_underscore(): def test_open_filename_with_underscore() -> None:
# Arrange # Arrange
# Created with `convert hopper.png hopper_underscore.xbm` # Created with `convert hopper.png hopper_underscore.xbm`
filename = "Tests/images/hopper_underscore.xbm" filename = "Tests/images/hopper_underscore.xbm"
@ -63,14 +64,14 @@ def test_open_filename_with_underscore():
assert im.size == (128, 128) assert im.size == (128, 128)
def test_invalid_file(): def test_invalid_file() -> None:
invalid_file = "Tests/images/flower.jpg" invalid_file = "Tests/images/flower.jpg"
with pytest.raises(SyntaxError): with pytest.raises(SyntaxError):
XbmImagePlugin.XbmImageFile(invalid_file) XbmImagePlugin.XbmImageFile(invalid_file)
def test_save_wrong_mode(tmp_path): def test_save_wrong_mode(tmp_path: Path) -> None:
im = hopper() im = hopper()
out = str(tmp_path / "temp.xbm") out = str(tmp_path / "temp.xbm")
@ -78,7 +79,7 @@ def test_save_wrong_mode(tmp_path):
im.save(out) im.save(out)
def test_hotspot(tmp_path): def test_hotspot(tmp_path: Path) -> None:
im = hopper("1") im = hopper("1")
out = str(tmp_path / "temp.xbm") out = str(tmp_path / "temp.xbm")

View File

@ -21,7 +21,7 @@ def tuple_to_ints(tp):
return int(x * 255.0), int(y * 255.0), int(z * 255.0) return int(x * 255.0), int(y * 255.0), int(z * 255.0)
def test_sanity(): def test_sanity() -> None:
Image.new("HSV", (100, 100)) Image.new("HSV", (100, 100))
@ -78,7 +78,7 @@ def to_rgb_colorsys(im):
return to_xxx_colorsys(im, colorsys.hsv_to_rgb, "RGB") return to_xxx_colorsys(im, colorsys.hsv_to_rgb, "RGB")
def test_wedge(): def test_wedge() -> None:
src = wedge().resize((3 * 32, 32), Image.Resampling.BILINEAR) src = wedge().resize((3 * 32, 32), Image.Resampling.BILINEAR)
im = src.convert("HSV") im = src.convert("HSV")
comparable = to_hsv_colorsys(src) comparable = to_hsv_colorsys(src)
@ -110,7 +110,7 @@ def test_wedge():
) )
def test_convert(): def test_convert() -> None:
im = hopper("RGB").convert("HSV") im = hopper("RGB").convert("HSV")
comparable = to_hsv_colorsys(hopper("RGB")) comparable = to_hsv_colorsys(hopper("RGB"))
@ -128,7 +128,7 @@ def test_convert():
) )
def test_hsv_to_rgb(): def test_hsv_to_rgb() -> None:
comparable = to_hsv_colorsys(hopper("RGB")) comparable = to_hsv_colorsys(hopper("RGB"))
converted = comparable.convert("RGB") converted = comparable.convert("RGB")
comparable = to_rgb_colorsys(comparable) comparable = to_rgb_colorsys(comparable)

View File

@ -7,6 +7,7 @@ import shutil
import sys import sys
import tempfile import tempfile
import warnings import warnings
from pathlib import Path
import pytest import pytest
@ -60,19 +61,19 @@ class TestImage:
"HSV", "HSV",
), ),
) )
def test_image_modes_success(self, mode): def test_image_modes_success(self, mode) -> None:
Image.new(mode, (1, 1)) Image.new(mode, (1, 1))
@pytest.mark.parametrize("mode", ("", "bad", "very very long")) @pytest.mark.parametrize("mode", ("", "bad", "very very long"))
def test_image_modes_fail(self, mode): def test_image_modes_fail(self, mode) -> None:
with pytest.raises(ValueError) as e: with pytest.raises(ValueError) as e:
Image.new(mode, (1, 1)) Image.new(mode, (1, 1))
assert str(e.value) == "unrecognized image mode" assert str(e.value) == "unrecognized image mode"
def test_exception_inheritance(self): def test_exception_inheritance(self) -> None:
assert issubclass(UnidentifiedImageError, OSError) assert issubclass(UnidentifiedImageError, OSError)
def test_sanity(self): def test_sanity(self) -> None:
im = Image.new("L", (100, 100)) im = Image.new("L", (100, 100))
assert repr(im)[:45] == "<PIL.Image.Image image mode=L size=100x100 at" assert repr(im)[:45] == "<PIL.Image.Image image mode=L size=100x100 at"
assert im.mode == "L" assert im.mode == "L"
@ -97,9 +98,9 @@ class TestImage:
# with pytest.raises(MemoryError): # with pytest.raises(MemoryError):
# Image.new("L", (1000000, 1000000)) # Image.new("L", (1000000, 1000000))
def test_repr_pretty(self): def test_repr_pretty(self) -> None:
class Pretty: class Pretty:
def text(self, text): def text(self, text) -> None:
self.pretty_output = text self.pretty_output = text
im = Image.new("L", (100, 100)) im = Image.new("L", (100, 100))
@ -108,7 +109,7 @@ class TestImage:
im._repr_pretty_(p, None) im._repr_pretty_(p, None)
assert p.pretty_output == "<PIL.Image.Image image mode=L size=100x100>" assert p.pretty_output == "<PIL.Image.Image image mode=L size=100x100>"
def test_open_formats(self): def test_open_formats(self) -> None:
PNGFILE = "Tests/images/hopper.png" PNGFILE = "Tests/images/hopper.png"
JPGFILE = "Tests/images/hopper.jpg" JPGFILE = "Tests/images/hopper.jpg"
@ -130,7 +131,7 @@ class TestImage:
assert im.mode == "RGB" assert im.mode == "RGB"
assert im.size == (128, 128) assert im.size == (128, 128)
def test_width_height(self): def test_width_height(self) -> None:
im = Image.new("RGB", (1, 2)) im = Image.new("RGB", (1, 2))
assert im.width == 1 assert im.width == 1
assert im.height == 2 assert im.height == 2
@ -138,29 +139,29 @@ class TestImage:
with pytest.raises(AttributeError): with pytest.raises(AttributeError):
im.size = (3, 4) im.size = (3, 4)
def test_set_mode(self): def test_set_mode(self) -> None:
im = Image.new("RGB", (1, 1)) im = Image.new("RGB", (1, 1))
with pytest.raises(AttributeError): with pytest.raises(AttributeError):
im.mode = "P" im.mode = "P"
def test_invalid_image(self): def test_invalid_image(self) -> None:
im = io.BytesIO(b"") im = io.BytesIO(b"")
with pytest.raises(UnidentifiedImageError): with pytest.raises(UnidentifiedImageError):
with Image.open(im): with Image.open(im):
pass pass
def test_bad_mode(self): def test_bad_mode(self) -> None:
with pytest.raises(ValueError): with pytest.raises(ValueError):
with Image.open("filename", "bad mode"): with Image.open("filename", "bad mode"):
pass pass
def test_stringio(self): def test_stringio(self) -> None:
with pytest.raises(ValueError): with pytest.raises(ValueError):
with Image.open(io.StringIO()): with Image.open(io.StringIO()):
pass pass
def test_pathlib(self, tmp_path): def test_pathlib(self, tmp_path: Path) -> None:
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:
@ -179,11 +180,11 @@ class TestImage:
os.remove(temp_file) os.remove(temp_file)
im.save(Path(temp_file)) im.save(Path(temp_file))
def test_fp_name(self, tmp_path): def test_fp_name(self, tmp_path: Path) -> None:
temp_file = str(tmp_path / "temp.jpg") temp_file = str(tmp_path / "temp.jpg")
class FP: class FP:
def write(self, b): def write(self, b) -> None:
pass pass
fp = FP() fp = FP()
@ -192,7 +193,7 @@ class TestImage:
im = hopper() im = hopper()
im.save(fp) im.save(fp)
def test_tempfile(self): def test_tempfile(self) -> None:
# see #1460, pathlib support breaks tempfile.TemporaryFile on py27 # see #1460, pathlib support breaks tempfile.TemporaryFile on py27
# Will error out on save on 3.0.0 # Will error out on save on 3.0.0
im = hopper() im = hopper()
@ -201,13 +202,13 @@ class TestImage:
fp.seek(0) fp.seek(0)
assert_image_similar_tofile(im, fp, 20) assert_image_similar_tofile(im, fp, 20)
def test_unknown_extension(self, tmp_path): def test_unknown_extension(self, tmp_path: Path) -> None:
im = hopper() im = hopper()
temp_file = str(tmp_path / "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)
def test_internals(self): def test_internals(self) -> None:
im = Image.new("L", (100, 100)) im = Image.new("L", (100, 100))
im.readonly = 1 im.readonly = 1
im._copy() im._copy()
@ -222,7 +223,7 @@ class TestImage:
sys.platform == "cygwin", sys.platform == "cygwin",
reason="Test requires opening an mmaped file for writing", reason="Test requires opening an mmaped file for writing",
) )
def test_readonly_save(self, tmp_path): def test_readonly_save(self, tmp_path: Path) -> None:
temp_file = str(tmp_path / "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)
@ -230,7 +231,7 @@ class TestImage:
assert im.readonly assert im.readonly
im.save(temp_file) im.save(temp_file)
def test_dump(self, tmp_path): def test_dump(self, tmp_path: Path) -> None:
im = Image.new("L", (10, 10)) im = Image.new("L", (10, 10))
im._dump(str(tmp_path / "temp_L.ppm")) im._dump(str(tmp_path / "temp_L.ppm"))
@ -241,7 +242,7 @@ class TestImage:
with pytest.raises(ValueError): with pytest.raises(ValueError):
im._dump(str(tmp_path / "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) -> None:
# Arrange # Arrange
item = Image.new("RGB", (25, 25), "#000") item = Image.new("RGB", (25, 25), "#000")
num = 12 num = 12
@ -251,7 +252,7 @@ class TestImage:
assert item is not None assert item is not None
assert item != num assert item != num
def test_expand_x(self): def test_expand_x(self) -> None:
# Arrange # Arrange
im = hopper() im = hopper()
orig_size = im.size orig_size = im.size
@ -264,7 +265,7 @@ class TestImage:
assert im.size[0] == orig_size[0] + 2 * xmargin assert im.size[0] == orig_size[0] + 2 * xmargin
assert im.size[1] == orig_size[1] + 2 * xmargin assert im.size[1] == orig_size[1] + 2 * xmargin
def test_expand_xy(self): def test_expand_xy(self) -> None:
# Arrange # Arrange
im = hopper() im = hopper()
orig_size = im.size orig_size = im.size
@ -278,12 +279,12 @@ class TestImage:
assert im.size[0] == orig_size[0] + 2 * xmargin assert im.size[0] == orig_size[0] + 2 * xmargin
assert im.size[1] == orig_size[1] + 2 * ymargin assert im.size[1] == orig_size[1] + 2 * ymargin
def test_getbands(self): def test_getbands(self) -> None:
# Assert # Assert
assert hopper("RGB").getbands() == ("R", "G", "B") assert hopper("RGB").getbands() == ("R", "G", "B")
assert hopper("YCbCr").getbands() == ("Y", "Cb", "Cr") assert hopper("YCbCr").getbands() == ("Y", "Cb", "Cr")
def test_getchannel_wrong_params(self): def test_getchannel_wrong_params(self) -> None:
im = hopper() im = hopper()
with pytest.raises(ValueError): with pytest.raises(ValueError):
@ -295,7 +296,7 @@ class TestImage:
with pytest.raises(ValueError): with pytest.raises(ValueError):
im.getchannel("1") im.getchannel("1")
def test_getchannel(self): def test_getchannel(self) -> None:
im = hopper("YCbCr") im = hopper("YCbCr")
Y, Cb, Cr = im.split() Y, Cb, Cr = im.split()
@ -306,7 +307,7 @@ class TestImage:
assert_image_equal(Cr, im.getchannel(2)) assert_image_equal(Cr, im.getchannel(2))
assert_image_equal(Cr, im.getchannel("Cr")) assert_image_equal(Cr, im.getchannel("Cr"))
def test_getbbox(self): def test_getbbox(self) -> None:
# Arrange # Arrange
im = hopper() im = hopper()
@ -316,7 +317,7 @@ class TestImage:
# Assert # Assert
assert bbox == (0, 0, 128, 128) assert bbox == (0, 0, 128, 128)
def test_ne(self): def test_ne(self) -> None:
# Arrange # Arrange
im1 = Image.new("RGB", (25, 25), "black") im1 = Image.new("RGB", (25, 25), "black")
im2 = Image.new("RGB", (25, 25), "white") im2 = Image.new("RGB", (25, 25), "white")
@ -324,7 +325,7 @@ class TestImage:
# Act / Assert # Act / Assert
assert im1 != im2 assert im1 != im2
def test_alpha_composite(self): def test_alpha_composite(self) -> None:
# https://stackoverflow.com/questions/3374878 # https://stackoverflow.com/questions/3374878
# Arrange # Arrange
expected_colors = sorted( expected_colors = sorted(
@ -355,7 +356,7 @@ class TestImage:
img_colors = sorted(img.getcolors()) img_colors = sorted(img.getcolors())
assert img_colors == expected_colors assert img_colors == expected_colors
def test_alpha_inplace(self): def test_alpha_inplace(self) -> None:
src = Image.new("RGBA", (128, 128), "blue") src = Image.new("RGBA", (128, 128), "blue")
over = Image.new("RGBA", (128, 128), "red") over = Image.new("RGBA", (128, 128), "red")
@ -407,7 +408,7 @@ class TestImage:
with pytest.raises(ValueError): with pytest.raises(ValueError):
source.alpha_composite(over, (0, 0), (0, -1)) source.alpha_composite(over, (0, 0), (0, -1))
def test_register_open_duplicates(self): def test_register_open_duplicates(self) -> None:
# Arrange # Arrange
factory, accept = Image.OPEN["JPEG"] factory, accept = Image.OPEN["JPEG"]
id_length = len(Image.ID) id_length = len(Image.ID)
@ -418,7 +419,7 @@ class TestImage:
# Assert # Assert
assert len(Image.ID) == id_length assert len(Image.ID) == id_length
def test_registered_extensions_uninitialized(self): def test_registered_extensions_uninitialized(self) -> None:
# Arrange # Arrange
Image._initialized = 0 Image._initialized = 0
@ -428,7 +429,7 @@ class TestImage:
# Assert # Assert
assert Image._initialized == 2 assert Image._initialized == 2
def test_registered_extensions(self): def test_registered_extensions(self) -> None:
# Arrange # Arrange
# Open an image to trigger plugin registration # Open an image to trigger plugin registration
with Image.open("Tests/images/rgb.jpg"): with Image.open("Tests/images/rgb.jpg"):
@ -442,7 +443,7 @@ class TestImage:
for ext in [".cur", ".icns", ".tif", ".tiff"]: for ext in [".cur", ".icns", ".tif", ".tiff"]:
assert ext in extensions assert ext in extensions
def test_effect_mandelbrot(self): def test_effect_mandelbrot(self) -> None:
# Arrange # Arrange
size = (512, 512) size = (512, 512)
extent = (-3, -2.5, 2, 2.5) extent = (-3, -2.5, 2, 2.5)
@ -455,7 +456,7 @@ class TestImage:
assert im.size == (512, 512) assert im.size == (512, 512)
assert_image_equal_tofile(im, "Tests/images/effect_mandelbrot.png") assert_image_equal_tofile(im, "Tests/images/effect_mandelbrot.png")
def test_effect_mandelbrot_bad_arguments(self): def test_effect_mandelbrot_bad_arguments(self) -> None:
# Arrange # Arrange
size = (512, 512) size = (512, 512)
# Get coordinates the wrong way round: # Get coordinates the wrong way round:
@ -467,7 +468,7 @@ class TestImage:
with pytest.raises(ValueError): with pytest.raises(ValueError):
Image.effect_mandelbrot(size, extent, quality) Image.effect_mandelbrot(size, extent, quality)
def test_effect_noise(self): def test_effect_noise(self) -> None:
# Arrange # Arrange
size = (100, 100) size = (100, 100)
sigma = 128 sigma = 128
@ -485,7 +486,7 @@ class TestImage:
p4 = im.getpixel((0, 4)) p4 = im.getpixel((0, 4))
assert_not_all_same([p0, p1, p2, p3, p4]) assert_not_all_same([p0, p1, p2, p3, p4])
def test_effect_spread(self): def test_effect_spread(self) -> None:
# Arrange # Arrange
im = hopper() im = hopper()
distance = 10 distance = 10
@ -497,7 +498,7 @@ class TestImage:
assert im.size == (128, 128) assert im.size == (128, 128)
assert_image_similar_tofile(im2, "Tests/images/effect_spread.png", 110) assert_image_similar_tofile(im2, "Tests/images/effect_spread.png", 110)
def test_effect_spread_zero(self): def test_effect_spread_zero(self) -> None:
# Arrange # Arrange
im = hopper() im = hopper()
distance = 0 distance = 0
@ -508,7 +509,7 @@ class TestImage:
# Assert # Assert
assert_image_equal(im, im2) assert_image_equal(im, im2)
def test_check_size(self): def test_check_size(self) -> None:
# Checking that the _check_size function throws value errors when we want it to # Checking that the _check_size function throws value errors 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
@ -537,10 +538,10 @@ class TestImage:
"PILLOW_VALGRIND_TEST" in os.environ, reason="Valgrind is slower" "PILLOW_VALGRIND_TEST" in os.environ, reason="Valgrind is slower"
) )
@pytest.mark.parametrize("size", ((0, 100000000), (100000000, 0))) @pytest.mark.parametrize("size", ((0, 100000000), (100000000, 0)))
def test_empty_image(self, size): def test_empty_image(self, size) -> None:
Image.new("RGB", size) Image.new("RGB", size)
def test_storage_neg(self): def test_storage_neg(self) -> None:
# Storage.c accepted negative values for xsize, ysize. Was # Storage.c accepted negative values for xsize, ysize. Was
# test_neg_ppm, but the core function for that has been # test_neg_ppm, but the core function for that has been
# removed Calling directly into core to test the error in # removed Calling directly into core to test the error in
@ -549,13 +550,13 @@ class TestImage:
with pytest.raises(ValueError): with pytest.raises(ValueError):
Image.core.fill("RGB", (2, -2), (0, 0, 0)) Image.core.fill("RGB", (2, -2), (0, 0, 0))
def test_one_item_tuple(self): def test_one_item_tuple(self) -> None:
for mode in ("I", "F", "L"): for mode in ("I", "F", "L"):
im = Image.new(mode, (100, 100), (5,)) im = Image.new(mode, (100, 100), (5,))
px = im.load() px = im.load()
assert px[0, 0] == 5 assert px[0, 0] == 5
def test_linear_gradient_wrong_mode(self): def test_linear_gradient_wrong_mode(self) -> None:
# Arrange # Arrange
wrong_mode = "RGB" wrong_mode = "RGB"
@ -564,7 +565,7 @@ class TestImage:
Image.linear_gradient(wrong_mode) Image.linear_gradient(wrong_mode)
@pytest.mark.parametrize("mode", ("L", "P", "I", "F")) @pytest.mark.parametrize("mode", ("L", "P", "I", "F"))
def test_linear_gradient(self, mode): def test_linear_gradient(self, mode) -> None:
# Arrange # Arrange
target_file = "Tests/images/linear_gradient.png" target_file = "Tests/images/linear_gradient.png"
@ -580,7 +581,7 @@ class TestImage:
target = target.convert(mode) target = target.convert(mode)
assert_image_equal(im, target) assert_image_equal(im, target)
def test_radial_gradient_wrong_mode(self): def test_radial_gradient_wrong_mode(self) -> None:
# Arrange # Arrange
wrong_mode = "RGB" wrong_mode = "RGB"
@ -589,7 +590,7 @@ class TestImage:
Image.radial_gradient(wrong_mode) Image.radial_gradient(wrong_mode)
@pytest.mark.parametrize("mode", ("L", "P", "I", "F")) @pytest.mark.parametrize("mode", ("L", "P", "I", "F"))
def test_radial_gradient(self, mode): def test_radial_gradient(self, mode) -> None:
# Arrange # Arrange
target_file = "Tests/images/radial_gradient.png" target_file = "Tests/images/radial_gradient.png"
@ -605,7 +606,7 @@ class TestImage:
target = target.convert(mode) target = target.convert(mode)
assert_image_equal(im, target) assert_image_equal(im, target)
def test_register_extensions(self): def test_register_extensions(self) -> None:
test_format = "a" test_format = "a"
exts = ["b", "c"] exts = ["b", "c"]
for ext in exts: for ext in exts:
@ -621,7 +622,7 @@ class TestImage:
assert ext_individual == ext_multiple assert ext_individual == ext_multiple
def test_remap_palette(self): def test_remap_palette(self) -> None:
# Test identity transform # Test identity transform
with Image.open("Tests/images/hopper.gif") as im: with Image.open("Tests/images/hopper.gif") as im:
assert_image_equal(im, im.remap_palette(list(range(256)))) assert_image_equal(im, im.remap_palette(list(range(256))))
@ -640,7 +641,7 @@ class TestImage:
with pytest.raises(ValueError): with pytest.raises(ValueError):
im.remap_palette(None) im.remap_palette(None)
def test_remap_palette_transparency(self): def test_remap_palette_transparency(self) -> None:
im = Image.new("P", (1, 2), (0, 0, 0)) im = Image.new("P", (1, 2), (0, 0, 0))
im.putpixel((0, 1), (255, 0, 0)) im.putpixel((0, 1), (255, 0, 0))
im.info["transparency"] = 0 im.info["transparency"] = 0
@ -655,7 +656,7 @@ class TestImage:
im_remapped = im.remap_palette([1, 0]) im_remapped = im.remap_palette([1, 0])
assert "transparency" not in im_remapped.info assert "transparency" not in im_remapped.info
def test__new(self): def test__new(self) -> None:
im = hopper("RGB") im = hopper("RGB")
im_p = hopper("P") im_p = hopper("P")
@ -664,7 +665,7 @@ class TestImage:
blank_p.palette = None blank_p.palette = None
blank_pa.palette = None blank_pa.palette = None
def _make_new(base_image, image, palette_result=None): def _make_new(base_image, image, palette_result=None) -> None:
new_image = base_image._new(image.im) new_image = base_image._new(image.im)
assert new_image.mode == image.mode assert new_image.mode == image.mode
assert new_image.size == image.size assert new_image.size == image.size
@ -679,7 +680,7 @@ class TestImage:
_make_new(im, blank_p, ImagePalette.ImagePalette()) _make_new(im, blank_p, ImagePalette.ImagePalette())
_make_new(im, blank_pa, ImagePalette.ImagePalette()) _make_new(im, blank_pa, ImagePalette.ImagePalette())
def test_p_from_rgb_rgba(self): def test_p_from_rgb_rgba(self) -> None:
for mode, color in [ for mode, color in [
("RGB", "#DDEEFF"), ("RGB", "#DDEEFF"),
("RGB", (221, 238, 255)), ("RGB", (221, 238, 255)),
@ -689,7 +690,7 @@ class TestImage:
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, tmp_path): def test_no_resource_warning_on_save(self, tmp_path: Path) -> None:
# 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"
@ -700,7 +701,7 @@ class TestImage:
with warnings.catch_warnings(): with warnings.catch_warnings():
im.save(temp_file) im.save(temp_file)
def test_no_new_file_on_error(self, tmp_path): def test_no_new_file_on_error(self, tmp_path: Path) -> None:
temp_file = str(tmp_path / "temp.jpg") temp_file = str(tmp_path / "temp.jpg")
im = Image.new("RGB", (0, 0)) im = Image.new("RGB", (0, 0))
@ -709,10 +710,10 @@ class TestImage:
assert not os.path.exists(temp_file) assert not os.path.exists(temp_file)
def test_load_on_nonexclusive_multiframe(self): def test_load_on_nonexclusive_multiframe(self) -> None:
with open("Tests/images/frozenpond.mpo", "rb") as fp: with open("Tests/images/frozenpond.mpo", "rb") as fp:
def act(fp): def act(fp) -> None:
im = Image.open(fp) im = Image.open(fp)
im.load() im.load()
@ -723,7 +724,7 @@ class TestImage:
assert not fp.closed assert not fp.closed
def test_empty_exif(self): def test_empty_exif(self) -> None:
with Image.open("Tests/images/exif.png") as im: with Image.open("Tests/images/exif.png") as im:
exif = im.getexif() exif = im.getexif()
assert dict(exif) assert dict(exif)
@ -739,7 +740,7 @@ class TestImage:
@mark_if_feature_version( @mark_if_feature_version(
pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing"
) )
def test_exif_jpeg(self, tmp_path): def test_exif_jpeg(self, tmp_path: Path) -> None:
with Image.open("Tests/images/exif-72dpi-int.jpg") as im: # Little endian with Image.open("Tests/images/exif-72dpi-int.jpg") as im: # Little endian
exif = im.getexif() exif = im.getexif()
assert 258 not in exif assert 258 not in exif
@ -785,7 +786,7 @@ class TestImage:
@skip_unless_feature("webp") @skip_unless_feature("webp")
@skip_unless_feature("webp_anim") @skip_unless_feature("webp_anim")
def test_exif_webp(self, tmp_path): def test_exif_webp(self, tmp_path: Path) -> None:
with Image.open("Tests/images/hopper.webp") as im: with Image.open("Tests/images/hopper.webp") as im:
exif = im.getexif() exif = im.getexif()
assert exif == {} assert exif == {}
@ -795,7 +796,7 @@ class TestImage:
exif[40963] = 455 exif[40963] = 455
exif[305] = "Pillow test" exif[305] = "Pillow test"
def check_exif(): def check_exif() -> None:
with Image.open(out) as reloaded: with Image.open(out) as reloaded:
reloaded_exif = reloaded.getexif() reloaded_exif = reloaded.getexif()
assert reloaded_exif[258] == 8 assert reloaded_exif[258] == 8
@ -807,7 +808,7 @@ class TestImage:
im.save(out, exif=exif, save_all=True) im.save(out, exif=exif, save_all=True)
check_exif() check_exif()
def test_exif_png(self, tmp_path): def test_exif_png(self, tmp_path: Path) -> None:
with Image.open("Tests/images/exif.png") as im: with Image.open("Tests/images/exif.png") as im:
exif = im.getexif() exif = im.getexif()
assert exif == {274: 1} assert exif == {274: 1}
@ -823,7 +824,7 @@ class TestImage:
reloaded_exif = reloaded.getexif() reloaded_exif = reloaded.getexif()
assert reloaded_exif == {258: 8, 40963: 455, 305: "Pillow test"} assert reloaded_exif == {258: 8, 40963: 455, 305: "Pillow test"}
def test_exif_interop(self): def test_exif_interop(self) -> None:
with Image.open("Tests/images/flower.jpg") as im: with Image.open("Tests/images/flower.jpg") as im:
exif = im.getexif() exif = im.getexif()
assert exif.get_ifd(0xA005) == { assert exif.get_ifd(0xA005) == {
@ -837,7 +838,7 @@ class TestImage:
reloaded_exif.load(exif.tobytes()) reloaded_exif.load(exif.tobytes())
assert reloaded_exif.get_ifd(0xA005) == exif.get_ifd(0xA005) assert reloaded_exif.get_ifd(0xA005) == exif.get_ifd(0xA005)
def test_exif_ifd1(self): def test_exif_ifd1(self) -> None:
with Image.open("Tests/images/flower.jpg") as im: with Image.open("Tests/images/flower.jpg") as im:
exif = im.getexif() exif = im.getexif()
assert exif.get_ifd(ExifTags.IFD.IFD1) == { assert exif.get_ifd(ExifTags.IFD.IFD1) == {
@ -849,7 +850,7 @@ class TestImage:
283: 180.0, 283: 180.0,
} }
def test_exif_ifd(self): def test_exif_ifd(self) -> None:
with Image.open("Tests/images/flower.jpg") as im: with Image.open("Tests/images/flower.jpg") as im:
exif = im.getexif() exif = im.getexif()
del exif.get_ifd(0x8769)[0xA005] del exif.get_ifd(0x8769)[0xA005]
@ -858,7 +859,7 @@ class TestImage:
reloaded_exif.load(exif.tobytes()) reloaded_exif.load(exif.tobytes())
assert reloaded_exif.get_ifd(0x8769) == exif.get_ifd(0x8769) assert reloaded_exif.get_ifd(0x8769) == exif.get_ifd(0x8769)
def test_exif_load_from_fp(self): def test_exif_load_from_fp(self) -> None:
with Image.open("Tests/images/flower.jpg") as im: with Image.open("Tests/images/flower.jpg") as im:
data = im.info["exif"] data = im.info["exif"]
if data.startswith(b"Exif\x00\x00"): if data.startswith(b"Exif\x00\x00"):
@ -879,7 +880,7 @@ class TestImage:
34665: 196, 34665: 196,
} }
def test_exif_hide_offsets(self): def test_exif_hide_offsets(self) -> None:
with Image.open("Tests/images/flower.jpg") as im: with Image.open("Tests/images/flower.jpg") as im:
exif = im.getexif() exif = im.getexif()
@ -905,18 +906,18 @@ class TestImage:
assert exif.get_ifd(0xA005) assert exif.get_ifd(0xA005)
@pytest.mark.parametrize("size", ((1, 0), (0, 1), (0, 0))) @pytest.mark.parametrize("size", ((1, 0), (0, 1), (0, 0)))
def test_zero_tobytes(self, size): def test_zero_tobytes(self, size) -> None:
im = Image.new("RGB", size) im = Image.new("RGB", size)
assert im.tobytes() == b"" assert im.tobytes() == b""
@pytest.mark.parametrize("size", ((1, 0), (0, 1), (0, 0))) @pytest.mark.parametrize("size", ((1, 0), (0, 1), (0, 0)))
def test_zero_frombytes(self, size): def test_zero_frombytes(self, size) -> None:
Image.frombytes("RGB", size, b"") Image.frombytes("RGB", size, b"")
im = Image.new("RGB", size) im = Image.new("RGB", size)
im.frombytes(b"") im.frombytes(b"")
def test_has_transparency_data(self): def test_has_transparency_data(self) -> None:
for mode in ("1", "L", "P", "RGB"): for mode in ("1", "L", "P", "RGB"):
im = Image.new(mode, (1, 1)) im = Image.new(mode, (1, 1))
assert not im.has_transparency_data assert not im.has_transparency_data
@ -941,7 +942,7 @@ class TestImage:
assert im.palette.mode == "RGBA" assert im.palette.mode == "RGBA"
assert im.has_transparency_data assert im.has_transparency_data
def test_apply_transparency(self): def test_apply_transparency(self) -> None:
im = Image.new("P", (1, 1)) im = Image.new("P", (1, 1))
im.putpalette((0, 0, 0, 1, 1, 1)) im.putpalette((0, 0, 0, 1, 1, 1))
assert im.palette.colors == {(0, 0, 0): 0, (1, 1, 1): 1} assert im.palette.colors == {(0, 0, 0): 0, (1, 1, 1): 1}
@ -970,7 +971,7 @@ class TestImage:
im.apply_transparency() im.apply_transparency()
assert im.palette.colors[(27, 35, 6, 214)] == 24 assert im.palette.colors[(27, 35, 6, 214)] == 24
def test_constants(self): def test_constants(self) -> None:
for enum in ( for enum in (
Image.Transpose, Image.Transpose,
Image.Transform, Image.Transform,
@ -995,7 +996,7 @@ class TestImage:
"01r_00.pcx", "01r_00.pcx",
], ],
) )
def test_overrun(self, path): def test_overrun(self, path) -> None:
"""For overrun completeness, test as: """For overrun completeness, test as:
valgrind pytest -qq Tests/test_image.py::TestImage::test_overrun | grep decode.c valgrind pytest -qq Tests/test_image.py::TestImage::test_overrun | grep decode.c
""" """
@ -1009,7 +1010,7 @@ class TestImage:
assert buffer_overrun or truncated assert buffer_overrun or truncated
def test_fli_overrun2(self): def test_fli_overrun2(self) -> None:
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)
@ -1017,12 +1018,12 @@ class TestImage:
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"
def test_exit_fp(self): def test_exit_fp(self) -> None:
with Image.new("L", (1, 1)) as im: with Image.new("L", (1, 1)) as im:
pass pass
assert not hasattr(im, "fp") assert not hasattr(im, "fp")
def test_close_graceful(self, caplog): def test_close_graceful(self, caplog) -> None:
with Image.open("Tests/images/hopper.jpg") as im: with Image.open("Tests/images/hopper.jpg") as im:
copy = im.copy() copy = im.copy()
with caplog.at_level(logging.DEBUG): with caplog.at_level(logging.DEBUG):
@ -1043,7 +1044,7 @@ def mock_encode(*args):
class TestRegistry: class TestRegistry:
def test_encode_registry(self): def test_encode_registry(self) -> None:
Image.register_encoder("MOCK", mock_encode) Image.register_encoder("MOCK", mock_encode)
assert "MOCK" in Image.ENCODERS assert "MOCK" in Image.ENCODERS
@ -1052,6 +1053,6 @@ class TestRegistry:
assert isinstance(enc, MockEncoder) assert isinstance(enc, MockEncoder)
assert enc.args == ("RGB", "args", "extra") assert enc.args == ("RGB", "args", "extra")
def test_encode_registry_fail(self): def test_encode_registry_fail(self) -> None:
with pytest.raises(OSError): with pytest.raises(OSError):
Image._getencoder("RGB", "DoesNotExist", ("args",), extra=("extra",)) Image._getencoder("RGB", "DoesNotExist", ("args",), extra=("extra",))

View File

@ -35,16 +35,16 @@ class AccessTest:
_need_cffi_access = False _need_cffi_access = False
@classmethod @classmethod
def setup_class(cls): def setup_class(cls) -> None:
Image.USE_CFFI_ACCESS = cls._need_cffi_access Image.USE_CFFI_ACCESS = cls._need_cffi_access
@classmethod @classmethod
def teardown_class(cls): def teardown_class(cls) -> None:
Image.USE_CFFI_ACCESS = cls._init_cffi_access Image.USE_CFFI_ACCESS = cls._init_cffi_access
class TestImagePutPixel(AccessTest): class TestImagePutPixel(AccessTest):
def test_sanity(self): def test_sanity(self) -> None:
im1 = hopper() im1 = hopper()
im2 = Image.new(im1.mode, im1.size, 0) im2 = Image.new(im1.mode, im1.size, 0)
@ -81,7 +81,7 @@ class TestImagePutPixel(AccessTest):
assert_image_equal(im1, im2) assert_image_equal(im1, im2)
def test_sanity_negative_index(self): def test_sanity_negative_index(self) -> None:
im1 = hopper() im1 = hopper()
im2 = Image.new(im1.mode, im1.size, 0) im2 = Image.new(im1.mode, im1.size, 0)
@ -119,7 +119,7 @@ class TestImagePutPixel(AccessTest):
assert_image_equal(im1, im2) assert_image_equal(im1, im2)
@pytest.mark.skipif(numpy is None, reason="NumPy not installed") @pytest.mark.skipif(numpy is None, reason="NumPy not installed")
def test_numpy(self): def test_numpy(self) -> None:
im = hopper() im = hopper()
pix = im.load() pix = im.load()
@ -138,7 +138,7 @@ class TestImageGetPixel(AccessTest):
return (16, 32, 49) return (16, 32, 49)
return tuple(range(1, bands + 1)) return tuple(range(1, bands + 1))
def check(self, mode, expected_color=None): def check(self, mode, expected_color=None) -> None:
if self._need_cffi_access and mode.startswith("BGR;"): if self._need_cffi_access and mode.startswith("BGR;"):
pytest.skip("Support not added to deprecated module for BGR;* modes") pytest.skip("Support not added to deprecated module for BGR;* modes")
@ -222,10 +222,10 @@ class TestImageGetPixel(AccessTest):
"YCbCr", "YCbCr",
), ),
) )
def test_basic(self, mode): def test_basic(self, mode) -> None:
self.check(mode) self.check(mode)
def test_list(self): def test_list(self) -> None:
im = hopper() im = hopper()
assert im.getpixel([0, 0]) == (20, 20, 70) assert im.getpixel([0, 0]) == (20, 20, 70)
@ -233,14 +233,14 @@ class TestImageGetPixel(AccessTest):
@pytest.mark.parametrize( @pytest.mark.parametrize(
"expected_color", (2**15 - 1, 2**15, 2**15 + 1, 2**16 - 1) "expected_color", (2**15 - 1, 2**15, 2**15 + 1, 2**16 - 1)
) )
def test_signedness(self, mode, expected_color): def test_signedness(self, mode, expected_color) -> None:
# see https://github.com/python-pillow/Pillow/issues/452 # see https://github.com/python-pillow/Pillow/issues/452
# pixelaccess is using signed int* instead of uint* # pixelaccess is using signed int* instead of uint*
self.check(mode, expected_color) self.check(mode, expected_color)
@pytest.mark.parametrize("mode", ("P", "PA")) @pytest.mark.parametrize("mode", ("P", "PA"))
@pytest.mark.parametrize("color", ((255, 0, 0), (255, 0, 0, 255))) @pytest.mark.parametrize("color", ((255, 0, 0), (255, 0, 0, 255)))
def test_p_putpixel_rgb_rgba(self, mode, color): def test_p_putpixel_rgb_rgba(self, mode, color) -> None:
im = Image.new(mode, (1, 1)) im = Image.new(mode, (1, 1))
im.putpixel((0, 0), color) im.putpixel((0, 0), color)
@ -264,7 +264,7 @@ class TestCffiGetPixel(TestImageGetPixel):
class TestCffi(AccessTest): class TestCffi(AccessTest):
_need_cffi_access = True _need_cffi_access = True
def _test_get_access(self, im): def _test_get_access(self, im) -> None:
"""Do we get the same thing as the old pixel access """Do we get the same thing as the old pixel access
Using private interfaces, forcing a capi access and Using private interfaces, forcing a capi access and
@ -282,7 +282,7 @@ class TestCffi(AccessTest):
with pytest.raises(ValueError): with pytest.raises(ValueError):
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) -> None:
with pytest.warns(DeprecationWarning): with pytest.warns(DeprecationWarning):
rgb = hopper("RGB") rgb = hopper("RGB")
rgb.load() rgb.load()
@ -301,7 +301,7 @@ class TestCffi(AccessTest):
# im = Image.new('I;32B', (10, 10), 2**10) # im = Image.new('I;32B', (10, 10), 2**10)
# self._test_get_access(im) # self._test_get_access(im)
def _test_set_access(self, im, color): def _test_set_access(self, im, color) -> None:
"""Are we writing the correct bits into the image? """Are we writing the correct bits into the image?
Using private interfaces, forcing a capi access and Using private interfaces, forcing a capi access and
@ -322,7 +322,7 @@ class TestCffi(AccessTest):
with pytest.raises(ValueError): with pytest.raises(ValueError):
access[(0, 0)] = color access[(0, 0)] = color
def test_set_vs_c(self): def test_set_vs_c(self) -> None:
rgb = hopper("RGB") rgb = hopper("RGB")
with pytest.warns(DeprecationWarning): with pytest.warns(DeprecationWarning):
rgb.load() rgb.load()
@ -345,11 +345,11 @@ class TestCffi(AccessTest):
# self._test_set_access(im, 2**13-1) # self._test_set_access(im, 2**13-1)
@pytest.mark.filterwarnings("ignore::DeprecationWarning") @pytest.mark.filterwarnings("ignore::DeprecationWarning")
def test_not_implemented(self): def test_not_implemented(self) -> None:
assert PyAccess.new(hopper("BGR;15")) is None assert PyAccess.new(hopper("BGR;15")) is None
# ref https://github.com/python-pillow/Pillow/pull/2009 # ref https://github.com/python-pillow/Pillow/pull/2009
def test_reference_counting(self): def test_reference_counting(self) -> None:
size = 10 size = 10
for _ in range(10): for _ in range(10):
@ -361,7 +361,7 @@ class TestCffi(AccessTest):
assert px[i, 0] == 0 assert px[i, 0] == 0
@pytest.mark.parametrize("mode", ("P", "PA")) @pytest.mark.parametrize("mode", ("P", "PA"))
def test_p_putpixel_rgb_rgba(self, mode): def test_p_putpixel_rgb_rgba(self, mode) -> None:
for color in ((255, 0, 0), (255, 0, 0, 127 if mode == "PA" else 255)): for color in ((255, 0, 0), (255, 0, 0, 127 if mode == "PA" else 255)):
im = Image.new(mode, (1, 1)) im = Image.new(mode, (1, 1))
with pytest.warns(DeprecationWarning): with pytest.warns(DeprecationWarning):
@ -379,7 +379,7 @@ class TestImagePutPixelError(AccessTest):
INVALID_TYPES = ["foo", 1.0, None] INVALID_TYPES = ["foo", 1.0, None]
@pytest.mark.parametrize("mode", IMAGE_MODES1) @pytest.mark.parametrize("mode", IMAGE_MODES1)
def test_putpixel_type_error1(self, mode): def test_putpixel_type_error1(self, mode) -> None:
im = hopper(mode) im = hopper(mode)
for v in self.INVALID_TYPES: for v in self.INVALID_TYPES:
with pytest.raises(TypeError, match="color must be int or tuple"): with pytest.raises(TypeError, match="color must be int or tuple"):
@ -402,14 +402,14 @@ class TestImagePutPixelError(AccessTest):
), ),
), ),
) )
def test_putpixel_invalid_number_of_bands(self, mode, band_numbers, match): def test_putpixel_invalid_number_of_bands(self, mode, band_numbers, match) -> None:
im = hopper(mode) im = hopper(mode)
for band_number in band_numbers: for band_number in band_numbers:
with pytest.raises(TypeError, match=match): with pytest.raises(TypeError, match=match):
im.putpixel((0, 0), (0,) * band_number) im.putpixel((0, 0), (0,) * band_number)
@pytest.mark.parametrize("mode", IMAGE_MODES2) @pytest.mark.parametrize("mode", IMAGE_MODES2)
def test_putpixel_type_error2(self, mode): def test_putpixel_type_error2(self, mode) -> None:
im = hopper(mode) im = hopper(mode)
for v in self.INVALID_TYPES: for v in self.INVALID_TYPES:
with pytest.raises( with pytest.raises(
@ -418,7 +418,7 @@ class TestImagePutPixelError(AccessTest):
im.putpixel((0, 0), v) im.putpixel((0, 0), v)
@pytest.mark.parametrize("mode", IMAGE_MODES1 + IMAGE_MODES2) @pytest.mark.parametrize("mode", IMAGE_MODES1 + IMAGE_MODES2)
def test_putpixel_overflow_error(self, mode): def test_putpixel_overflow_error(self, mode) -> None:
im = hopper(mode) im = hopper(mode)
with pytest.raises(OverflowError): with pytest.raises(OverflowError):
im.putpixel((0, 0), 2**80) im.putpixel((0, 0), 2**80)
@ -427,7 +427,7 @@ class TestImagePutPixelError(AccessTest):
class TestEmbeddable: class TestEmbeddable:
@pytest.mark.xfail(reason="failing test") @pytest.mark.xfail(reason="failing test")
@pytest.mark.skipif(not is_win32(), reason="requires Windows") @pytest.mark.skipif(not is_win32(), reason="requires Windows")
def test_embeddable(self): def test_embeddable(self) -> None:
import ctypes import ctypes
from setuptools.command.build_ext import new_compiler from setuptools.command.build_ext import new_compiler

View File

@ -12,12 +12,12 @@ numpy = pytest.importorskip("numpy", reason="NumPy not installed")
im = hopper().resize((128, 100)) im = hopper().resize((128, 100))
def test_toarray(): def test_toarray() -> None:
def test(mode): def test(mode):
ai = numpy.array(im.convert(mode)) ai = numpy.array(im.convert(mode))
return ai.shape, ai.dtype.str, ai.nbytes return ai.shape, ai.dtype.str, ai.nbytes
def test_with_dtype(dtype): def test_with_dtype(dtype) -> None:
ai = numpy.array(im, dtype=dtype) ai = numpy.array(im, dtype=dtype)
assert ai.dtype == dtype assert ai.dtype == dtype
@ -46,11 +46,11 @@ def test_toarray():
numpy.array(im_truncated) numpy.array(im_truncated)
def test_fromarray(): def test_fromarray() -> None:
class Wrapper: class Wrapper:
"""Class with API matching Image.fromarray""" """Class with API matching Image.fromarray"""
def __init__(self, img, arr_params): def __init__(self, img, arr_params) -> None:
self.img = img self.img = img
self.__array_interface__ = arr_params self.__array_interface__ = arr_params
@ -89,7 +89,7 @@ def test_fromarray():
Image.fromarray(wrapped) Image.fromarray(wrapped)
def test_fromarray_palette(): def test_fromarray_palette() -> None:
# Arrange # Arrange
i = im.convert("L") i = im.convert("L")
a = numpy.array(i) a = numpy.array(i)

View File

@ -19,7 +19,7 @@ def draft_roundtrip(in_mode, in_size, req_mode, req_size):
return im return im
def test_size(): def test_size() -> None:
for in_size, req_size, out_size in [ for in_size, req_size, out_size in [
((435, 361), (2048, 2048), (435, 361)), # bigger ((435, 361), (2048, 2048), (435, 361)), # bigger
((435, 361), (435, 361), (435, 361)), # same ((435, 361), (435, 361), (435, 361)), # same
@ -48,7 +48,7 @@ def test_size():
assert im.size == out_size assert im.size == out_size
def test_mode(): def test_mode() -> None:
for in_mode, req_mode, out_mode in [ for in_mode, req_mode, out_mode in [
("RGB", "1", "RGB"), ("RGB", "1", "RGB"),
("RGB", "L", "L"), ("RGB", "L", "L"),
@ -68,7 +68,7 @@ def test_mode():
assert im.mode == out_mode assert im.mode == out_mode
def test_several_drafts(): def test_several_drafts() -> None:
im = draft_roundtrip("L", (128, 128), None, (64, 64)) im = draft_roundtrip("L", (128, 128), None, (64, 64))
im.draft(None, (64, 64)) im.draft(None, (64, 64))
im.load() im.load()

View File

@ -3,7 +3,7 @@ from __future__ import annotations
from .helper import hopper from .helper import hopper
def test_entropy(): def test_entropy() -> None:
def entropy(mode): def entropy(mode):
return hopper(mode).entropy() return hopper(mode).entropy()

View File

@ -36,7 +36,7 @@ from .helper import assert_image_equal, hopper
), ),
) )
@pytest.mark.parametrize("mode", ("L", "I", "RGB", "CMYK")) @pytest.mark.parametrize("mode", ("L", "I", "RGB", "CMYK"))
def test_sanity(filter_to_apply, mode): def test_sanity(filter_to_apply, mode) -> None:
im = hopper(mode) im = hopper(mode)
if mode != "I" or isinstance(filter_to_apply, ImageFilter.BuiltinFilter): if mode != "I" or isinstance(filter_to_apply, ImageFilter.BuiltinFilter):
out = im.filter(filter_to_apply) out = im.filter(filter_to_apply)
@ -45,7 +45,7 @@ def test_sanity(filter_to_apply, mode):
@pytest.mark.parametrize("mode", ("L", "I", "RGB", "CMYK")) @pytest.mark.parametrize("mode", ("L", "I", "RGB", "CMYK"))
def test_sanity_error(mode): def test_sanity_error(mode) -> None:
with pytest.raises(TypeError): with pytest.raises(TypeError):
im = hopper(mode) im = hopper(mode)
im.filter("hello") im.filter("hello")
@ -53,7 +53,7 @@ def test_sanity_error(mode):
# crashes on small images # crashes on small images
@pytest.mark.parametrize("size", ((1, 1), (2, 2), (3, 3))) @pytest.mark.parametrize("size", ((1, 1), (2, 2), (3, 3)))
def test_crash(size): def test_crash(size) -> None:
im = Image.new("RGB", size) im = Image.new("RGB", size)
im.filter(ImageFilter.SMOOTH) im.filter(ImageFilter.SMOOTH)
@ -67,7 +67,7 @@ def test_crash(size):
("RGB", ((4, 0, 0), (0, 0, 0))), ("RGB", ((4, 0, 0), (0, 0, 0))),
), ),
) )
def test_modefilter(mode, expected): def test_modefilter(mode, expected) -> None:
im = Image.new(mode, (3, 3), None) im = Image.new(mode, (3, 3), None)
im.putdata(list(range(9))) im.putdata(list(range(9)))
# image is: # image is:
@ -90,7 +90,7 @@ def test_modefilter(mode, expected):
("F", (0.0, 4.0, 8.0)), ("F", (0.0, 4.0, 8.0)),
), ),
) )
def test_rankfilter(mode, expected): def test_rankfilter(mode, expected) -> None:
im = Image.new(mode, (3, 3), None) im = Image.new(mode, (3, 3), None)
im.putdata(list(range(9))) im.putdata(list(range(9)))
# image is: # image is:
@ -106,7 +106,7 @@ def test_rankfilter(mode, expected):
@pytest.mark.parametrize( @pytest.mark.parametrize(
"filter", (ImageFilter.MinFilter, ImageFilter.MedianFilter, ImageFilter.MaxFilter) "filter", (ImageFilter.MinFilter, ImageFilter.MedianFilter, ImageFilter.MaxFilter)
) )
def test_rankfilter_error(filter): def test_rankfilter_error(filter) -> None:
with pytest.raises(ValueError): with pytest.raises(ValueError):
im = Image.new("P", (3, 3), None) im = Image.new("P", (3, 3), None)
im.putdata(list(range(9))) im.putdata(list(range(9)))
@ -117,27 +117,27 @@ def test_rankfilter_error(filter):
im.filter(filter).getpixel((1, 1)) im.filter(filter).getpixel((1, 1))
def test_rankfilter_properties(): def test_rankfilter_properties() -> None:
rankfilter = ImageFilter.RankFilter(1, 2) rankfilter = ImageFilter.RankFilter(1, 2)
assert rankfilter.size == 1 assert rankfilter.size == 1
assert rankfilter.rank == 2 assert rankfilter.rank == 2
def test_builtinfilter_p(): def test_builtinfilter_p() -> None:
builtin_filter = ImageFilter.BuiltinFilter() builtin_filter = ImageFilter.BuiltinFilter()
with pytest.raises(ValueError): with pytest.raises(ValueError):
builtin_filter.filter(hopper("P")) builtin_filter.filter(hopper("P"))
def test_kernel_not_enough_coefficients(): def test_kernel_not_enough_coefficients() -> None:
with pytest.raises(ValueError): with pytest.raises(ValueError):
ImageFilter.Kernel((3, 3), (0, 0)) ImageFilter.Kernel((3, 3), (0, 0))
@pytest.mark.parametrize("mode", ("L", "LA", "I", "RGB", "CMYK")) @pytest.mark.parametrize("mode", ("L", "LA", "I", "RGB", "CMYK"))
def test_consistency_3x3(mode): def test_consistency_3x3(mode) -> None:
with Image.open("Tests/images/hopper.bmp") as source: with Image.open("Tests/images/hopper.bmp") as source:
reference_name = "hopper_emboss" reference_name = "hopper_emboss"
reference_name += "_I.png" if mode == "I" else ".bmp" reference_name += "_I.png" if mode == "I" else ".bmp"
@ -163,7 +163,7 @@ def test_consistency_3x3(mode):
@pytest.mark.parametrize("mode", ("L", "LA", "I", "RGB", "CMYK")) @pytest.mark.parametrize("mode", ("L", "LA", "I", "RGB", "CMYK"))
def test_consistency_5x5(mode): def test_consistency_5x5(mode) -> None:
with Image.open("Tests/images/hopper.bmp") as source: with Image.open("Tests/images/hopper.bmp") as source:
reference_name = "hopper_emboss_more" reference_name = "hopper_emboss_more"
reference_name += "_I.png" if mode == "I" else ".bmp" reference_name += "_I.png" if mode == "I" else ".bmp"
@ -199,7 +199,7 @@ def test_consistency_5x5(mode):
(2, -2), (2, -2),
), ),
) )
def test_invalid_box_blur_filter(radius): def test_invalid_box_blur_filter(radius) -> None:
with pytest.raises(ValueError): with pytest.raises(ValueError):
ImageFilter.BoxBlur(radius) ImageFilter.BoxBlur(radius)

View File

@ -5,7 +5,7 @@ from PIL import Image
from .helper import hopper from .helper import hopper
def test_extrema(): def test_extrema() -> None:
def extrema(mode): def extrema(mode):
return hopper(mode).getextrema() return hopper(mode).getextrema()
@ -20,7 +20,7 @@ def test_extrema():
assert extrema("I;16") == (1, 255) assert extrema("I;16") == (1, 255)
def test_true_16(): def test_true_16() -> None:
with Image.open("Tests/images/16_bit_noise.tif") as im: with Image.open("Tests/images/16_bit_noise.tif") as im:
assert im.mode == "I;16" assert im.mode == "I;16"
extrema = im.getextrema() extrema = im.getextrema()

View File

@ -5,7 +5,7 @@ from PIL import Image
from .helper import hopper from .helper import hopper
def test_palette(): def test_palette() -> None:
def palette(mode): def palette(mode):
p = hopper(mode).getpalette() p = hopper(mode).getpalette()
if p: if p:
@ -23,7 +23,7 @@ def test_palette():
assert palette("YCbCr") is None assert palette("YCbCr") is None
def test_palette_rawmode(): def test_palette_rawmode() -> None:
im = Image.new("P", (1, 1)) im = Image.new("P", (1, 1))
im.putpalette((1, 2, 3)) im.putpalette((1, 2, 3))

View File

@ -10,14 +10,14 @@ from PIL import Image
from .helper import hopper from .helper import hopper
def test_sanity(): def test_sanity() -> None:
im = hopper() im = hopper()
pix = im.load() pix = im.load()
assert pix[0, 0] == (20, 20, 70) assert pix[0, 0] == (20, 20, 70)
def test_close(): def test_close() -> None:
im = Image.open("Tests/images/hopper.gif") im = Image.open("Tests/images/hopper.gif")
im.close() im.close()
with pytest.raises(ValueError): with pytest.raises(ValueError):
@ -26,7 +26,7 @@ def test_close():
im.getpixel((0, 0)) im.getpixel((0, 0))
def test_close_after_load(caplog): def test_close_after_load(caplog) -> None:
im = Image.open("Tests/images/hopper.gif") im = Image.open("Tests/images/hopper.gif")
im.load() im.load()
with caplog.at_level(logging.DEBUG): with caplog.at_level(logging.DEBUG):
@ -34,7 +34,7 @@ def test_close_after_load(caplog):
assert len(caplog.records) == 0 assert len(caplog.records) == 0
def test_contextmanager(): def test_contextmanager() -> None:
fn = None fn = None
with Image.open("Tests/images/hopper.gif") as im: with Image.open("Tests/images/hopper.gif") as im:
fn = im.fp.fileno() fn = im.fp.fileno()
@ -44,7 +44,7 @@ def test_contextmanager():
os.fstat(fn) os.fstat(fn)
def test_contextmanager_non_exclusive_fp(): def test_contextmanager_non_exclusive_fp() -> None:
with open("Tests/images/hopper.gif", "rb") as fp: with open("Tests/images/hopper.gif", "rb") as fp:
with Image.open(fp): with Image.open(fp):
pass pass

View File

@ -7,7 +7,7 @@ from PIL import Image, ImageMode
from .helper import hopper from .helper import hopper
def test_sanity(): def test_sanity() -> None:
with hopper() as im: with hopper() as im:
im.mode im.mode
@ -69,7 +69,7 @@ def test_sanity():
) )
def test_properties( def test_properties(
mode, expected_base, expected_type, expected_bands, expected_band_names mode, expected_base, expected_type, expected_bands, expected_band_names
): ) -> None:
assert Image.getmodebase(mode) == expected_base assert Image.getmodebase(mode) == expected_base
assert Image.getmodetype(mode) == expected_type assert Image.getmodetype(mode) == expected_type
assert Image.getmodebands(mode) == expected_bands assert Image.getmodebands(mode) == expected_bands

View File

@ -11,7 +11,7 @@ class TestImagingPaste:
masks = {} masks = {}
size = 128 size = 128
def assert_9points_image(self, im, expected): def assert_9points_image(self, im, expected) -> None:
expected = [ expected = [
point[0] if im.mode == "L" else point[: len(im.mode)] for point in expected point[0] if im.mode == "L" else point[: len(im.mode)] for point in expected
] ]
@ -29,7 +29,7 @@ class TestImagingPaste:
] ]
assert actual == expected assert actual == expected
def assert_9points_paste(self, im, im2, mask, expected): def assert_9points_paste(self, im, im2, mask, expected) -> None:
im3 = im.copy() im3 = im.copy()
im3.paste(im2, (0, 0), mask) im3.paste(im2, (0, 0), mask)
self.assert_9points_image(im3, expected) self.assert_9points_image(im3, expected)
@ -106,7 +106,7 @@ class TestImagingPaste:
) )
@pytest.mark.parametrize("mode", ["RGBA", "RGB", "L"]) @pytest.mark.parametrize("mode", ["RGBA", "RGB", "L"])
def test_image_solid(self, mode): def test_image_solid(self, mode) -> None:
im = Image.new(mode, (200, 200), "red") im = Image.new(mode, (200, 200), "red")
im2 = getattr(self, "gradient_" + mode) im2 = getattr(self, "gradient_" + mode)
@ -116,7 +116,7 @@ class TestImagingPaste:
assert_image_equal(im, im2) assert_image_equal(im, im2)
@pytest.mark.parametrize("mode", ["RGBA", "RGB", "L"]) @pytest.mark.parametrize("mode", ["RGBA", "RGB", "L"])
def test_image_mask_1(self, mode): def test_image_mask_1(self, mode) -> None:
im = Image.new(mode, (200, 200), "white") im = Image.new(mode, (200, 200), "white")
im2 = getattr(self, "gradient_" + mode) im2 = getattr(self, "gradient_" + mode)
@ -138,7 +138,7 @@ class TestImagingPaste:
) )
@pytest.mark.parametrize("mode", ["RGBA", "RGB", "L"]) @pytest.mark.parametrize("mode", ["RGBA", "RGB", "L"])
def test_image_mask_L(self, mode): def test_image_mask_L(self, mode) -> None:
im = Image.new(mode, (200, 200), "white") im = Image.new(mode, (200, 200), "white")
im2 = getattr(self, "gradient_" + mode) im2 = getattr(self, "gradient_" + mode)
@ -160,7 +160,7 @@ class TestImagingPaste:
) )
@pytest.mark.parametrize("mode", ["RGBA", "RGB", "L"]) @pytest.mark.parametrize("mode", ["RGBA", "RGB", "L"])
def test_image_mask_LA(self, mode): def test_image_mask_LA(self, mode) -> None:
im = Image.new(mode, (200, 200), "white") im = Image.new(mode, (200, 200), "white")
im2 = getattr(self, "gradient_" + mode) im2 = getattr(self, "gradient_" + mode)
@ -182,7 +182,7 @@ class TestImagingPaste:
) )
@pytest.mark.parametrize("mode", ["RGBA", "RGB", "L"]) @pytest.mark.parametrize("mode", ["RGBA", "RGB", "L"])
def test_image_mask_RGBA(self, mode): def test_image_mask_RGBA(self, mode) -> None:
im = Image.new(mode, (200, 200), "white") im = Image.new(mode, (200, 200), "white")
im2 = getattr(self, "gradient_" + mode) im2 = getattr(self, "gradient_" + mode)
@ -204,7 +204,7 @@ class TestImagingPaste:
) )
@pytest.mark.parametrize("mode", ["RGBA", "RGB", "L"]) @pytest.mark.parametrize("mode", ["RGBA", "RGB", "L"])
def test_image_mask_RGBa(self, mode): def test_image_mask_RGBa(self, mode) -> None:
im = Image.new(mode, (200, 200), "white") im = Image.new(mode, (200, 200), "white")
im2 = getattr(self, "gradient_" + mode) im2 = getattr(self, "gradient_" + mode)
@ -226,7 +226,7 @@ class TestImagingPaste:
) )
@pytest.mark.parametrize("mode", ["RGBA", "RGB", "L"]) @pytest.mark.parametrize("mode", ["RGBA", "RGB", "L"])
def test_color_solid(self, mode): def test_color_solid(self, mode) -> None:
im = Image.new(mode, (200, 200), "black") im = Image.new(mode, (200, 200), "black")
rect = (12, 23, 128 + 12, 128 + 23) rect = (12, 23, 128 + 12, 128 + 23)
@ -239,7 +239,7 @@ class TestImagingPaste:
assert sum(head[:255]) == 0 assert sum(head[:255]) == 0
@pytest.mark.parametrize("mode", ["RGBA", "RGB", "L"]) @pytest.mark.parametrize("mode", ["RGBA", "RGB", "L"])
def test_color_mask_1(self, mode): def test_color_mask_1(self, mode) -> None:
im = Image.new(mode, (200, 200), (50, 60, 70, 80)[: len(mode)]) im = Image.new(mode, (200, 200), (50, 60, 70, 80)[: len(mode)])
color = (10, 20, 30, 40)[: len(mode)] color = (10, 20, 30, 40)[: len(mode)]
@ -261,7 +261,7 @@ class TestImagingPaste:
) )
@pytest.mark.parametrize("mode", ["RGBA", "RGB", "L"]) @pytest.mark.parametrize("mode", ["RGBA", "RGB", "L"])
def test_color_mask_L(self, mode): def test_color_mask_L(self, mode) -> None:
im = getattr(self, "gradient_" + mode).copy() im = getattr(self, "gradient_" + mode).copy()
color = "white" color = "white"
@ -283,7 +283,7 @@ class TestImagingPaste:
) )
@pytest.mark.parametrize("mode", ["RGBA", "RGB", "L"]) @pytest.mark.parametrize("mode", ["RGBA", "RGB", "L"])
def test_color_mask_RGBA(self, mode): def test_color_mask_RGBA(self, mode) -> None:
im = getattr(self, "gradient_" + mode).copy() im = getattr(self, "gradient_" + mode).copy()
color = "white" color = "white"
@ -305,7 +305,7 @@ class TestImagingPaste:
) )
@pytest.mark.parametrize("mode", ["RGBA", "RGB", "L"]) @pytest.mark.parametrize("mode", ["RGBA", "RGB", "L"])
def test_color_mask_RGBa(self, mode): def test_color_mask_RGBa(self, mode) -> None:
im = getattr(self, "gradient_" + mode).copy() im = getattr(self, "gradient_" + mode).copy()
color = "white" color = "white"
@ -326,7 +326,7 @@ class TestImagingPaste:
], ],
) )
def test_different_sizes(self): def test_different_sizes(self) -> None:
im = Image.new("RGB", (100, 100)) im = Image.new("RGB", (100, 100))
im2 = Image.new("RGB", (50, 50)) im2 = Image.new("RGB", (50, 50))

View File

@ -10,7 +10,7 @@ from PIL import Image
from .helper import assert_image_equal, hopper from .helper import assert_image_equal, hopper
def test_sanity(): def test_sanity() -> None:
im1 = hopper() im1 = hopper()
data = list(im1.getdata()) data = list(im1.getdata())
@ -29,7 +29,7 @@ def test_sanity():
assert_image_equal(im1, im2) assert_image_equal(im1, im2)
def test_long_integers(): def test_long_integers() -> None:
# see bug-200802-systemerror # see bug-200802-systemerror
def put(value): def put(value):
im = Image.new("RGBA", (1, 1)) im = Image.new("RGBA", (1, 1))
@ -46,19 +46,19 @@ def test_long_integers():
assert put(sys.maxsize) == (255, 255, 255, 127) assert put(sys.maxsize) == (255, 255, 255, 127)
def test_pypy_performance(): def test_pypy_performance() -> None:
im = Image.new("L", (256, 256)) im = Image.new("L", (256, 256))
im.putdata(list(range(256)) * 256) im.putdata(list(range(256)) * 256)
def test_mode_with_L_with_float(): def test_mode_with_L_with_float() -> None:
im = Image.new("L", (1, 1), 0) im = Image.new("L", (1, 1), 0)
im.putdata([2.0]) im.putdata([2.0])
assert im.getpixel((0, 0)) == 2 assert im.getpixel((0, 0)) == 2
@pytest.mark.parametrize("mode", ("I", "I;16", "I;16L", "I;16B")) @pytest.mark.parametrize("mode", ("I", "I;16", "I;16L", "I;16B"))
def test_mode_i(mode): def test_mode_i(mode) -> None:
src = hopper("L") src = hopper("L")
data = list(src.getdata()) data = list(src.getdata())
im = Image.new(mode, src.size, 0) im = Image.new(mode, src.size, 0)
@ -68,7 +68,7 @@ def test_mode_i(mode):
assert list(im.getdata()) == target assert list(im.getdata()) == target
def test_mode_F(): def test_mode_F() -> None:
src = hopper("L") src = hopper("L")
data = list(src.getdata()) data = list(src.getdata())
im = Image.new("F", src.size, 0) im = Image.new("F", src.size, 0)
@ -79,7 +79,7 @@ def test_mode_F():
@pytest.mark.parametrize("mode", ("BGR;15", "BGR;16", "BGR;24")) @pytest.mark.parametrize("mode", ("BGR;15", "BGR;16", "BGR;24"))
def test_mode_BGR(mode): def test_mode_BGR(mode) -> None:
data = [(16, 32, 49), (32, 32, 98)] data = [(16, 32, 49), (32, 32, 98)]
im = Image.new(mode, (1, 2)) im = Image.new(mode, (1, 2))
im.putdata(data) im.putdata(data)
@ -87,7 +87,7 @@ def test_mode_BGR(mode):
assert list(im.getdata()) == data assert list(im.getdata()) == data
def test_array_B(): def test_array_B() -> None:
# shouldn't segfault # shouldn't segfault
# see https://github.com/python-pillow/Pillow/issues/1008 # see https://github.com/python-pillow/Pillow/issues/1008
@ -98,7 +98,7 @@ def test_array_B():
assert len(im.getdata()) == len(arr) assert len(im.getdata()) == len(arr)
def test_array_F(): def test_array_F() -> None:
# shouldn't segfault # shouldn't segfault
# see https://github.com/python-pillow/Pillow/issues/1008 # see https://github.com/python-pillow/Pillow/issues/1008
@ -109,7 +109,7 @@ def test_array_F():
assert len(im.getdata()) == len(arr) assert len(im.getdata()) == len(arr)
def test_not_flattened(): def test_not_flattened() -> None:
im = Image.new("L", (1, 1)) im = Image.new("L", (1, 1))
with pytest.raises(TypeError): with pytest.raises(TypeError):
im.putdata([[0]]) im.putdata([[0]])

View File

@ -7,7 +7,7 @@ from PIL import Image, ImagePalette
from .helper import assert_image_equal, assert_image_equal_tofile, hopper from .helper import assert_image_equal, assert_image_equal_tofile, hopper
def test_putpalette(): def test_putpalette() -> None:
def palette(mode): def palette(mode):
im = hopper(mode).copy() im = hopper(mode).copy()
im.putpalette(list(range(256)) * 3) im.putpalette(list(range(256)) * 3)
@ -43,7 +43,7 @@ def test_putpalette():
im.putpalette(list(range(256)) * 3) im.putpalette(list(range(256)) * 3)
def test_imagepalette(): def test_imagepalette() -> None:
im = hopper("P") im = hopper("P")
im.putpalette(ImagePalette.negative()) im.putpalette(ImagePalette.negative())
assert_image_equal_tofile(im.convert("RGB"), "Tests/images/palette_negative.png") assert_image_equal_tofile(im.convert("RGB"), "Tests/images/palette_negative.png")
@ -57,7 +57,7 @@ def test_imagepalette():
assert_image_equal_tofile(im.convert("RGB"), "Tests/images/palette_wedge.png") assert_image_equal_tofile(im.convert("RGB"), "Tests/images/palette_wedge.png")
def test_putpalette_with_alpha_values(): def test_putpalette_with_alpha_values() -> None:
with Image.open("Tests/images/transparent.gif") as im: with Image.open("Tests/images/transparent.gif") as im:
expected = im.convert("RGBA") expected = im.convert("RGBA")
@ -81,19 +81,19 @@ def test_putpalette_with_alpha_values():
("RGBAX", (1, 2, 3, 4, 0)), ("RGBAX", (1, 2, 3, 4, 0)),
), ),
) )
def test_rgba_palette(mode, palette): def test_rgba_palette(mode, palette) -> None:
im = Image.new("P", (1, 1)) im = Image.new("P", (1, 1))
im.putpalette(palette, mode) im.putpalette(palette, mode)
assert im.getpalette() == [1, 2, 3] assert im.getpalette() == [1, 2, 3]
assert im.palette.colors == {(1, 2, 3, 4): 0} assert im.palette.colors == {(1, 2, 3, 4): 0}
def test_empty_palette(): def test_empty_palette() -> None:
im = Image.new("P", (1, 1)) im = Image.new("P", (1, 1))
assert im.getpalette() == [] assert im.getpalette() == []
def test_undefined_palette_index(): def test_undefined_palette_index() -> None:
im = Image.new("P", (1, 1), 3) im = Image.new("P", (1, 1), 3)
im.putpalette((1, 2, 3)) im.putpalette((1, 2, 3))
assert im.convert("RGB").getpixel((0, 0)) == (0, 0, 0) assert im.convert("RGB").getpixel((0, 0)) == (0, 0, 0)

View File

@ -48,7 +48,7 @@ gradients_image.load()
((1, 3), (10, 4)), ((1, 3), (10, 4)),
), ),
) )
def test_args_factor(size, expected): def test_args_factor(size, expected) -> None:
im = Image.new("L", (10, 10)) im = Image.new("L", (10, 10))
assert expected == im.reduce(size).size assert expected == im.reduce(size).size
@ -56,7 +56,7 @@ def test_args_factor(size, expected):
@pytest.mark.parametrize( @pytest.mark.parametrize(
"size, expected_error", ((0, ValueError), (2.0, TypeError), ((0, 10), ValueError)) "size, expected_error", ((0, ValueError), (2.0, TypeError), ((0, 10), ValueError))
) )
def test_args_factor_error(size, expected_error): def test_args_factor_error(size, expected_error) -> None:
im = Image.new("L", (10, 10)) im = Image.new("L", (10, 10))
with pytest.raises(expected_error): with pytest.raises(expected_error):
im.reduce(size) im.reduce(size)
@ -69,7 +69,7 @@ def test_args_factor_error(size, expected_error):
((5, 5, 6, 6), (1, 1)), ((5, 5, 6, 6), (1, 1)),
), ),
) )
def test_args_box(size, expected): def test_args_box(size, expected) -> None:
im = Image.new("L", (10, 10)) im = Image.new("L", (10, 10))
assert expected == im.reduce(2, size).size assert expected == im.reduce(2, size).size
@ -86,14 +86,14 @@ def test_args_box(size, expected):
((5, 0, 5, 10), ValueError), ((5, 0, 5, 10), ValueError),
), ),
) )
def test_args_box_error(size, expected_error): def test_args_box_error(size, expected_error) -> None:
im = Image.new("L", (10, 10)) im = Image.new("L", (10, 10))
with pytest.raises(expected_error): with pytest.raises(expected_error):
im.reduce(2, size).size im.reduce(2, size).size
@pytest.mark.parametrize("mode", ("P", "1", "I;16")) @pytest.mark.parametrize("mode", ("P", "1", "I;16"))
def test_unsupported_modes(mode): def test_unsupported_modes(mode) -> None:
im = Image.new("P", (10, 10)) im = Image.new("P", (10, 10))
with pytest.raises(ValueError): with pytest.raises(ValueError):
im.reduce(3) im.reduce(3)
@ -119,14 +119,16 @@ def get_image(mode):
return im.crop((0, 0, im.width, im.height - 5)) return im.crop((0, 0, im.width, im.height - 5))
def compare_reduce_with_box(im, factor): def compare_reduce_with_box(im, factor) -> None:
box = (11, 13, 146, 164) box = (11, 13, 146, 164)
reduced = im.reduce(factor, box=box) reduced = im.reduce(factor, box=box)
reference = im.crop(box).reduce(factor) reference = im.crop(box).reduce(factor)
assert reduced == reference assert reduced == reference
def compare_reduce_with_reference(im, factor, average_diff=0.4, max_diff=1): def compare_reduce_with_reference(
im, factor, average_diff: float = 0.4, max_diff: int = 1
) -> None:
"""Image.reduce() should look very similar to Image.resize(BOX). """Image.reduce() should look very similar to Image.resize(BOX).
A reference image is compiled from a large source area A reference image is compiled from a large source area
@ -171,7 +173,7 @@ def compare_reduce_with_reference(im, factor, average_diff=0.4, max_diff=1):
assert_compare_images(reduced, reference, average_diff, max_diff) assert_compare_images(reduced, reference, average_diff, max_diff)
def assert_compare_images(a, b, max_average_diff, max_diff=255): def assert_compare_images(a, b, max_average_diff, max_diff: int = 255) -> None:
assert a.mode == b.mode, f"got mode {repr(a.mode)}, expected {repr(b.mode)}" assert a.mode == b.mode, f"got mode {repr(a.mode)}, expected {repr(b.mode)}"
assert a.size == b.size, f"got size {repr(a.size)}, expected {repr(b.size)}" assert a.size == b.size, f"got size {repr(a.size)}, expected {repr(b.size)}"
@ -199,20 +201,20 @@ def assert_compare_images(a, b, max_average_diff, max_diff=255):
@pytest.mark.parametrize("factor", remarkable_factors) @pytest.mark.parametrize("factor", remarkable_factors)
def test_mode_L(factor): def test_mode_L(factor) -> None:
im = get_image("L") im = get_image("L")
compare_reduce_with_reference(im, factor) compare_reduce_with_reference(im, factor)
compare_reduce_with_box(im, factor) compare_reduce_with_box(im, factor)
@pytest.mark.parametrize("factor", remarkable_factors) @pytest.mark.parametrize("factor", remarkable_factors)
def test_mode_LA(factor): def test_mode_LA(factor) -> None:
im = get_image("LA") im = get_image("LA")
compare_reduce_with_reference(im, factor, 0.8, 5) compare_reduce_with_reference(im, factor, 0.8, 5)
@pytest.mark.parametrize("factor", remarkable_factors) @pytest.mark.parametrize("factor", remarkable_factors)
def test_mode_LA_opaque(factor): def test_mode_LA_opaque(factor) -> None:
im = get_image("LA") im = get_image("LA")
# With opaque alpha, an error should be way smaller. # With opaque alpha, an error should be way smaller.
im.putalpha(Image.new("L", im.size, 255)) im.putalpha(Image.new("L", im.size, 255))
@ -221,27 +223,27 @@ def test_mode_LA_opaque(factor):
@pytest.mark.parametrize("factor", remarkable_factors) @pytest.mark.parametrize("factor", remarkable_factors)
def test_mode_La(factor): def test_mode_La(factor) -> None:
im = get_image("La") im = get_image("La")
compare_reduce_with_reference(im, factor) compare_reduce_with_reference(im, factor)
compare_reduce_with_box(im, factor) compare_reduce_with_box(im, factor)
@pytest.mark.parametrize("factor", remarkable_factors) @pytest.mark.parametrize("factor", remarkable_factors)
def test_mode_RGB(factor): def test_mode_RGB(factor) -> None:
im = get_image("RGB") im = get_image("RGB")
compare_reduce_with_reference(im, factor) compare_reduce_with_reference(im, factor)
compare_reduce_with_box(im, factor) compare_reduce_with_box(im, factor)
@pytest.mark.parametrize("factor", remarkable_factors) @pytest.mark.parametrize("factor", remarkable_factors)
def test_mode_RGBA(factor): def test_mode_RGBA(factor) -> None:
im = get_image("RGBA") im = get_image("RGBA")
compare_reduce_with_reference(im, factor, 0.8, 5) compare_reduce_with_reference(im, factor, 0.8, 5)
@pytest.mark.parametrize("factor", remarkable_factors) @pytest.mark.parametrize("factor", remarkable_factors)
def test_mode_RGBA_opaque(factor): def test_mode_RGBA_opaque(factor) -> None:
im = get_image("RGBA") im = get_image("RGBA")
# With opaque alpha, an error should be way smaller. # With opaque alpha, an error should be way smaller.
im.putalpha(Image.new("L", im.size, 255)) im.putalpha(Image.new("L", im.size, 255))
@ -250,27 +252,27 @@ def test_mode_RGBA_opaque(factor):
@pytest.mark.parametrize("factor", remarkable_factors) @pytest.mark.parametrize("factor", remarkable_factors)
def test_mode_RGBa(factor): def test_mode_RGBa(factor) -> None:
im = get_image("RGBa") im = get_image("RGBa")
compare_reduce_with_reference(im, factor) compare_reduce_with_reference(im, factor)
compare_reduce_with_box(im, factor) compare_reduce_with_box(im, factor)
@pytest.mark.parametrize("factor", remarkable_factors) @pytest.mark.parametrize("factor", remarkable_factors)
def test_mode_I(factor): def test_mode_I(factor) -> None:
im = get_image("I") im = get_image("I")
compare_reduce_with_reference(im, factor) compare_reduce_with_reference(im, factor)
compare_reduce_with_box(im, factor) compare_reduce_with_box(im, factor)
@pytest.mark.parametrize("factor", remarkable_factors) @pytest.mark.parametrize("factor", remarkable_factors)
def test_mode_F(factor): def test_mode_F(factor) -> None:
im = get_image("F") im = get_image("F")
compare_reduce_with_reference(im, factor, 0, 0) compare_reduce_with_reference(im, factor, 0, 0)
compare_reduce_with_box(im, factor) compare_reduce_with_box(im, factor)
@skip_unless_feature("jpg_2000") @skip_unless_feature("jpg_2000")
def test_jpeg2k(): def test_jpeg2k() -> None:
with Image.open("Tests/images/test-card-lossless.jp2") as im: with Image.open("Tests/images/test-card-lossless.jp2") as im:
assert im.reduce(2).size == (320, 240) assert im.reduce(2).size == (320, 240)

View File

@ -16,7 +16,7 @@ from .helper import (
class TestImagingResampleVulnerability: 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) -> None:
im = hopper("L") im = hopper("L")
size_too_large = 0x100000008 // 4 size_too_large = 0x100000008 // 4
size_normal = 1000 # unimportant size_normal = 1000 # unimportant
@ -28,7 +28,7 @@ class TestImagingResampleVulnerability:
# any resampling filter will do here # any resampling filter will do here
im.im.resize((xsize, ysize), Image.Resampling.BILINEAR) im.im.resize((xsize, ysize), Image.Resampling.BILINEAR)
def test_invalid_size(self): def test_invalid_size(self) -> None:
im = hopper() im = hopper()
# Should not crash # Should not crash
@ -40,7 +40,7 @@ class TestImagingResampleVulnerability:
with pytest.raises(ValueError): with pytest.raises(ValueError):
im.resize((100, -100)) im.resize((100, -100))
def test_modify_after_resizing(self): def test_modify_after_resizing(self) -> None:
im = hopper("RGB") im = hopper("RGB")
# get copy with same size # get copy with same size
copy = im.resize(im.size) copy = im.resize(im.size)
@ -83,7 +83,7 @@ class TestImagingCoreResampleAccuracy:
s_px[size[0] - x - 1, y] = 255 - val s_px[size[0] - x - 1, y] = 255 - val
return sample return sample
def check_case(self, case, sample): def check_case(self, case, sample) -> None:
s_px = sample.load() s_px = sample.load()
c_px = case.load() c_px = case.load()
for y in range(case.size[1]): for y in range(case.size[1]):
@ -103,7 +103,7 @@ class TestImagingCoreResampleAccuracy:
) )
@pytest.mark.parametrize("mode", ("RGBX", "RGB", "La", "L")) @pytest.mark.parametrize("mode", ("RGBX", "RGB", "La", "L"))
def test_reduce_box(self, mode): def test_reduce_box(self, mode) -> None:
case = self.make_case(mode, (8, 8), 0xE1) case = self.make_case(mode, (8, 8), 0xE1)
case = case.resize((4, 4), Image.Resampling.BOX) case = case.resize((4, 4), Image.Resampling.BOX)
# fmt: off # fmt: off
@ -114,7 +114,7 @@ class TestImagingCoreResampleAccuracy:
self.check_case(channel, self.make_sample(data, (4, 4))) self.check_case(channel, self.make_sample(data, (4, 4)))
@pytest.mark.parametrize("mode", ("RGBX", "RGB", "La", "L")) @pytest.mark.parametrize("mode", ("RGBX", "RGB", "La", "L"))
def test_reduce_bilinear(self, mode): def test_reduce_bilinear(self, mode) -> None:
case = self.make_case(mode, (8, 8), 0xE1) case = self.make_case(mode, (8, 8), 0xE1)
case = case.resize((4, 4), Image.Resampling.BILINEAR) case = case.resize((4, 4), Image.Resampling.BILINEAR)
# fmt: off # fmt: off
@ -125,7 +125,7 @@ class TestImagingCoreResampleAccuracy:
self.check_case(channel, self.make_sample(data, (4, 4))) self.check_case(channel, self.make_sample(data, (4, 4)))
@pytest.mark.parametrize("mode", ("RGBX", "RGB", "La", "L")) @pytest.mark.parametrize("mode", ("RGBX", "RGB", "La", "L"))
def test_reduce_hamming(self, mode): def test_reduce_hamming(self, mode) -> None:
case = self.make_case(mode, (8, 8), 0xE1) case = self.make_case(mode, (8, 8), 0xE1)
case = case.resize((4, 4), Image.Resampling.HAMMING) case = case.resize((4, 4), Image.Resampling.HAMMING)
# fmt: off # fmt: off
@ -136,7 +136,7 @@ class TestImagingCoreResampleAccuracy:
self.check_case(channel, self.make_sample(data, (4, 4))) self.check_case(channel, self.make_sample(data, (4, 4)))
@pytest.mark.parametrize("mode", ("RGBX", "RGB", "La", "L")) @pytest.mark.parametrize("mode", ("RGBX", "RGB", "La", "L"))
def test_reduce_bicubic(self, mode): def test_reduce_bicubic(self, mode) -> None:
case = self.make_case(mode, (12, 12), 0xE1) case = self.make_case(mode, (12, 12), 0xE1)
case = case.resize((6, 6), Image.Resampling.BICUBIC) case = case.resize((6, 6), Image.Resampling.BICUBIC)
# fmt: off # fmt: off
@ -148,7 +148,7 @@ class TestImagingCoreResampleAccuracy:
self.check_case(channel, self.make_sample(data, (6, 6))) self.check_case(channel, self.make_sample(data, (6, 6)))
@pytest.mark.parametrize("mode", ("RGBX", "RGB", "La", "L")) @pytest.mark.parametrize("mode", ("RGBX", "RGB", "La", "L"))
def test_reduce_lanczos(self, mode): def test_reduce_lanczos(self, mode) -> None:
case = self.make_case(mode, (16, 16), 0xE1) case = self.make_case(mode, (16, 16), 0xE1)
case = case.resize((8, 8), Image.Resampling.LANCZOS) case = case.resize((8, 8), Image.Resampling.LANCZOS)
# fmt: off # fmt: off
@ -161,7 +161,7 @@ class TestImagingCoreResampleAccuracy:
self.check_case(channel, self.make_sample(data, (8, 8))) self.check_case(channel, self.make_sample(data, (8, 8)))
@pytest.mark.parametrize("mode", ("RGBX", "RGB", "La", "L")) @pytest.mark.parametrize("mode", ("RGBX", "RGB", "La", "L"))
def test_enlarge_box(self, mode): def test_enlarge_box(self, mode) -> None:
case = self.make_case(mode, (2, 2), 0xE1) case = self.make_case(mode, (2, 2), 0xE1)
case = case.resize((4, 4), Image.Resampling.BOX) case = case.resize((4, 4), Image.Resampling.BOX)
# fmt: off # fmt: off
@ -172,7 +172,7 @@ class TestImagingCoreResampleAccuracy:
self.check_case(channel, self.make_sample(data, (4, 4))) self.check_case(channel, self.make_sample(data, (4, 4)))
@pytest.mark.parametrize("mode", ("RGBX", "RGB", "La", "L")) @pytest.mark.parametrize("mode", ("RGBX", "RGB", "La", "L"))
def test_enlarge_bilinear(self, mode): def test_enlarge_bilinear(self, mode) -> None:
case = self.make_case(mode, (2, 2), 0xE1) case = self.make_case(mode, (2, 2), 0xE1)
case = case.resize((4, 4), Image.Resampling.BILINEAR) case = case.resize((4, 4), Image.Resampling.BILINEAR)
# fmt: off # fmt: off
@ -183,7 +183,7 @@ class TestImagingCoreResampleAccuracy:
self.check_case(channel, self.make_sample(data, (4, 4))) self.check_case(channel, self.make_sample(data, (4, 4)))
@pytest.mark.parametrize("mode", ("RGBX", "RGB", "La", "L")) @pytest.mark.parametrize("mode", ("RGBX", "RGB", "La", "L"))
def test_enlarge_hamming(self, mode): def test_enlarge_hamming(self, mode) -> None:
case = self.make_case(mode, (2, 2), 0xE1) case = self.make_case(mode, (2, 2), 0xE1)
case = case.resize((4, 4), Image.Resampling.HAMMING) case = case.resize((4, 4), Image.Resampling.HAMMING)
# fmt: off # fmt: off
@ -194,7 +194,7 @@ class TestImagingCoreResampleAccuracy:
self.check_case(channel, self.make_sample(data, (4, 4))) self.check_case(channel, self.make_sample(data, (4, 4)))
@pytest.mark.parametrize("mode", ("RGBX", "RGB", "La", "L")) @pytest.mark.parametrize("mode", ("RGBX", "RGB", "La", "L"))
def test_enlarge_bicubic(self, mode): def test_enlarge_bicubic(self, mode) -> None:
case = self.make_case(mode, (4, 4), 0xE1) case = self.make_case(mode, (4, 4), 0xE1)
case = case.resize((8, 8), Image.Resampling.BICUBIC) case = case.resize((8, 8), Image.Resampling.BICUBIC)
# fmt: off # fmt: off
@ -207,7 +207,7 @@ class TestImagingCoreResampleAccuracy:
self.check_case(channel, self.make_sample(data, (8, 8))) self.check_case(channel, self.make_sample(data, (8, 8)))
@pytest.mark.parametrize("mode", ("RGBX", "RGB", "La", "L")) @pytest.mark.parametrize("mode", ("RGBX", "RGB", "La", "L"))
def test_enlarge_lanczos(self, mode): def test_enlarge_lanczos(self, mode) -> None:
case = self.make_case(mode, (6, 6), 0xE1) case = self.make_case(mode, (6, 6), 0xE1)
case = case.resize((12, 12), Image.Resampling.LANCZOS) case = case.resize((12, 12), Image.Resampling.LANCZOS)
data = ( data = (
@ -221,7 +221,7 @@ class TestImagingCoreResampleAccuracy:
for channel in case.split(): for channel in case.split():
self.check_case(channel, self.make_sample(data, (12, 12))) self.check_case(channel, self.make_sample(data, (12, 12)))
def test_box_filter_correct_range(self): def test_box_filter_correct_range(self) -> None:
im = Image.new("RGB", (8, 8), "#1688ff").resize( im = Image.new("RGB", (8, 8), "#1688ff").resize(
(100, 100), Image.Resampling.BOX (100, 100), Image.Resampling.BOX
) )
@ -234,7 +234,7 @@ class TestCoreResampleConsistency:
im = Image.new(mode, (512, 9), fill) im = Image.new(mode, (512, 9), fill)
return im.resize((9, 512), Image.Resampling.LANCZOS), im.load()[0, 0] return im.resize((9, 512), Image.Resampling.LANCZOS), im.load()[0, 0]
def run_case(self, case): def run_case(self, case) -> None:
channel, color = case channel, color = case
px = channel.load() px = channel.load()
for x in range(channel.size[0]): for x in range(channel.size[0]):
@ -243,7 +243,7 @@ class TestCoreResampleConsistency:
message = f"{px[x, y]} != {color} for pixel {(x, y)}" message = f"{px[x, y]} != {color} for pixel {(x, y)}"
assert px[x, y] == color, message assert px[x, y] == color, message
def test_8u(self): def test_8u(self) -> None:
im, color = self.make_case("RGB", (0, 64, 255)) im, color = self.make_case("RGB", (0, 64, 255))
r, g, b = im.split() r, g, b = im.split()
self.run_case((r, color[0])) self.run_case((r, color[0]))
@ -251,13 +251,13 @@ class TestCoreResampleConsistency:
self.run_case((b, color[2])) self.run_case((b, color[2]))
self.run_case(self.make_case("L", 12)) self.run_case(self.make_case("L", 12))
def test_32i(self): def test_32i(self) -> None:
self.run_case(self.make_case("I", 12)) self.run_case(self.make_case("I", 12))
self.run_case(self.make_case("I", 0x7FFFFFFF)) self.run_case(self.make_case("I", 0x7FFFFFFF))
self.run_case(self.make_case("I", -12)) self.run_case(self.make_case("I", -12))
self.run_case(self.make_case("I", -1 << 31)) self.run_case(self.make_case("I", -1 << 31))
def test_32f(self): def test_32f(self) -> None:
self.run_case(self.make_case("F", 1)) self.run_case(self.make_case("F", 1))
self.run_case(self.make_case("F", 3.40282306074e38)) self.run_case(self.make_case("F", 3.40282306074e38))
self.run_case(self.make_case("F", 1.175494e-38)) self.run_case(self.make_case("F", 1.175494e-38))
@ -275,7 +275,7 @@ class TestCoreResampleAlphaCorrect:
px[x, y] = tuple(pix) px[x, y] = tuple(pix)
return i return i
def run_levels_case(self, i): def run_levels_case(self, i) -> None:
px = i.load() px = i.load()
for y in range(i.size[1]): for y in range(i.size[1]):
used_colors = {px[x, y][0] for x in range(i.size[0])} used_colors = {px[x, y][0] for x in range(i.size[0])}
@ -285,7 +285,7 @@ class TestCoreResampleAlphaCorrect:
) )
@pytest.mark.xfail(reason="Current implementation isn't precise enough") @pytest.mark.xfail(reason="Current implementation isn't precise enough")
def test_levels_rgba(self): def test_levels_rgba(self) -> None:
case = self.make_levels_case("RGBA") case = self.make_levels_case("RGBA")
self.run_levels_case(case.resize((512, 32), Image.Resampling.BOX)) self.run_levels_case(case.resize((512, 32), Image.Resampling.BOX))
self.run_levels_case(case.resize((512, 32), Image.Resampling.BILINEAR)) self.run_levels_case(case.resize((512, 32), Image.Resampling.BILINEAR))
@ -294,7 +294,7 @@ class TestCoreResampleAlphaCorrect:
self.run_levels_case(case.resize((512, 32), Image.Resampling.LANCZOS)) self.run_levels_case(case.resize((512, 32), Image.Resampling.LANCZOS))
@pytest.mark.xfail(reason="Current implementation isn't precise enough") @pytest.mark.xfail(reason="Current implementation isn't precise enough")
def test_levels_la(self): def test_levels_la(self) -> None:
case = self.make_levels_case("LA") case = self.make_levels_case("LA")
self.run_levels_case(case.resize((512, 32), Image.Resampling.BOX)) self.run_levels_case(case.resize((512, 32), Image.Resampling.BOX))
self.run_levels_case(case.resize((512, 32), Image.Resampling.BILINEAR)) self.run_levels_case(case.resize((512, 32), Image.Resampling.BILINEAR))
@ -312,7 +312,7 @@ class TestCoreResampleAlphaCorrect:
px[x + xdiv4, y + ydiv4] = clean_pixel px[x + xdiv4, y + ydiv4] = clean_pixel
return i return i
def run_dirty_case(self, i, clean_pixel): def run_dirty_case(self, i, clean_pixel) -> None:
px = i.load() px = i.load()
for y in range(i.size[1]): for y in range(i.size[1]):
for x in range(i.size[0]): for x in range(i.size[0]):
@ -323,7 +323,7 @@ class TestCoreResampleAlphaCorrect:
) )
assert px[x, y][:3] == clean_pixel, message assert px[x, y][:3] == clean_pixel, message
def test_dirty_pixels_rgba(self): def test_dirty_pixels_rgba(self) -> None:
case = self.make_dirty_case("RGBA", (255, 255, 0, 128), (0, 0, 255, 0)) case = self.make_dirty_case("RGBA", (255, 255, 0, 128), (0, 0, 255, 0))
self.run_dirty_case(case.resize((20, 20), Image.Resampling.BOX), (255, 255, 0)) self.run_dirty_case(case.resize((20, 20), Image.Resampling.BOX), (255, 255, 0))
self.run_dirty_case( self.run_dirty_case(
@ -339,7 +339,7 @@ class TestCoreResampleAlphaCorrect:
case.resize((20, 20), Image.Resampling.LANCZOS), (255, 255, 0) case.resize((20, 20), Image.Resampling.LANCZOS), (255, 255, 0)
) )
def test_dirty_pixels_la(self): def test_dirty_pixels_la(self) -> None:
case = self.make_dirty_case("LA", (255, 128), (0, 0)) case = self.make_dirty_case("LA", (255, 128), (0, 0))
self.run_dirty_case(case.resize((20, 20), Image.Resampling.BOX), (255,)) self.run_dirty_case(case.resize((20, 20), Image.Resampling.BOX), (255,))
self.run_dirty_case(case.resize((20, 20), Image.Resampling.BILINEAR), (255,)) self.run_dirty_case(case.resize((20, 20), Image.Resampling.BILINEAR), (255,))
@ -355,22 +355,22 @@ class TestCoreResamplePasses:
yield yield
assert Image.core.get_stats()["new_count"] - count == diff assert Image.core.get_stats()["new_count"] - count == diff
def test_horizontal(self): def test_horizontal(self) -> None:
im = hopper("L") im = hopper("L")
with self.count(1): with self.count(1):
im.resize((im.size[0] - 10, im.size[1]), Image.Resampling.BILINEAR) im.resize((im.size[0] - 10, im.size[1]), Image.Resampling.BILINEAR)
def test_vertical(self): def test_vertical(self) -> None:
im = hopper("L") im = hopper("L")
with self.count(1): with self.count(1):
im.resize((im.size[0], im.size[1] - 10), Image.Resampling.BILINEAR) im.resize((im.size[0], im.size[1] - 10), Image.Resampling.BILINEAR)
def test_both(self): def test_both(self) -> None:
im = hopper("L") im = hopper("L")
with self.count(2): with self.count(2):
im.resize((im.size[0] - 10, im.size[1] - 10), Image.Resampling.BILINEAR) im.resize((im.size[0] - 10, im.size[1] - 10), Image.Resampling.BILINEAR)
def test_box_horizontal(self): def test_box_horizontal(self) -> None:
im = hopper("L") im = hopper("L")
box = (20, 0, im.size[0] - 20, im.size[1]) box = (20, 0, im.size[0] - 20, im.size[1])
with self.count(1): with self.count(1):
@ -380,7 +380,7 @@ class TestCoreResamplePasses:
cropped = im.crop(box).resize(im.size, Image.Resampling.BILINEAR) cropped = im.crop(box).resize(im.size, Image.Resampling.BILINEAR)
assert_image_similar(with_box, cropped, 0.1) assert_image_similar(with_box, cropped, 0.1)
def test_box_vertical(self): def test_box_vertical(self) -> None:
im = hopper("L") im = hopper("L")
box = (0, 20, im.size[0], im.size[1] - 20) box = (0, 20, im.size[0], im.size[1] - 20)
with self.count(1): with self.count(1):
@ -392,7 +392,7 @@ class TestCoreResamplePasses:
class TestCoreResampleCoefficients: class TestCoreResampleCoefficients:
def test_reduce(self): def test_reduce(self) -> None:
test_color = 254 test_color = 254
for size in range(400000, 400010, 2): for size in range(400000, 400010, 2):
@ -404,7 +404,7 @@ class TestCoreResampleCoefficients:
if px[2, 0] != test_color // 2: if px[2, 0] != test_color // 2:
assert test_color // 2 == px[2, 0] assert test_color // 2 == px[2, 0]
def test_non_zero_coefficients(self): def test_non_zero_coefficients(self) -> None:
# regression test for the wrong coefficients calculation # regression test for the wrong coefficients calculation
# due to bug https://github.com/python-pillow/Pillow/issues/2161 # due to bug https://github.com/python-pillow/Pillow/issues/2161
im = Image.new("RGBA", (1280, 1280), (0x20, 0x40, 0x60, 0xFF)) im = Image.new("RGBA", (1280, 1280), (0x20, 0x40, 0x60, 0xFF))
@ -432,7 +432,7 @@ class TestCoreResampleBox:
Image.Resampling.LANCZOS, Image.Resampling.LANCZOS,
), ),
) )
def test_wrong_arguments(self, resample): def test_wrong_arguments(self, resample) -> None:
im = hopper() im = hopper()
im.resize((32, 32), resample, (0, 0, im.width, im.height)) im.resize((32, 32), resample, (0, 0, im.width, im.height))
im.resize((32, 32), resample, (20, 20, im.width, im.height)) im.resize((32, 32), resample, (20, 20, im.width, im.height))
@ -478,7 +478,7 @@ class TestCoreResampleBox:
@mark_if_feature_version( @mark_if_feature_version(
pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing"
) )
def test_tiles(self): def test_tiles(self) -> None:
with Image.open("Tests/images/flower.jpg") as im: with Image.open("Tests/images/flower.jpg") as im:
assert im.size == (480, 360) assert im.size == (480, 360)
dst_size = (251, 188) dst_size = (251, 188)
@ -491,7 +491,7 @@ class TestCoreResampleBox:
@mark_if_feature_version( @mark_if_feature_version(
pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing"
) )
def test_subsample(self): def test_subsample(self) -> None:
# This test shows advantages of the subpixel resizing # This test shows advantages of the subpixel resizing
# after supersampling (e.g. during JPEG decoding). # after supersampling (e.g. during JPEG decoding).
with Image.open("Tests/images/flower.jpg") as im: with Image.open("Tests/images/flower.jpg") as im:
@ -518,14 +518,14 @@ class TestCoreResampleBox:
@pytest.mark.parametrize( @pytest.mark.parametrize(
"resample", (Image.Resampling.NEAREST, Image.Resampling.BILINEAR) "resample", (Image.Resampling.NEAREST, Image.Resampling.BILINEAR)
) )
def test_formats(self, mode, resample): def test_formats(self, mode, resample) -> None:
im = hopper(mode) im = hopper(mode)
box = (20, 20, im.size[0] - 20, im.size[1] - 20) box = (20, 20, im.size[0] - 20, im.size[1] - 20)
with_box = im.resize((32, 32), resample, box) with_box = im.resize((32, 32), resample, box)
cropped = im.crop(box).resize((32, 32), resample) cropped = im.crop(box).resize((32, 32), resample)
assert_image_similar(cropped, with_box, 0.4) assert_image_similar(cropped, with_box, 0.4)
def test_passthrough(self): def test_passthrough(self) -> None:
# When no resize is required # When no resize is required
im = hopper() im = hopper()
@ -539,7 +539,7 @@ class TestCoreResampleBox:
assert res.size == size assert res.size == size
assert_image_equal(res, im.crop(box), f">>> {size} {box}") assert_image_equal(res, im.crop(box), f">>> {size} {box}")
def test_no_passthrough(self): def test_no_passthrough(self) -> None:
# When resize is required # When resize is required
im = hopper() im = hopper()
@ -558,7 +558,7 @@ class TestCoreResampleBox:
@pytest.mark.parametrize( @pytest.mark.parametrize(
"flt", (Image.Resampling.NEAREST, Image.Resampling.BICUBIC) "flt", (Image.Resampling.NEAREST, Image.Resampling.BICUBIC)
) )
def test_skip_horizontal(self, flt): def test_skip_horizontal(self, flt) -> None:
# Can skip resize for one dimension # Can skip resize for one dimension
im = hopper() im = hopper()
@ -581,7 +581,7 @@ class TestCoreResampleBox:
@pytest.mark.parametrize( @pytest.mark.parametrize(
"flt", (Image.Resampling.NEAREST, Image.Resampling.BICUBIC) "flt", (Image.Resampling.NEAREST, Image.Resampling.BICUBIC)
) )
def test_skip_vertical(self, flt): def test_skip_vertical(self, flt) -> None:
# Can skip resize for one dimension # Can skip resize for one dimension
im = hopper() im = hopper()

View File

@ -12,7 +12,7 @@ from .helper import (
) )
def rotate(im, mode, angle, center=None, translate=None): def rotate(im, mode, angle, center=None, translate=None) -> None:
out = im.rotate(angle, center=center, translate=translate) out = im.rotate(angle, center=center, translate=translate)
assert out.mode == mode assert out.mode == mode
assert out.size == im.size # default rotate clips output assert out.size == im.size # default rotate clips output
@ -27,13 +27,13 @@ def rotate(im, mode, angle, center=None, translate=None):
@pytest.mark.parametrize("mode", ("1", "P", "L", "RGB", "I", "F")) @pytest.mark.parametrize("mode", ("1", "P", "L", "RGB", "I", "F"))
def test_mode(mode): def test_mode(mode) -> None:
im = hopper(mode) im = hopper(mode)
rotate(im, mode, 45) rotate(im, mode, 45)
@pytest.mark.parametrize("angle", (0, 90, 180, 270)) @pytest.mark.parametrize("angle", (0, 90, 180, 270))
def test_angle(angle): def test_angle(angle) -> None:
with Image.open("Tests/images/test-card.png") as im: with Image.open("Tests/images/test-card.png") as im:
rotate(im, im.mode, angle) rotate(im, im.mode, angle)
@ -42,12 +42,12 @@ def test_angle(angle):
@pytest.mark.parametrize("angle", (0, 45, 90, 180, 270)) @pytest.mark.parametrize("angle", (0, 45, 90, 180, 270))
def test_zero(angle): def test_zero(angle) -> None:
im = Image.new("RGB", (0, 0)) im = Image.new("RGB", (0, 0))
rotate(im, im.mode, angle) rotate(im, im.mode, angle)
def test_resample(): def test_resample() -> None:
# Target image creation, inspected by eye. # Target image creation, inspected by eye.
# >>> im = Image.open('Tests/images/hopper.ppm') # >>> im = Image.open('Tests/images/hopper.ppm')
# >>> im = im.rotate(45, resample=Image.Resampling.BICUBIC, expand=True) # >>> im = im.rotate(45, resample=Image.Resampling.BICUBIC, expand=True)
@ -64,7 +64,7 @@ def test_resample():
assert_image_similar(im, target, epsilon) assert_image_similar(im, target, epsilon)
def test_center_0(): def test_center_0() -> None:
im = hopper() im = hopper()
im = im.rotate(45, center=(0, 0), resample=Image.Resampling.BICUBIC) im = im.rotate(45, center=(0, 0), resample=Image.Resampling.BICUBIC)
@ -75,7 +75,7 @@ def test_center_0():
assert_image_similar(im, target, 15) assert_image_similar(im, target, 15)
def test_center_14(): def test_center_14() -> None:
im = hopper() im = hopper()
im = im.rotate(45, center=(14, 14), resample=Image.Resampling.BICUBIC) im = im.rotate(45, center=(14, 14), resample=Image.Resampling.BICUBIC)
@ -86,7 +86,7 @@ def test_center_14():
assert_image_similar(im, target, 10) assert_image_similar(im, target, 10)
def test_translate(): def test_translate() -> None:
im = hopper() im = hopper()
with Image.open("Tests/images/hopper_45.png") as target: with Image.open("Tests/images/hopper_45.png") as target:
target_origin = (target.size[1] / 2 - 64) - 5 target_origin = (target.size[1] / 2 - 64) - 5
@ -99,7 +99,7 @@ def test_translate():
assert_image_similar(im, target, 1) assert_image_similar(im, target, 1)
def test_fastpath_center(): def test_fastpath_center() -> None:
# if the center is -1,-1 and we rotate by 90<=x<=270 the # if the center is -1,-1 and we rotate by 90<=x<=270 the
# resulting image should be black # resulting image should be black
for angle in (90, 180, 270): for angle in (90, 180, 270):
@ -107,7 +107,7 @@ def test_fastpath_center():
assert_image_equal(im, Image.new("RGB", im.size, "black")) assert_image_equal(im, Image.new("RGB", im.size, "black"))
def test_fastpath_translate(): def test_fastpath_translate() -> None:
# if we post-translate by -128 # if we post-translate by -128
# resulting image should be black # resulting image should be black
for angle in (0, 90, 180, 270): for angle in (0, 90, 180, 270):
@ -115,26 +115,26 @@ def test_fastpath_translate():
assert_image_equal(im, Image.new("RGB", im.size, "black")) assert_image_equal(im, Image.new("RGB", im.size, "black"))
def test_center(): def test_center() -> None:
im = hopper() im = hopper()
rotate(im, im.mode, 45, center=(0, 0)) rotate(im, im.mode, 45, center=(0, 0))
rotate(im, im.mode, 45, translate=(im.size[0] / 2, 0)) rotate(im, im.mode, 45, translate=(im.size[0] / 2, 0))
rotate(im, im.mode, 45, center=(0, 0), translate=(im.size[0] / 2, 0)) rotate(im, im.mode, 45, center=(0, 0), translate=(im.size[0] / 2, 0))
def test_rotate_no_fill(): def test_rotate_no_fill() -> None:
im = Image.new("RGB", (100, 100), "green") im = Image.new("RGB", (100, 100), "green")
im = im.rotate(45) im = im.rotate(45)
assert_image_equal_tofile(im, "Tests/images/rotate_45_no_fill.png") assert_image_equal_tofile(im, "Tests/images/rotate_45_no_fill.png")
def test_rotate_with_fill(): def test_rotate_with_fill() -> None:
im = Image.new("RGB", (100, 100), "green") im = Image.new("RGB", (100, 100), "green")
im = im.rotate(45, fillcolor="white") im = im.rotate(45, fillcolor="white")
assert_image_equal_tofile(im, "Tests/images/rotate_45_with_fill.png") assert_image_equal_tofile(im, "Tests/images/rotate_45_with_fill.png")
def test_alpha_rotate_no_fill(): def test_alpha_rotate_no_fill() -> None:
# Alpha images are handled differently internally # Alpha images are handled differently internally
im = Image.new("RGBA", (10, 10), "green") im = Image.new("RGBA", (10, 10), "green")
im = im.rotate(45, expand=1) im = im.rotate(45, expand=1)
@ -142,7 +142,7 @@ def test_alpha_rotate_no_fill():
assert corner == (0, 0, 0, 0) assert corner == (0, 0, 0, 0)
def test_alpha_rotate_with_fill(): def test_alpha_rotate_with_fill() -> None:
# Alpha images are handled differently internally # Alpha images are handled differently internally
im = Image.new("RGBA", (10, 10), "green") im = Image.new("RGBA", (10, 10), "green")
im = im.rotate(45, expand=1, fillcolor=(255, 0, 0, 255)) im = im.rotate(45, expand=1, fillcolor=(255, 0, 0, 255))

View File

@ -14,14 +14,14 @@ from .helper import (
) )
def test_sanity(): def test_sanity() -> None:
im = hopper() im = hopper()
assert im.thumbnail((100, 100)) is None assert im.thumbnail((100, 100)) is None
assert im.size == (100, 100) assert im.size == (100, 100)
def test_aspect(): def test_aspect() -> None:
im = Image.new("L", (128, 128)) im = Image.new("L", (128, 128))
im.thumbnail((100, 100)) im.thumbnail((100, 100))
assert im.size == (100, 100) assert im.size == (100, 100)
@ -67,19 +67,19 @@ def test_aspect():
assert im.size == (75, 23) # ratio is 3.260869565217 assert im.size == (75, 23) # ratio is 3.260869565217
def test_division_by_zero(): def test_division_by_zero() -> None:
im = Image.new("L", (200, 2)) im = Image.new("L", (200, 2))
im.thumbnail((75, 75)) im.thumbnail((75, 75))
assert im.size == (75, 1) assert im.size == (75, 1)
def test_float(): def test_float() -> None:
im = Image.new("L", (128, 128)) im = Image.new("L", (128, 128))
im.thumbnail((99.9, 99.9)) im.thumbnail((99.9, 99.9))
assert im.size == (99, 99) assert im.size == (99, 99)
def test_no_resize(): def test_no_resize() -> None:
# Check that draft() can resize the image to the destination size # Check that draft() can resize the image to the destination size
with Image.open("Tests/images/hopper.jpg") as im: with Image.open("Tests/images/hopper.jpg") as im:
im.draft(None, (64, 64)) im.draft(None, (64, 64))
@ -92,7 +92,7 @@ def test_no_resize():
@skip_unless_feature("libtiff") @skip_unless_feature("libtiff")
def test_load_first(): def test_load_first() -> None:
# load() may change the size of the image # load() may change the size of the image
# Test that thumbnail() is calling it before performing size calculations # Test that thumbnail() is calling it before performing size calculations
with Image.open("Tests/images/g4_orientation_5.tif") as im: with Image.open("Tests/images/g4_orientation_5.tif") as im:
@ -106,7 +106,7 @@ def test_load_first():
assert im.size == (590, 88) assert im.size == (590, 88)
def test_load_first_unless_jpeg(): def test_load_first_unless_jpeg() -> None:
# Test that thumbnail() still uses draft() for JPEG # Test that thumbnail() still uses draft() for JPEG
with Image.open("Tests/images/hopper.jpg") as im: with Image.open("Tests/images/hopper.jpg") as im:
draft = im.draft draft = im.draft
@ -124,7 +124,7 @@ def test_load_first_unless_jpeg():
# valgrind test is failing with memory allocated in libjpeg # valgrind test is failing with memory allocated in libjpeg
@pytest.mark.valgrind_known_error(reason="Known Failing") @pytest.mark.valgrind_known_error(reason="Known Failing")
def test_DCT_scaling_edges(): def test_DCT_scaling_edges() -> None:
# Make an image with red borders and size (N * 8) + 1 to cross DCT grid # Make an image with red borders and size (N * 8) + 1 to cross DCT grid
im = Image.new("RGB", (257, 257), "red") im = Image.new("RGB", (257, 257), "red")
im.paste(Image.new("RGB", (235, 235)), (11, 11)) im.paste(Image.new("RGB", (235, 235)), (11, 11))
@ -138,7 +138,7 @@ def test_DCT_scaling_edges():
assert_image_similar(thumb, ref, 1.5) assert_image_similar(thumb, ref, 1.5)
def test_reducing_gap_values(): def test_reducing_gap_values() -> None:
im = hopper() im = hopper()
im.thumbnail((18, 18), Image.Resampling.BICUBIC) im.thumbnail((18, 18), Image.Resampling.BICUBIC)
@ -155,7 +155,7 @@ def test_reducing_gap_values():
assert_image_similar(ref, im, 3.5) assert_image_similar(ref, im, 3.5)
def test_reducing_gap_for_DCT_scaling(): def test_reducing_gap_for_DCT_scaling() -> None:
with Image.open("Tests/images/hopper.jpg") as ref: with Image.open("Tests/images/hopper.jpg") as ref:
# thumbnail should call draft with reducing_gap scale # thumbnail should call draft with reducing_gap scale
ref.draft(None, (18 * 3, 18 * 3)) ref.draft(None, (18 * 3, 18 * 3))

View File

@ -10,7 +10,7 @@ from .helper import assert_image_equal, assert_image_similar, hopper
class TestImageTransform: class TestImageTransform:
def test_sanity(self): def test_sanity(self) -> None:
im = hopper() im = hopper()
for transform in ( for transform in (
@ -31,7 +31,7 @@ class TestImageTransform:
): ):
assert_image_equal(im, im.transform(im.size, transform)) assert_image_equal(im, im.transform(im.size, transform))
def test_info(self): def test_info(self) -> None:
comment = b"File written by Adobe Photoshop\xa8 4.0" comment = b"File written by Adobe Photoshop\xa8 4.0"
with Image.open("Tests/images/hopper.gif") as im: with Image.open("Tests/images/hopper.gif") as im:
@ -41,14 +41,14 @@ class TestImageTransform:
new_im = im.transform((100, 100), transform) new_im = im.transform((100, 100), transform)
assert new_im.info["comment"] == comment assert new_im.info["comment"] == comment
def test_palette(self): def test_palette(self) -> None:
with Image.open("Tests/images/hopper.gif") as im: with Image.open("Tests/images/hopper.gif") as im:
transformed = im.transform( transformed = im.transform(
im.size, Image.Transform.AFFINE, [1, 0, 0, 0, 1, 0] im.size, Image.Transform.AFFINE, [1, 0, 0, 0, 1, 0]
) )
assert im.palette.palette == transformed.palette.palette assert im.palette.palette == transformed.palette.palette
def test_extent(self): def test_extent(self) -> None:
im = hopper("RGB") im = hopper("RGB")
(w, h) = im.size (w, h) = im.size
transformed = im.transform( transformed = im.transform(
@ -63,7 +63,7 @@ class TestImageTransform:
# undone -- precision? # undone -- precision?
assert_image_similar(transformed, scaled, 23) assert_image_similar(transformed, scaled, 23)
def test_quad(self): def test_quad(self) -> None:
# one simple quad transform, equivalent to scale & crop upper left quad # one simple quad transform, equivalent to scale & crop upper left quad
im = hopper("RGB") im = hopper("RGB")
(w, h) = im.size (w, h) = im.size
@ -91,7 +91,7 @@ class TestImageTransform:
("LA", (76, 0)), ("LA", (76, 0)),
), ),
) )
def test_fill(self, mode, expected_pixel): def test_fill(self, mode, expected_pixel) -> None:
im = hopper(mode) im = hopper(mode)
(w, h) = im.size (w, h) = im.size
transformed = im.transform( transformed = im.transform(
@ -103,7 +103,7 @@ class TestImageTransform:
) )
assert transformed.getpixel((w - 1, h - 1)) == expected_pixel assert transformed.getpixel((w - 1, h - 1)) == expected_pixel
def test_mesh(self): def test_mesh(self) -> None:
# this should be a checkerboard of halfsized hoppers in ul, lr # this should be a checkerboard of halfsized hoppers in ul, lr
im = hopper("RGBA") im = hopper("RGBA")
(w, h) = im.size (w, h) = im.size
@ -142,7 +142,7 @@ class TestImageTransform:
assert_image_equal(blank, transformed.crop((w // 2, 0, w, h // 2))) assert_image_equal(blank, transformed.crop((w // 2, 0, w, h // 2)))
assert_image_equal(blank, transformed.crop((0, h // 2, w // 2, h))) assert_image_equal(blank, transformed.crop((0, h // 2, w // 2, h)))
def _test_alpha_premult(self, op): def _test_alpha_premult(self, op) -> None:
# create image with half white, half black, # create image with half white, half black,
# with the black half transparent. # with the black half transparent.
# do op, # do op,
@ -158,13 +158,13 @@ class TestImageTransform:
hist = im_background.histogram() hist = im_background.histogram()
assert 40 * 10 == hist[-1] assert 40 * 10 == hist[-1]
def test_alpha_premult_resize(self): def test_alpha_premult_resize(self) -> None:
def op(im, sz): def op(im, sz):
return im.resize(sz, Image.Resampling.BILINEAR) return im.resize(sz, Image.Resampling.BILINEAR)
self._test_alpha_premult(op) self._test_alpha_premult(op)
def test_alpha_premult_transform(self): def test_alpha_premult_transform(self) -> None:
def op(im, sz): def op(im, sz):
(w, h) = im.size (w, h) = im.size
return im.transform( return im.transform(
@ -173,7 +173,7 @@ class TestImageTransform:
self._test_alpha_premult(op) self._test_alpha_premult(op)
def _test_nearest(self, op, mode): def _test_nearest(self, op, mode) -> None:
# create white image with half transparent, # create white image with half transparent,
# do op, # do op,
# the image should remain white with half transparent # the image should remain white with half transparent
@ -196,14 +196,14 @@ class TestImageTransform:
) )
@pytest.mark.parametrize("mode", ("RGBA", "LA")) @pytest.mark.parametrize("mode", ("RGBA", "LA"))
def test_nearest_resize(self, mode): def test_nearest_resize(self, mode) -> None:
def op(im, sz): def op(im, sz):
return im.resize(sz, Image.Resampling.NEAREST) return im.resize(sz, Image.Resampling.NEAREST)
self._test_nearest(op, mode) self._test_nearest(op, mode)
@pytest.mark.parametrize("mode", ("RGBA", "LA")) @pytest.mark.parametrize("mode", ("RGBA", "LA"))
def test_nearest_transform(self, mode): def test_nearest_transform(self, mode) -> None:
def op(im, sz): def op(im, sz):
(w, h) = im.size (w, h) = im.size
return im.transform( return im.transform(
@ -212,7 +212,7 @@ class TestImageTransform:
self._test_nearest(op, mode) self._test_nearest(op, mode)
def test_blank_fill(self): def test_blank_fill(self) -> None:
# attempting to hit # attempting to hit
# https://github.com/python-pillow/Pillow/issues/254 reported # https://github.com/python-pillow/Pillow/issues/254 reported
# #
@ -234,13 +234,13 @@ class TestImageTransform:
self.test_mesh() self.test_mesh()
def test_missing_method_data(self): def test_missing_method_data(self) -> None:
with hopper() as im: with hopper() as im:
with pytest.raises(ValueError): with pytest.raises(ValueError):
im.transform((100, 100), None) im.transform((100, 100), None)
@pytest.mark.parametrize("resample", (Image.Resampling.BOX, "unknown")) @pytest.mark.parametrize("resample", (Image.Resampling.BOX, "unknown"))
def test_unknown_resampling_filter(self, resample): def test_unknown_resampling_filter(self, resample) -> None:
with hopper() as im: with hopper() as im:
(w, h) = im.size (w, h) = im.size
with pytest.raises(ValueError): with pytest.raises(ValueError):
@ -263,7 +263,7 @@ class TestImageTransformAffine:
(270, Image.Transpose.ROTATE_270), (270, Image.Transpose.ROTATE_270),
), ),
) )
def test_rotate(self, deg, transpose): def test_rotate(self, deg, transpose) -> None:
im = self._test_image() im = self._test_image()
angle = -math.radians(deg) angle = -math.radians(deg)
@ -313,7 +313,7 @@ class TestImageTransformAffine:
(Image.Resampling.BICUBIC, 1), (Image.Resampling.BICUBIC, 1),
), ),
) )
def test_resize(self, scale, epsilon_scale, resample, epsilon): def test_resize(self, scale, epsilon_scale, resample, epsilon) -> None:
im = self._test_image() im = self._test_image()
size_up = int(round(im.width * scale)), int(round(im.height * scale)) size_up = int(round(im.width * scale)), int(round(im.height * scale))
@ -342,7 +342,7 @@ class TestImageTransformAffine:
(Image.Resampling.BICUBIC, 1), (Image.Resampling.BICUBIC, 1),
), ),
) )
def test_translate(self, x, y, epsilon_scale, resample, epsilon): def test_translate(self, x, y, epsilon_scale, resample, epsilon) -> None:
im = self._test_image() im = self._test_image()
size_up = int(round(im.width + x)), int(round(im.height + y)) size_up = int(round(im.width + x)), int(round(im.height + y))

View File

@ -15,7 +15,7 @@ WHITE = (255, 255, 255)
GRAY = 128 GRAY = 128
def test_sanity(): def test_sanity() -> None:
im = hopper("L") im = hopper("L")
ImageChops.constant(im, 128) ImageChops.constant(im, 128)
@ -48,7 +48,7 @@ def test_sanity():
ImageChops.offset(im, 10, 20) ImageChops.offset(im, 10, 20)
def test_add(): def test_add() -> None:
# Arrange # Arrange
with Image.open("Tests/images/imagedraw_ellipse_RGB.png") as im1: with Image.open("Tests/images/imagedraw_ellipse_RGB.png") as im1:
with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im2: with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im2:
@ -60,7 +60,7 @@ def test_add():
assert new.getpixel((50, 50)) == ORANGE assert new.getpixel((50, 50)) == ORANGE
def test_add_scale_offset(): def test_add_scale_offset() -> None:
# Arrange # Arrange
with Image.open("Tests/images/imagedraw_ellipse_RGB.png") as im1: with Image.open("Tests/images/imagedraw_ellipse_RGB.png") as im1:
with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im2: with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im2:
@ -72,7 +72,7 @@ def test_add_scale_offset():
assert new.getpixel((50, 50)) == (202, 151, 100) assert new.getpixel((50, 50)) == (202, 151, 100)
def test_add_clip(): def test_add_clip() -> None:
# Arrange # Arrange
im = hopper() im = hopper()
@ -83,7 +83,7 @@ def test_add_clip():
assert new.getpixel((50, 50)) == (255, 255, 254) assert new.getpixel((50, 50)) == (255, 255, 254)
def test_add_modulo(): def test_add_modulo() -> None:
# Arrange # Arrange
with Image.open("Tests/images/imagedraw_ellipse_RGB.png") as im1: with Image.open("Tests/images/imagedraw_ellipse_RGB.png") as im1:
with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im2: with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im2:
@ -95,7 +95,7 @@ def test_add_modulo():
assert new.getpixel((50, 50)) == ORANGE assert new.getpixel((50, 50)) == ORANGE
def test_add_modulo_no_clip(): def test_add_modulo_no_clip() -> None:
# Arrange # Arrange
im = hopper() im = hopper()
@ -106,7 +106,7 @@ def test_add_modulo_no_clip():
assert new.getpixel((50, 50)) == (224, 76, 254) assert new.getpixel((50, 50)) == (224, 76, 254)
def test_blend(): def test_blend() -> None:
# Arrange # Arrange
with Image.open("Tests/images/imagedraw_ellipse_RGB.png") as im1: with Image.open("Tests/images/imagedraw_ellipse_RGB.png") as im1:
with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im2: with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im2:
@ -118,7 +118,7 @@ def test_blend():
assert new.getpixel((50, 50)) == BROWN assert new.getpixel((50, 50)) == BROWN
def test_constant(): def test_constant() -> None:
# Arrange # Arrange
im = Image.new("RGB", (20, 10)) im = Image.new("RGB", (20, 10))
@ -131,7 +131,7 @@ def test_constant():
assert new.getpixel((19, 9)) == GRAY assert new.getpixel((19, 9)) == GRAY
def test_darker_image(): def test_darker_image() -> None:
# Arrange # Arrange
with Image.open("Tests/images/imagedraw_chord_RGB.png") as im1: with Image.open("Tests/images/imagedraw_chord_RGB.png") as im1:
with Image.open("Tests/images/imagedraw_outline_chord_RGB.png") as im2: with Image.open("Tests/images/imagedraw_outline_chord_RGB.png") as im2:
@ -142,7 +142,7 @@ def test_darker_image():
assert_image_equal(new, im2) assert_image_equal(new, im2)
def test_darker_pixel(): def test_darker_pixel() -> None:
# Arrange # Arrange
im1 = hopper() im1 = hopper()
with Image.open("Tests/images/imagedraw_chord_RGB.png") as im2: with Image.open("Tests/images/imagedraw_chord_RGB.png") as im2:
@ -153,7 +153,7 @@ def test_darker_pixel():
assert new.getpixel((50, 50)) == (240, 166, 0) assert new.getpixel((50, 50)) == (240, 166, 0)
def test_difference(): def test_difference() -> None:
# Arrange # Arrange
with Image.open("Tests/images/imagedraw_arc_end_le_start.png") as im1: with Image.open("Tests/images/imagedraw_arc_end_le_start.png") as im1:
with Image.open("Tests/images/imagedraw_arc_no_loops.png") as im2: with Image.open("Tests/images/imagedraw_arc_no_loops.png") as im2:
@ -164,7 +164,7 @@ def test_difference():
assert new.getbbox() == (25, 25, 76, 76) assert new.getbbox() == (25, 25, 76, 76)
def test_difference_pixel(): def test_difference_pixel() -> None:
# Arrange # Arrange
im1 = hopper() im1 = hopper()
with Image.open("Tests/images/imagedraw_polygon_kite_RGB.png") as im2: with Image.open("Tests/images/imagedraw_polygon_kite_RGB.png") as im2:
@ -175,7 +175,7 @@ def test_difference_pixel():
assert new.getpixel((50, 50)) == (240, 166, 128) assert new.getpixel((50, 50)) == (240, 166, 128)
def test_duplicate(): def test_duplicate() -> None:
# Arrange # Arrange
im = hopper() im = hopper()
@ -186,7 +186,7 @@ def test_duplicate():
assert_image_equal(new, im) assert_image_equal(new, im)
def test_invert(): def test_invert() -> None:
# Arrange # Arrange
with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im: with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im:
# Act # Act
@ -198,7 +198,7 @@ def test_invert():
assert new.getpixel((50, 50)) == CYAN assert new.getpixel((50, 50)) == CYAN
def test_lighter_image(): def test_lighter_image() -> None:
# Arrange # Arrange
with Image.open("Tests/images/imagedraw_chord_RGB.png") as im1: with Image.open("Tests/images/imagedraw_chord_RGB.png") as im1:
with Image.open("Tests/images/imagedraw_outline_chord_RGB.png") as im2: with Image.open("Tests/images/imagedraw_outline_chord_RGB.png") as im2:
@ -209,7 +209,7 @@ def test_lighter_image():
assert_image_equal(new, im1) assert_image_equal(new, im1)
def test_lighter_pixel(): def test_lighter_pixel() -> None:
# Arrange # Arrange
im1 = hopper() im1 = hopper()
with Image.open("Tests/images/imagedraw_chord_RGB.png") as im2: with Image.open("Tests/images/imagedraw_chord_RGB.png") as im2:
@ -220,7 +220,7 @@ def test_lighter_pixel():
assert new.getpixel((50, 50)) == (255, 255, 127) assert new.getpixel((50, 50)) == (255, 255, 127)
def test_multiply_black(): def test_multiply_black() -> None:
"""If you multiply an image with a solid black image, """If you multiply an image with a solid black image,
the result is black.""" the result is black."""
# Arrange # Arrange
@ -234,7 +234,7 @@ def test_multiply_black():
assert_image_equal(new, black) assert_image_equal(new, black)
def test_multiply_green(): def test_multiply_green() -> None:
# Arrange # Arrange
with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im: with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im:
green = Image.new("RGB", im.size, "green") green = Image.new("RGB", im.size, "green")
@ -248,7 +248,7 @@ def test_multiply_green():
assert new.getpixel((50, 50)) == BLACK assert new.getpixel((50, 50)) == BLACK
def test_multiply_white(): def test_multiply_white() -> None:
"""If you multiply with a solid white image, the image is unaffected.""" """If you multiply with a solid white image, the image is unaffected."""
# Arrange # Arrange
im1 = hopper() im1 = hopper()
@ -261,7 +261,7 @@ def test_multiply_white():
assert_image_equal(new, im1) assert_image_equal(new, im1)
def test_offset(): def test_offset() -> None:
# Arrange # Arrange
xoffset = 45 xoffset = 45
yoffset = 20 yoffset = 20
@ -278,7 +278,7 @@ def test_offset():
assert ImageChops.offset(im, xoffset) == ImageChops.offset(im, xoffset, xoffset) assert ImageChops.offset(im, xoffset) == ImageChops.offset(im, xoffset, xoffset)
def test_screen(): def test_screen() -> None:
# Arrange # Arrange
with Image.open("Tests/images/imagedraw_ellipse_RGB.png") as im1: with Image.open("Tests/images/imagedraw_ellipse_RGB.png") as im1:
with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im2: with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im2:
@ -290,7 +290,7 @@ def test_screen():
assert new.getpixel((50, 50)) == ORANGE assert new.getpixel((50, 50)) == ORANGE
def test_subtract(): def test_subtract() -> None:
# Arrange # Arrange
with Image.open("Tests/images/imagedraw_chord_RGB.png") as im1: with Image.open("Tests/images/imagedraw_chord_RGB.png") as im1:
with Image.open("Tests/images/imagedraw_outline_chord_RGB.png") as im2: with Image.open("Tests/images/imagedraw_outline_chord_RGB.png") as im2:
@ -303,7 +303,7 @@ def test_subtract():
assert new.getpixel((50, 52)) == BLACK assert new.getpixel((50, 52)) == BLACK
def test_subtract_scale_offset(): def test_subtract_scale_offset() -> None:
# Arrange # Arrange
with Image.open("Tests/images/imagedraw_chord_RGB.png") as im1: with Image.open("Tests/images/imagedraw_chord_RGB.png") as im1:
with Image.open("Tests/images/imagedraw_outline_chord_RGB.png") as im2: with Image.open("Tests/images/imagedraw_outline_chord_RGB.png") as im2:
@ -315,7 +315,7 @@ def test_subtract_scale_offset():
assert new.getpixel((50, 50)) == (100, 202, 100) assert new.getpixel((50, 50)) == (100, 202, 100)
def test_subtract_clip(): def test_subtract_clip() -> None:
# Arrange # Arrange
im1 = hopper() im1 = hopper()
with Image.open("Tests/images/imagedraw_chord_RGB.png") as im2: with Image.open("Tests/images/imagedraw_chord_RGB.png") as im2:
@ -326,7 +326,7 @@ def test_subtract_clip():
assert new.getpixel((50, 50)) == (0, 0, 127) assert new.getpixel((50, 50)) == (0, 0, 127)
def test_subtract_modulo(): def test_subtract_modulo() -> None:
# Arrange # Arrange
with Image.open("Tests/images/imagedraw_chord_RGB.png") as im1: with Image.open("Tests/images/imagedraw_chord_RGB.png") as im1:
with Image.open("Tests/images/imagedraw_outline_chord_RGB.png") as im2: with Image.open("Tests/images/imagedraw_outline_chord_RGB.png") as im2:
@ -339,7 +339,7 @@ def test_subtract_modulo():
assert new.getpixel((50, 52)) == BLACK assert new.getpixel((50, 52)) == BLACK
def test_subtract_modulo_no_clip(): def test_subtract_modulo_no_clip() -> None:
# Arrange # Arrange
im1 = hopper() im1 = hopper()
with Image.open("Tests/images/imagedraw_chord_RGB.png") as im2: with Image.open("Tests/images/imagedraw_chord_RGB.png") as im2:
@ -350,7 +350,7 @@ def test_subtract_modulo_no_clip():
assert new.getpixel((50, 50)) == (241, 167, 127) assert new.getpixel((50, 50)) == (241, 167, 127)
def test_soft_light(): def test_soft_light() -> None:
# Arrange # Arrange
with Image.open("Tests/images/hopper.png") as im1: with Image.open("Tests/images/hopper.png") as im1:
with Image.open("Tests/images/hopper-XYZ.png") as im2: with Image.open("Tests/images/hopper-XYZ.png") as im2:
@ -362,7 +362,7 @@ def test_soft_light():
assert new.getpixel((15, 100)) == (1, 1, 3) assert new.getpixel((15, 100)) == (1, 1, 3)
def test_hard_light(): def test_hard_light() -> None:
# Arrange # Arrange
with Image.open("Tests/images/hopper.png") as im1: with Image.open("Tests/images/hopper.png") as im1:
with Image.open("Tests/images/hopper-XYZ.png") as im2: with Image.open("Tests/images/hopper-XYZ.png") as im2:
@ -374,7 +374,7 @@ def test_hard_light():
assert new.getpixel((15, 100)) == (1, 1, 2) assert new.getpixel((15, 100)) == (1, 1, 2)
def test_overlay(): def test_overlay() -> None:
# Arrange # Arrange
with Image.open("Tests/images/hopper.png") as im1: with Image.open("Tests/images/hopper.png") as im1:
with Image.open("Tests/images/hopper-XYZ.png") as im2: with Image.open("Tests/images/hopper-XYZ.png") as im2:
@ -386,7 +386,7 @@ def test_overlay():
assert new.getpixel((15, 100)) == (1, 1, 2) assert new.getpixel((15, 100)) == (1, 1, 2)
def test_logical(): def test_logical() -> None:
def table(op, a, b): def table(op, a, b):
out = [] out = []
for x in (a, b): for x in (a, b):

View File

@ -5,6 +5,7 @@ import os
import re import re
import shutil import shutil
from io import BytesIO from io import BytesIO
from pathlib import Path
import pytest import pytest
@ -32,7 +33,7 @@ SRGB = "Tests/icc/sRGB_IEC61966-2-1_black_scaled.icc"
HAVE_PROFILE = os.path.exists(SRGB) HAVE_PROFILE = os.path.exists(SRGB)
def setup_module(): def setup_module() -> None:
try: try:
from PIL import ImageCms from PIL import ImageCms
@ -42,12 +43,12 @@ def setup_module():
pytest.skip(str(v)) pytest.skip(str(v))
def skip_missing(): def skip_missing() -> None:
if not HAVE_PROFILE: if not HAVE_PROFILE:
pytest.skip("SRGB profile not available") pytest.skip("SRGB profile not available")
def test_sanity(): def test_sanity() -> None:
# basic smoke test. # basic smoke test.
# this mostly follows the cms_test outline. # this mostly follows the cms_test outline.
with pytest.warns(DeprecationWarning): with pytest.warns(DeprecationWarning):
@ -91,7 +92,7 @@ def test_sanity():
hopper().point(t) hopper().point(t)
def test_flags(): def test_flags() -> None:
assert ImageCms.Flags.NONE == 0 assert ImageCms.Flags.NONE == 0
assert ImageCms.Flags.GRIDPOINTS(0) == ImageCms.Flags.NONE assert ImageCms.Flags.GRIDPOINTS(0) == ImageCms.Flags.NONE
assert ImageCms.Flags.GRIDPOINTS(256) == ImageCms.Flags.NONE assert ImageCms.Flags.GRIDPOINTS(256) == ImageCms.Flags.NONE
@ -101,7 +102,7 @@ def test_flags():
assert ImageCms.Flags.GRIDPOINTS(511) == ImageCms.Flags.GRIDPOINTS(255) assert ImageCms.Flags.GRIDPOINTS(511) == ImageCms.Flags.GRIDPOINTS(255)
def test_name(): def test_name() -> None:
skip_missing() skip_missing()
# get profile information for file # get profile information for file
assert ( assert (
@ -110,7 +111,7 @@ def test_name():
) )
def test_info(): def test_info() -> None:
skip_missing() skip_missing()
assert ImageCms.getProfileInfo(SRGB).splitlines() == [ assert ImageCms.getProfileInfo(SRGB).splitlines() == [
"sRGB IEC61966-2-1 black scaled", "sRGB IEC61966-2-1 black scaled",
@ -120,7 +121,7 @@ def test_info():
] ]
def test_copyright(): def test_copyright() -> None:
skip_missing() skip_missing()
assert ( assert (
ImageCms.getProfileCopyright(SRGB).strip() ImageCms.getProfileCopyright(SRGB).strip()
@ -128,12 +129,12 @@ def test_copyright():
) )
def test_manufacturer(): def test_manufacturer() -> None:
skip_missing() skip_missing()
assert ImageCms.getProfileManufacturer(SRGB).strip() == "" assert ImageCms.getProfileManufacturer(SRGB).strip() == ""
def test_model(): def test_model() -> None:
skip_missing() skip_missing()
assert ( assert (
ImageCms.getProfileModel(SRGB).strip() ImageCms.getProfileModel(SRGB).strip()
@ -141,14 +142,14 @@ def test_model():
) )
def test_description(): def test_description() -> None:
skip_missing() skip_missing()
assert ( assert (
ImageCms.getProfileDescription(SRGB).strip() == "sRGB IEC61966-2-1 black scaled" ImageCms.getProfileDescription(SRGB).strip() == "sRGB IEC61966-2-1 black scaled"
) )
def test_intent(): def test_intent() -> None:
skip_missing() skip_missing()
assert ImageCms.getDefaultIntent(SRGB) == 0 assert ImageCms.getDefaultIntent(SRGB) == 0
support = ImageCms.isIntentSupported( support = ImageCms.isIntentSupported(
@ -157,7 +158,7 @@ def test_intent():
assert support == 1 assert support == 1
def test_profile_object(): def test_profile_object() -> None:
# same, using profile object # same, using profile object
p = ImageCms.createProfile("sRGB") p = ImageCms.createProfile("sRGB")
# assert ImageCms.getProfileName(p).strip() == "sRGB built-in - (lcms internal)" # assert ImageCms.getProfileName(p).strip() == "sRGB built-in - (lcms internal)"
@ -170,7 +171,7 @@ def test_profile_object():
assert support == 1 assert support == 1
def test_extensions(): def test_extensions() -> None:
# extensions # extensions
with Image.open("Tests/images/rgb.jpg") as i: with Image.open("Tests/images/rgb.jpg") as i:
@ -181,7 +182,7 @@ def test_extensions():
) )
def test_exceptions(): def test_exceptions() -> None:
# Test mode mismatch # Test mode mismatch
psRGB = ImageCms.createProfile("sRGB") psRGB = ImageCms.createProfile("sRGB")
pLab = ImageCms.createProfile("LAB") pLab = ImageCms.createProfile("LAB")
@ -207,17 +208,17 @@ def test_exceptions():
ImageCms.isIntentSupported(SRGB, None, None) ImageCms.isIntentSupported(SRGB, None, None)
def test_display_profile(): def test_display_profile() -> None:
# try fetching the profile for the current display device # try fetching the profile for the current display device
ImageCms.get_display_profile() ImageCms.get_display_profile()
def test_lab_color_profile(): def test_lab_color_profile() -> None:
ImageCms.createProfile("LAB", 5000) ImageCms.createProfile("LAB", 5000)
ImageCms.createProfile("LAB", 6500) ImageCms.createProfile("LAB", 6500)
def test_unsupported_color_space(): def test_unsupported_color_space() -> None:
with pytest.raises( with pytest.raises(
ImageCms.PyCMSError, ImageCms.PyCMSError,
match=re.escape( match=re.escape(
@ -227,7 +228,7 @@ def test_unsupported_color_space():
ImageCms.createProfile("unsupported") ImageCms.createProfile("unsupported")
def test_invalid_color_temperature(): def test_invalid_color_temperature() -> None:
with pytest.raises( with pytest.raises(
ImageCms.PyCMSError, ImageCms.PyCMSError,
match='Color temperature must be numeric, "invalid" not valid', match='Color temperature must be numeric, "invalid" not valid',
@ -236,7 +237,7 @@ def test_invalid_color_temperature():
@pytest.mark.parametrize("flag", ("my string", -1)) @pytest.mark.parametrize("flag", ("my string", -1))
def test_invalid_flag(flag): def test_invalid_flag(flag) -> None:
with hopper() as im: with hopper() as im:
with pytest.raises( with pytest.raises(
ImageCms.PyCMSError, match="flags must be an integer between 0 and " ImageCms.PyCMSError, match="flags must be an integer between 0 and "
@ -244,7 +245,7 @@ def test_invalid_flag(flag):
ImageCms.profileToProfile(im, "foo", "bar", flags=flag) ImageCms.profileToProfile(im, "foo", "bar", flags=flag)
def test_simple_lab(): def test_simple_lab() -> None:
i = Image.new("RGB", (10, 10), (128, 128, 128)) i = Image.new("RGB", (10, 10), (128, 128, 128))
psRGB = ImageCms.createProfile("sRGB") psRGB = ImageCms.createProfile("sRGB")
@ -268,7 +269,7 @@ def test_simple_lab():
assert list(b_data) == [128] * 100 assert list(b_data) == [128] * 100
def test_lab_color(): def test_lab_color() -> None:
psRGB = ImageCms.createProfile("sRGB") psRGB = ImageCms.createProfile("sRGB")
pLab = ImageCms.createProfile("LAB") pLab = ImageCms.createProfile("LAB")
t = ImageCms.buildTransform(psRGB, pLab, "RGB", "LAB") t = ImageCms.buildTransform(psRGB, pLab, "RGB", "LAB")
@ -283,7 +284,7 @@ def test_lab_color():
assert_image_similar_tofile(i, "Tests/images/hopper.Lab.tif", 3.5) assert_image_similar_tofile(i, "Tests/images/hopper.Lab.tif", 3.5)
def test_lab_srgb(): def test_lab_srgb() -> None:
psRGB = ImageCms.createProfile("sRGB") psRGB = ImageCms.createProfile("sRGB")
pLab = ImageCms.createProfile("LAB") pLab = ImageCms.createProfile("LAB")
t = ImageCms.buildTransform(pLab, psRGB, "LAB", "RGB") t = ImageCms.buildTransform(pLab, psRGB, "LAB", "RGB")
@ -300,7 +301,7 @@ def test_lab_srgb():
assert "sRGB" in ImageCms.getProfileDescription(profile) assert "sRGB" in ImageCms.getProfileDescription(profile)
def test_lab_roundtrip(): def test_lab_roundtrip() -> None:
# check to see if we're at least internally consistent. # check to see if we're at least internally consistent.
psRGB = ImageCms.createProfile("sRGB") psRGB = ImageCms.createProfile("sRGB")
pLab = ImageCms.createProfile("LAB") pLab = ImageCms.createProfile("LAB")
@ -317,7 +318,7 @@ def test_lab_roundtrip():
assert_image_similar(hopper(), out, 2) assert_image_similar(hopper(), out, 2)
def test_profile_tobytes(): def test_profile_tobytes() -> None:
with Image.open("Tests/images/rgb.jpg") as i: with Image.open("Tests/images/rgb.jpg") as i:
p = ImageCms.getOpenProfile(BytesIO(i.info["icc_profile"])) p = ImageCms.getOpenProfile(BytesIO(i.info["icc_profile"]))
@ -329,12 +330,12 @@ def test_profile_tobytes():
assert ImageCms.getProfileDescription(p) == ImageCms.getProfileDescription(p2) assert ImageCms.getProfileDescription(p) == ImageCms.getProfileDescription(p2)
def test_extended_information(): def test_extended_information() -> None:
skip_missing() skip_missing()
o = ImageCms.getOpenProfile(SRGB) o = ImageCms.getOpenProfile(SRGB)
p = o.profile p = o.profile
def assert_truncated_tuple_equal(tup1, tup2, digits=10): def assert_truncated_tuple_equal(tup1, tup2, digits: int = 10) -> None:
# Helper function to reduce precision of tuples of floats # Helper function to reduce precision of tuples of floats
# recursively and then check equality. # recursively and then check equality.
power = 10**digits power = 10**digits
@ -476,7 +477,7 @@ def test_extended_information():
assert p.xcolor_space == "RGB " assert p.xcolor_space == "RGB "
def test_non_ascii_path(tmp_path): def test_non_ascii_path(tmp_path: Path) -> None:
skip_missing() skip_missing()
tempfile = str(tmp_path / ("temp_" + chr(128) + ".icc")) tempfile = str(tmp_path / ("temp_" + chr(128) + ".icc"))
try: try:
@ -489,7 +490,7 @@ def test_non_ascii_path(tmp_path):
assert p.model == "IEC 61966-2-1 Default RGB Colour Space - sRGB" assert p.model == "IEC 61966-2-1 Default RGB Colour Space - sRGB"
def test_profile_typesafety(): def test_profile_typesafety() -> None:
"""Profile init type safety """Profile init type safety
prepatch, these would segfault, postpatch they should emit a typeerror prepatch, these would segfault, postpatch they should emit a typeerror
@ -501,7 +502,7 @@ def test_profile_typesafety():
ImageCms.ImageCmsProfile(1).tobytes() ImageCms.ImageCmsProfile(1).tobytes()
def assert_aux_channel_preserved(mode, transform_in_place, preserved_channel): def assert_aux_channel_preserved(mode, transform_in_place, preserved_channel) -> None:
def create_test_image(): def create_test_image():
# set up test image with something interesting in the tested aux channel. # set up test image with something interesting in the tested aux channel.
# fmt: off # fmt: off
@ -556,31 +557,31 @@ def assert_aux_channel_preserved(mode, transform_in_place, preserved_channel):
assert_image_equal(source_image_aux, result_image_aux) assert_image_equal(source_image_aux, result_image_aux)
def test_preserve_auxiliary_channels_rgba(): def test_preserve_auxiliary_channels_rgba() -> None:
assert_aux_channel_preserved( assert_aux_channel_preserved(
mode="RGBA", transform_in_place=False, preserved_channel="A" mode="RGBA", transform_in_place=False, preserved_channel="A"
) )
def test_preserve_auxiliary_channels_rgba_in_place(): def test_preserve_auxiliary_channels_rgba_in_place() -> None:
assert_aux_channel_preserved( assert_aux_channel_preserved(
mode="RGBA", transform_in_place=True, preserved_channel="A" mode="RGBA", transform_in_place=True, preserved_channel="A"
) )
def test_preserve_auxiliary_channels_rgbx(): def test_preserve_auxiliary_channels_rgbx() -> None:
assert_aux_channel_preserved( assert_aux_channel_preserved(
mode="RGBX", transform_in_place=False, preserved_channel="X" mode="RGBX", transform_in_place=False, preserved_channel="X"
) )
def test_preserve_auxiliary_channels_rgbx_in_place(): def test_preserve_auxiliary_channels_rgbx_in_place() -> None:
assert_aux_channel_preserved( assert_aux_channel_preserved(
mode="RGBX", transform_in_place=True, preserved_channel="X" mode="RGBX", transform_in_place=True, preserved_channel="X"
) )
def test_auxiliary_channels_isolated(): def test_auxiliary_channels_isolated() -> None:
# test data in aux channels does not affect non-aux channels # test data in aux channels does not affect non-aux channels
aux_channel_formats = [ aux_channel_formats = [
# format, profile, color-only format, source test image # format, profile, color-only format, source test image
@ -630,7 +631,7 @@ def test_auxiliary_channels_isolated():
@pytest.mark.parametrize("mode", ("RGB", "RGBA", "RGBX")) @pytest.mark.parametrize("mode", ("RGB", "RGBA", "RGBX"))
def test_rgb_lab(mode): def test_rgb_lab(mode) -> None:
im = Image.new(mode, (1, 1)) im = Image.new(mode, (1, 1))
converted_im = im.convert("LAB") converted_im = im.convert("LAB")
assert converted_im.getpixel((0, 0)) == (0, 128, 128) assert converted_im.getpixel((0, 0)) == (0, 128, 128)

View File

@ -5,7 +5,7 @@ import pytest
from PIL import Image, ImageColor from PIL import Image, ImageColor
def test_hash(): def test_hash() -> None:
# short 3 components # short 3 components
assert (255, 0, 0) == ImageColor.getrgb("#f00") assert (255, 0, 0) == ImageColor.getrgb("#f00")
assert (0, 255, 0) == ImageColor.getrgb("#0f0") assert (0, 255, 0) == ImageColor.getrgb("#0f0")
@ -57,7 +57,7 @@ def test_hash():
ImageColor.getrgb("#f00000 ") ImageColor.getrgb("#f00000 ")
def test_colormap(): def test_colormap() -> None:
assert (0, 0, 0) == ImageColor.getrgb("black") assert (0, 0, 0) == ImageColor.getrgb("black")
assert (255, 255, 255) == ImageColor.getrgb("white") assert (255, 255, 255) == ImageColor.getrgb("white")
assert (255, 255, 255) == ImageColor.getrgb("WHITE") assert (255, 255, 255) == ImageColor.getrgb("WHITE")
@ -66,7 +66,7 @@ def test_colormap():
ImageColor.getrgb("black ") ImageColor.getrgb("black ")
def test_functions(): def test_functions() -> None:
# rgb numbers # rgb numbers
assert (255, 0, 0) == ImageColor.getrgb("rgb(255,0,0)") assert (255, 0, 0) == ImageColor.getrgb("rgb(255,0,0)")
assert (0, 255, 0) == ImageColor.getrgb("rgb(0,255,0)") assert (0, 255, 0) == ImageColor.getrgb("rgb(0,255,0)")
@ -160,7 +160,7 @@ def test_functions():
# look for rounding errors (based on code by Tim Hatch) # look for rounding errors (based on code by Tim Hatch)
def test_rounding_errors(): def test_rounding_errors() -> None:
for color in ImageColor.colormap: for color in ImageColor.colormap:
expected = Image.new("RGB", (1, 1), color).convert("L").getpixel((0, 0)) expected = Image.new("RGB", (1, 1), color).convert("L").getpixel((0, 0))
actual = ImageColor.getcolor(color, "L") actual = ImageColor.getcolor(color, "L")
@ -195,11 +195,11 @@ def test_rounding_errors():
Image.new("LA", (1, 1), "white") Image.new("LA", (1, 1), "white")
def test_color_hsv(): def test_color_hsv() -> None:
assert (170, 255, 255) == ImageColor.getcolor("hsv(240, 100%, 100%)", "HSV") assert (170, 255, 255) == ImageColor.getcolor("hsv(240, 100%, 100%)", "HSV")
def test_color_too_long(): def test_color_too_long() -> None:
# Arrange # Arrange
color_too_long = "hsl(" + "1" * 40 + "," + "1" * 40 + "%," + "1" * 40 + "%)" color_too_long = "hsl(" + "1" * 40 + "," + "1" * 40 + "%," + "1" * 40 + "%)"

View File

@ -47,7 +47,7 @@ KITE_POINTS = (
) )
def test_sanity(): def test_sanity() -> None:
im = hopper("RGB").copy() im = hopper("RGB").copy()
draw = ImageDraw.ImageDraw(im) draw = ImageDraw.ImageDraw(im)
@ -59,13 +59,13 @@ def test_sanity():
draw.rectangle(list(range(4))) draw.rectangle(list(range(4)))
def test_valueerror(): def test_valueerror() -> None:
with Image.open("Tests/images/chi.gif") as im: with Image.open("Tests/images/chi.gif") as im:
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
draw.line((0, 0), fill=(0, 0, 0)) draw.line((0, 0), fill=(0, 0, 0))
def test_mode_mismatch(): def test_mode_mismatch() -> None:
im = hopper("RGB").copy() im = hopper("RGB").copy()
with pytest.raises(ValueError): with pytest.raises(ValueError):
@ -74,7 +74,7 @@ def test_mode_mismatch():
@pytest.mark.parametrize("bbox", BBOX) @pytest.mark.parametrize("bbox", BBOX)
@pytest.mark.parametrize("start, end", ((0, 180), (0.5, 180.4))) @pytest.mark.parametrize("start, end", ((0, 180), (0.5, 180.4)))
def test_arc(bbox, start, end): def test_arc(bbox, start, end) -> None:
# Arrange # Arrange
im = Image.new("RGB", (W, H)) im = Image.new("RGB", (W, H))
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
@ -87,7 +87,7 @@ def test_arc(bbox, start, end):
@pytest.mark.parametrize("bbox", BBOX) @pytest.mark.parametrize("bbox", BBOX)
def test_arc_end_le_start(bbox): def test_arc_end_le_start(bbox) -> None:
# Arrange # Arrange
im = Image.new("RGB", (W, H)) im = Image.new("RGB", (W, H))
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
@ -102,7 +102,7 @@ def test_arc_end_le_start(bbox):
@pytest.mark.parametrize("bbox", BBOX) @pytest.mark.parametrize("bbox", BBOX)
def test_arc_no_loops(bbox): def test_arc_no_loops(bbox) -> None:
# No need to go in loops # No need to go in loops
# Arrange # Arrange
im = Image.new("RGB", (W, H)) im = Image.new("RGB", (W, H))
@ -118,7 +118,7 @@ def test_arc_no_loops(bbox):
@pytest.mark.parametrize("bbox", BBOX) @pytest.mark.parametrize("bbox", BBOX)
def test_arc_width(bbox): def test_arc_width(bbox) -> None:
# Arrange # Arrange
im = Image.new("RGB", (W, H)) im = Image.new("RGB", (W, H))
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
@ -131,7 +131,7 @@ def test_arc_width(bbox):
@pytest.mark.parametrize("bbox", BBOX) @pytest.mark.parametrize("bbox", BBOX)
def test_arc_width_pieslice_large(bbox): def test_arc_width_pieslice_large(bbox) -> None:
# Tests an arc with a large enough width that it is a pieslice # Tests an arc with a large enough width that it is a pieslice
# Arrange # Arrange
im = Image.new("RGB", (W, H)) im = Image.new("RGB", (W, H))
@ -145,7 +145,7 @@ def test_arc_width_pieslice_large(bbox):
@pytest.mark.parametrize("bbox", BBOX) @pytest.mark.parametrize("bbox", BBOX)
def test_arc_width_fill(bbox): def test_arc_width_fill(bbox) -> None:
# Arrange # Arrange
im = Image.new("RGB", (W, H)) im = Image.new("RGB", (W, H))
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
@ -158,7 +158,7 @@ def test_arc_width_fill(bbox):
@pytest.mark.parametrize("bbox", BBOX) @pytest.mark.parametrize("bbox", BBOX)
def test_arc_width_non_whole_angle(bbox): def test_arc_width_non_whole_angle(bbox) -> None:
# Arrange # Arrange
im = Image.new("RGB", (W, H)) im = Image.new("RGB", (W, H))
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
@ -171,7 +171,7 @@ def test_arc_width_non_whole_angle(bbox):
assert_image_similar_tofile(im, expected, 1) assert_image_similar_tofile(im, expected, 1)
def test_arc_high(): def test_arc_high() -> None:
# Arrange # Arrange
im = Image.new("RGB", (200, 200)) im = Image.new("RGB", (200, 200))
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
@ -184,7 +184,7 @@ def test_arc_high():
assert_image_equal_tofile(im, "Tests/images/imagedraw_arc_high.png") assert_image_equal_tofile(im, "Tests/images/imagedraw_arc_high.png")
def test_bitmap(): def test_bitmap() -> None:
# Arrange # Arrange
im = Image.new("RGB", (W, H)) im = Image.new("RGB", (W, H))
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
@ -200,7 +200,7 @@ def test_bitmap():
@pytest.mark.parametrize("mode", ("RGB", "L")) @pytest.mark.parametrize("mode", ("RGB", "L"))
@pytest.mark.parametrize("bbox", BBOX) @pytest.mark.parametrize("bbox", BBOX)
def test_chord(mode, bbox): def test_chord(mode, bbox) -> None:
# Arrange # Arrange
im = Image.new(mode, (W, H)) im = Image.new(mode, (W, H))
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
@ -214,7 +214,7 @@ def test_chord(mode, bbox):
@pytest.mark.parametrize("bbox", BBOX) @pytest.mark.parametrize("bbox", BBOX)
def test_chord_width(bbox): def test_chord_width(bbox) -> None:
# Arrange # Arrange
im = Image.new("RGB", (W, H)) im = Image.new("RGB", (W, H))
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
@ -227,7 +227,7 @@ def test_chord_width(bbox):
@pytest.mark.parametrize("bbox", BBOX) @pytest.mark.parametrize("bbox", BBOX)
def test_chord_width_fill(bbox): def test_chord_width_fill(bbox) -> None:
# Arrange # Arrange
im = Image.new("RGB", (W, H)) im = Image.new("RGB", (W, H))
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
@ -240,7 +240,7 @@ def test_chord_width_fill(bbox):
@pytest.mark.parametrize("bbox", BBOX) @pytest.mark.parametrize("bbox", BBOX)
def test_chord_zero_width(bbox): def test_chord_zero_width(bbox) -> None:
# Arrange # Arrange
im = Image.new("RGB", (W, H)) im = Image.new("RGB", (W, H))
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
@ -252,7 +252,7 @@ def test_chord_zero_width(bbox):
assert_image_equal_tofile(im, "Tests/images/imagedraw_chord_zero_width.png") assert_image_equal_tofile(im, "Tests/images/imagedraw_chord_zero_width.png")
def test_chord_too_fat(): def test_chord_too_fat() -> None:
# Arrange # Arrange
im = Image.new("RGB", (100, 100)) im = Image.new("RGB", (100, 100))
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
@ -266,7 +266,7 @@ def test_chord_too_fat():
@pytest.mark.parametrize("mode", ("RGB", "L")) @pytest.mark.parametrize("mode", ("RGB", "L"))
@pytest.mark.parametrize("bbox", BBOX) @pytest.mark.parametrize("bbox", BBOX)
def test_ellipse(mode, bbox): def test_ellipse(mode, bbox) -> None:
# Arrange # Arrange
im = Image.new(mode, (W, H)) im = Image.new(mode, (W, H))
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
@ -280,7 +280,7 @@ def test_ellipse(mode, bbox):
@pytest.mark.parametrize("bbox", BBOX) @pytest.mark.parametrize("bbox", BBOX)
def test_ellipse_translucent(bbox): def test_ellipse_translucent(bbox) -> None:
# Arrange # Arrange
im = Image.new("RGB", (W, H)) im = Image.new("RGB", (W, H))
draw = ImageDraw.Draw(im, "RGBA") draw = ImageDraw.Draw(im, "RGBA")
@ -293,7 +293,7 @@ def test_ellipse_translucent(bbox):
assert_image_similar_tofile(im, expected, 1) assert_image_similar_tofile(im, expected, 1)
def test_ellipse_edge(): def test_ellipse_edge() -> None:
# Arrange # Arrange
im = Image.new("RGB", (W, H)) im = Image.new("RGB", (W, H))
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
@ -305,7 +305,7 @@ def test_ellipse_edge():
assert_image_similar_tofile(im, "Tests/images/imagedraw_ellipse_edge.png", 1) assert_image_similar_tofile(im, "Tests/images/imagedraw_ellipse_edge.png", 1)
def test_ellipse_symmetric(): def test_ellipse_symmetric() -> None:
for width, bbox in ( for width, bbox in (
(100, (24, 24, 75, 75)), (100, (24, 24, 75, 75)),
(101, (25, 25, 75, 75)), (101, (25, 25, 75, 75)),
@ -317,7 +317,7 @@ def test_ellipse_symmetric():
@pytest.mark.parametrize("bbox", BBOX) @pytest.mark.parametrize("bbox", BBOX)
def test_ellipse_width(bbox): def test_ellipse_width(bbox) -> None:
# Arrange # Arrange
im = Image.new("RGB", (W, H)) im = Image.new("RGB", (W, H))
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
@ -329,7 +329,7 @@ def test_ellipse_width(bbox):
assert_image_similar_tofile(im, "Tests/images/imagedraw_ellipse_width.png", 1) assert_image_similar_tofile(im, "Tests/images/imagedraw_ellipse_width.png", 1)
def test_ellipse_width_large(): def test_ellipse_width_large() -> None:
# Arrange # Arrange
im = Image.new("RGB", (500, 500)) im = Image.new("RGB", (500, 500))
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
@ -342,7 +342,7 @@ def test_ellipse_width_large():
@pytest.mark.parametrize("bbox", BBOX) @pytest.mark.parametrize("bbox", BBOX)
def test_ellipse_width_fill(bbox): def test_ellipse_width_fill(bbox) -> None:
# Arrange # Arrange
im = Image.new("RGB", (W, H)) im = Image.new("RGB", (W, H))
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
@ -355,7 +355,7 @@ def test_ellipse_width_fill(bbox):
@pytest.mark.parametrize("bbox", BBOX) @pytest.mark.parametrize("bbox", BBOX)
def test_ellipse_zero_width(bbox): def test_ellipse_zero_width(bbox) -> None:
# Arrange # Arrange
im = Image.new("RGB", (W, H)) im = Image.new("RGB", (W, H))
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
@ -394,13 +394,13 @@ def ellipse_various_sizes_helper(filled):
return im return im
def test_ellipse_various_sizes(): def test_ellipse_various_sizes() -> None:
im = ellipse_various_sizes_helper(False) im = ellipse_various_sizes_helper(False)
assert_image_equal_tofile(im, "Tests/images/imagedraw_ellipse_various_sizes.png") assert_image_equal_tofile(im, "Tests/images/imagedraw_ellipse_various_sizes.png")
def test_ellipse_various_sizes_filled(): def test_ellipse_various_sizes_filled() -> None:
im = ellipse_various_sizes_helper(True) im = ellipse_various_sizes_helper(True)
assert_image_equal_tofile( assert_image_equal_tofile(
@ -409,7 +409,7 @@ def test_ellipse_various_sizes_filled():
@pytest.mark.parametrize("points", POINTS) @pytest.mark.parametrize("points", POINTS)
def test_line(points): def test_line(points) -> None:
# Arrange # Arrange
im = Image.new("RGB", (W, H)) im = Image.new("RGB", (W, H))
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
@ -421,7 +421,7 @@ def test_line(points):
assert_image_equal_tofile(im, "Tests/images/imagedraw_line.png") assert_image_equal_tofile(im, "Tests/images/imagedraw_line.png")
def test_shape1(): def test_shape1() -> None:
# Arrange # Arrange
im = Image.new("RGB", (100, 100), "white") im = Image.new("RGB", (100, 100), "white")
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
@ -442,7 +442,7 @@ def test_shape1():
assert_image_equal_tofile(im, "Tests/images/imagedraw_shape1.png") assert_image_equal_tofile(im, "Tests/images/imagedraw_shape1.png")
def test_shape2(): def test_shape2() -> None:
# Arrange # Arrange
im = Image.new("RGB", (100, 100), "white") im = Image.new("RGB", (100, 100), "white")
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
@ -463,7 +463,7 @@ def test_shape2():
assert_image_equal_tofile(im, "Tests/images/imagedraw_shape2.png") assert_image_equal_tofile(im, "Tests/images/imagedraw_shape2.png")
def test_transform(): def test_transform() -> None:
# Arrange # Arrange
im = Image.new("RGB", (100, 100), "white") im = Image.new("RGB", (100, 100), "white")
expected = im.copy() expected = im.copy()
@ -482,7 +482,7 @@ def test_transform():
@pytest.mark.parametrize("bbox", BBOX) @pytest.mark.parametrize("bbox", BBOX)
@pytest.mark.parametrize("start, end", ((-92, 46), (-92.2, 46.2))) @pytest.mark.parametrize("start, end", ((-92, 46), (-92.2, 46.2)))
def test_pieslice(bbox, start, end): def test_pieslice(bbox, start, end) -> None:
# Arrange # Arrange
im = Image.new("RGB", (W, H)) im = Image.new("RGB", (W, H))
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
@ -495,7 +495,7 @@ def test_pieslice(bbox, start, end):
@pytest.mark.parametrize("bbox", BBOX) @pytest.mark.parametrize("bbox", BBOX)
def test_pieslice_width(bbox): def test_pieslice_width(bbox) -> None:
# Arrange # Arrange
im = Image.new("RGB", (W, H)) im = Image.new("RGB", (W, H))
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
@ -508,7 +508,7 @@ def test_pieslice_width(bbox):
@pytest.mark.parametrize("bbox", BBOX) @pytest.mark.parametrize("bbox", BBOX)
def test_pieslice_width_fill(bbox): def test_pieslice_width_fill(bbox) -> None:
# Arrange # Arrange
im = Image.new("RGB", (W, H)) im = Image.new("RGB", (W, H))
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
@ -522,7 +522,7 @@ def test_pieslice_width_fill(bbox):
@pytest.mark.parametrize("bbox", BBOX) @pytest.mark.parametrize("bbox", BBOX)
def test_pieslice_zero_width(bbox): def test_pieslice_zero_width(bbox) -> None:
# Arrange # Arrange
im = Image.new("RGB", (W, H)) im = Image.new("RGB", (W, H))
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
@ -534,7 +534,7 @@ def test_pieslice_zero_width(bbox):
assert_image_equal_tofile(im, "Tests/images/imagedraw_pieslice_zero_width.png") assert_image_equal_tofile(im, "Tests/images/imagedraw_pieslice_zero_width.png")
def test_pieslice_wide(): def test_pieslice_wide() -> None:
# Arrange # Arrange
im = Image.new("RGB", (200, 100)) im = Image.new("RGB", (200, 100))
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
@ -546,7 +546,7 @@ def test_pieslice_wide():
assert_image_equal_tofile(im, "Tests/images/imagedraw_pieslice_wide.png") assert_image_equal_tofile(im, "Tests/images/imagedraw_pieslice_wide.png")
def test_pieslice_no_spikes(): def test_pieslice_no_spikes() -> None:
im = Image.new("RGB", (161, 161), "white") im = Image.new("RGB", (161, 161), "white")
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
cxs = ( cxs = (
@ -577,7 +577,7 @@ def test_pieslice_no_spikes():
@pytest.mark.parametrize("points", POINTS) @pytest.mark.parametrize("points", POINTS)
def test_point(points): def test_point(points) -> None:
# Arrange # Arrange
im = Image.new("RGB", (W, H)) im = Image.new("RGB", (W, H))
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
@ -589,7 +589,7 @@ def test_point(points):
assert_image_equal_tofile(im, "Tests/images/imagedraw_point.png") assert_image_equal_tofile(im, "Tests/images/imagedraw_point.png")
def test_point_I16(): def test_point_I16() -> None:
# Arrange # Arrange
im = Image.new("I;16", (1, 1)) im = Image.new("I;16", (1, 1))
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
@ -602,7 +602,7 @@ def test_point_I16():
@pytest.mark.parametrize("points", POINTS) @pytest.mark.parametrize("points", POINTS)
def test_polygon(points): def test_polygon(points) -> None:
# Arrange # Arrange
im = Image.new("RGB", (W, H)) im = Image.new("RGB", (W, H))
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
@ -616,7 +616,7 @@ def test_polygon(points):
@pytest.mark.parametrize("mode", ("RGB", "L")) @pytest.mark.parametrize("mode", ("RGB", "L"))
@pytest.mark.parametrize("kite_points", KITE_POINTS) @pytest.mark.parametrize("kite_points", KITE_POINTS)
def test_polygon_kite(mode, kite_points): def test_polygon_kite(mode, kite_points) -> None:
# Test drawing lines of different gradients (dx>dy, dy>dx) and # Test drawing lines of different gradients (dx>dy, dy>dx) and
# vertical (dx==0) and horizontal (dy==0) lines # vertical (dx==0) and horizontal (dy==0) lines
# Arrange # Arrange
@ -631,7 +631,7 @@ def test_polygon_kite(mode, kite_points):
assert_image_equal_tofile(im, expected) assert_image_equal_tofile(im, expected)
def test_polygon_1px_high(): def test_polygon_1px_high() -> None:
# Test drawing a 1px high polygon # Test drawing a 1px high polygon
# Arrange # Arrange
im = Image.new("RGB", (3, 3)) im = Image.new("RGB", (3, 3))
@ -645,7 +645,7 @@ def test_polygon_1px_high():
assert_image_equal_tofile(im, expected) assert_image_equal_tofile(im, expected)
def test_polygon_1px_high_translucent(): def test_polygon_1px_high_translucent() -> None:
# Test drawing a translucent 1px high polygon # Test drawing a translucent 1px high polygon
# Arrange # Arrange
im = Image.new("RGB", (4, 3)) im = Image.new("RGB", (4, 3))
@ -659,7 +659,7 @@ def test_polygon_1px_high_translucent():
assert_image_equal_tofile(im, expected) assert_image_equal_tofile(im, expected)
def test_polygon_translucent(): def test_polygon_translucent() -> None:
# Arrange # Arrange
im = Image.new("RGB", (W, H)) im = Image.new("RGB", (W, H))
draw = ImageDraw.Draw(im, "RGBA") draw = ImageDraw.Draw(im, "RGBA")
@ -673,7 +673,7 @@ def test_polygon_translucent():
@pytest.mark.parametrize("bbox", BBOX) @pytest.mark.parametrize("bbox", BBOX)
def test_rectangle(bbox): def test_rectangle(bbox) -> None:
# Arrange # Arrange
im = Image.new("RGB", (W, H)) im = Image.new("RGB", (W, H))
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
@ -685,7 +685,7 @@ def test_rectangle(bbox):
assert_image_equal_tofile(im, "Tests/images/imagedraw_rectangle.png") assert_image_equal_tofile(im, "Tests/images/imagedraw_rectangle.png")
def test_big_rectangle(): def test_big_rectangle() -> None:
# Test drawing a rectangle bigger than the image # Test drawing a rectangle bigger than the image
# Arrange # Arrange
im = Image.new("RGB", (W, H)) im = Image.new("RGB", (W, H))
@ -700,7 +700,7 @@ def test_big_rectangle():
@pytest.mark.parametrize("bbox", BBOX) @pytest.mark.parametrize("bbox", BBOX)
def test_rectangle_width(bbox): def test_rectangle_width(bbox) -> None:
# Arrange # Arrange
im = Image.new("RGB", (W, H)) im = Image.new("RGB", (W, H))
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
@ -714,7 +714,7 @@ def test_rectangle_width(bbox):
@pytest.mark.parametrize("bbox", BBOX) @pytest.mark.parametrize("bbox", BBOX)
def test_rectangle_width_fill(bbox): def test_rectangle_width_fill(bbox) -> None:
# Arrange # Arrange
im = Image.new("RGB", (W, H)) im = Image.new("RGB", (W, H))
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
@ -728,7 +728,7 @@ def test_rectangle_width_fill(bbox):
@pytest.mark.parametrize("bbox", BBOX) @pytest.mark.parametrize("bbox", BBOX)
def test_rectangle_zero_width(bbox): def test_rectangle_zero_width(bbox) -> None:
# Arrange # Arrange
im = Image.new("RGB", (W, H)) im = Image.new("RGB", (W, H))
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
@ -741,7 +741,7 @@ def test_rectangle_zero_width(bbox):
@pytest.mark.parametrize("bbox", BBOX) @pytest.mark.parametrize("bbox", BBOX)
def test_rectangle_I16(bbox): def test_rectangle_I16(bbox) -> None:
# Arrange # Arrange
im = Image.new("I;16", (W, H)) im = Image.new("I;16", (W, H))
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
@ -754,7 +754,7 @@ def test_rectangle_I16(bbox):
@pytest.mark.parametrize("bbox", BBOX) @pytest.mark.parametrize("bbox", BBOX)
def test_rectangle_translucent_outline(bbox): def test_rectangle_translucent_outline(bbox) -> None:
# Arrange # Arrange
im = Image.new("RGB", (W, H)) im = Image.new("RGB", (W, H))
draw = ImageDraw.Draw(im, "RGBA") draw = ImageDraw.Draw(im, "RGBA")
@ -772,7 +772,7 @@ def test_rectangle_translucent_outline(bbox):
"xy", "xy",
[(10, 20, 190, 180), ([10, 20], [190, 180]), ((10, 20), (190, 180))], [(10, 20, 190, 180), ([10, 20], [190, 180]), ((10, 20), (190, 180))],
) )
def test_rounded_rectangle(xy): def test_rounded_rectangle(xy) -> None:
# Arrange # Arrange
im = Image.new("RGB", (200, 200)) im = Image.new("RGB", (200, 200))
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
@ -788,7 +788,9 @@ def test_rounded_rectangle(xy):
@pytest.mark.parametrize("top_right", (True, False)) @pytest.mark.parametrize("top_right", (True, False))
@pytest.mark.parametrize("bottom_right", (True, False)) @pytest.mark.parametrize("bottom_right", (True, False))
@pytest.mark.parametrize("bottom_left", (True, False)) @pytest.mark.parametrize("bottom_left", (True, False))
def test_rounded_rectangle_corners(top_left, top_right, bottom_right, bottom_left): def test_rounded_rectangle_corners(
top_left, top_right, bottom_right, bottom_left
) -> None:
corners = (top_left, top_right, bottom_right, bottom_left) corners = (top_left, top_right, bottom_right, bottom_left)
# Arrange # Arrange
@ -822,7 +824,7 @@ def test_rounded_rectangle_corners(top_left, top_right, bottom_right, bottom_lef
((10, 20, 190, 181), 85, "height"), ((10, 20, 190, 181), 85, "height"),
], ],
) )
def test_rounded_rectangle_non_integer_radius(xy, radius, type): def test_rounded_rectangle_non_integer_radius(xy, radius, type) -> None:
# Arrange # Arrange
im = Image.new("RGB", (200, 200)) im = Image.new("RGB", (200, 200))
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
@ -838,7 +840,7 @@ def test_rounded_rectangle_non_integer_radius(xy, radius, type):
@pytest.mark.parametrize("bbox", BBOX) @pytest.mark.parametrize("bbox", BBOX)
def test_rounded_rectangle_zero_radius(bbox): def test_rounded_rectangle_zero_radius(bbox) -> None:
# Arrange # Arrange
im = Image.new("RGB", (W, H)) im = Image.new("RGB", (W, H))
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
@ -860,7 +862,7 @@ def test_rounded_rectangle_zero_radius(bbox):
((20, 20, 80, 80), "both"), ((20, 20, 80, 80), "both"),
], ],
) )
def test_rounded_rectangle_translucent(xy, suffix): def test_rounded_rectangle_translucent(xy, suffix) -> None:
# Arrange # Arrange
im = Image.new("RGB", (W, H)) im = Image.new("RGB", (W, H))
draw = ImageDraw.Draw(im, "RGBA") draw = ImageDraw.Draw(im, "RGBA")
@ -877,7 +879,7 @@ def test_rounded_rectangle_translucent(xy, suffix):
@pytest.mark.parametrize("bbox", BBOX) @pytest.mark.parametrize("bbox", BBOX)
def test_floodfill(bbox): def test_floodfill(bbox) -> None:
red = ImageColor.getrgb("red") red = ImageColor.getrgb("red")
for mode, value in [("L", 1), ("RGBA", (255, 0, 0, 0)), ("RGB", red)]: for mode, value in [("L", 1), ("RGBA", (255, 0, 0, 0)), ("RGB", red)]:
@ -910,7 +912,7 @@ def test_floodfill(bbox):
@pytest.mark.parametrize("bbox", BBOX) @pytest.mark.parametrize("bbox", BBOX)
def test_floodfill_border(bbox): def test_floodfill_border(bbox) -> None:
# floodfill() is experimental # floodfill() is experimental
# Arrange # Arrange
@ -932,7 +934,7 @@ def test_floodfill_border(bbox):
@pytest.mark.parametrize("bbox", BBOX) @pytest.mark.parametrize("bbox", BBOX)
def test_floodfill_thresh(bbox): def test_floodfill_thresh(bbox) -> None:
# floodfill() is experimental # floodfill() is experimental
# Arrange # Arrange
@ -948,7 +950,7 @@ def test_floodfill_thresh(bbox):
assert_image_equal_tofile(im, "Tests/images/imagedraw_floodfill2.png") assert_image_equal_tofile(im, "Tests/images/imagedraw_floodfill2.png")
def test_floodfill_not_negative(): def test_floodfill_not_negative() -> None:
# floodfill() is experimental # floodfill() is experimental
# Test that floodfill does not extend into negative coordinates # Test that floodfill does not extend into negative coordinates
@ -976,7 +978,7 @@ def create_base_image_draw(
return img, ImageDraw.Draw(img) return img, ImageDraw.Draw(img)
def test_square(): def test_square() -> None:
expected = os.path.join(IMAGES_PATH, "square.png") expected = os.path.join(IMAGES_PATH, "square.png")
img, draw = create_base_image_draw((10, 10)) img, draw = create_base_image_draw((10, 10))
draw.polygon([(2, 2), (2, 7), (7, 7), (7, 2)], BLACK) draw.polygon([(2, 2), (2, 7), (7, 7), (7, 2)], BLACK)
@ -989,7 +991,7 @@ def test_square():
assert_image_equal_tofile(img, expected, "square as normal rectangle failed") assert_image_equal_tofile(img, expected, "square as normal rectangle failed")
def test_triangle_right(): def test_triangle_right() -> None:
img, draw = create_base_image_draw((20, 20)) img, draw = create_base_image_draw((20, 20))
draw.polygon([(3, 5), (17, 5), (10, 12)], BLACK) draw.polygon([(3, 5), (17, 5), (10, 12)], BLACK)
assert_image_equal_tofile( assert_image_equal_tofile(
@ -1001,7 +1003,7 @@ def test_triangle_right():
"fill, suffix", "fill, suffix",
((BLACK, "width"), (None, "width_no_fill")), ((BLACK, "width"), (None, "width_no_fill")),
) )
def test_triangle_right_width(fill, suffix): def test_triangle_right_width(fill, suffix) -> None:
img, draw = create_base_image_draw((100, 100)) img, draw = create_base_image_draw((100, 100))
draw.polygon([(15, 25), (85, 25), (50, 60)], fill, WHITE, width=5) draw.polygon([(15, 25), (85, 25), (50, 60)], fill, WHITE, width=5)
assert_image_equal_tofile( assert_image_equal_tofile(
@ -1009,7 +1011,7 @@ def test_triangle_right_width(fill, suffix):
) )
def test_line_horizontal(): def test_line_horizontal() -> None:
img, draw = create_base_image_draw((20, 20)) img, draw = create_base_image_draw((20, 20))
draw.line((5, 5, 14, 5), BLACK, 2) draw.line((5, 5, 14, 5), BLACK, 2)
assert_image_equal_tofile( assert_image_equal_tofile(
@ -1047,7 +1049,7 @@ def test_line_horizontal():
) )
def test_line_h_s1_w2(): def test_line_h_s1_w2() -> None:
pytest.skip("failing") pytest.skip("failing")
img, draw = create_base_image_draw((20, 20)) img, draw = create_base_image_draw((20, 20))
draw.line((5, 5, 14, 6), BLACK, 2) draw.line((5, 5, 14, 6), BLACK, 2)
@ -1058,7 +1060,7 @@ def test_line_h_s1_w2():
) )
def test_line_vertical(): def test_line_vertical() -> None:
img, draw = create_base_image_draw((20, 20)) img, draw = create_base_image_draw((20, 20))
draw.line((5, 5, 5, 14), BLACK, 2) draw.line((5, 5, 5, 14), BLACK, 2)
assert_image_equal_tofile( assert_image_equal_tofile(
@ -1104,7 +1106,7 @@ def test_line_vertical():
) )
def test_line_oblique_45(): def test_line_oblique_45() -> None:
expected = os.path.join(IMAGES_PATH, "line_oblique_45_w3px_a.png") expected = os.path.join(IMAGES_PATH, "line_oblique_45_w3px_a.png")
img, draw = create_base_image_draw((20, 20)) img, draw = create_base_image_draw((20, 20))
draw.line((5, 5, 14, 14), BLACK, 3) draw.line((5, 5, 14, 14), BLACK, 3)
@ -1126,7 +1128,7 @@ def test_line_oblique_45():
) )
def test_wide_line_dot(): def test_wide_line_dot() -> None:
# Test drawing a wide "line" from one point to another just draws a single point # Test drawing a wide "line" from one point to another just draws a single point
# Arrange # Arrange
im = Image.new("RGB", (W, H)) im = Image.new("RGB", (W, H))
@ -1139,7 +1141,7 @@ def test_wide_line_dot():
assert_image_similar_tofile(im, "Tests/images/imagedraw_wide_line_dot.png", 1) assert_image_similar_tofile(im, "Tests/images/imagedraw_wide_line_dot.png", 1)
def test_wide_line_larger_than_int(): def test_wide_line_larger_than_int() -> None:
# Arrange # Arrange
im = Image.new("RGB", (W, H)) im = Image.new("RGB", (W, H))
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
@ -1233,7 +1235,7 @@ def test_wide_line_larger_than_int():
], ],
], ],
) )
def test_line_joint(xy): def test_line_joint(xy) -> None:
im = Image.new("RGB", (500, 325)) im = Image.new("RGB", (500, 325))
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
@ -1244,7 +1246,7 @@ def test_line_joint(xy):
assert_image_similar_tofile(im, "Tests/images/imagedraw_line_joint_curve.png", 3) assert_image_similar_tofile(im, "Tests/images/imagedraw_line_joint_curve.png", 3)
def test_textsize_empty_string(): def test_textsize_empty_string() -> None:
# https://github.com/python-pillow/Pillow/issues/2783 # https://github.com/python-pillow/Pillow/issues/2783
# Arrange # Arrange
im = Image.new("RGB", (W, H)) im = Image.new("RGB", (W, H))
@ -1260,7 +1262,7 @@ def test_textsize_empty_string():
@skip_unless_feature("freetype2") @skip_unless_feature("freetype2")
def test_textbbox_stroke(): def test_textbbox_stroke() -> None:
# Arrange # Arrange
im = Image.new("RGB", (W, H)) im = Image.new("RGB", (W, H))
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
@ -1274,7 +1276,7 @@ def test_textbbox_stroke():
@skip_unless_feature("freetype2") @skip_unless_feature("freetype2")
def test_stroke(): def test_stroke() -> None:
for suffix, stroke_fill in {"same": None, "different": "#0f0"}.items(): for suffix, stroke_fill in {"same": None, "different": "#0f0"}.items():
# Arrange # Arrange
im = Image.new("RGB", (120, 130)) im = Image.new("RGB", (120, 130))
@ -1291,7 +1293,7 @@ def test_stroke():
@skip_unless_feature("freetype2") @skip_unless_feature("freetype2")
def test_stroke_descender(): def test_stroke_descender() -> None:
# Arrange # Arrange
im = Image.new("RGB", (120, 130)) im = Image.new("RGB", (120, 130))
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
@ -1305,7 +1307,7 @@ def test_stroke_descender():
@skip_unless_feature("freetype2") @skip_unless_feature("freetype2")
def test_split_word(): def test_split_word() -> None:
# Arrange # Arrange
im = Image.new("RGB", (230, 55)) im = Image.new("RGB", (230, 55))
expected = im.copy() expected = im.copy()
@ -1326,7 +1328,7 @@ def test_split_word():
@skip_unless_feature("freetype2") @skip_unless_feature("freetype2")
def test_stroke_multiline(): def test_stroke_multiline() -> None:
# Arrange # Arrange
im = Image.new("RGB", (100, 250)) im = Image.new("RGB", (100, 250))
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
@ -1342,7 +1344,7 @@ def test_stroke_multiline():
@skip_unless_feature("freetype2") @skip_unless_feature("freetype2")
def test_setting_default_font(): def test_setting_default_font() -> None:
# Arrange # Arrange
im = Image.new("RGB", (100, 250)) im = Image.new("RGB", (100, 250))
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
@ -1359,7 +1361,7 @@ def test_setting_default_font():
assert isinstance(draw.getfont(), ImageFont.load_default().__class__) assert isinstance(draw.getfont(), ImageFont.load_default().__class__)
def test_default_font_size(): def test_default_font_size() -> None:
freetype_support = features.check_module("freetype2") freetype_support = features.check_module("freetype2")
text = "Default font at a specific size." text = "Default font at a specific size."
@ -1386,7 +1388,7 @@ def test_default_font_size():
@pytest.mark.parametrize("bbox", BBOX) @pytest.mark.parametrize("bbox", BBOX)
def test_same_color_outline(bbox): def test_same_color_outline(bbox) -> None:
# Prepare shape # Prepare shape
x0, y0 = 5, 5 x0, y0 = 5, 5
x1, y1 = 5, 50 x1, y1 = 5, 50
@ -1432,7 +1434,7 @@ def test_same_color_outline(bbox):
(3, "triangle_width", {"width": 5, "outline": "yellow"}), (3, "triangle_width", {"width": 5, "outline": "yellow"}),
], ],
) )
def test_draw_regular_polygon(n_sides, polygon_name, args): def test_draw_regular_polygon(n_sides, polygon_name, args) -> None:
im = Image.new("RGBA", size=(W, H), color=(255, 0, 0, 0)) im = Image.new("RGBA", size=(W, H), color=(255, 0, 0, 0))
filename = f"Tests/images/imagedraw_{polygon_name}.png" filename = f"Tests/images/imagedraw_{polygon_name}.png"
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
@ -1469,7 +1471,7 @@ def test_draw_regular_polygon(n_sides, polygon_name, args):
), ),
], ],
) )
def test_compute_regular_polygon_vertices(n_sides, expected_vertices): def test_compute_regular_polygon_vertices(n_sides, expected_vertices) -> None:
bounding_circle = (W // 2, H // 2, 25) bounding_circle = (W // 2, H // 2, 25)
vertices = ImageDraw._compute_regular_polygon_vertices(bounding_circle, n_sides, 0) vertices = ImageDraw._compute_regular_polygon_vertices(bounding_circle, n_sides, 0)
assert vertices == expected_vertices assert vertices == expected_vertices
@ -1521,13 +1523,13 @@ def test_compute_regular_polygon_vertices(n_sides, expected_vertices):
) )
def test_compute_regular_polygon_vertices_input_error_handling( def test_compute_regular_polygon_vertices_input_error_handling(
n_sides, bounding_circle, rotation, expected_error, error_message n_sides, bounding_circle, rotation, expected_error, error_message
): ) -> None:
with pytest.raises(expected_error) as e: with pytest.raises(expected_error) as e:
ImageDraw._compute_regular_polygon_vertices(bounding_circle, n_sides, rotation) ImageDraw._compute_regular_polygon_vertices(bounding_circle, n_sides, rotation)
assert str(e.value) == error_message assert str(e.value) == error_message
def test_continuous_horizontal_edges_polygon(): def test_continuous_horizontal_edges_polygon() -> None:
xy = [ xy = [
(2, 6), (2, 6),
(6, 6), (6, 6),
@ -1546,7 +1548,7 @@ def test_continuous_horizontal_edges_polygon():
) )
def test_discontiguous_corners_polygon(): def test_discontiguous_corners_polygon() -> None:
img, draw = create_base_image_draw((84, 68)) img, draw = create_base_image_draw((84, 68))
draw.polygon(((1, 21), (34, 4), (71, 1), (38, 18)), BLACK) draw.polygon(((1, 21), (34, 4), (71, 1), (38, 18)), BLACK)
draw.polygon(((71, 44), (38, 27), (1, 24)), BLACK) draw.polygon(((71, 44), (38, 27), (1, 24)), BLACK)
@ -1558,7 +1560,7 @@ def test_discontiguous_corners_polygon():
assert_image_similar_tofile(img, expected, 1) assert_image_similar_tofile(img, expected, 1)
def test_polygon2(): def test_polygon2() -> None:
im = Image.new("RGB", (W, H)) im = Image.new("RGB", (W, H))
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
draw.polygon([(18, 30), (19, 31), (18, 30), (85, 30), (60, 72)], "red") draw.polygon([(18, 30), (19, 31), (18, 30), (85, 30), (60, 72)], "red")
@ -1567,7 +1569,7 @@ def test_polygon2():
@pytest.mark.parametrize("xy", ((1, 1, 0, 1), (1, 1, 1, 0))) @pytest.mark.parametrize("xy", ((1, 1, 0, 1), (1, 1, 1, 0)))
def test_incorrectly_ordered_coordinates(xy): def test_incorrectly_ordered_coordinates(xy) -> None:
im = Image.new("RGB", (W, H)) im = Image.new("RGB", (W, H))
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
with pytest.raises(ValueError): with pytest.raises(ValueError):

View File

@ -43,7 +43,7 @@ POINTS = (
FONT_PATH = "Tests/fonts/FreeMono.ttf" FONT_PATH = "Tests/fonts/FreeMono.ttf"
def test_sanity(): def test_sanity() -> None:
im = hopper("RGB").copy() im = hopper("RGB").copy()
draw = ImageDraw2.Draw(im) draw = ImageDraw2.Draw(im)
@ -56,7 +56,7 @@ def test_sanity():
@pytest.mark.parametrize("bbox", BBOX) @pytest.mark.parametrize("bbox", BBOX)
def test_ellipse(bbox): def test_ellipse(bbox) -> None:
# Arrange # Arrange
im = Image.new("RGB", (W, H)) im = Image.new("RGB", (W, H))
draw = ImageDraw2.Draw(im) draw = ImageDraw2.Draw(im)
@ -70,7 +70,7 @@ def test_ellipse(bbox):
assert_image_similar_tofile(im, "Tests/images/imagedraw_ellipse_RGB.png", 1) assert_image_similar_tofile(im, "Tests/images/imagedraw_ellipse_RGB.png", 1)
def test_ellipse_edge(): def test_ellipse_edge() -> None:
# Arrange # Arrange
im = Image.new("RGB", (W, H)) im = Image.new("RGB", (W, H))
draw = ImageDraw2.Draw(im) draw = ImageDraw2.Draw(im)
@ -84,7 +84,7 @@ def test_ellipse_edge():
@pytest.mark.parametrize("points", POINTS) @pytest.mark.parametrize("points", POINTS)
def test_line(points): def test_line(points) -> None:
# Arrange # Arrange
im = Image.new("RGB", (W, H)) im = Image.new("RGB", (W, H))
draw = ImageDraw2.Draw(im) draw = ImageDraw2.Draw(im)
@ -98,7 +98,7 @@ def test_line(points):
@pytest.mark.parametrize("points", POINTS) @pytest.mark.parametrize("points", POINTS)
def test_line_pen_as_brush(points): def test_line_pen_as_brush(points) -> None:
# Arrange # Arrange
im = Image.new("RGB", (W, H)) im = Image.new("RGB", (W, H))
draw = ImageDraw2.Draw(im) draw = ImageDraw2.Draw(im)
@ -114,7 +114,7 @@ def test_line_pen_as_brush(points):
@pytest.mark.parametrize("points", POINTS) @pytest.mark.parametrize("points", POINTS)
def test_polygon(points): def test_polygon(points) -> None:
# Arrange # Arrange
im = Image.new("RGB", (W, H)) im = Image.new("RGB", (W, H))
draw = ImageDraw2.Draw(im) draw = ImageDraw2.Draw(im)
@ -129,7 +129,7 @@ def test_polygon(points):
@pytest.mark.parametrize("bbox", BBOX) @pytest.mark.parametrize("bbox", BBOX)
def test_rectangle(bbox): def test_rectangle(bbox) -> None:
# Arrange # Arrange
im = Image.new("RGB", (W, H)) im = Image.new("RGB", (W, H))
draw = ImageDraw2.Draw(im) draw = ImageDraw2.Draw(im)
@ -143,7 +143,7 @@ def test_rectangle(bbox):
assert_image_equal_tofile(im, "Tests/images/imagedraw_rectangle.png") assert_image_equal_tofile(im, "Tests/images/imagedraw_rectangle.png")
def test_big_rectangle(): def test_big_rectangle() -> None:
# Test drawing a rectangle bigger than the image # Test drawing a rectangle bigger than the image
# Arrange # Arrange
im = Image.new("RGB", (W, H)) im = Image.new("RGB", (W, H))
@ -160,7 +160,7 @@ def test_big_rectangle():
@skip_unless_feature("freetype2") @skip_unless_feature("freetype2")
def test_text(): def test_text() -> None:
# Arrange # Arrange
im = Image.new("RGB", (W, H)) im = Image.new("RGB", (W, H))
draw = ImageDraw2.Draw(im) draw = ImageDraw2.Draw(im)
@ -175,7 +175,7 @@ def test_text():
@skip_unless_feature("freetype2") @skip_unless_feature("freetype2")
def test_textbbox(): def test_textbbox() -> None:
# Arrange # Arrange
im = Image.new("RGB", (W, H)) im = Image.new("RGB", (W, H))
draw = ImageDraw2.Draw(im) draw = ImageDraw2.Draw(im)
@ -190,7 +190,7 @@ def test_textbbox():
@skip_unless_feature("freetype2") @skip_unless_feature("freetype2")
def test_textsize_empty_string(): def test_textsize_empty_string() -> None:
# Arrange # Arrange
im = Image.new("RGB", (W, H)) im = Image.new("RGB", (W, H))
draw = ImageDraw2.Draw(im) draw = ImageDraw2.Draw(im)
@ -206,7 +206,7 @@ def test_textsize_empty_string():
@skip_unless_feature("freetype2") @skip_unless_feature("freetype2")
def test_flush(): def test_flush() -> None:
# Arrange # Arrange
im = Image.new("RGB", (W, H)) im = Image.new("RGB", (W, H))
draw = ImageDraw2.Draw(im) draw = ImageDraw2.Draw(im)

View File

@ -7,7 +7,7 @@ from PIL import Image, ImageEnhance
from .helper import assert_image_equal, hopper from .helper import assert_image_equal, hopper
def test_sanity(): def test_sanity() -> None:
# FIXME: assert_image # FIXME: assert_image
# Implicit asserts no exception: # Implicit asserts no exception:
ImageEnhance.Color(hopper()).enhance(0.5) ImageEnhance.Color(hopper()).enhance(0.5)
@ -16,7 +16,7 @@ def test_sanity():
ImageEnhance.Sharpness(hopper()).enhance(0.5) ImageEnhance.Sharpness(hopper()).enhance(0.5)
def test_crash(): def test_crash() -> None:
# crashes on small images # crashes on small images
im = Image.new("RGB", (1, 1)) im = Image.new("RGB", (1, 1))
ImageEnhance.Sharpness(im).enhance(0.5) ImageEnhance.Sharpness(im).enhance(0.5)
@ -34,7 +34,7 @@ def _half_transparent_image():
return im return im
def _check_alpha(im, original, op, amount): def _check_alpha(im, original, op, amount) -> None:
assert im.getbands() == original.getbands() assert im.getbands() == original.getbands()
assert_image_equal( assert_image_equal(
im.getchannel("A"), im.getchannel("A"),
@ -44,7 +44,7 @@ def _check_alpha(im, original, op, amount):
@pytest.mark.parametrize("op", ("Color", "Brightness", "Contrast", "Sharpness")) @pytest.mark.parametrize("op", ("Color", "Brightness", "Contrast", "Sharpness"))
def test_alpha(op): def test_alpha(op) -> None:
# Issue https://github.com/python-pillow/Pillow/issues/899 # Issue https://github.com/python-pillow/Pillow/issues/899
# Is alpha preserved through image enhancement? # Is alpha preserved through image enhancement?

View File

@ -30,7 +30,7 @@ SAFEBLOCK = ImageFile.SAFEBLOCK
class TestImageFile: class TestImageFile:
def test_parser(self): def test_parser(self) -> None:
def roundtrip(format): def roundtrip(format):
im = hopper("L").resize((1000, 1000), Image.Resampling.NEAREST) im = hopper("L").resize((1000, 1000), Image.Resampling.NEAREST)
if format in ("MSP", "XBM"): if format in ("MSP", "XBM"):
@ -84,7 +84,7 @@ class TestImageFile:
with pytest.raises(OSError): with pytest.raises(OSError):
roundtrip("PDF") roundtrip("PDF")
def test_ico(self): def test_ico(self) -> None:
with open("Tests/images/python.ico", "rb") as f: with open("Tests/images/python.ico", "rb") as f:
data = f.read() data = f.read()
with ImageFile.Parser() as p: with ImageFile.Parser() as p:
@ -93,7 +93,7 @@ class TestImageFile:
@skip_unless_feature("webp") @skip_unless_feature("webp")
@skip_unless_feature("webp_anim") @skip_unless_feature("webp_anim")
def test_incremental_webp(self): def test_incremental_webp(self) -> None:
with ImageFile.Parser() as p: with ImageFile.Parser() as p:
with open("Tests/images/hopper.webp", "rb") as f: with open("Tests/images/hopper.webp", "rb") as f:
p.feed(f.read(1024)) p.feed(f.read(1024))
@ -105,7 +105,7 @@ class TestImageFile:
assert (128, 128) == p.image.size assert (128, 128) == p.image.size
@skip_unless_feature("zlib") @skip_unless_feature("zlib")
def test_safeblock(self): def test_safeblock(self) -> None:
im1 = hopper() im1 = hopper()
try: try:
@ -116,17 +116,17 @@ class TestImageFile:
assert_image_equal(im1, im2) assert_image_equal(im1, im2)
def test_raise_oserror(self): def test_raise_oserror(self) -> None:
with pytest.warns(DeprecationWarning): with pytest.warns(DeprecationWarning):
with pytest.raises(OSError): with pytest.raises(OSError):
ImageFile.raise_oserror(1) ImageFile.raise_oserror(1)
def test_raise_typeerror(self): def test_raise_typeerror(self) -> None:
with pytest.raises(TypeError): with pytest.raises(TypeError):
parser = ImageFile.Parser() parser = ImageFile.Parser()
parser.feed(1) parser.feed(1)
def test_negative_stride(self): def test_negative_stride(self) -> None:
with open("Tests/images/raw_negative_stride.bin", "rb") as f: with open("Tests/images/raw_negative_stride.bin", "rb") as f:
input = f.read() input = f.read()
p = ImageFile.Parser() p = ImageFile.Parser()
@ -134,11 +134,11 @@ class TestImageFile:
with pytest.raises(OSError): with pytest.raises(OSError):
p.close() p.close()
def test_no_format(self): def test_no_format(self) -> None:
buf = BytesIO(b"\x00" * 255) buf = BytesIO(b"\x00" * 255)
class DummyImageFile(ImageFile.ImageFile): class DummyImageFile(ImageFile.ImageFile):
def _open(self): def _open(self) -> None:
self._mode = "RGB" self._mode = "RGB"
self._size = (1, 1) self._size = (1, 1)
@ -146,12 +146,12 @@ class TestImageFile:
assert im.format is None assert im.format is None
assert im.get_format_mimetype() is None assert im.get_format_mimetype() is None
def test_oserror(self): def test_oserror(self) -> None:
im = Image.new("RGB", (1, 1)) im = Image.new("RGB", (1, 1))
with pytest.raises(OSError): with pytest.raises(OSError):
im.save(BytesIO(), "JPEG2000", num_resolutions=2) im.save(BytesIO(), "JPEG2000", num_resolutions=2)
def test_truncated(self): def test_truncated(self) -> None:
b = BytesIO( b = BytesIO(
b"BM000000000000" # head_data b"BM000000000000" # head_data
+ _binary.o32le( + _binary.o32le(
@ -166,7 +166,7 @@ class TestImageFile:
assert str(e.value) == "Truncated File Read" assert str(e.value) == "Truncated File Read"
@skip_unless_feature("zlib") @skip_unless_feature("zlib")
def test_truncated_with_errors(self): def test_truncated_with_errors(self) -> None:
with Image.open("Tests/images/truncated_image.png") as im: with Image.open("Tests/images/truncated_image.png") as im:
with pytest.raises(OSError): with pytest.raises(OSError):
im.load() im.load()
@ -176,7 +176,7 @@ class TestImageFile:
im.load() im.load()
@skip_unless_feature("zlib") @skip_unless_feature("zlib")
def test_truncated_without_errors(self): def test_truncated_without_errors(self) -> None:
with Image.open("Tests/images/truncated_image.png") as im: with Image.open("Tests/images/truncated_image.png") as im:
ImageFile.LOAD_TRUNCATED_IMAGES = True ImageFile.LOAD_TRUNCATED_IMAGES = True
try: try:
@ -185,13 +185,13 @@ class TestImageFile:
ImageFile.LOAD_TRUNCATED_IMAGES = False ImageFile.LOAD_TRUNCATED_IMAGES = False
@skip_unless_feature("zlib") @skip_unless_feature("zlib")
def test_broken_datastream_with_errors(self): def test_broken_datastream_with_errors(self) -> None:
with Image.open("Tests/images/broken_data_stream.png") as im: with Image.open("Tests/images/broken_data_stream.png") as im:
with pytest.raises(OSError): with pytest.raises(OSError):
im.load() im.load()
@skip_unless_feature("zlib") @skip_unless_feature("zlib")
def test_broken_datastream_without_errors(self): def test_broken_datastream_without_errors(self) -> None:
with Image.open("Tests/images/broken_data_stream.png") as im: with Image.open("Tests/images/broken_data_stream.png") as im:
ImageFile.LOAD_TRUNCATED_IMAGES = True ImageFile.LOAD_TRUNCATED_IMAGES = True
try: try:
@ -210,7 +210,7 @@ class MockPyEncoder(ImageFile.PyEncoder):
def encode(self, buffer): def encode(self, buffer):
return 1, 1, b"" return 1, 1, b""
def cleanup(self): def cleanup(self) -> None:
self.cleanup_called = True self.cleanup_called = True
@ -218,7 +218,7 @@ xoff, yoff, xsize, ysize = 10, 20, 100, 100
class MockImageFile(ImageFile.ImageFile): class MockImageFile(ImageFile.ImageFile):
def _open(self): def _open(self) -> None:
self.rawmode = "RGBA" self.rawmode = "RGBA"
self._mode = "RGBA" self._mode = "RGBA"
self._size = (200, 200) self._size = (200, 200)
@ -227,7 +227,7 @@ class MockImageFile(ImageFile.ImageFile):
class CodecsTest: class CodecsTest:
@classmethod @classmethod
def setup_class(cls): def setup_class(cls) -> None:
cls.decoder = MockPyDecoder(None) cls.decoder = MockPyDecoder(None)
cls.encoder = MockPyEncoder(None) cls.encoder = MockPyEncoder(None)
@ -244,7 +244,7 @@ class CodecsTest:
class TestPyDecoder(CodecsTest): class TestPyDecoder(CodecsTest):
def test_setimage(self): def test_setimage(self) -> None:
buf = BytesIO(b"\x00" * 255) buf = BytesIO(b"\x00" * 255)
im = MockImageFile(buf) im = MockImageFile(buf)
@ -259,7 +259,7 @@ class TestPyDecoder(CodecsTest):
with pytest.raises(ValueError): with pytest.raises(ValueError):
self.decoder.set_as_raw(b"\x00") self.decoder.set_as_raw(b"\x00")
def test_extents_none(self): def test_extents_none(self) -> None:
buf = BytesIO(b"\x00" * 255) buf = BytesIO(b"\x00" * 255)
im = MockImageFile(buf) im = MockImageFile(buf)
@ -272,7 +272,7 @@ class TestPyDecoder(CodecsTest):
assert self.decoder.state.xsize == 200 assert self.decoder.state.xsize == 200
assert self.decoder.state.ysize == 200 assert self.decoder.state.ysize == 200
def test_negsize(self): def test_negsize(self) -> None:
buf = BytesIO(b"\x00" * 255) buf = BytesIO(b"\x00" * 255)
im = MockImageFile(buf) im = MockImageFile(buf)
@ -285,7 +285,7 @@ class TestPyDecoder(CodecsTest):
with pytest.raises(ValueError): with pytest.raises(ValueError):
im.load() im.load()
def test_oversize(self): def test_oversize(self) -> None:
buf = BytesIO(b"\x00" * 255) buf = BytesIO(b"\x00" * 255)
im = MockImageFile(buf) im = MockImageFile(buf)
@ -298,14 +298,14 @@ class TestPyDecoder(CodecsTest):
with pytest.raises(ValueError): with pytest.raises(ValueError):
im.load() im.load()
def test_decode(self): def test_decode(self) -> None:
decoder = ImageFile.PyDecoder(None) decoder = ImageFile.PyDecoder(None)
with pytest.raises(NotImplementedError): with pytest.raises(NotImplementedError):
decoder.decode(None) decoder.decode(None)
class TestPyEncoder(CodecsTest): class TestPyEncoder(CodecsTest):
def test_setimage(self): def test_setimage(self) -> None:
buf = BytesIO(b"\x00" * 255) buf = BytesIO(b"\x00" * 255)
im = MockImageFile(buf) im = MockImageFile(buf)
@ -320,7 +320,7 @@ class TestPyEncoder(CodecsTest):
assert self.encoder.state.xsize == xsize assert self.encoder.state.xsize == xsize
assert self.encoder.state.ysize == ysize assert self.encoder.state.ysize == ysize
def test_extents_none(self): def test_extents_none(self) -> None:
buf = BytesIO(b"\x00" * 255) buf = BytesIO(b"\x00" * 255)
im = MockImageFile(buf) im = MockImageFile(buf)
@ -334,7 +334,7 @@ class TestPyEncoder(CodecsTest):
assert self.encoder.state.xsize == 200 assert self.encoder.state.xsize == 200
assert self.encoder.state.ysize == 200 assert self.encoder.state.ysize == 200
def test_negsize(self): def test_negsize(self) -> None:
buf = BytesIO(b"\x00" * 255) buf = BytesIO(b"\x00" * 255)
im = MockImageFile(buf) im = MockImageFile(buf)
@ -352,7 +352,7 @@ class TestPyEncoder(CodecsTest):
im, fp, [("MOCK", (xoff, yoff, xoff + xsize, -10), 0, "RGB")] im, fp, [("MOCK", (xoff, yoff, xoff + xsize, -10), 0, "RGB")]
) )
def test_oversize(self): def test_oversize(self) -> None:
buf = BytesIO(b"\x00" * 255) buf = BytesIO(b"\x00" * 255)
im = MockImageFile(buf) im = MockImageFile(buf)
@ -372,7 +372,7 @@ class TestPyEncoder(CodecsTest):
[("MOCK", (xoff, yoff, xoff + xsize, yoff + ysize + 100), 0, "RGB")], [("MOCK", (xoff, yoff, xoff + xsize, yoff + ysize + 100), 0, "RGB")],
) )
def test_encode(self): def test_encode(self) -> None:
encoder = ImageFile.PyEncoder(None) encoder = ImageFile.PyEncoder(None)
with pytest.raises(NotImplementedError): with pytest.raises(NotImplementedError):
encoder.encode(None) encoder.encode(None)
@ -388,6 +388,6 @@ class TestPyEncoder(CodecsTest):
with pytest.raises(NotImplementedError): with pytest.raises(NotImplementedError):
encoder.encode_to_file(None, None) encoder.encode_to_file(None, None)
def test_zero_height(self): def test_zero_height(self) -> None:
with pytest.raises(UnidentifiedImageError): with pytest.raises(UnidentifiedImageError):
Image.open("Tests/images/zero_height.j2k") Image.open("Tests/images/zero_height.j2k")

View File

@ -31,7 +31,7 @@ TEST_TEXT = "hey you\nyou are awesome\nthis looks awkward"
pytestmark = skip_unless_feature("freetype2") pytestmark = skip_unless_feature("freetype2")
def test_sanity(): def test_sanity() -> None:
assert re.search(r"\d+\.\d+\.\d+$", features.version_module("freetype2")) assert re.search(r"\d+\.\d+\.\d+$", features.version_module("freetype2"))
@ -51,7 +51,7 @@ def font(layout_engine):
return ImageFont.truetype(FONT_PATH, FONT_SIZE, layout_engine=layout_engine) return ImageFont.truetype(FONT_PATH, FONT_SIZE, layout_engine=layout_engine)
def test_font_properties(font): def test_font_properties(font) -> None:
assert font.path == FONT_PATH assert font.path == FONT_PATH
assert font.size == FONT_SIZE assert font.size == FONT_SIZE
@ -80,11 +80,11 @@ def _render(font, layout_engine):
@pytest.mark.parametrize("font", (FONT_PATH, Path(FONT_PATH))) @pytest.mark.parametrize("font", (FONT_PATH, Path(FONT_PATH)))
def test_font_with_name(layout_engine, font): def test_font_with_name(layout_engine, font) -> None:
_render(font, layout_engine) _render(font, layout_engine)
def test_font_with_filelike(layout_engine): def test_font_with_filelike(layout_engine) -> None:
def _font_as_bytes(): def _font_as_bytes():
with open(FONT_PATH, "rb") as f: with open(FONT_PATH, "rb") as f:
font_bytes = BytesIO(f.read()) font_bytes = BytesIO(f.read())
@ -102,12 +102,12 @@ def test_font_with_filelike(layout_engine):
# _render(shared_bytes) # _render(shared_bytes)
def test_font_with_open_file(layout_engine): def test_font_with_open_file(layout_engine) -> None:
with open(FONT_PATH, "rb") as f: with open(FONT_PATH, "rb") as f:
_render(f, layout_engine) _render(f, layout_engine)
def test_render_equal(layout_engine): def test_render_equal(layout_engine) -> None:
img_path = _render(FONT_PATH, layout_engine) img_path = _render(FONT_PATH, layout_engine)
with open(FONT_PATH, "rb") as f: with open(FONT_PATH, "rb") as f:
font_filelike = BytesIO(f.read()) font_filelike = BytesIO(f.read())
@ -116,7 +116,7 @@ def test_render_equal(layout_engine):
assert_image_equal(img_path, img_filelike) assert_image_equal(img_path, img_filelike)
def test_non_ascii_path(tmp_path, layout_engine): def test_non_ascii_path(tmp_path: Path, layout_engine) -> None:
tempfile = str(tmp_path / ("temp_" + chr(128) + ".ttf")) tempfile = str(tmp_path / ("temp_" + chr(128) + ".ttf"))
try: try:
shutil.copy(FONT_PATH, tempfile) shutil.copy(FONT_PATH, tempfile)
@ -126,7 +126,7 @@ def test_non_ascii_path(tmp_path, layout_engine):
ImageFont.truetype(tempfile, FONT_SIZE, layout_engine=layout_engine) ImageFont.truetype(tempfile, FONT_SIZE, layout_engine=layout_engine)
def test_transparent_background(font): def test_transparent_background(font) -> None:
im = Image.new(mode="RGBA", size=(300, 100)) im = Image.new(mode="RGBA", size=(300, 100))
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
@ -140,7 +140,7 @@ def test_transparent_background(font):
assert_image_similar_tofile(im.convert("L"), target, 0.01) assert_image_similar_tofile(im.convert("L"), target, 0.01)
def test_I16(font): def test_I16(font) -> None:
im = Image.new(mode="I;16", size=(300, 100)) im = Image.new(mode="I;16", size=(300, 100))
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
@ -153,7 +153,7 @@ def test_I16(font):
assert_image_similar_tofile(im.convert("L"), target, 0.01) assert_image_similar_tofile(im.convert("L"), target, 0.01)
def test_textbbox_equal(font): def test_textbbox_equal(font) -> None:
im = Image.new(mode="RGB", size=(300, 100)) im = Image.new(mode="RGB", size=(300, 100))
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
@ -182,7 +182,7 @@ def test_textbbox_equal(font):
) )
def test_getlength( def test_getlength(
text, mode, fontname, size, layout_engine, length_basic, length_raqm text, mode, fontname, size, layout_engine, length_basic, length_raqm
): ) -> None:
f = ImageFont.truetype("Tests/fonts/" + fontname, size, layout_engine=layout_engine) f = ImageFont.truetype("Tests/fonts/" + fontname, size, layout_engine=layout_engine)
im = Image.new(mode, (1, 1), 0) im = Image.new(mode, (1, 1), 0)
@ -197,7 +197,7 @@ def test_getlength(
assert length == length_raqm assert length == length_raqm
def test_float_size(): def test_float_size() -> None:
lengths = [] lengths = []
for size in (48, 48.5, 49): for size in (48, 48.5, 49):
f = ImageFont.truetype( f = ImageFont.truetype(
@ -207,7 +207,7 @@ def test_float_size():
assert lengths[0] != lengths[1] != lengths[2] assert lengths[0] != lengths[1] != lengths[2]
def test_render_multiline(font): def test_render_multiline(font) -> None:
im = Image.new(mode="RGB", size=(300, 100)) im = Image.new(mode="RGB", size=(300, 100))
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
line_spacing = font.getbbox("A")[3] + 4 line_spacing = font.getbbox("A")[3] + 4
@ -223,7 +223,7 @@ def test_render_multiline(font):
assert_image_similar_tofile(im, "Tests/images/multiline_text.png", 6.2) assert_image_similar_tofile(im, "Tests/images/multiline_text.png", 6.2)
def test_render_multiline_text(font): def test_render_multiline_text(font) -> None:
# Test that text() correctly connects to multiline_text() # Test that text() correctly connects to multiline_text()
# and that align defaults to left # and that align defaults to left
im = Image.new(mode="RGB", size=(300, 100)) im = Image.new(mode="RGB", size=(300, 100))
@ -243,7 +243,7 @@ def test_render_multiline_text(font):
@pytest.mark.parametrize( @pytest.mark.parametrize(
"align, ext", (("left", ""), ("center", "_center"), ("right", "_right")) "align, ext", (("left", ""), ("center", "_center"), ("right", "_right"))
) )
def test_render_multiline_text_align(font, align, ext): def test_render_multiline_text_align(font, align, ext) -> None:
im = Image.new(mode="RGB", size=(300, 100)) im = Image.new(mode="RGB", size=(300, 100))
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
draw.multiline_text((0, 0), TEST_TEXT, font=font, align=align) draw.multiline_text((0, 0), TEST_TEXT, font=font, align=align)
@ -251,7 +251,7 @@ def test_render_multiline_text_align(font, align, ext):
assert_image_similar_tofile(im, f"Tests/images/multiline_text{ext}.png", 0.01) assert_image_similar_tofile(im, f"Tests/images/multiline_text{ext}.png", 0.01)
def test_unknown_align(font): def test_unknown_align(font) -> None:
im = Image.new(mode="RGB", size=(300, 100)) im = Image.new(mode="RGB", size=(300, 100))
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
@ -260,14 +260,14 @@ def test_unknown_align(font):
draw.multiline_text((0, 0), TEST_TEXT, font=font, align="unknown") draw.multiline_text((0, 0), TEST_TEXT, font=font, align="unknown")
def test_draw_align(font): def test_draw_align(font) -> None:
im = Image.new("RGB", (300, 100), "white") im = Image.new("RGB", (300, 100), "white")
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
line = "some text" line = "some text"
draw.text((100, 40), line, (0, 0, 0), font=font, align="left") draw.text((100, 40), line, (0, 0, 0), font=font, align="left")
def test_multiline_bbox(font): def test_multiline_bbox(font) -> None:
im = Image.new(mode="RGB", size=(300, 100)) im = Image.new(mode="RGB", size=(300, 100))
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
@ -285,7 +285,7 @@ def test_multiline_bbox(font):
draw.textbbox((0, 0), TEST_TEXT, font=font, spacing=4) draw.textbbox((0, 0), TEST_TEXT, font=font, spacing=4)
def test_multiline_width(font): def test_multiline_width(font) -> None:
im = Image.new(mode="RGB", size=(300, 100)) im = Image.new(mode="RGB", size=(300, 100))
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
@ -295,7 +295,7 @@ def test_multiline_width(font):
) )
def test_multiline_spacing(font): def test_multiline_spacing(font) -> None:
im = Image.new(mode="RGB", size=(300, 100)) im = Image.new(mode="RGB", size=(300, 100))
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
draw.multiline_text((0, 0), TEST_TEXT, font=font, spacing=10) draw.multiline_text((0, 0), TEST_TEXT, font=font, spacing=10)
@ -306,7 +306,7 @@ def test_multiline_spacing(font):
@pytest.mark.parametrize( @pytest.mark.parametrize(
"orientation", (Image.Transpose.ROTATE_90, Image.Transpose.ROTATE_270) "orientation", (Image.Transpose.ROTATE_90, Image.Transpose.ROTATE_270)
) )
def test_rotated_transposed_font(font, orientation): def test_rotated_transposed_font(font, orientation) -> None:
img_gray = Image.new("L", (100, 100)) img_gray = Image.new("L", (100, 100))
draw = ImageDraw.Draw(img_gray) draw = ImageDraw.Draw(img_gray)
word = "testing" word = "testing"
@ -347,7 +347,7 @@ def test_rotated_transposed_font(font, orientation):
Image.Transpose.FLIP_TOP_BOTTOM, Image.Transpose.FLIP_TOP_BOTTOM,
), ),
) )
def test_unrotated_transposed_font(font, orientation): def test_unrotated_transposed_font(font, orientation) -> None:
img_gray = Image.new("L", (100, 100)) img_gray = Image.new("L", (100, 100))
draw = ImageDraw.Draw(img_gray) draw = ImageDraw.Draw(img_gray)
word = "testing" word = "testing"
@ -382,7 +382,7 @@ def test_unrotated_transposed_font(font, orientation):
@pytest.mark.parametrize( @pytest.mark.parametrize(
"orientation", (Image.Transpose.ROTATE_90, Image.Transpose.ROTATE_270) "orientation", (Image.Transpose.ROTATE_90, Image.Transpose.ROTATE_270)
) )
def test_rotated_transposed_font_get_mask(font, orientation): def test_rotated_transposed_font_get_mask(font, orientation) -> None:
# Arrange # Arrange
text = "mask this" text = "mask this"
transposed_font = ImageFont.TransposedFont(font, orientation=orientation) transposed_font = ImageFont.TransposedFont(font, orientation=orientation)
@ -403,7 +403,7 @@ def test_rotated_transposed_font_get_mask(font, orientation):
Image.Transpose.FLIP_TOP_BOTTOM, Image.Transpose.FLIP_TOP_BOTTOM,
), ),
) )
def test_unrotated_transposed_font_get_mask(font, orientation): def test_unrotated_transposed_font_get_mask(font, orientation) -> None:
# Arrange # Arrange
text = "mask this" text = "mask this"
transposed_font = ImageFont.TransposedFont(font, orientation=orientation) transposed_font = ImageFont.TransposedFont(font, orientation=orientation)
@ -415,11 +415,11 @@ def test_unrotated_transposed_font_get_mask(font, orientation):
assert mask.size == (108, 13) assert mask.size == (108, 13)
def test_free_type_font_get_name(font): def test_free_type_font_get_name(font) -> None:
assert ("FreeMono", "Regular") == font.getname() assert ("FreeMono", "Regular") == font.getname()
def test_free_type_font_get_metrics(font): def test_free_type_font_get_metrics(font) -> None:
ascent, descent = font.getmetrics() ascent, descent = font.getmetrics()
assert isinstance(ascent, int) assert isinstance(ascent, int)
@ -427,7 +427,7 @@ def test_free_type_font_get_metrics(font):
assert (ascent, descent) == (16, 4) assert (ascent, descent) == (16, 4)
def test_free_type_font_get_mask(font): def test_free_type_font_get_mask(font) -> None:
# Arrange # Arrange
text = "mask this" text = "mask this"
@ -438,7 +438,7 @@ def test_free_type_font_get_mask(font):
assert mask.size == (108, 13) assert mask.size == (108, 13)
def test_load_path_not_found(): def test_load_path_not_found() -> None:
# Arrange # Arrange
filename = "somefilenamethatdoesntexist.ttf" filename = "somefilenamethatdoesntexist.ttf"
@ -449,13 +449,13 @@ def test_load_path_not_found():
ImageFont.truetype(filename) ImageFont.truetype(filename)
def test_load_non_font_bytes(): def test_load_non_font_bytes() -> None:
with open("Tests/images/hopper.jpg", "rb") as f: with open("Tests/images/hopper.jpg", "rb") as f:
with pytest.raises(OSError): with pytest.raises(OSError):
ImageFont.truetype(f) ImageFont.truetype(f)
def test_default_font(): def test_default_font() -> None:
# Arrange # Arrange
txt = "This is a default font using FreeType support." txt = "This is a default font using FreeType support."
im = Image.new(mode="RGB", size=(300, 100)) im = Image.new(mode="RGB", size=(300, 100))
@ -473,16 +473,16 @@ def test_default_font():
@pytest.mark.parametrize("mode", (None, "1", "RGBA")) @pytest.mark.parametrize("mode", (None, "1", "RGBA"))
def test_getbbox(font, mode): def test_getbbox(font, mode) -> None:
assert (0, 4, 12, 16) == font.getbbox("A", mode) assert (0, 4, 12, 16) == font.getbbox("A", mode)
def test_getbbox_empty(font): def test_getbbox_empty(font) -> None:
# issue #2614, should not crash. # issue #2614, should not crash.
assert (0, 0, 0, 0) == font.getbbox("") assert (0, 0, 0, 0) == font.getbbox("")
def test_render_empty(font): def test_render_empty(font) -> None:
# issue 2666 # issue 2666
im = Image.new(mode="RGB", size=(300, 100)) im = Image.new(mode="RGB", size=(300, 100))
target = im.copy() target = im.copy()
@ -492,7 +492,7 @@ def test_render_empty(font):
assert_image_equal(im, target) assert_image_equal(im, target)
def test_unicode_extended(layout_engine): def test_unicode_extended(layout_engine) -> None:
# issue #3777 # issue #3777
text = "A\u278A\U0001F12B" text = "A\u278A\U0001F12B"
target = "Tests/images/unicode_extended.png" target = "Tests/images/unicode_extended.png"
@ -515,8 +515,8 @@ def test_unicode_extended(layout_engine):
(("linux", "/usr/local/share/fonts"), ("darwin", "/System/Library/Fonts")), (("linux", "/usr/local/share/fonts"), ("darwin", "/System/Library/Fonts")),
) )
@pytest.mark.skipif(is_win32(), reason="requires Unix or macOS") @pytest.mark.skipif(is_win32(), reason="requires Unix or macOS")
def test_find_font(monkeypatch, platform, font_directory): def test_find_font(monkeypatch, platform, font_directory) -> None:
def _test_fake_loading_font(path_to_fake, fontname): def _test_fake_loading_font(path_to_fake, fontname) -> None:
# Make a copy of FreeTypeFont so we can patch the original # Make a copy of FreeTypeFont so we can patch the original
free_type_font = copy.deepcopy(ImageFont.FreeTypeFont) free_type_font = copy.deepcopy(ImageFont.FreeTypeFont)
with monkeypatch.context() as m: with monkeypatch.context() as m:
@ -567,7 +567,7 @@ def test_find_font(monkeypatch, platform, font_directory):
_test_fake_loading_font(font_directory + "/Duplicate.ttf", "Duplicate") _test_fake_loading_font(font_directory + "/Duplicate.ttf", "Duplicate")
def test_imagefont_getters(font): def test_imagefont_getters(font) -> None:
assert font.getmetrics() == (16, 4) assert font.getmetrics() == (16, 4)
assert font.font.ascent == 16 assert font.font.ascent == 16
assert font.font.descent == 4 assert font.font.descent == 4
@ -588,7 +588,7 @@ def test_imagefont_getters(font):
@pytest.mark.parametrize("stroke_width", (0, 2)) @pytest.mark.parametrize("stroke_width", (0, 2))
def test_getsize_stroke(font, stroke_width): def test_getsize_stroke(font, stroke_width) -> None:
assert font.getbbox("A", stroke_width=stroke_width) == ( assert font.getbbox("A", stroke_width=stroke_width) == (
0 - stroke_width, 0 - stroke_width,
4 - stroke_width, 4 - stroke_width,
@ -597,7 +597,7 @@ def test_getsize_stroke(font, stroke_width):
) )
def test_complex_font_settings(): def test_complex_font_settings() -> None:
t = ImageFont.truetype(FONT_PATH, FONT_SIZE, layout_engine=ImageFont.Layout.BASIC) t = ImageFont.truetype(FONT_PATH, FONT_SIZE, layout_engine=ImageFont.Layout.BASIC)
with pytest.raises(KeyError): with pytest.raises(KeyError):
t.getmask("абвг", direction="rtl") t.getmask("абвг", direction="rtl")
@ -607,7 +607,7 @@ def test_complex_font_settings():
t.getmask("абвг", language="sr") t.getmask("абвг", language="sr")
def test_variation_get(font): def test_variation_get(font) -> None:
freetype = parse_version(features.version_module("freetype2")) freetype = parse_version(features.version_module("freetype2"))
if freetype < parse_version("2.9.1"): if freetype < parse_version("2.9.1"):
with pytest.raises(NotImplementedError): with pytest.raises(NotImplementedError):
@ -677,7 +677,7 @@ def _check_text(font, path, epsilon):
raise raise
def test_variation_set_by_name(font): def test_variation_set_by_name(font) -> None:
freetype = parse_version(features.version_module("freetype2")) freetype = parse_version(features.version_module("freetype2"))
if freetype < parse_version("2.9.1"): if freetype < parse_version("2.9.1"):
with pytest.raises(NotImplementedError): with pytest.raises(NotImplementedError):
@ -702,7 +702,7 @@ def test_variation_set_by_name(font):
_check_text(font, "Tests/images/variation_tiny_name.png", 40) _check_text(font, "Tests/images/variation_tiny_name.png", 40)
def test_variation_set_by_axes(font): def test_variation_set_by_axes(font) -> None:
freetype = parse_version(features.version_module("freetype2")) freetype = parse_version(features.version_module("freetype2"))
if freetype < parse_version("2.9.1"): if freetype < parse_version("2.9.1"):
with pytest.raises(NotImplementedError): with pytest.raises(NotImplementedError):
@ -737,7 +737,7 @@ def test_variation_set_by_axes(font):
), ),
ids=("ls", "ms", "rs", "ma", "mt", "mm", "mb", "md"), ids=("ls", "ms", "rs", "ma", "mt", "mm", "mb", "md"),
) )
def test_anchor(layout_engine, anchor, left, top): def test_anchor(layout_engine, anchor, left, top) -> None:
name, text = "quick", "Quick" name, text = "quick", "Quick"
path = f"Tests/images/test_anchor_{name}_{anchor}.png" path = f"Tests/images/test_anchor_{name}_{anchor}.png"
@ -782,7 +782,7 @@ def test_anchor(layout_engine, anchor, left, top):
("md", "center"), ("md", "center"),
), ),
) )
def test_anchor_multiline(layout_engine, anchor, align): def test_anchor_multiline(layout_engine, anchor, align) -> None:
target = f"Tests/images/test_anchor_multiline_{anchor}_{align}.png" target = f"Tests/images/test_anchor_multiline_{anchor}_{align}.png"
text = "a\nlong\ntext sample" text = "a\nlong\ntext sample"
@ -800,7 +800,7 @@ def test_anchor_multiline(layout_engine, anchor, align):
assert_image_similar_tofile(im, target, 4) assert_image_similar_tofile(im, target, 4)
def test_anchor_invalid(font): def test_anchor_invalid(font) -> None:
im = Image.new("RGB", (100, 100), "white") im = Image.new("RGB", (100, 100), "white")
d = ImageDraw.Draw(im) d = ImageDraw.Draw(im)
d.font = font d.font = font
@ -826,7 +826,7 @@ def test_anchor_invalid(font):
@pytest.mark.parametrize("bpp", (1, 2, 4, 8)) @pytest.mark.parametrize("bpp", (1, 2, 4, 8))
def test_bitmap_font(layout_engine, bpp): def test_bitmap_font(layout_engine, bpp) -> None:
text = "Bitmap Font" text = "Bitmap Font"
layout_name = ["basic", "raqm"][layout_engine] layout_name = ["basic", "raqm"][layout_engine]
target = f"Tests/images/bitmap_font_{bpp}_{layout_name}.png" target = f"Tests/images/bitmap_font_{bpp}_{layout_name}.png"
@ -843,7 +843,7 @@ def test_bitmap_font(layout_engine, bpp):
assert_image_equal_tofile(im, target) assert_image_equal_tofile(im, target)
def test_bitmap_font_stroke(layout_engine): def test_bitmap_font_stroke(layout_engine) -> None:
text = "Bitmap Font" text = "Bitmap Font"
layout_name = ["basic", "raqm"][layout_engine] layout_name = ["basic", "raqm"][layout_engine]
target = f"Tests/images/bitmap_font_stroke_{layout_name}.png" target = f"Tests/images/bitmap_font_stroke_{layout_name}.png"
@ -861,7 +861,7 @@ def test_bitmap_font_stroke(layout_engine):
@pytest.mark.parametrize("embedded_color", (False, True)) @pytest.mark.parametrize("embedded_color", (False, True))
def test_bitmap_blend(layout_engine, embedded_color): def test_bitmap_blend(layout_engine, embedded_color) -> None:
font = ImageFont.truetype( font = ImageFont.truetype(
"Tests/fonts/EBDTTestFont.ttf", size=64, layout_engine=layout_engine "Tests/fonts/EBDTTestFont.ttf", size=64, layout_engine=layout_engine
) )
@ -873,7 +873,7 @@ def test_bitmap_blend(layout_engine, embedded_color):
assert_image_equal_tofile(im, "Tests/images/bitmap_font_blend.png") assert_image_equal_tofile(im, "Tests/images/bitmap_font_blend.png")
def test_standard_embedded_color(layout_engine): def test_standard_embedded_color(layout_engine) -> None:
txt = "Hello World!" txt = "Hello World!"
ttf = ImageFont.truetype(FONT_PATH, 40, layout_engine=layout_engine) ttf = ImageFont.truetype(FONT_PATH, 40, layout_engine=layout_engine)
ttf.getbbox(txt) ttf.getbbox(txt)
@ -908,7 +908,7 @@ def test_float_coord(layout_engine, fontmode):
raise raise
def test_cbdt(layout_engine): def test_cbdt(layout_engine) -> None:
try: try:
font = ImageFont.truetype( font = ImageFont.truetype(
"Tests/fonts/CBDTTestFont.ttf", size=64, layout_engine=layout_engine "Tests/fonts/CBDTTestFont.ttf", size=64, layout_engine=layout_engine
@ -925,7 +925,7 @@ def test_cbdt(layout_engine):
pytest.skip("freetype compiled without libpng or CBDT support") pytest.skip("freetype compiled without libpng or CBDT support")
def test_cbdt_mask(layout_engine): def test_cbdt_mask(layout_engine) -> None:
try: try:
font = ImageFont.truetype( font = ImageFont.truetype(
"Tests/fonts/CBDTTestFont.ttf", size=64, layout_engine=layout_engine "Tests/fonts/CBDTTestFont.ttf", size=64, layout_engine=layout_engine
@ -942,7 +942,7 @@ def test_cbdt_mask(layout_engine):
pytest.skip("freetype compiled without libpng or CBDT support") pytest.skip("freetype compiled without libpng or CBDT support")
def test_sbix(layout_engine): def test_sbix(layout_engine) -> None:
try: try:
font = ImageFont.truetype( font = ImageFont.truetype(
"Tests/fonts/chromacheck-sbix.woff", size=300, layout_engine=layout_engine "Tests/fonts/chromacheck-sbix.woff", size=300, layout_engine=layout_engine
@ -959,7 +959,7 @@ def test_sbix(layout_engine):
pytest.skip("freetype compiled without libpng or SBIX support") pytest.skip("freetype compiled without libpng or SBIX support")
def test_sbix_mask(layout_engine): def test_sbix_mask(layout_engine) -> None:
try: try:
font = ImageFont.truetype( font = ImageFont.truetype(
"Tests/fonts/chromacheck-sbix.woff", size=300, layout_engine=layout_engine "Tests/fonts/chromacheck-sbix.woff", size=300, layout_engine=layout_engine
@ -977,7 +977,7 @@ def test_sbix_mask(layout_engine):
@skip_unless_feature_version("freetype2", "2.10.0") @skip_unless_feature_version("freetype2", "2.10.0")
def test_colr(layout_engine): def test_colr(layout_engine) -> None:
font = ImageFont.truetype( font = ImageFont.truetype(
"Tests/fonts/BungeeColor-Regular_colr_Windows.ttf", "Tests/fonts/BungeeColor-Regular_colr_Windows.ttf",
size=64, size=64,
@ -993,7 +993,7 @@ def test_colr(layout_engine):
@skip_unless_feature_version("freetype2", "2.10.0") @skip_unless_feature_version("freetype2", "2.10.0")
def test_colr_mask(layout_engine): def test_colr_mask(layout_engine) -> None:
font = ImageFont.truetype( font = ImageFont.truetype(
"Tests/fonts/BungeeColor-Regular_colr_Windows.ttf", "Tests/fonts/BungeeColor-Regular_colr_Windows.ttf",
size=64, size=64,
@ -1008,7 +1008,7 @@ def test_colr_mask(layout_engine):
assert_image_similar_tofile(im, "Tests/images/colr_bungee_mask.png", 22) assert_image_similar_tofile(im, "Tests/images/colr_bungee_mask.png", 22)
def test_woff2(layout_engine): def test_woff2(layout_engine) -> None:
try: try:
font = ImageFont.truetype( font = ImageFont.truetype(
"Tests/fonts/OpenSans.woff2", "Tests/fonts/OpenSans.woff2",
@ -1027,7 +1027,7 @@ def test_woff2(layout_engine):
assert_image_similar_tofile(im, "Tests/images/test_woff2.png", 5) assert_image_similar_tofile(im, "Tests/images/test_woff2.png", 5)
def test_render_mono_size(): def test_render_mono_size() -> None:
# issue 4177 # issue 4177
im = Image.new("P", (100, 30), "white") im = Image.new("P", (100, 30), "white")
@ -1042,7 +1042,7 @@ def test_render_mono_size():
assert_image_equal_tofile(im, "Tests/images/text_mono.gif") assert_image_equal_tofile(im, "Tests/images/text_mono.gif")
def test_too_many_characters(font): def test_too_many_characters(font) -> None:
with pytest.raises(ValueError): with pytest.raises(ValueError):
font.getlength("A" * 1_000_001) font.getlength("A" * 1_000_001)
with pytest.raises(ValueError): with pytest.raises(ValueError):
@ -1070,14 +1070,14 @@ def test_too_many_characters(font):
"Tests/fonts/oom-4da0210eb7081b0bf15bf16cc4c52ce02c1e1bbc.ttf", "Tests/fonts/oom-4da0210eb7081b0bf15bf16cc4c52ce02c1e1bbc.ttf",
], ],
) )
def test_oom(test_file): def test_oom(test_file) -> None:
with open(test_file, "rb") as f: with open(test_file, "rb") as f:
font = ImageFont.truetype(BytesIO(f.read())) font = ImageFont.truetype(BytesIO(f.read()))
with pytest.raises(Image.DecompressionBombError): with pytest.raises(Image.DecompressionBombError):
font.getmask("Test Text") font.getmask("Test Text")
def test_raqm_missing_warning(monkeypatch): def test_raqm_missing_warning(monkeypatch) -> None:
monkeypatch.setattr(ImageFont.core, "HAVE_RAQM", False) monkeypatch.setattr(ImageFont.core, "HAVE_RAQM", False)
with pytest.warns(UserWarning) as record: with pytest.warns(UserWarning) as record:
font = ImageFont.truetype( font = ImageFont.truetype(
@ -1091,6 +1091,6 @@ def test_raqm_missing_warning(monkeypatch):
@pytest.mark.parametrize("size", [-1, 0]) @pytest.mark.parametrize("size", [-1, 0])
def test_invalid_truetype_sizes_raise_valueerror(layout_engine, size): def test_invalid_truetype_sizes_raise_valueerror(layout_engine, size) -> None:
with pytest.raises(ValueError): with pytest.raises(ValueError):
ImageFont.truetype(FONT_PATH, size, layout_engine=layout_engine) ImageFont.truetype(FONT_PATH, size, layout_engine=layout_engine)

View File

@ -12,7 +12,7 @@ FONT_PATH = "Tests/fonts/DejaVuSans/DejaVuSans.ttf"
pytestmark = skip_unless_feature("raqm") pytestmark = skip_unless_feature("raqm")
def test_english(): def test_english() -> None:
# smoke test, this should not fail # smoke test, this should not fail
ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE) ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE)
im = Image.new(mode="RGB", size=(300, 100)) im = Image.new(mode="RGB", size=(300, 100))
@ -20,7 +20,7 @@ def test_english():
draw.text((0, 0), "TEST", font=ttf, fill=500, direction="ltr") draw.text((0, 0), "TEST", font=ttf, fill=500, direction="ltr")
def test_complex_text(): def test_complex_text() -> None:
ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE) ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE)
im = Image.new(mode="RGB", size=(300, 100)) im = Image.new(mode="RGB", size=(300, 100))
@ -31,7 +31,7 @@ def test_complex_text():
assert_image_similar_tofile(im, target, 0.5) assert_image_similar_tofile(im, target, 0.5)
def test_y_offset(): def test_y_offset() -> None:
ttf = ImageFont.truetype("Tests/fonts/NotoNastaliqUrdu-Regular.ttf", FONT_SIZE) ttf = ImageFont.truetype("Tests/fonts/NotoNastaliqUrdu-Regular.ttf", FONT_SIZE)
im = Image.new(mode="RGB", size=(300, 100)) im = Image.new(mode="RGB", size=(300, 100))
@ -42,7 +42,7 @@ def test_y_offset():
assert_image_similar_tofile(im, target, 1.7) assert_image_similar_tofile(im, target, 1.7)
def test_complex_unicode_text(): def test_complex_unicode_text() -> None:
ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE) ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE)
im = Image.new(mode="RGB", size=(300, 100)) im = Image.new(mode="RGB", size=(300, 100))
@ -62,7 +62,7 @@ def test_complex_unicode_text():
assert_image_similar_tofile(im, target, 2.33) assert_image_similar_tofile(im, target, 2.33)
def test_text_direction_rtl(): def test_text_direction_rtl() -> None:
ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE) ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE)
im = Image.new(mode="RGB", size=(300, 100)) im = Image.new(mode="RGB", size=(300, 100))
@ -73,7 +73,7 @@ def test_text_direction_rtl():
assert_image_similar_tofile(im, target, 0.5) assert_image_similar_tofile(im, target, 0.5)
def test_text_direction_ltr(): def test_text_direction_ltr() -> None:
ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE) ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE)
im = Image.new(mode="RGB", size=(300, 100)) im = Image.new(mode="RGB", size=(300, 100))
@ -84,7 +84,7 @@ def test_text_direction_ltr():
assert_image_similar_tofile(im, target, 0.5) assert_image_similar_tofile(im, target, 0.5)
def test_text_direction_rtl2(): def test_text_direction_rtl2() -> None:
ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE) ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE)
im = Image.new(mode="RGB", size=(300, 100)) im = Image.new(mode="RGB", size=(300, 100))
@ -95,7 +95,7 @@ def test_text_direction_rtl2():
assert_image_similar_tofile(im, target, 0.5) assert_image_similar_tofile(im, target, 0.5)
def test_text_direction_ttb(): def test_text_direction_ttb() -> None:
ttf = ImageFont.truetype("Tests/fonts/NotoSansJP-Regular.otf", FONT_SIZE) ttf = ImageFont.truetype("Tests/fonts/NotoSansJP-Regular.otf", FONT_SIZE)
im = Image.new(mode="RGB", size=(100, 300)) im = Image.new(mode="RGB", size=(100, 300))
@ -110,7 +110,7 @@ def test_text_direction_ttb():
assert_image_similar_tofile(im, target, 2.8) assert_image_similar_tofile(im, target, 2.8)
def test_text_direction_ttb_stroke(): def test_text_direction_ttb_stroke() -> None:
ttf = ImageFont.truetype("Tests/fonts/NotoSansJP-Regular.otf", 50) ttf = ImageFont.truetype("Tests/fonts/NotoSansJP-Regular.otf", 50)
im = Image.new(mode="RGB", size=(100, 300)) im = Image.new(mode="RGB", size=(100, 300))
@ -133,7 +133,7 @@ def test_text_direction_ttb_stroke():
assert_image_similar_tofile(im, target, 19.4) assert_image_similar_tofile(im, target, 19.4)
def test_ligature_features(): def test_ligature_features() -> None:
ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE) ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE)
im = Image.new(mode="RGB", size=(300, 100)) im = Image.new(mode="RGB", size=(300, 100))
@ -146,7 +146,7 @@ def test_ligature_features():
assert liga_bbox == (0, 4, 13, 19) assert liga_bbox == (0, 4, 13, 19)
def test_kerning_features(): def test_kerning_features() -> None:
ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE) ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE)
im = Image.new(mode="RGB", size=(300, 100)) im = Image.new(mode="RGB", size=(300, 100))
@ -157,7 +157,7 @@ def test_kerning_features():
assert_image_similar_tofile(im, target, 0.5) assert_image_similar_tofile(im, target, 0.5)
def test_arabictext_features(): def test_arabictext_features() -> None:
ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE) ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE)
im = Image.new(mode="RGB", size=(300, 100)) im = Image.new(mode="RGB", size=(300, 100))
@ -174,7 +174,7 @@ def test_arabictext_features():
assert_image_similar_tofile(im, target, 0.5) assert_image_similar_tofile(im, target, 0.5)
def test_x_max_and_y_offset(): def test_x_max_and_y_offset() -> None:
ttf = ImageFont.truetype("Tests/fonts/ArefRuqaa-Regular.ttf", 40) ttf = ImageFont.truetype("Tests/fonts/ArefRuqaa-Regular.ttf", 40)
im = Image.new(mode="RGB", size=(50, 100)) im = Image.new(mode="RGB", size=(50, 100))
@ -185,7 +185,7 @@ def test_x_max_and_y_offset():
assert_image_similar_tofile(im, target, 0.5) assert_image_similar_tofile(im, target, 0.5)
def test_language(): def test_language() -> None:
ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE) ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE)
im = Image.new(mode="RGB", size=(300, 100)) im = Image.new(mode="RGB", size=(300, 100))
@ -208,7 +208,7 @@ def test_language():
), ),
ids=("None", "ltr", "rtl2", "rtl", "ttb"), ids=("None", "ltr", "rtl2", "rtl", "ttb"),
) )
def test_getlength(mode, text, direction, expected): def test_getlength(mode, text, direction, expected) -> None:
ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE) ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE)
im = Image.new(mode, (1, 1), 0) im = Image.new(mode, (1, 1), 0)
d = ImageDraw.Draw(im) d = ImageDraw.Draw(im)
@ -230,7 +230,7 @@ def test_getlength(mode, text, direction, expected):
("i" + ("\u030C" * 15) + "i", "i" + "\u032C" * 15 + "i", "\u035Cii", "i\u0305i"), ("i" + ("\u030C" * 15) + "i", "i" + "\u032C" * 15 + "i", "\u035Cii", "i\u0305i"),
ids=("caron-above", "caron-below", "double-breve", "overline"), ids=("caron-above", "caron-below", "double-breve", "overline"),
) )
def test_getlength_combine(mode, direction, text): def test_getlength_combine(mode, direction, text) -> None:
if text == "i\u0305i" and direction == "ttb": if text == "i\u0305i" and direction == "ttb":
pytest.skip("fails with this font") pytest.skip("fails with this font")
@ -250,7 +250,7 @@ def test_getlength_combine(mode, direction, text):
@pytest.mark.parametrize("anchor", ("lt", "mm", "rb", "sm")) @pytest.mark.parametrize("anchor", ("lt", "mm", "rb", "sm"))
def test_anchor_ttb(anchor): def test_anchor_ttb(anchor) -> None:
text = "f" text = "f"
path = f"Tests/images/test_anchor_ttb_{text}_{anchor}.png" path = f"Tests/images/test_anchor_ttb_{text}_{anchor}.png"
f = ImageFont.truetype("Tests/fonts/NotoSans-Regular.ttf", 120) f = ImageFont.truetype("Tests/fonts/NotoSans-Regular.ttf", 120)
@ -306,7 +306,7 @@ combine_tests = (
@pytest.mark.parametrize( @pytest.mark.parametrize(
"name, text, anchor, dir, epsilon", combine_tests, ids=[r[0] for r in combine_tests] "name, text, anchor, dir, epsilon", combine_tests, ids=[r[0] for r in combine_tests]
) )
def test_combine(name, text, dir, anchor, epsilon): def test_combine(name, text, dir, anchor, epsilon) -> None:
path = f"Tests/images/test_combine_{name}.png" path = f"Tests/images/test_combine_{name}.png"
f = ImageFont.truetype("Tests/fonts/NotoSans-Regular.ttf", 48) f = ImageFont.truetype("Tests/fonts/NotoSans-Regular.ttf", 48)
@ -337,7 +337,7 @@ def test_combine(name, text, dir, anchor, epsilon):
("rm", "right"), # pass with getsize ("rm", "right"), # pass with getsize
), ),
) )
def test_combine_multiline(anchor, align): def test_combine_multiline(anchor, align) -> None:
# test that multiline text uses getlength, not getsize or getbbox # test that multiline text uses getlength, not getsize or getbbox
path = f"Tests/images/test_combine_multiline_{anchor}_{align}.png" path = f"Tests/images/test_combine_multiline_{anchor}_{align}.png"
@ -355,7 +355,7 @@ def test_combine_multiline(anchor, align):
assert_image_similar_tofile(im, path, 0.015) assert_image_similar_tofile(im, path, 0.015)
def test_anchor_invalid_ttb(): def test_anchor_invalid_ttb() -> None:
font = ImageFont.truetype(FONT_PATH, FONT_SIZE) font = ImageFont.truetype(FONT_PATH, FONT_SIZE)
im = Image.new("RGB", (100, 100), "white") im = Image.new("RGB", (100, 100), "white")
d = ImageDraw.Draw(im) d = ImageDraw.Draw(im)

View File

@ -12,16 +12,16 @@ from .helper import assert_image_equal_tofile
original_core = ImageFont.core original_core = ImageFont.core
def setup_module(): def setup_module() -> None:
if features.check_module("freetype2"): if features.check_module("freetype2"):
ImageFont.core = _util.DeferredError(ImportError) ImageFont.core = _util.DeferredError(ImportError)
def teardown_module(): def teardown_module() -> None:
ImageFont.core = original_core ImageFont.core = original_core
def test_default_font(): def test_default_font() -> None:
# Arrange # Arrange
txt = 'This is a "better than nothing" default font.' txt = 'This is a "better than nothing" default font.'
im = Image.new(mode="RGB", size=(300, 100)) im = Image.new(mode="RGB", size=(300, 100))
@ -35,12 +35,12 @@ def test_default_font():
assert_image_equal_tofile(im, "Tests/images/default_font.png") assert_image_equal_tofile(im, "Tests/images/default_font.png")
def test_size_without_freetype(): def test_size_without_freetype() -> None:
with pytest.raises(ImportError): with pytest.raises(ImportError):
ImageFont.load_default(size=14) ImageFont.load_default(size=14)
def test_unicode(): def test_unicode() -> None:
# should not segfault, should return UnicodeDecodeError # should not segfault, should return UnicodeDecodeError
# issue #2826 # issue #2826
font = ImageFont.load_default() font = ImageFont.load_default()
@ -48,7 +48,7 @@ def test_unicode():
font.getbbox("") font.getbbox("")
def test_textbbox(): def test_textbbox() -> None:
im = Image.new("RGB", (200, 200)) im = Image.new("RGB", (200, 200))
d = ImageDraw.Draw(im) d = ImageDraw.Draw(im)
default_font = ImageFont.load_default() default_font = ImageFont.load_default()
@ -56,7 +56,7 @@ def test_textbbox():
assert d.textbbox((0, 0), "test", font=default_font) == (0, 0, 24, 11) assert d.textbbox((0, 0), "test", font=default_font) == (0, 0, 24, 11)
def test_decompression_bomb(): def test_decompression_bomb() -> None:
glyph = struct.pack(">hhhhhhhhhh", 1, 0, 0, 0, 256, 256, 0, 0, 256, 256) glyph = struct.pack(">hhhhhhhhhh", 1, 0, 0, 0, 256, 256, 0, 0, 256, 256)
fp = BytesIO(b"PILfont\n\nDATA\n" + glyph * 256) fp = BytesIO(b"PILfont\n\nDATA\n" + glyph * 256)
@ -67,7 +67,7 @@ def test_decompression_bomb():
@pytest.mark.timeout(4) @pytest.mark.timeout(4)
def test_oom(): def test_oom() -> None:
glyph = struct.pack( glyph = struct.pack(
">hhhhhhhhhh", 1, 0, -32767, -32767, 32767, 32767, -32767, -32767, 32767, 32767 ">hhhhhhhhhh", 1, 0, -32767, -32767, 32767, 32767, -32767, -32767, 32767, 32767
) )

View File

@ -20,7 +20,7 @@ class TestImageGrab:
@pytest.mark.skipif( @pytest.mark.skipif(
sys.platform not in ("win32", "darwin"), reason="requires Windows or macOS" sys.platform not in ("win32", "darwin"), reason="requires Windows or macOS"
) )
def test_grab(self): def test_grab(self) -> None:
ImageGrab.grab() ImageGrab.grab()
ImageGrab.grab(include_layered_windows=True) ImageGrab.grab(include_layered_windows=True)
ImageGrab.grab(all_screens=True) ImageGrab.grab(all_screens=True)
@ -29,7 +29,7 @@ class TestImageGrab:
assert im.size == (40, 60) assert im.size == (40, 60)
@skip_unless_feature("xcb") @skip_unless_feature("xcb")
def test_grab_x11(self): def test_grab_x11(self) -> None:
try: try:
if sys.platform not in ("win32", "darwin"): if sys.platform not in ("win32", "darwin"):
ImageGrab.grab() ImageGrab.grab()
@ -39,7 +39,7 @@ class TestImageGrab:
pytest.skip(str(e)) pytest.skip(str(e))
@pytest.mark.skipif(Image.core.HAVE_XCB, reason="tests missing XCB") @pytest.mark.skipif(Image.core.HAVE_XCB, reason="tests missing XCB")
def test_grab_no_xcb(self): def test_grab_no_xcb(self) -> None:
if sys.platform not in ("win32", "darwin") and not shutil.which( if sys.platform not in ("win32", "darwin") and not shutil.which(
"gnome-screenshot" "gnome-screenshot"
): ):
@ -52,12 +52,12 @@ class TestImageGrab:
assert str(e.value).startswith("Pillow was built without XCB support") assert str(e.value).startswith("Pillow was built without XCB support")
@skip_unless_feature("xcb") @skip_unless_feature("xcb")
def test_grab_invalid_xdisplay(self): def test_grab_invalid_xdisplay(self) -> None:
with pytest.raises(OSError) as e: with pytest.raises(OSError) as e:
ImageGrab.grab(xdisplay="error.test:0.0") ImageGrab.grab(xdisplay="error.test:0.0")
assert str(e.value).startswith("X connection failed") assert str(e.value).startswith("X connection failed")
def test_grabclipboard(self): def test_grabclipboard(self) -> None:
if sys.platform == "darwin": if sys.platform == "darwin":
subprocess.call(["screencapture", "-cx"]) subprocess.call(["screencapture", "-cx"])
elif sys.platform == "win32": elif sys.platform == "win32":
@ -82,7 +82,7 @@ $bmp = New-Object Drawing.Bitmap 200, 200
ImageGrab.grabclipboard() ImageGrab.grabclipboard()
@pytest.mark.skipif(sys.platform != "win32", reason="Windows only") @pytest.mark.skipif(sys.platform != "win32", reason="Windows only")
def test_grabclipboard_file(self): def test_grabclipboard_file(self) -> None:
p = subprocess.Popen(["powershell", "-command", "-"], stdin=subprocess.PIPE) p = subprocess.Popen(["powershell", "-command", "-"], stdin=subprocess.PIPE)
p.stdin.write(rb'Set-Clipboard -Path "Tests\images\hopper.gif"') p.stdin.write(rb'Set-Clipboard -Path "Tests\images\hopper.gif"')
p.communicate() p.communicate()
@ -92,7 +92,7 @@ $bmp = New-Object Drawing.Bitmap 200, 200
assert os.path.samefile(im[0], "Tests/images/hopper.gif") assert os.path.samefile(im[0], "Tests/images/hopper.gif")
@pytest.mark.skipif(sys.platform != "win32", reason="Windows only") @pytest.mark.skipif(sys.platform != "win32", reason="Windows only")
def test_grabclipboard_png(self): def test_grabclipboard_png(self) -> None:
p = subprocess.Popen(["powershell", "-command", "-"], stdin=subprocess.PIPE) p = subprocess.Popen(["powershell", "-command", "-"], stdin=subprocess.PIPE)
p.stdin.write( p.stdin.write(
rb"""$bytes = [System.IO.File]::ReadAllBytes("Tests\images\hopper.png") rb"""$bytes = [System.IO.File]::ReadAllBytes("Tests\images\hopper.png")
@ -113,7 +113,7 @@ $ms = new-object System.IO.MemoryStream(, $bytes)
reason="Linux with wl-clipboard only", reason="Linux with wl-clipboard only",
) )
@pytest.mark.parametrize("ext", ("gif", "png", "ico")) @pytest.mark.parametrize("ext", ("gif", "png", "ico"))
def test_grabclipboard_wl_clipboard(self, ext): def test_grabclipboard_wl_clipboard(self, ext) -> None:
image_path = "Tests/images/hopper." + ext image_path = "Tests/images/hopper." + ext
with open(image_path, "rb") as fp: with open(image_path, "rb") as fp:
subprocess.call(["wl-copy"], stdin=fp) subprocess.call(["wl-copy"], stdin=fp)

View File

@ -24,7 +24,7 @@ B2 = B.resize((2, 2))
images = {"A": A, "B": B, "F": F, "I": I} images = {"A": A, "B": B, "F": F, "I": I}
def test_sanity(): def test_sanity() -> None:
assert ImageMath.eval("1") == 1 assert ImageMath.eval("1") == 1
assert ImageMath.eval("1+A", A=2) == 3 assert ImageMath.eval("1+A", A=2) == 3
assert pixel(ImageMath.eval("A+B", A=A, B=B)) == "I 3" assert pixel(ImageMath.eval("A+B", A=A, B=B)) == "I 3"
@ -33,7 +33,7 @@ def test_sanity():
assert pixel(ImageMath.eval("int(float(A)+B)", images)) == "I 3" assert pixel(ImageMath.eval("int(float(A)+B)", images)) == "I 3"
def test_ops(): def test_ops() -> None:
assert pixel(ImageMath.eval("-A", images)) == "I -1" assert pixel(ImageMath.eval("-A", images)) == "I -1"
assert pixel(ImageMath.eval("+B", images)) == "L 2" assert pixel(ImageMath.eval("+B", images)) == "L 2"
@ -60,51 +60,51 @@ def test_ops():
"(lambda: (lambda: exec('pass'))())()", "(lambda: (lambda: exec('pass'))())()",
), ),
) )
def test_prevent_exec(expression): def test_prevent_exec(expression) -> None:
with pytest.raises(ValueError): with pytest.raises(ValueError):
ImageMath.eval(expression) ImageMath.eval(expression)
def test_prevent_double_underscores(): def test_prevent_double_underscores() -> None:
with pytest.raises(ValueError): with pytest.raises(ValueError):
ImageMath.eval("1", {"__": None}) ImageMath.eval("1", {"__": None})
def test_prevent_builtins(): def test_prevent_builtins() -> None:
with pytest.raises(ValueError): with pytest.raises(ValueError):
ImageMath.eval("(lambda: exec('exit()'))()", {"exec": None}) ImageMath.eval("(lambda: exec('exit()'))()", {"exec": None})
def test_logical(): def test_logical() -> None:
assert pixel(ImageMath.eval("not A", images)) == 0 assert pixel(ImageMath.eval("not A", images)) == 0
assert pixel(ImageMath.eval("A and B", images)) == "L 2" assert pixel(ImageMath.eval("A and B", images)) == "L 2"
assert pixel(ImageMath.eval("A or B", images)) == "L 1" assert pixel(ImageMath.eval("A or B", images)) == "L 1"
def test_convert(): def test_convert() -> None:
assert pixel(ImageMath.eval("convert(A+B, 'L')", images)) == "L 3" assert pixel(ImageMath.eval("convert(A+B, 'L')", images)) == "L 3"
assert pixel(ImageMath.eval("convert(A+B, '1')", images)) == "1 0" assert pixel(ImageMath.eval("convert(A+B, '1')", images)) == "1 0"
assert pixel(ImageMath.eval("convert(A+B, 'RGB')", images)) == "RGB (3, 3, 3)" assert pixel(ImageMath.eval("convert(A+B, 'RGB')", images)) == "RGB (3, 3, 3)"
def test_compare(): def test_compare() -> None:
assert pixel(ImageMath.eval("min(A, B)", images)) == "I 1" assert pixel(ImageMath.eval("min(A, B)", images)) == "I 1"
assert pixel(ImageMath.eval("max(A, B)", images)) == "I 2" assert pixel(ImageMath.eval("max(A, B)", images)) == "I 2"
assert pixel(ImageMath.eval("A == 1", images)) == "I 1" assert pixel(ImageMath.eval("A == 1", images)) == "I 1"
assert pixel(ImageMath.eval("A == 2", images)) == "I 0" assert pixel(ImageMath.eval("A == 2", images)) == "I 0"
def test_one_image_larger(): def test_one_image_larger() -> None:
assert pixel(ImageMath.eval("A+B", A=A2, B=B)) == "I 3" assert pixel(ImageMath.eval("A+B", A=A2, B=B)) == "I 3"
assert pixel(ImageMath.eval("A+B", A=A, B=B2)) == "I 3" assert pixel(ImageMath.eval("A+B", A=A, B=B2)) == "I 3"
def test_abs(): def test_abs() -> None:
assert pixel(ImageMath.eval("abs(A)", A=A)) == "I 1" assert pixel(ImageMath.eval("abs(A)", A=A)) == "I 1"
assert pixel(ImageMath.eval("abs(B)", B=B)) == "I 2" assert pixel(ImageMath.eval("abs(B)", B=B)) == "I 2"
def test_binary_mod(): def test_binary_mod() -> None:
assert pixel(ImageMath.eval("A%A", A=A)) == "I 0" assert pixel(ImageMath.eval("A%A", A=A)) == "I 0"
assert pixel(ImageMath.eval("B%B", B=B)) == "I 0" assert pixel(ImageMath.eval("B%B", B=B)) == "I 0"
assert pixel(ImageMath.eval("A%B", A=A, B=B)) == "I 1" assert pixel(ImageMath.eval("A%B", A=A, B=B)) == "I 1"
@ -113,90 +113,90 @@ def test_binary_mod():
assert pixel(ImageMath.eval("Z%B", B=B, Z=Z)) == "I 0" assert pixel(ImageMath.eval("Z%B", B=B, Z=Z)) == "I 0"
def test_bitwise_invert(): def test_bitwise_invert() -> None:
assert pixel(ImageMath.eval("~Z", Z=Z)) == "I -1" assert pixel(ImageMath.eval("~Z", Z=Z)) == "I -1"
assert pixel(ImageMath.eval("~A", A=A)) == "I -2" assert pixel(ImageMath.eval("~A", A=A)) == "I -2"
assert pixel(ImageMath.eval("~B", B=B)) == "I -3" assert pixel(ImageMath.eval("~B", B=B)) == "I -3"
def test_bitwise_and(): def test_bitwise_and() -> None:
assert pixel(ImageMath.eval("Z&Z", A=A, Z=Z)) == "I 0" assert pixel(ImageMath.eval("Z&Z", A=A, Z=Z)) == "I 0"
assert pixel(ImageMath.eval("Z&A", A=A, Z=Z)) == "I 0" assert pixel(ImageMath.eval("Z&A", A=A, Z=Z)) == "I 0"
assert pixel(ImageMath.eval("A&Z", A=A, Z=Z)) == "I 0" assert pixel(ImageMath.eval("A&Z", A=A, Z=Z)) == "I 0"
assert pixel(ImageMath.eval("A&A", A=A, Z=Z)) == "I 1" assert pixel(ImageMath.eval("A&A", A=A, Z=Z)) == "I 1"
def test_bitwise_or(): def test_bitwise_or() -> None:
assert pixel(ImageMath.eval("Z|Z", A=A, Z=Z)) == "I 0" assert pixel(ImageMath.eval("Z|Z", A=A, Z=Z)) == "I 0"
assert pixel(ImageMath.eval("Z|A", A=A, Z=Z)) == "I 1" assert pixel(ImageMath.eval("Z|A", A=A, Z=Z)) == "I 1"
assert pixel(ImageMath.eval("A|Z", A=A, Z=Z)) == "I 1" assert pixel(ImageMath.eval("A|Z", A=A, Z=Z)) == "I 1"
assert pixel(ImageMath.eval("A|A", A=A, Z=Z)) == "I 1" assert pixel(ImageMath.eval("A|A", A=A, Z=Z)) == "I 1"
def test_bitwise_xor(): def test_bitwise_xor() -> None:
assert pixel(ImageMath.eval("Z^Z", A=A, Z=Z)) == "I 0" assert pixel(ImageMath.eval("Z^Z", A=A, Z=Z)) == "I 0"
assert pixel(ImageMath.eval("Z^A", A=A, Z=Z)) == "I 1" assert pixel(ImageMath.eval("Z^A", A=A, Z=Z)) == "I 1"
assert pixel(ImageMath.eval("A^Z", A=A, Z=Z)) == "I 1" assert pixel(ImageMath.eval("A^Z", A=A, Z=Z)) == "I 1"
assert pixel(ImageMath.eval("A^A", A=A, Z=Z)) == "I 0" assert pixel(ImageMath.eval("A^A", A=A, Z=Z)) == "I 0"
def test_bitwise_leftshift(): def test_bitwise_leftshift() -> None:
assert pixel(ImageMath.eval("Z<<0", Z=Z)) == "I 0" assert pixel(ImageMath.eval("Z<<0", Z=Z)) == "I 0"
assert pixel(ImageMath.eval("Z<<1", Z=Z)) == "I 0" assert pixel(ImageMath.eval("Z<<1", Z=Z)) == "I 0"
assert pixel(ImageMath.eval("A<<0", A=A)) == "I 1" assert pixel(ImageMath.eval("A<<0", A=A)) == "I 1"
assert pixel(ImageMath.eval("A<<1", A=A)) == "I 2" assert pixel(ImageMath.eval("A<<1", A=A)) == "I 2"
def test_bitwise_rightshift(): def test_bitwise_rightshift() -> None:
assert pixel(ImageMath.eval("Z>>0", Z=Z)) == "I 0" assert pixel(ImageMath.eval("Z>>0", Z=Z)) == "I 0"
assert pixel(ImageMath.eval("Z>>1", Z=Z)) == "I 0" assert pixel(ImageMath.eval("Z>>1", Z=Z)) == "I 0"
assert pixel(ImageMath.eval("A>>0", A=A)) == "I 1" assert pixel(ImageMath.eval("A>>0", A=A)) == "I 1"
assert pixel(ImageMath.eval("A>>1", A=A)) == "I 0" assert pixel(ImageMath.eval("A>>1", A=A)) == "I 0"
def test_logical_eq(): def test_logical_eq() -> None:
assert pixel(ImageMath.eval("A==A", A=A)) == "I 1" assert pixel(ImageMath.eval("A==A", A=A)) == "I 1"
assert pixel(ImageMath.eval("B==B", B=B)) == "I 1" assert pixel(ImageMath.eval("B==B", B=B)) == "I 1"
assert pixel(ImageMath.eval("A==B", A=A, B=B)) == "I 0" assert pixel(ImageMath.eval("A==B", A=A, B=B)) == "I 0"
assert pixel(ImageMath.eval("B==A", A=A, B=B)) == "I 0" assert pixel(ImageMath.eval("B==A", A=A, B=B)) == "I 0"
def test_logical_ne(): def test_logical_ne() -> None:
assert pixel(ImageMath.eval("A!=A", A=A)) == "I 0" assert pixel(ImageMath.eval("A!=A", A=A)) == "I 0"
assert pixel(ImageMath.eval("B!=B", B=B)) == "I 0" assert pixel(ImageMath.eval("B!=B", B=B)) == "I 0"
assert pixel(ImageMath.eval("A!=B", A=A, B=B)) == "I 1" assert pixel(ImageMath.eval("A!=B", A=A, B=B)) == "I 1"
assert pixel(ImageMath.eval("B!=A", A=A, B=B)) == "I 1" assert pixel(ImageMath.eval("B!=A", A=A, B=B)) == "I 1"
def test_logical_lt(): def test_logical_lt() -> None:
assert pixel(ImageMath.eval("A<A", A=A)) == "I 0" assert pixel(ImageMath.eval("A<A", A=A)) == "I 0"
assert pixel(ImageMath.eval("B<B", B=B)) == "I 0" assert pixel(ImageMath.eval("B<B", B=B)) == "I 0"
assert pixel(ImageMath.eval("A<B", A=A, B=B)) == "I 1" assert pixel(ImageMath.eval("A<B", A=A, B=B)) == "I 1"
assert pixel(ImageMath.eval("B<A", A=A, B=B)) == "I 0" assert pixel(ImageMath.eval("B<A", A=A, B=B)) == "I 0"
def test_logical_le(): def test_logical_le() -> None:
assert pixel(ImageMath.eval("A<=A", A=A)) == "I 1" assert pixel(ImageMath.eval("A<=A", A=A)) == "I 1"
assert pixel(ImageMath.eval("B<=B", B=B)) == "I 1" assert pixel(ImageMath.eval("B<=B", B=B)) == "I 1"
assert pixel(ImageMath.eval("A<=B", A=A, B=B)) == "I 1" assert pixel(ImageMath.eval("A<=B", A=A, B=B)) == "I 1"
assert pixel(ImageMath.eval("B<=A", A=A, B=B)) == "I 0" assert pixel(ImageMath.eval("B<=A", A=A, B=B)) == "I 0"
def test_logical_gt(): def test_logical_gt() -> None:
assert pixel(ImageMath.eval("A>A", A=A)) == "I 0" assert pixel(ImageMath.eval("A>A", A=A)) == "I 0"
assert pixel(ImageMath.eval("B>B", B=B)) == "I 0" assert pixel(ImageMath.eval("B>B", B=B)) == "I 0"
assert pixel(ImageMath.eval("A>B", A=A, B=B)) == "I 0" assert pixel(ImageMath.eval("A>B", A=A, B=B)) == "I 0"
assert pixel(ImageMath.eval("B>A", A=A, B=B)) == "I 1" assert pixel(ImageMath.eval("B>A", A=A, B=B)) == "I 1"
def test_logical_ge(): def test_logical_ge() -> None:
assert pixel(ImageMath.eval("A>=A", A=A)) == "I 1" assert pixel(ImageMath.eval("A>=A", A=A)) == "I 1"
assert pixel(ImageMath.eval("B>=B", B=B)) == "I 1" assert pixel(ImageMath.eval("B>=B", B=B)) == "I 1"
assert pixel(ImageMath.eval("A>=B", A=A, B=B)) == "I 0" assert pixel(ImageMath.eval("A>=B", A=A, B=B)) == "I 0"
assert pixel(ImageMath.eval("B>=A", A=A, B=B)) == "I 1" assert pixel(ImageMath.eval("B>=A", A=A, B=B)) == "I 1"
def test_logical_equal(): def test_logical_equal() -> None:
assert pixel(ImageMath.eval("equal(A, A)", A=A)) == "I 1" assert pixel(ImageMath.eval("equal(A, A)", A=A)) == "I 1"
assert pixel(ImageMath.eval("equal(B, B)", B=B)) == "I 1" assert pixel(ImageMath.eval("equal(B, B)", B=B)) == "I 1"
assert pixel(ImageMath.eval("equal(Z, Z)", Z=Z)) == "I 1" assert pixel(ImageMath.eval("equal(Z, Z)", Z=Z)) == "I 1"
@ -205,7 +205,7 @@ def test_logical_equal():
assert pixel(ImageMath.eval("equal(A, Z)", A=A, Z=Z)) == "I 0" assert pixel(ImageMath.eval("equal(A, Z)", A=A, Z=Z)) == "I 0"
def test_logical_not_equal(): def test_logical_not_equal() -> None:
assert pixel(ImageMath.eval("notequal(A, A)", A=A)) == "I 0" assert pixel(ImageMath.eval("notequal(A, A)", A=A)) == "I 0"
assert pixel(ImageMath.eval("notequal(B, B)", B=B)) == "I 0" assert pixel(ImageMath.eval("notequal(B, B)", B=B)) == "I 0"
assert pixel(ImageMath.eval("notequal(Z, Z)", Z=Z)) == "I 0" assert pixel(ImageMath.eval("notequal(Z, Z)", Z=Z)) == "I 0"

View File

@ -1,6 +1,8 @@
# Test the ImageMorphology functionality # Test the ImageMorphology functionality
from __future__ import annotations from __future__ import annotations
from pathlib import Path
import pytest import pytest
from PIL import Image, ImageMorph, _imagingmorph from PIL import Image, ImageMorph, _imagingmorph
@ -50,18 +52,18 @@ def img_string_normalize(im):
return img_to_string(string_to_img(im)) return img_to_string(string_to_img(im))
def assert_img_equal_img_string(a, b_string): def assert_img_equal_img_string(a, b_string) -> None:
assert img_to_string(a) == img_string_normalize(b_string) assert img_to_string(a) == img_string_normalize(b_string)
def test_str_to_img(): def test_str_to_img() -> None:
assert_image_equal_tofile(A, "Tests/images/morph_a.png") assert_image_equal_tofile(A, "Tests/images/morph_a.png")
@pytest.mark.parametrize( @pytest.mark.parametrize(
"op", ("corner", "dilation4", "dilation8", "erosion4", "erosion8", "edge") "op", ("corner", "dilation4", "dilation8", "erosion4", "erosion8", "edge")
) )
def test_lut(op): def test_lut(op) -> None:
lb = ImageMorph.LutBuilder(op_name=op) lb = ImageMorph.LutBuilder(op_name=op)
assert lb.get_lut() is None assert lb.get_lut() is None
@ -70,7 +72,7 @@ def test_lut(op):
assert lut == bytearray(f.read()) assert lut == bytearray(f.read())
def test_no_operator_loaded(): def test_no_operator_loaded() -> None:
mop = ImageMorph.MorphOp() mop = ImageMorph.MorphOp()
with pytest.raises(Exception) as e: with pytest.raises(Exception) as e:
mop.apply(None) mop.apply(None)
@ -84,7 +86,7 @@ def test_no_operator_loaded():
# Test the named patterns # Test the named patterns
def test_erosion8(): def test_erosion8() -> None:
# erosion8 # erosion8
mop = ImageMorph.MorphOp(op_name="erosion8") mop = ImageMorph.MorphOp(op_name="erosion8")
count, Aout = mop.apply(A) count, Aout = mop.apply(A)
@ -103,7 +105,7 @@ def test_erosion8():
) )
def test_dialation8(): def test_dialation8() -> None:
# dialation8 # dialation8
mop = ImageMorph.MorphOp(op_name="dilation8") mop = ImageMorph.MorphOp(op_name="dilation8")
count, Aout = mop.apply(A) count, Aout = mop.apply(A)
@ -122,7 +124,7 @@ def test_dialation8():
) )
def test_erosion4(): def test_erosion4() -> None:
# erosion4 # erosion4
mop = ImageMorph.MorphOp(op_name="dilation4") mop = ImageMorph.MorphOp(op_name="dilation4")
count, Aout = mop.apply(A) count, Aout = mop.apply(A)
@ -141,7 +143,7 @@ def test_erosion4():
) )
def test_edge(): def test_edge() -> None:
# edge # edge
mop = ImageMorph.MorphOp(op_name="edge") mop = ImageMorph.MorphOp(op_name="edge")
count, Aout = mop.apply(A) count, Aout = mop.apply(A)
@ -160,7 +162,7 @@ def test_edge():
) )
def test_corner(): def test_corner() -> None:
# Create a corner detector pattern # Create a corner detector pattern
mop = ImageMorph.MorphOp(patterns=["1:(... ... ...)->0", "4:(00. 01. ...)->1"]) mop = ImageMorph.MorphOp(patterns=["1:(... ... ...)->0", "4:(00. 01. ...)->1"])
count, Aout = mop.apply(A) count, Aout = mop.apply(A)
@ -188,7 +190,7 @@ def test_corner():
assert tuple(coords) == ((2, 2), (4, 2), (2, 4), (4, 4)) assert tuple(coords) == ((2, 2), (4, 2), (2, 4), (4, 4))
def test_mirroring(): def test_mirroring() -> None:
# Test 'M' for mirroring # Test 'M' for mirroring
mop = ImageMorph.MorphOp(patterns=["1:(... ... ...)->0", "M:(00. 01. ...)->1"]) mop = ImageMorph.MorphOp(patterns=["1:(... ... ...)->0", "M:(00. 01. ...)->1"])
count, Aout = mop.apply(A) count, Aout = mop.apply(A)
@ -207,7 +209,7 @@ def test_mirroring():
) )
def test_negate(): def test_negate() -> None:
# Test 'N' for negate # Test 'N' for negate
mop = ImageMorph.MorphOp(patterns=["1:(... ... ...)->0", "N:(00. 01. ...)->1"]) mop = ImageMorph.MorphOp(patterns=["1:(... ... ...)->0", "N:(00. 01. ...)->1"])
count, Aout = mop.apply(A) count, Aout = mop.apply(A)
@ -226,7 +228,7 @@ def test_negate():
) )
def test_incorrect_mode(): def test_incorrect_mode() -> None:
im = hopper("RGB") im = hopper("RGB")
mop = ImageMorph.MorphOp(op_name="erosion8") mop = ImageMorph.MorphOp(op_name="erosion8")
@ -241,7 +243,7 @@ def test_incorrect_mode():
assert str(e.value) == "Image mode must be L" assert str(e.value) == "Image mode must be L"
def test_add_patterns(): def test_add_patterns() -> None:
# Arrange # Arrange
lb = ImageMorph.LutBuilder(op_name="corner") lb = ImageMorph.LutBuilder(op_name="corner")
assert lb.patterns == ["1:(... ... ...)->0", "4:(00. 01. ...)->1"] assert lb.patterns == ["1:(... ... ...)->0", "4:(00. 01. ...)->1"]
@ -259,12 +261,12 @@ def test_add_patterns():
] ]
def test_unknown_pattern(): def test_unknown_pattern() -> None:
with pytest.raises(Exception): with pytest.raises(Exception):
ImageMorph.LutBuilder(op_name="unknown") ImageMorph.LutBuilder(op_name="unknown")
def test_pattern_syntax_error(): def test_pattern_syntax_error() -> None:
# Arrange # Arrange
lb = ImageMorph.LutBuilder(op_name="corner") lb = ImageMorph.LutBuilder(op_name="corner")
new_patterns = ["a pattern with a syntax error"] new_patterns = ["a pattern with a syntax error"]
@ -276,7 +278,7 @@ def test_pattern_syntax_error():
assert str(e.value) == 'Syntax error in pattern "a pattern with a syntax error"' assert str(e.value) == 'Syntax error in pattern "a pattern with a syntax error"'
def test_load_invalid_mrl(): def test_load_invalid_mrl() -> None:
# Arrange # Arrange
invalid_mrl = "Tests/images/hopper.png" invalid_mrl = "Tests/images/hopper.png"
mop = ImageMorph.MorphOp() mop = ImageMorph.MorphOp()
@ -287,7 +289,7 @@ def test_load_invalid_mrl():
assert str(e.value) == "Wrong size operator file!" assert str(e.value) == "Wrong size operator file!"
def test_roundtrip_mrl(tmp_path): def test_roundtrip_mrl(tmp_path: Path) -> None:
# Arrange # Arrange
tempfile = str(tmp_path / "temp.mrl") tempfile = str(tmp_path / "temp.mrl")
mop = ImageMorph.MorphOp(op_name="corner") mop = ImageMorph.MorphOp(op_name="corner")
@ -301,7 +303,7 @@ def test_roundtrip_mrl(tmp_path):
assert mop.lut == initial_lut assert mop.lut == initial_lut
def test_set_lut(): def test_set_lut() -> None:
# Arrange # Arrange
lb = ImageMorph.LutBuilder(op_name="corner") lb = ImageMorph.LutBuilder(op_name="corner")
lut = lb.build_lut() lut = lb.build_lut()
@ -314,7 +316,7 @@ def test_set_lut():
assert mop.lut == lut assert mop.lut == lut
def test_wrong_mode(): def test_wrong_mode() -> None:
lut = ImageMorph.LutBuilder(op_name="corner").build_lut() lut = ImageMorph.LutBuilder(op_name="corner").build_lut()
imrgb = Image.new("RGB", (10, 10)) imrgb = Image.new("RGB", (10, 10))
iml = Image.new("L", (10, 10)) iml = Image.new("L", (10, 10))

View File

@ -22,7 +22,7 @@ class Deformer:
deformer = Deformer() deformer = Deformer()
def test_sanity(): def test_sanity() -> None:
ImageOps.autocontrast(hopper("L")) ImageOps.autocontrast(hopper("L"))
ImageOps.autocontrast(hopper("RGB")) ImageOps.autocontrast(hopper("RGB"))
@ -84,7 +84,7 @@ def test_sanity():
ImageOps.exif_transpose(hopper("RGB")) ImageOps.exif_transpose(hopper("RGB"))
def test_1pxfit(): def test_1pxfit() -> None:
# Division by zero in equalize if image is 1 pixel high # Division by zero in equalize if image is 1 pixel high
newimg = ImageOps.fit(hopper("RGB").resize((1, 1)), (35, 35)) newimg = ImageOps.fit(hopper("RGB").resize((1, 1)), (35, 35))
assert newimg.size == (35, 35) assert newimg.size == (35, 35)
@ -96,7 +96,7 @@ def test_1pxfit():
assert newimg.size == (35, 35) assert newimg.size == (35, 35)
def test_fit_same_ratio(): def test_fit_same_ratio() -> None:
# The ratio for this image is 1000.0 / 755 = 1.3245033112582782 # The ratio for this image is 1000.0 / 755 = 1.3245033112582782
# If the ratios are not acknowledged to be the same, # If the ratios are not acknowledged to be the same,
# and Pillow attempts to adjust the width to # and Pillow attempts to adjust the width to
@ -108,13 +108,13 @@ def test_fit_same_ratio():
@pytest.mark.parametrize("new_size", ((256, 256), (512, 256), (256, 512))) @pytest.mark.parametrize("new_size", ((256, 256), (512, 256), (256, 512)))
def test_contain(new_size): def test_contain(new_size) -> None:
im = hopper() im = hopper()
new_im = ImageOps.contain(im, new_size) new_im = ImageOps.contain(im, new_size)
assert new_im.size == (256, 256) assert new_im.size == (256, 256)
def test_contain_round(): def test_contain_round() -> None:
im = Image.new("1", (43, 63), 1) im = Image.new("1", (43, 63), 1)
new_im = ImageOps.contain(im, (5, 7)) new_im = ImageOps.contain(im, (5, 7))
assert new_im.width == 5 assert new_im.width == 5
@ -132,13 +132,13 @@ def test_contain_round():
("hopper.png", (256, 256)), # square ("hopper.png", (256, 256)), # square
), ),
) )
def test_cover(image_name, expected_size): def test_cover(image_name, expected_size) -> None:
with Image.open("Tests/images/" + image_name) as im: with Image.open("Tests/images/" + image_name) as im:
new_im = ImageOps.cover(im, (256, 256)) new_im = ImageOps.cover(im, (256, 256))
assert new_im.size == expected_size assert new_im.size == expected_size
def test_pad(): def test_pad() -> None:
# Same ratio # Same ratio
im = hopper() im = hopper()
new_size = (im.width * 2, im.height * 2) new_size = (im.width * 2, im.height * 2)
@ -158,7 +158,7 @@ def test_pad():
) )
def test_pad_round(): def test_pad_round() -> None:
im = Image.new("1", (1, 1), 1) im = Image.new("1", (1, 1), 1)
new_im = ImageOps.pad(im, (4, 1)) new_im = ImageOps.pad(im, (4, 1))
assert new_im.load()[2, 0] == 1 assert new_im.load()[2, 0] == 1
@ -168,7 +168,7 @@ def test_pad_round():
@pytest.mark.parametrize("mode", ("P", "PA")) @pytest.mark.parametrize("mode", ("P", "PA"))
def test_palette(mode): def test_palette(mode) -> None:
im = hopper(mode) im = hopper(mode)
# Expand # Expand
@ -182,7 +182,7 @@ def test_palette(mode):
) )
def test_pil163(): def test_pil163() -> None:
# Division by zero in equalize if < 255 pixels in image (@PIL163) # Division by zero in equalize if < 255 pixels in image (@PIL163)
i = hopper("RGB").resize((15, 16)) i = hopper("RGB").resize((15, 16))
@ -192,7 +192,7 @@ def test_pil163():
ImageOps.equalize(i.convert("RGB")) ImageOps.equalize(i.convert("RGB"))
def test_scale(): def test_scale() -> None:
# Test the scaling function # Test the scaling function
i = hopper("L").resize((50, 50)) i = hopper("L").resize((50, 50))
@ -210,7 +210,7 @@ def test_scale():
@pytest.mark.parametrize("border", (10, (1, 2, 3, 4))) @pytest.mark.parametrize("border", (10, (1, 2, 3, 4)))
def test_expand_palette(border): def test_expand_palette(border) -> None:
with Image.open("Tests/images/p_16.tga") as im: with Image.open("Tests/images/p_16.tga") as im:
im_expanded = ImageOps.expand(im, border, (255, 0, 0)) im_expanded = ImageOps.expand(im, border, (255, 0, 0))
@ -236,7 +236,7 @@ def test_expand_palette(border):
assert_image_equal(im_cropped, im) assert_image_equal(im_cropped, im)
def test_colorize_2color(): def test_colorize_2color() -> None:
# Test the colorizing function with 2-color functionality # Test the colorizing function with 2-color functionality
# Open test image (256px by 10px, black to white) # Open test image (256px by 10px, black to white)
@ -270,7 +270,7 @@ def test_colorize_2color():
) )
def test_colorize_2color_offset(): def test_colorize_2color_offset() -> None:
# Test the colorizing function with 2-color functionality and offset # Test the colorizing function with 2-color functionality and offset
# Open test image (256px by 10px, black to white) # Open test image (256px by 10px, black to white)
@ -306,7 +306,7 @@ def test_colorize_2color_offset():
) )
def test_colorize_3color_offset(): def test_colorize_3color_offset() -> None:
# Test the colorizing function with 3-color functionality and offset # Test the colorizing function with 3-color functionality and offset
# Open test image (256px by 10px, black to white) # Open test image (256px by 10px, black to white)
@ -359,14 +359,14 @@ def test_colorize_3color_offset():
) )
def test_exif_transpose(): def test_exif_transpose() -> None:
exts = [".jpg"] exts = [".jpg"]
if features.check("webp") and features.check("webp_anim"): if features.check("webp") and features.check("webp_anim"):
exts.append(".webp") exts.append(".webp")
for ext in exts: for ext in exts:
with Image.open("Tests/images/hopper" + ext) as base_im: with Image.open("Tests/images/hopper" + ext) as base_im:
def check(orientation_im): def check(orientation_im) -> None:
for im in [ for im in [
orientation_im, orientation_im,
orientation_im.copy(), orientation_im.copy(),
@ -423,7 +423,7 @@ def test_exif_transpose():
assert 0x0112 not in transposed_im.getexif() assert 0x0112 not in transposed_im.getexif()
def test_exif_transpose_in_place(): def test_exif_transpose_in_place() -> None:
with Image.open("Tests/images/orientation_rectangle.jpg") as im: with Image.open("Tests/images/orientation_rectangle.jpg") as im:
assert im.size == (2, 1) assert im.size == (2, 1)
assert im.getexif()[0x0112] == 8 assert im.getexif()[0x0112] == 8
@ -435,13 +435,13 @@ def test_exif_transpose_in_place():
assert_image_equal(im, expected) assert_image_equal(im, expected)
def test_autocontrast_unsupported_mode(): def test_autocontrast_unsupported_mode() -> None:
im = Image.new("RGBA", (1, 1)) im = Image.new("RGBA", (1, 1))
with pytest.raises(OSError): with pytest.raises(OSError):
ImageOps.autocontrast(im) ImageOps.autocontrast(im)
def test_autocontrast_cutoff(): def test_autocontrast_cutoff() -> None:
# Test the cutoff argument of autocontrast # Test the cutoff argument of autocontrast
with Image.open("Tests/images/bw_gradient.png") as img: with Image.open("Tests/images/bw_gradient.png") as img:
@ -452,7 +452,7 @@ def test_autocontrast_cutoff():
assert autocontrast(10) != autocontrast((1, 10)) assert autocontrast(10) != autocontrast((1, 10))
def test_autocontrast_mask_toy_input(): def test_autocontrast_mask_toy_input() -> None:
# Test the mask argument of autocontrast # Test the mask argument of autocontrast
with Image.open("Tests/images/bw_gradient.png") as img: with Image.open("Tests/images/bw_gradient.png") as img:
rect_mask = Image.new("L", img.size, 0) rect_mask = Image.new("L", img.size, 0)
@ -471,7 +471,7 @@ def test_autocontrast_mask_toy_input():
assert ImageStat.Stat(result_nomask).median == [128] assert ImageStat.Stat(result_nomask).median == [128]
def test_autocontrast_mask_real_input(): def test_autocontrast_mask_real_input() -> None:
# Test the autocontrast with a rectangular mask # Test the autocontrast with a rectangular mask
with Image.open("Tests/images/iptc.jpg") as img: with Image.open("Tests/images/iptc.jpg") as img:
rect_mask = Image.new("L", img.size, 0) rect_mask = Image.new("L", img.size, 0)
@ -498,7 +498,7 @@ def test_autocontrast_mask_real_input():
) )
def test_autocontrast_preserve_tone(): def test_autocontrast_preserve_tone() -> None:
def autocontrast(mode, preserve_tone): def autocontrast(mode, preserve_tone):
im = hopper(mode) im = hopper(mode)
return ImageOps.autocontrast(im, preserve_tone=preserve_tone).histogram() return ImageOps.autocontrast(im, preserve_tone=preserve_tone).histogram()
@ -507,7 +507,7 @@ def test_autocontrast_preserve_tone():
assert autocontrast("L", True) == autocontrast("L", False) assert autocontrast("L", True) == autocontrast("L", False)
def test_autocontrast_preserve_gradient(): def test_autocontrast_preserve_gradient() -> None:
gradient = Image.linear_gradient("L") gradient = Image.linear_gradient("L")
# test with a grayscale gradient that extends to 0,255. # test with a grayscale gradient that extends to 0,255.
@ -533,7 +533,7 @@ def test_autocontrast_preserve_gradient():
@pytest.mark.parametrize( @pytest.mark.parametrize(
"color", ((255, 255, 255), (127, 255, 0), (127, 127, 127), (0, 0, 0)) "color", ((255, 255, 255), (127, 255, 0), (127, 127, 127), (0, 0, 0))
) )
def test_autocontrast_preserve_one_color(color): def test_autocontrast_preserve_one_color(color) -> None:
img = Image.new("RGB", (10, 10), color) img = Image.new("RGB", (10, 10), color)
# single color images shouldn't change # single color images shouldn't change

View File

@ -18,7 +18,7 @@ def test_images():
im.close() im.close()
def test_filter_api(test_images): def test_filter_api(test_images) -> None:
im = test_images["im"] im = test_images["im"]
test_filter = ImageFilter.GaussianBlur(2.0) test_filter = ImageFilter.GaussianBlur(2.0)
@ -32,7 +32,7 @@ def test_filter_api(test_images):
assert i.size == (128, 128) assert i.size == (128, 128)
def test_usm_formats(test_images): def test_usm_formats(test_images) -> None:
im = test_images["im"] im = test_images["im"]
usm = ImageFilter.UnsharpMask usm = ImageFilter.UnsharpMask
@ -50,7 +50,7 @@ def test_usm_formats(test_images):
im.convert("YCbCr").filter(usm) im.convert("YCbCr").filter(usm)
def test_blur_formats(test_images): def test_blur_formats(test_images) -> None:
im = test_images["im"] im = test_images["im"]
blur = ImageFilter.GaussianBlur blur = ImageFilter.GaussianBlur
@ -68,7 +68,7 @@ def test_blur_formats(test_images):
im.convert("YCbCr").filter(blur) im.convert("YCbCr").filter(blur)
def test_usm_accuracy(test_images): def test_usm_accuracy(test_images) -> None:
snakes = test_images["snakes"] snakes = test_images["snakes"]
src = snakes.convert("RGB") src = snakes.convert("RGB")
@ -77,7 +77,7 @@ def test_usm_accuracy(test_images):
assert i.tobytes() == src.tobytes() assert i.tobytes() == src.tobytes()
def test_blur_accuracy(test_images): def test_blur_accuracy(test_images) -> None:
snakes = test_images["snakes"] snakes = test_images["snakes"]
i = snakes.filter(ImageFilter.GaussianBlur(0.4)) i = snakes.filter(ImageFilter.GaussianBlur(0.4))

View File

@ -1,5 +1,7 @@
from __future__ import annotations from __future__ import annotations
from pathlib import Path
import pytest import pytest
from PIL import Image, ImagePalette from PIL import Image, ImagePalette
@ -7,19 +9,19 @@ from PIL import Image, ImagePalette
from .helper import assert_image_equal, assert_image_equal_tofile from .helper import assert_image_equal, assert_image_equal_tofile
def test_sanity(): def test_sanity() -> None:
palette = ImagePalette.ImagePalette("RGB", list(range(256)) * 3) palette = ImagePalette.ImagePalette("RGB", list(range(256)) * 3)
assert len(palette.colors) == 256 assert len(palette.colors) == 256
def test_reload(): def test_reload() -> None:
with Image.open("Tests/images/hopper.gif") as im: with Image.open("Tests/images/hopper.gif") as im:
original = im.copy() original = im.copy()
im.palette.dirty = 1 im.palette.dirty = 1
assert_image_equal(im.convert("RGB"), original.convert("RGB")) assert_image_equal(im.convert("RGB"), original.convert("RGB"))
def test_getcolor(): def test_getcolor() -> None:
palette = ImagePalette.ImagePalette() palette = ImagePalette.ImagePalette()
assert len(palette.palette) == 0 assert len(palette.palette) == 0
assert len(palette.colors) == 0 assert len(palette.colors) == 0
@ -46,7 +48,7 @@ def test_getcolor():
palette.getcolor("unknown") palette.getcolor("unknown")
def test_getcolor_rgba_color_rgb_palette(): def test_getcolor_rgba_color_rgb_palette() -> None:
palette = ImagePalette.ImagePalette("RGB") palette = ImagePalette.ImagePalette("RGB")
# Opaque RGBA colors are converted # Opaque RGBA colors are converted
@ -65,7 +67,7 @@ def test_getcolor_rgba_color_rgb_palette():
(255, ImagePalette.ImagePalette("RGB", list(range(256)) * 3)), (255, ImagePalette.ImagePalette("RGB", list(range(256)) * 3)),
], ],
) )
def test_getcolor_not_special(index, palette): def test_getcolor_not_special(index, palette) -> None:
im = Image.new("P", (1, 1)) im = Image.new("P", (1, 1))
# Do not use transparency index as a new color # Do not use transparency index as a new color
@ -79,7 +81,7 @@ def test_getcolor_not_special(index, palette):
assert index2 not in (index, index1) assert index2 not in (index, index1)
def test_file(tmp_path): def test_file(tmp_path: Path) -> None:
palette = ImagePalette.ImagePalette("RGB", list(range(256)) * 3) palette = ImagePalette.ImagePalette("RGB", list(range(256)) * 3)
f = str(tmp_path / "temp.lut") f = str(tmp_path / "temp.lut")
@ -97,7 +99,7 @@ def test_file(tmp_path):
assert p.palette == palette.tobytes() assert p.palette == palette.tobytes()
def test_make_linear_lut(): def test_make_linear_lut() -> None:
# Arrange # Arrange
black = 0 black = 0
white = 255 white = 255
@ -113,7 +115,7 @@ def test_make_linear_lut():
assert lut[i] == i assert lut[i] == i
def test_make_linear_lut_not_yet_implemented(): def test_make_linear_lut_not_yet_implemented() -> None:
# Update after FIXME # Update after FIXME
# Arrange # Arrange
black = 1 black = 1
@ -124,7 +126,7 @@ def test_make_linear_lut_not_yet_implemented():
ImagePalette.make_linear_lut(black, white) ImagePalette.make_linear_lut(black, white)
def test_make_gamma_lut(): def test_make_gamma_lut() -> None:
# Arrange # Arrange
exp = 5 exp = 5
@ -142,7 +144,7 @@ def test_make_gamma_lut():
assert lut[255] == 255 assert lut[255] == 255
def test_rawmode_valueerrors(tmp_path): def test_rawmode_valueerrors(tmp_path: Path) -> None:
# Arrange # Arrange
palette = ImagePalette.raw("RGB", list(range(256)) * 3) palette = ImagePalette.raw("RGB", list(range(256)) * 3)
@ -156,7 +158,7 @@ def test_rawmode_valueerrors(tmp_path):
palette.save(f) palette.save(f)
def test_getdata(): def test_getdata() -> None:
# Arrange # Arrange
data_in = list(range(256)) * 3 data_in = list(range(256)) * 3
palette = ImagePalette.ImagePalette("RGB", data_in) palette = ImagePalette.ImagePalette("RGB", data_in)
@ -168,7 +170,7 @@ def test_getdata():
assert mode == "RGB" assert mode == "RGB"
def test_rawmode_getdata(): def test_rawmode_getdata() -> None:
# Arrange # Arrange
data_in = list(range(256)) * 3 data_in = list(range(256)) * 3
palette = ImagePalette.raw("RGB", data_in) palette = ImagePalette.raw("RGB", data_in)
@ -181,7 +183,7 @@ def test_rawmode_getdata():
assert data_in == data_out assert data_in == data_out
def test_2bit_palette(tmp_path): def test_2bit_palette(tmp_path: Path) -> None:
# issue #2258, 2 bit palettes are corrupted. # issue #2258, 2 bit palettes are corrupted.
outfile = str(tmp_path / "temp.png") outfile = str(tmp_path / "temp.png")
@ -193,6 +195,6 @@ def test_2bit_palette(tmp_path):
assert_image_equal_tofile(img, outfile) assert_image_equal_tofile(img, outfile)
def test_invalid_palette(): def test_invalid_palette() -> None:
with pytest.raises(OSError): with pytest.raises(OSError):
ImagePalette.load("Tests/images/hopper.jpg") ImagePalette.load("Tests/images/hopper.jpg")

View File

@ -9,7 +9,7 @@ import pytest
from PIL import Image, ImagePath from PIL import Image, ImagePath
def test_path(): def test_path() -> None:
p = ImagePath.Path(list(range(10))) p = ImagePath.Path(list(range(10)))
# sequence interface # sequence interface
@ -57,7 +57,7 @@ def test_path():
ImagePath.Path((0, 1)), ImagePath.Path((0, 1)),
), ),
) )
def test_path_constructors(coords): def test_path_constructors(coords) -> None:
# Arrange / Act # Arrange / Act
p = ImagePath.Path(coords) p = ImagePath.Path(coords)
@ -75,7 +75,7 @@ def test_path_constructors(coords):
[[0.0, 1.0]], [[0.0, 1.0]],
), ),
) )
def test_invalid_path_constructors(coords): def test_invalid_path_constructors(coords) -> None:
# Act # Act
with pytest.raises(ValueError) as e: with pytest.raises(ValueError) as e:
ImagePath.Path(coords) ImagePath.Path(coords)
@ -93,7 +93,7 @@ def test_invalid_path_constructors(coords):
[0, 1, 2], [0, 1, 2],
), ),
) )
def test_path_odd_number_of_coordinates(coords): def test_path_odd_number_of_coordinates(coords) -> None:
# Act # Act
with pytest.raises(ValueError) as e: with pytest.raises(ValueError) as e:
ImagePath.Path(coords) ImagePath.Path(coords)
@ -111,7 +111,7 @@ def test_path_odd_number_of_coordinates(coords):
(1, (0.0, 0.0, 0.0, 0.0)), (1, (0.0, 0.0, 0.0, 0.0)),
], ],
) )
def test_getbbox(coords, expected): def test_getbbox(coords, expected) -> None:
# Arrange # Arrange
p = ImagePath.Path(coords) p = ImagePath.Path(coords)
@ -119,7 +119,7 @@ def test_getbbox(coords, expected):
assert p.getbbox() == expected assert p.getbbox() == expected
def test_getbbox_no_args(): def test_getbbox_no_args() -> None:
# Arrange # Arrange
p = ImagePath.Path([0, 1, 2, 3]) p = ImagePath.Path([0, 1, 2, 3])
@ -135,7 +135,7 @@ def test_getbbox_no_args():
(list(range(6)), [(0.0, 3.0), (4.0, 9.0), (8.0, 15.0)]), (list(range(6)), [(0.0, 3.0), (4.0, 9.0), (8.0, 15.0)]),
], ],
) )
def test_map(coords, expected): def test_map(coords, expected) -> None:
# Arrange # Arrange
p = ImagePath.Path(coords) p = ImagePath.Path(coords)
@ -147,7 +147,7 @@ def test_map(coords, expected):
assert list(p) == expected assert list(p) == expected
def test_transform(): def test_transform() -> None:
# Arrange # Arrange
p = ImagePath.Path([0, 1, 2, 3]) p = ImagePath.Path([0, 1, 2, 3])
theta = math.pi / 15 theta = math.pi / 15
@ -165,7 +165,7 @@ def test_transform():
] ]
def test_transform_with_wrap(): def test_transform_with_wrap() -> None:
# Arrange # Arrange
p = ImagePath.Path([0, 1, 2, 3]) p = ImagePath.Path([0, 1, 2, 3])
theta = math.pi / 15 theta = math.pi / 15
@ -184,7 +184,7 @@ def test_transform_with_wrap():
] ]
def test_overflow_segfault(): def test_overflow_segfault() -> None:
# Some Pythons fail getting the argument as an integer, and it falls # Some Pythons fail getting the argument as an integer, and it falls
# through to the sequence. Seeing this on 32-bit Windows. # through to the sequence. Seeing this on 32-bit Windows.
with pytest.raises((TypeError, MemoryError)): with pytest.raises((TypeError, MemoryError)):
@ -198,12 +198,12 @@ def test_overflow_segfault():
class Evil: class Evil:
def __init__(self): def __init__(self) -> None:
self.corrupt = Image.core.path(0x4000000000000000) self.corrupt = Image.core.path(0x4000000000000000)
def __getitem__(self, i): def __getitem__(self, i):
x = self.corrupt[i] x = self.corrupt[i]
return struct.pack("dd", x[0], x[1]) return struct.pack("dd", x[0], x[1])
def __setitem__(self, i, x): def __setitem__(self, i, x) -> None:
self.corrupt[i] = struct.unpack("dd", x) self.corrupt[i] = struct.unpack("dd", x)

View File

@ -16,7 +16,7 @@ if ImageQt.qt_is_installed:
from PIL.ImageQt import qRgba from PIL.ImageQt import qRgba
def test_rgb(): def test_rgb() -> None:
# from https://doc.qt.io/archives/qt-4.8/qcolor.html # from https://doc.qt.io/archives/qt-4.8/qcolor.html
# typedef QRgb # typedef QRgb
# An ARGB quadruplet on the format #AARRGGBB, # An ARGB quadruplet on the format #AARRGGBB,
@ -28,7 +28,7 @@ def test_rgb():
assert qRgb(0, 0, 0) == qRgba(0, 0, 0, 255) assert qRgb(0, 0, 0) == qRgba(0, 0, 0, 255)
def checkrgb(r, g, b): def checkrgb(r, g, b) -> None:
val = ImageQt.rgb(r, g, b) val = ImageQt.rgb(r, g, b)
val = val % 2**24 # drop the alpha val = val % 2**24 # drop the alpha
assert val >> 16 == r assert val >> 16 == r
@ -41,7 +41,7 @@ def test_rgb():
checkrgb(0, 0, 255) checkrgb(0, 0, 255)
def test_image(): def test_image() -> None:
modes = ["1", "RGB", "RGBA", "L", "P"] modes = ["1", "RGB", "RGBA", "L", "P"]
qt_format = ImageQt.QImage.Format if ImageQt.qt_version == "6" else ImageQt.QImage qt_format = ImageQt.QImage.Format if ImageQt.qt_version == "6" else ImageQt.QImage
if hasattr(qt_format, "Format_Grayscale16"): # Qt 5.13+ if hasattr(qt_format, "Format_Grayscale16"): # Qt 5.13+
@ -55,6 +55,6 @@ def test_image():
assert_image_similar(roundtripped_im, im, 1) assert_image_similar(roundtripped_im, im, 1)
def test_closed_file(): def test_closed_file() -> None:
with warnings.catch_warnings(): with warnings.catch_warnings():
ImageQt.ImageQt("Tests/images/hopper.gif") ImageQt.ImageQt("Tests/images/hopper.gif")

View File

@ -1,5 +1,7 @@
from __future__ import annotations from __future__ import annotations
from pathlib import Path
import pytest import pytest
from PIL import Image, ImageSequence, TiffImagePlugin from PIL import Image, ImageSequence, TiffImagePlugin
@ -7,7 +9,7 @@ from PIL import Image, ImageSequence, TiffImagePlugin
from .helper import assert_image_equal, hopper, skip_unless_feature from .helper import assert_image_equal, hopper, skip_unless_feature
def test_sanity(tmp_path): def test_sanity(tmp_path: Path) -> None:
test_file = str(tmp_path / "temp.im") test_file = str(tmp_path / "temp.im")
im = hopper("RGB") im = hopper("RGB")
@ -27,7 +29,7 @@ def test_sanity(tmp_path):
ImageSequence.Iterator(0) ImageSequence.Iterator(0)
def test_iterator(): def test_iterator() -> None:
with Image.open("Tests/images/multipage.tiff") as im: with Image.open("Tests/images/multipage.tiff") as im:
i = ImageSequence.Iterator(im) i = ImageSequence.Iterator(im)
for index in range(0, im.n_frames): for index in range(0, im.n_frames):
@ -38,14 +40,14 @@ def test_iterator():
next(i) next(i)
def test_iterator_min_frame(): def test_iterator_min_frame() -> None:
with Image.open("Tests/images/hopper.psd") as im: with Image.open("Tests/images/hopper.psd") as im:
i = ImageSequence.Iterator(im) i = ImageSequence.Iterator(im)
for index in range(1, im.n_frames): for index in range(1, im.n_frames):
assert i[index] == next(i) assert i[index] == next(i)
def _test_multipage_tiff(): def _test_multipage_tiff() -> None:
with Image.open("Tests/images/multipage.tiff") as im: with Image.open("Tests/images/multipage.tiff") as im:
for index, frame in enumerate(ImageSequence.Iterator(im)): for index, frame in enumerate(ImageSequence.Iterator(im)):
frame.load() frame.load()
@ -53,18 +55,18 @@ def _test_multipage_tiff():
frame.convert("RGB") frame.convert("RGB")
def test_tiff(): def test_tiff() -> None:
_test_multipage_tiff() _test_multipage_tiff()
@skip_unless_feature("libtiff") @skip_unless_feature("libtiff")
def test_libtiff(): def test_libtiff() -> None:
TiffImagePlugin.READ_LIBTIFF = True TiffImagePlugin.READ_LIBTIFF = True
_test_multipage_tiff() _test_multipage_tiff()
TiffImagePlugin.READ_LIBTIFF = False TiffImagePlugin.READ_LIBTIFF = False
def test_consecutive(): def test_consecutive() -> None:
with Image.open("Tests/images/multipage.tiff") as im: with Image.open("Tests/images/multipage.tiff") as im:
first_frame = None first_frame = None
for frame in ImageSequence.Iterator(im): for frame in ImageSequence.Iterator(im):
@ -75,7 +77,7 @@ def test_consecutive():
break break
def test_palette_mmap(): def test_palette_mmap() -> None:
# Using mmap in ImageFile can require to reload the palette. # Using mmap in ImageFile can require to reload the palette.
with Image.open("Tests/images/multipage-mmap.tiff") as im: with Image.open("Tests/images/multipage-mmap.tiff") as im:
color1 = im.getpalette()[:3] color1 = im.getpalette()[:3]
@ -84,7 +86,7 @@ def test_palette_mmap():
assert color1 == color2 assert color1 == color2
def test_all_frames(): def test_all_frames() -> None:
# Test a single image # Test a single image
with Image.open("Tests/images/iss634.gif") as im: with Image.open("Tests/images/iss634.gif") as im:
ims = ImageSequence.all_frames(im) ims = ImageSequence.all_frames(im)

View File

@ -7,12 +7,12 @@ from PIL import Image, ImageShow
from .helper import hopper, is_win32, on_ci from .helper import hopper, is_win32, on_ci
def test_sanity(): def test_sanity() -> None:
dir(Image) dir(Image)
dir(ImageShow) dir(ImageShow)
def test_register(): def test_register() -> None:
# Test registering a viewer that is not a class # Test registering a viewer that is not a class
ImageShow.register("not a class") ImageShow.register("not a class")
@ -24,9 +24,9 @@ def test_register():
"order", "order",
[-1, 0], [-1, 0],
) )
def test_viewer_show(order): def test_viewer_show(order) -> None:
class TestViewer(ImageShow.Viewer): class TestViewer(ImageShow.Viewer):
def show_image(self, image, **options): def show_image(self, image, **options) -> bool:
self.methodCalled = True self.methodCalled = True
return True return True
@ -48,12 +48,12 @@ def test_viewer_show(order):
reason="Only run on CIs; hangs on Windows CIs", reason="Only run on CIs; hangs on Windows CIs",
) )
@pytest.mark.parametrize("mode", ("1", "I;16", "LA", "RGB", "RGBA")) @pytest.mark.parametrize("mode", ("1", "I;16", "LA", "RGB", "RGBA"))
def test_show(mode): def test_show(mode) -> None:
im = hopper(mode) im = hopper(mode)
assert ImageShow.show(im) assert ImageShow.show(im)
def test_show_without_viewers(): def test_show_without_viewers() -> None:
viewers = ImageShow._viewers viewers = ImageShow._viewers
ImageShow._viewers = [] ImageShow._viewers = []
@ -63,7 +63,7 @@ def test_show_without_viewers():
ImageShow._viewers = viewers ImageShow._viewers = viewers
def test_viewer(): def test_viewer() -> None:
viewer = ImageShow.Viewer() viewer = ImageShow.Viewer()
assert viewer.get_format(None) is None assert viewer.get_format(None) is None
@ -73,14 +73,14 @@ def test_viewer():
@pytest.mark.parametrize("viewer", ImageShow._viewers) @pytest.mark.parametrize("viewer", ImageShow._viewers)
def test_viewers(viewer): def test_viewers(viewer) -> None:
try: try:
viewer.get_command("test.jpg") viewer.get_command("test.jpg")
except NotImplementedError: except NotImplementedError:
pass pass
def test_ipythonviewer(): def test_ipythonviewer() -> None:
pytest.importorskip("IPython", reason="IPython not installed") pytest.importorskip("IPython", reason="IPython not installed")
for viewer in ImageShow._viewers: for viewer in ImageShow._viewers:
if isinstance(viewer, ImageShow.IPythonViewer): if isinstance(viewer, ImageShow.IPythonViewer):

View File

@ -7,7 +7,7 @@ from PIL import Image, ImageStat
from .helper import hopper from .helper import hopper
def test_sanity(): def test_sanity() -> None:
im = hopper() im = hopper()
st = ImageStat.Stat(im) st = ImageStat.Stat(im)
@ -31,7 +31,7 @@ def test_sanity():
ImageStat.Stat(1) ImageStat.Stat(1)
def test_hopper(): def test_hopper() -> None:
im = hopper() im = hopper()
st = ImageStat.Stat(im) st = ImageStat.Stat(im)
@ -44,7 +44,7 @@ def test_hopper():
assert st.sum[2] == 1563008 assert st.sum[2] == 1563008
def test_constant(): def test_constant() -> None:
im = Image.new("L", (128, 128), 128) im = Image.new("L", (128, 128), 128)
st = ImageStat.Stat(im) st = ImageStat.Stat(im)

View File

@ -23,7 +23,7 @@ TK_MODES = ("1", "L", "P", "RGB", "RGBA")
pytestmark = pytest.mark.skipif(not HAS_TK, reason="Tk not installed") pytestmark = pytest.mark.skipif(not HAS_TK, reason="Tk not installed")
def setup_module(): def setup_module() -> None:
try: try:
# setup tk # setup tk
tk.Frame() tk.Frame()
@ -34,7 +34,7 @@ def setup_module():
pytest.skip(f"TCL Error: {v}") pytest.skip(f"TCL Error: {v}")
def test_kw(): def test_kw() -> None:
TEST_JPG = "Tests/images/hopper.jpg" TEST_JPG = "Tests/images/hopper.jpg"
TEST_PNG = "Tests/images/hopper.png" TEST_PNG = "Tests/images/hopper.png"
with Image.open(TEST_JPG) as im1: with Image.open(TEST_JPG) as im1:
@ -57,7 +57,7 @@ def test_kw():
@pytest.mark.parametrize("mode", TK_MODES) @pytest.mark.parametrize("mode", TK_MODES)
def test_photoimage(mode): def test_photoimage(mode) -> None:
# test as image: # test as image:
im = hopper(mode) im = hopper(mode)
@ -71,7 +71,7 @@ def test_photoimage(mode):
assert_image_equal(reloaded, im.convert("RGBA")) assert_image_equal(reloaded, im.convert("RGBA"))
def test_photoimage_apply_transparency(): def test_photoimage_apply_transparency() -> None:
with Image.open("Tests/images/pil123p.png") as im: with Image.open("Tests/images/pil123p.png") as im:
im_tk = ImageTk.PhotoImage(im) im_tk = ImageTk.PhotoImage(im)
reloaded = ImageTk.getimage(im_tk) reloaded = ImageTk.getimage(im_tk)
@ -79,7 +79,7 @@ def test_photoimage_apply_transparency():
@pytest.mark.parametrize("mode", TK_MODES) @pytest.mark.parametrize("mode", TK_MODES)
def test_photoimage_blank(mode): def test_photoimage_blank(mode) -> None:
# test a image using mode/size: # test a image using mode/size:
im_tk = ImageTk.PhotoImage(mode, (100, 100)) im_tk = ImageTk.PhotoImage(mode, (100, 100))
@ -91,7 +91,7 @@ def test_photoimage_blank(mode):
assert_image_equal(reloaded.convert(mode), im) assert_image_equal(reloaded.convert(mode), im)
def test_bitmapimage(): def test_bitmapimage() -> None:
im = hopper("1") im = hopper("1")
# this should not crash # this should not crash

View File

@ -8,10 +8,10 @@ from .helper import hopper, is_win32
class TestImageWin: class TestImageWin:
def test_sanity(self): def test_sanity(self) -> None:
dir(ImageWin) dir(ImageWin)
def test_hdc(self): def test_hdc(self) -> None:
# Arrange # Arrange
dc = 50 dc = 50
@ -22,7 +22,7 @@ class TestImageWin:
# Assert # Assert
assert dc2 == 50 assert dc2 == 50
def test_hwnd(self): def test_hwnd(self) -> None:
# Arrange # Arrange
wnd = 50 wnd = 50
@ -36,7 +36,7 @@ class TestImageWin:
@pytest.mark.skipif(not is_win32(), reason="Windows only") @pytest.mark.skipif(not is_win32(), reason="Windows only")
class TestImageWinDib: class TestImageWinDib:
def test_dib_image(self): def test_dib_image(self) -> None:
# Arrange # Arrange
im = hopper() im = hopper()
@ -46,7 +46,7 @@ class TestImageWinDib:
# Assert # Assert
assert dib.size == im.size assert dib.size == im.size
def test_dib_mode_string(self): def test_dib_mode_string(self) -> None:
# Arrange # Arrange
mode = "RGBA" mode = "RGBA"
size = (128, 128) size = (128, 128)
@ -57,7 +57,7 @@ class TestImageWinDib:
# Assert # Assert
assert dib.size == (128, 128) assert dib.size == (128, 128)
def test_dib_paste(self): def test_dib_paste(self) -> None:
# Arrange # Arrange
im = hopper() im = hopper()
@ -71,7 +71,7 @@ class TestImageWinDib:
# Assert # Assert
assert dib.size == (128, 128) assert dib.size == (128, 128)
def test_dib_paste_bbox(self): def test_dib_paste_bbox(self) -> None:
# Arrange # Arrange
im = hopper() im = hopper()
bbox = (0, 0, 10, 10) bbox = (0, 0, 10, 10)
@ -86,7 +86,7 @@ class TestImageWinDib:
# Assert # Assert
assert dib.size == (128, 128) assert dib.size == (128, 128)
def test_dib_frombytes_tobytes_roundtrip(self): def test_dib_frombytes_tobytes_roundtrip(self) -> None:
# Arrange # Arrange
# Make two different DIB images # Make two different DIB images
im = hopper() im = hopper()

View File

@ -1,6 +1,7 @@
from __future__ import annotations from __future__ import annotations
from io import BytesIO from io import BytesIO
from pathlib import Path
from PIL import Image, ImageWin from PIL import Image, ImageWin
@ -83,7 +84,7 @@ if is_win32():
memcpy(bp + bf.bfOffBits, pixels, bi.biSizeImage) memcpy(bp + bf.bfOffBits, pixels, bi.biSizeImage)
return bytearray(buf) return bytearray(buf)
def test_pointer(tmp_path): def test_pointer(tmp_path: Path) -> None:
im = hopper() im = hopper()
(width, height) = im.size (width, height) = im.size
opath = str(tmp_path / "temp.png") opath = str(tmp_path / "temp.png")

View File

@ -10,7 +10,7 @@ X = 255
class TestLibPack: class TestLibPack:
def assert_pack(self, mode, rawmode, data, *pixels): def assert_pack(self, mode, rawmode, data, *pixels) -> None:
""" """
data - either raw bytes with data or just number of bytes in rawmode. data - either raw bytes with data or just number of bytes in rawmode.
""" """
@ -24,7 +24,7 @@ class TestLibPack:
assert data == im.tobytes("raw", rawmode) assert data == im.tobytes("raw", rawmode)
def test_1(self): def test_1(self) -> None:
self.assert_pack("1", "1", b"\x01", 0, 0, 0, 0, 0, 0, 0, X) self.assert_pack("1", "1", b"\x01", 0, 0, 0, 0, 0, 0, 0, X)
self.assert_pack("1", "1;I", b"\x01", X, X, X, X, X, X, X, 0) self.assert_pack("1", "1;I", b"\x01", X, X, X, X, X, X, X, 0)
self.assert_pack("1", "1;R", b"\x01", X, 0, 0, 0, 0, 0, 0, 0) self.assert_pack("1", "1;R", b"\x01", X, 0, 0, 0, 0, 0, 0, 0)
@ -37,29 +37,29 @@ class TestLibPack:
self.assert_pack("1", "L", b"\xff\x00\x00\xff\x00\x00", X, 0, 0, X, 0, 0) self.assert_pack("1", "L", b"\xff\x00\x00\xff\x00\x00", X, 0, 0, X, 0, 0)
def test_L(self): def test_L(self) -> None:
self.assert_pack("L", "L", 1, 1, 2, 3, 4) self.assert_pack("L", "L", 1, 1, 2, 3, 4)
self.assert_pack("L", "L;16", b"\x00\xc6\x00\xaf", 198, 175) self.assert_pack("L", "L;16", b"\x00\xc6\x00\xaf", 198, 175)
self.assert_pack("L", "L;16B", b"\xc6\x00\xaf\x00", 198, 175) self.assert_pack("L", "L;16B", b"\xc6\x00\xaf\x00", 198, 175)
def test_LA(self): def test_LA(self) -> None:
self.assert_pack("LA", "LA", 2, (1, 2), (3, 4), (5, 6)) self.assert_pack("LA", "LA", 2, (1, 2), (3, 4), (5, 6))
self.assert_pack("LA", "LA;L", 2, (1, 4), (2, 5), (3, 6)) self.assert_pack("LA", "LA;L", 2, (1, 4), (2, 5), (3, 6))
def test_La(self): def test_La(self) -> None:
self.assert_pack("La", "La", 2, (1, 2), (3, 4), (5, 6)) self.assert_pack("La", "La", 2, (1, 2), (3, 4), (5, 6))
def test_P(self): def test_P(self) -> None:
self.assert_pack("P", "P;1", b"\xe4", 1, 1, 1, 0, 0, 255, 0, 0) self.assert_pack("P", "P;1", b"\xe4", 1, 1, 1, 0, 0, 255, 0, 0)
self.assert_pack("P", "P;2", b"\xe4", 3, 2, 1, 0) self.assert_pack("P", "P;2", b"\xe4", 3, 2, 1, 0)
self.assert_pack("P", "P;4", b"\x02\xef", 0, 2, 14, 15) self.assert_pack("P", "P;4", b"\x02\xef", 0, 2, 14, 15)
self.assert_pack("P", "P", 1, 1, 2, 3, 4) self.assert_pack("P", "P", 1, 1, 2, 3, 4)
def test_PA(self): def test_PA(self) -> None:
self.assert_pack("PA", "PA", 2, (1, 2), (3, 4), (5, 6)) self.assert_pack("PA", "PA", 2, (1, 2), (3, 4), (5, 6))
self.assert_pack("PA", "PA;L", 2, (1, 4), (2, 5), (3, 6)) self.assert_pack("PA", "PA;L", 2, (1, 4), (2, 5), (3, 6))
def test_RGB(self): def test_RGB(self) -> None:
self.assert_pack("RGB", "RGB", 3, (1, 2, 3), (4, 5, 6), (7, 8, 9)) self.assert_pack("RGB", "RGB", 3, (1, 2, 3), (4, 5, 6), (7, 8, 9))
self.assert_pack( self.assert_pack(
"RGB", "RGBX", b"\x01\x02\x03\xff\x05\x06\x07\xff", (1, 2, 3), (5, 6, 7) "RGB", "RGBX", b"\x01\x02\x03\xff\x05\x06\x07\xff", (1, 2, 3), (5, 6, 7)
@ -79,7 +79,7 @@ class TestLibPack:
self.assert_pack("RGB", "G", 1, (9, 1, 9), (9, 2, 9), (9, 3, 9)) self.assert_pack("RGB", "G", 1, (9, 1, 9), (9, 2, 9), (9, 3, 9))
self.assert_pack("RGB", "B", 1, (9, 9, 1), (9, 9, 2), (9, 9, 3)) self.assert_pack("RGB", "B", 1, (9, 9, 1), (9, 9, 2), (9, 9, 3))
def test_RGBA(self): def test_RGBA(self) -> None:
self.assert_pack("RGBA", "RGBA", 4, (1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12)) self.assert_pack("RGBA", "RGBA", 4, (1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12))
self.assert_pack( self.assert_pack(
"RGBA", "RGBA;L", 4, (1, 4, 7, 10), (2, 5, 8, 11), (3, 6, 9, 12) "RGBA", "RGBA;L", 4, (1, 4, 7, 10), (2, 5, 8, 11), (3, 6, 9, 12)
@ -101,12 +101,12 @@ class TestLibPack:
self.assert_pack("RGBA", "B", 1, (6, 7, 1, 9), (6, 7, 2, 0), (6, 7, 3, 9)) self.assert_pack("RGBA", "B", 1, (6, 7, 1, 9), (6, 7, 2, 0), (6, 7, 3, 9))
self.assert_pack("RGBA", "A", 1, (6, 7, 0, 1), (6, 7, 0, 2), (0, 7, 0, 3)) self.assert_pack("RGBA", "A", 1, (6, 7, 0, 1), (6, 7, 0, 2), (0, 7, 0, 3))
def test_RGBa(self): def test_RGBa(self) -> None:
self.assert_pack("RGBa", "RGBa", 4, (1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12)) self.assert_pack("RGBa", "RGBa", 4, (1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12))
self.assert_pack("RGBa", "BGRa", 4, (3, 2, 1, 4), (7, 6, 5, 8), (11, 10, 9, 12)) self.assert_pack("RGBa", "BGRa", 4, (3, 2, 1, 4), (7, 6, 5, 8), (11, 10, 9, 12))
self.assert_pack("RGBa", "aBGR", 4, (4, 3, 2, 1), (8, 7, 6, 5), (12, 11, 10, 9)) self.assert_pack("RGBa", "aBGR", 4, (4, 3, 2, 1), (8, 7, 6, 5), (12, 11, 10, 9))
def test_RGBX(self): def test_RGBX(self) -> None:
self.assert_pack("RGBX", "RGBX", 4, (1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12)) self.assert_pack("RGBX", "RGBX", 4, (1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12))
self.assert_pack( self.assert_pack(
"RGBX", "RGBX;L", 4, (1, 4, 7, 10), (2, 5, 8, 11), (3, 6, 9, 12) "RGBX", "RGBX;L", 4, (1, 4, 7, 10), (2, 5, 8, 11), (3, 6, 9, 12)
@ -134,7 +134,7 @@ class TestLibPack:
self.assert_pack("RGBX", "B", 1, (6, 7, 1, 9), (6, 7, 2, 0), (6, 7, 3, 9)) self.assert_pack("RGBX", "B", 1, (6, 7, 1, 9), (6, 7, 2, 0), (6, 7, 3, 9))
self.assert_pack("RGBX", "X", 1, (6, 7, 0, 1), (6, 7, 0, 2), (0, 7, 0, 3)) self.assert_pack("RGBX", "X", 1, (6, 7, 0, 1), (6, 7, 0, 2), (0, 7, 0, 3))
def test_CMYK(self): def test_CMYK(self) -> None:
self.assert_pack("CMYK", "CMYK", 4, (1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12)) self.assert_pack("CMYK", "CMYK", 4, (1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12))
self.assert_pack( self.assert_pack(
"CMYK", "CMYK",
@ -149,7 +149,7 @@ class TestLibPack:
) )
self.assert_pack("CMYK", "K", 1, (6, 7, 0, 1), (6, 7, 0, 2), (0, 7, 0, 3)) self.assert_pack("CMYK", "K", 1, (6, 7, 0, 1), (6, 7, 0, 2), (0, 7, 0, 3))
def test_YCbCr(self): def test_YCbCr(self) -> None:
self.assert_pack("YCbCr", "YCbCr", 3, (1, 2, 3), (4, 5, 6), (7, 8, 9)) self.assert_pack("YCbCr", "YCbCr", 3, (1, 2, 3), (4, 5, 6), (7, 8, 9))
self.assert_pack("YCbCr", "YCbCr;L", 3, (1, 4, 7), (2, 5, 8), (3, 6, 9)) self.assert_pack("YCbCr", "YCbCr;L", 3, (1, 4, 7), (2, 5, 8), (3, 6, 9))
self.assert_pack( self.assert_pack(
@ -172,19 +172,19 @@ class TestLibPack:
self.assert_pack("YCbCr", "Cb", 1, (6, 1, 8, 9), (6, 2, 8, 9), (6, 3, 8, 9)) self.assert_pack("YCbCr", "Cb", 1, (6, 1, 8, 9), (6, 2, 8, 9), (6, 3, 8, 9))
self.assert_pack("YCbCr", "Cr", 1, (6, 7, 1, 9), (6, 7, 2, 0), (6, 7, 3, 9)) self.assert_pack("YCbCr", "Cr", 1, (6, 7, 1, 9), (6, 7, 2, 0), (6, 7, 3, 9))
def test_LAB(self): def test_LAB(self) -> None:
self.assert_pack("LAB", "LAB", 3, (1, 130, 131), (4, 133, 134), (7, 136, 137)) self.assert_pack("LAB", "LAB", 3, (1, 130, 131), (4, 133, 134), (7, 136, 137))
self.assert_pack("LAB", "L", 1, (1, 9, 9), (2, 9, 9), (3, 9, 9)) self.assert_pack("LAB", "L", 1, (1, 9, 9), (2, 9, 9), (3, 9, 9))
self.assert_pack("LAB", "A", 1, (9, 1, 9), (9, 2, 9), (9, 3, 9)) self.assert_pack("LAB", "A", 1, (9, 1, 9), (9, 2, 9), (9, 3, 9))
self.assert_pack("LAB", "B", 1, (9, 9, 1), (9, 9, 2), (9, 9, 3)) self.assert_pack("LAB", "B", 1, (9, 9, 1), (9, 9, 2), (9, 9, 3))
def test_HSV(self): def test_HSV(self) -> None:
self.assert_pack("HSV", "HSV", 3, (1, 2, 3), (4, 5, 6), (7, 8, 9)) self.assert_pack("HSV", "HSV", 3, (1, 2, 3), (4, 5, 6), (7, 8, 9))
self.assert_pack("HSV", "H", 1, (1, 9, 9), (2, 9, 9), (3, 9, 9)) self.assert_pack("HSV", "H", 1, (1, 9, 9), (2, 9, 9), (3, 9, 9))
self.assert_pack("HSV", "S", 1, (9, 1, 9), (9, 2, 9), (9, 3, 9)) self.assert_pack("HSV", "S", 1, (9, 1, 9), (9, 2, 9), (9, 3, 9))
self.assert_pack("HSV", "V", 1, (9, 9, 1), (9, 9, 2), (9, 9, 3)) self.assert_pack("HSV", "V", 1, (9, 9, 1), (9, 9, 2), (9, 9, 3))
def test_I(self): def test_I(self) -> None:
self.assert_pack("I", "I;16B", 2, 0x0102, 0x0304) self.assert_pack("I", "I;16B", 2, 0x0102, 0x0304)
self.assert_pack( self.assert_pack(
"I", "I;32S", b"\x83\x00\x00\x01\x01\x00\x00\x83", 0x01000083, -2097151999 "I", "I;32S", b"\x83\x00\x00\x01\x01\x00\x00\x83", 0x01000083, -2097151999
@ -209,10 +209,10 @@ class TestLibPack:
0x01000083, 0x01000083,
) )
def test_I16(self): def test_I16(self) -> None:
self.assert_pack("I;16N", "I;16N", 2, 0x0201, 0x0403, 0x0605) self.assert_pack("I;16N", "I;16N", 2, 0x0201, 0x0403, 0x0605)
def test_F_float(self): def test_F_float(self) -> None:
self.assert_pack("F", "F;32F", 4, 1.539989614439558e-36, 4.063216068939723e-34) self.assert_pack("F", "F;32F", 4, 1.539989614439558e-36, 4.063216068939723e-34)
if sys.byteorder == "little": if sys.byteorder == "little":
@ -228,7 +228,7 @@ class TestLibPack:
class TestLibUnpack: class TestLibUnpack:
def assert_unpack(self, mode, rawmode, data, *pixels): def assert_unpack(self, mode, rawmode, data, *pixels) -> None:
""" """
data - either raw bytes with data or just number of bytes in rawmode. data - either raw bytes with data or just number of bytes in rawmode.
""" """
@ -241,7 +241,7 @@ class TestLibUnpack:
for x, pixel in enumerate(pixels): for x, pixel in enumerate(pixels):
assert pixel == im.getpixel((x, 0)) assert pixel == im.getpixel((x, 0))
def test_1(self): def test_1(self) -> None:
self.assert_unpack("1", "1", b"\x01", 0, 0, 0, 0, 0, 0, 0, X) self.assert_unpack("1", "1", b"\x01", 0, 0, 0, 0, 0, 0, 0, X)
self.assert_unpack("1", "1;I", b"\x01", X, X, X, X, X, X, X, 0) self.assert_unpack("1", "1;I", b"\x01", X, X, X, X, X, X, X, 0)
self.assert_unpack("1", "1;R", b"\x01", X, 0, 0, 0, 0, 0, 0, 0) self.assert_unpack("1", "1;R", b"\x01", X, 0, 0, 0, 0, 0, 0, 0)
@ -254,7 +254,7 @@ class TestLibUnpack:
self.assert_unpack("1", "1;8", b"\x00\x01\x02\xff", 0, X, X, X) self.assert_unpack("1", "1;8", b"\x00\x01\x02\xff", 0, X, X, X)
def test_L(self): def test_L(self) -> None:
self.assert_unpack("L", "L;2", b"\xe4", 255, 170, 85, 0) self.assert_unpack("L", "L;2", b"\xe4", 255, 170, 85, 0)
self.assert_unpack("L", "L;2I", b"\xe4", 0, 85, 170, 255) self.assert_unpack("L", "L;2I", b"\xe4", 0, 85, 170, 255)
self.assert_unpack("L", "L;2R", b"\xe4", 0, 170, 85, 255) self.assert_unpack("L", "L;2R", b"\xe4", 0, 170, 85, 255)
@ -273,14 +273,14 @@ class TestLibUnpack:
self.assert_unpack("L", "L;16", b"\x00\xc6\x00\xaf", 198, 175) self.assert_unpack("L", "L;16", b"\x00\xc6\x00\xaf", 198, 175)
self.assert_unpack("L", "L;16B", b"\xc6\x00\xaf\x00", 198, 175) self.assert_unpack("L", "L;16B", b"\xc6\x00\xaf\x00", 198, 175)
def test_LA(self): def test_LA(self) -> None:
self.assert_unpack("LA", "LA", 2, (1, 2), (3, 4), (5, 6)) self.assert_unpack("LA", "LA", 2, (1, 2), (3, 4), (5, 6))
self.assert_unpack("LA", "LA;L", 2, (1, 4), (2, 5), (3, 6)) self.assert_unpack("LA", "LA;L", 2, (1, 4), (2, 5), (3, 6))
def test_La(self): def test_La(self) -> None:
self.assert_unpack("La", "La", 2, (1, 2), (3, 4), (5, 6)) self.assert_unpack("La", "La", 2, (1, 2), (3, 4), (5, 6))
def test_P(self): def test_P(self) -> None:
self.assert_unpack("P", "P;1", b"\xe4", 1, 1, 1, 0, 0, 1, 0, 0) self.assert_unpack("P", "P;1", b"\xe4", 1, 1, 1, 0, 0, 1, 0, 0)
self.assert_unpack("P", "P;2", b"\xe4", 3, 2, 1, 0) self.assert_unpack("P", "P;2", b"\xe4", 3, 2, 1, 0)
# erroneous? # erroneous?
@ -291,11 +291,11 @@ class TestLibUnpack:
self.assert_unpack("P", "P", 1, 1, 2, 3, 4) self.assert_unpack("P", "P", 1, 1, 2, 3, 4)
self.assert_unpack("P", "P;R", 1, 128, 64, 192, 32) self.assert_unpack("P", "P;R", 1, 128, 64, 192, 32)
def test_PA(self): def test_PA(self) -> None:
self.assert_unpack("PA", "PA", 2, (1, 2), (3, 4), (5, 6)) self.assert_unpack("PA", "PA", 2, (1, 2), (3, 4), (5, 6))
self.assert_unpack("PA", "PA;L", 2, (1, 4), (2, 5), (3, 6)) self.assert_unpack("PA", "PA;L", 2, (1, 4), (2, 5), (3, 6))
def test_RGB(self): def test_RGB(self) -> None:
self.assert_unpack("RGB", "RGB", 3, (1, 2, 3), (4, 5, 6), (7, 8, 9)) self.assert_unpack("RGB", "RGB", 3, (1, 2, 3), (4, 5, 6), (7, 8, 9))
self.assert_unpack("RGB", "RGB;L", 3, (1, 4, 7), (2, 5, 8), (3, 6, 9)) self.assert_unpack("RGB", "RGB;L", 3, (1, 4, 7), (2, 5, 8), (3, 6, 9))
self.assert_unpack("RGB", "RGB;R", 3, (128, 64, 192), (32, 160, 96)) self.assert_unpack("RGB", "RGB;R", 3, (128, 64, 192), (32, 160, 96))
@ -346,14 +346,14 @@ class TestLibUnpack:
"RGB", "CMYK", 4, (250, 249, 248), (242, 241, 240), (234, 233, 233) "RGB", "CMYK", 4, (250, 249, 248), (242, 241, 240), (234, 233, 233)
) )
def test_BGR(self): def test_BGR(self) -> None:
self.assert_unpack("BGR;15", "BGR;15", 3, (8, 131, 0), (24, 0, 8), (41, 131, 8)) self.assert_unpack("BGR;15", "BGR;15", 3, (8, 131, 0), (24, 0, 8), (41, 131, 8))
self.assert_unpack( self.assert_unpack(
"BGR;16", "BGR;16", 3, (8, 64, 0), (24, 129, 0), (41, 194, 0) "BGR;16", "BGR;16", 3, (8, 64, 0), (24, 129, 0), (41, 194, 0)
) )
self.assert_unpack("BGR;24", "BGR;24", 3, (1, 2, 3), (4, 5, 6), (7, 8, 9)) self.assert_unpack("BGR;24", "BGR;24", 3, (1, 2, 3), (4, 5, 6), (7, 8, 9))
def test_RGBA(self): def test_RGBA(self) -> None:
self.assert_unpack("RGBA", "LA", 2, (1, 1, 1, 2), (3, 3, 3, 4), (5, 5, 5, 6)) self.assert_unpack("RGBA", "LA", 2, (1, 1, 1, 2), (3, 3, 3, 4), (5, 5, 5, 6))
self.assert_unpack( self.assert_unpack(
"RGBA", "LA;16B", 4, (1, 1, 1, 3), (5, 5, 5, 7), (9, 9, 9, 11) "RGBA", "LA;16B", 4, (1, 1, 1, 3), (5, 5, 5, 7), (9, 9, 9, 11)
@ -522,7 +522,7 @@ class TestLibUnpack:
"RGBA", "A;16N", 2, (0, 0, 0, 1), (0, 0, 0, 3), (0, 0, 0, 5) "RGBA", "A;16N", 2, (0, 0, 0, 1), (0, 0, 0, 3), (0, 0, 0, 5)
) )
def test_RGBa(self): def test_RGBa(self) -> None:
self.assert_unpack( self.assert_unpack(
"RGBa", "RGBa", 4, (1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12) "RGBa", "RGBa", 4, (1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12)
) )
@ -536,7 +536,7 @@ class TestLibUnpack:
"RGBa", "aBGR", 4, (4, 3, 2, 1), (8, 7, 6, 5), (12, 11, 10, 9) "RGBa", "aBGR", 4, (4, 3, 2, 1), (8, 7, 6, 5), (12, 11, 10, 9)
) )
def test_RGBX(self): def test_RGBX(self) -> None:
self.assert_unpack("RGBX", "RGB", 3, (1, 2, 3, X), (4, 5, 6, X), (7, 8, 9, X)) self.assert_unpack("RGBX", "RGB", 3, (1, 2, 3, X), (4, 5, 6, X), (7, 8, 9, X))
self.assert_unpack("RGBX", "RGB;L", 3, (1, 4, 7, X), (2, 5, 8, X), (3, 6, 9, X)) self.assert_unpack("RGBX", "RGB;L", 3, (1, 4, 7, X), (2, 5, 8, X), (3, 6, 9, X))
self.assert_unpack("RGBX", "RGB;16B", 6, (1, 3, 5, X), (7, 9, 11, X)) self.assert_unpack("RGBX", "RGB;16B", 6, (1, 3, 5, X), (7, 9, 11, X))
@ -581,7 +581,7 @@ class TestLibUnpack:
self.assert_unpack("RGBX", "B", 1, (0, 0, 1, 0), (0, 0, 2, 0), (0, 0, 3, 0)) self.assert_unpack("RGBX", "B", 1, (0, 0, 1, 0), (0, 0, 2, 0), (0, 0, 3, 0))
self.assert_unpack("RGBX", "X", 1, (0, 0, 0, 1), (0, 0, 0, 2), (0, 0, 0, 3)) self.assert_unpack("RGBX", "X", 1, (0, 0, 0, 1), (0, 0, 0, 2), (0, 0, 0, 3))
def test_CMYK(self): def test_CMYK(self) -> None:
self.assert_unpack( self.assert_unpack(
"CMYK", "CMYK", 4, (1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12) "CMYK", "CMYK", 4, (1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12)
) )
@ -619,25 +619,25 @@ class TestLibUnpack:
"CMYK", "K;I", 1, (0, 0, 0, 254), (0, 0, 0, 253), (0, 0, 0, 252) "CMYK", "K;I", 1, (0, 0, 0, 254), (0, 0, 0, 253), (0, 0, 0, 252)
) )
def test_YCbCr(self): def test_YCbCr(self) -> None:
self.assert_unpack("YCbCr", "YCbCr", 3, (1, 2, 3), (4, 5, 6), (7, 8, 9)) self.assert_unpack("YCbCr", "YCbCr", 3, (1, 2, 3), (4, 5, 6), (7, 8, 9))
self.assert_unpack("YCbCr", "YCbCr;L", 3, (1, 4, 7), (2, 5, 8), (3, 6, 9)) self.assert_unpack("YCbCr", "YCbCr;L", 3, (1, 4, 7), (2, 5, 8), (3, 6, 9))
self.assert_unpack("YCbCr", "YCbCrK", 4, (1, 2, 3), (5, 6, 7), (9, 10, 11)) self.assert_unpack("YCbCr", "YCbCrK", 4, (1, 2, 3), (5, 6, 7), (9, 10, 11))
self.assert_unpack("YCbCr", "YCbCrX", 4, (1, 2, 3), (5, 6, 7), (9, 10, 11)) self.assert_unpack("YCbCr", "YCbCrX", 4, (1, 2, 3), (5, 6, 7), (9, 10, 11))
def test_LAB(self): def test_LAB(self) -> None:
self.assert_unpack("LAB", "LAB", 3, (1, 130, 131), (4, 133, 134), (7, 136, 137)) self.assert_unpack("LAB", "LAB", 3, (1, 130, 131), (4, 133, 134), (7, 136, 137))
self.assert_unpack("LAB", "L", 1, (1, 0, 0), (2, 0, 0), (3, 0, 0)) self.assert_unpack("LAB", "L", 1, (1, 0, 0), (2, 0, 0), (3, 0, 0))
self.assert_unpack("LAB", "A", 1, (0, 1, 0), (0, 2, 0), (0, 3, 0)) self.assert_unpack("LAB", "A", 1, (0, 1, 0), (0, 2, 0), (0, 3, 0))
self.assert_unpack("LAB", "B", 1, (0, 0, 1), (0, 0, 2), (0, 0, 3)) self.assert_unpack("LAB", "B", 1, (0, 0, 1), (0, 0, 2), (0, 0, 3))
def test_HSV(self): def test_HSV(self) -> None:
self.assert_unpack("HSV", "HSV", 3, (1, 2, 3), (4, 5, 6), (7, 8, 9)) self.assert_unpack("HSV", "HSV", 3, (1, 2, 3), (4, 5, 6), (7, 8, 9))
self.assert_unpack("HSV", "H", 1, (1, 0, 0), (2, 0, 0), (3, 0, 0)) self.assert_unpack("HSV", "H", 1, (1, 0, 0), (2, 0, 0), (3, 0, 0))
self.assert_unpack("HSV", "S", 1, (0, 1, 0), (0, 2, 0), (0, 3, 0)) self.assert_unpack("HSV", "S", 1, (0, 1, 0), (0, 2, 0), (0, 3, 0))
self.assert_unpack("HSV", "V", 1, (0, 0, 1), (0, 0, 2), (0, 0, 3)) self.assert_unpack("HSV", "V", 1, (0, 0, 1), (0, 0, 2), (0, 0, 3))
def test_I(self): def test_I(self) -> None:
self.assert_unpack("I", "I;8", 1, 0x01, 0x02, 0x03, 0x04) self.assert_unpack("I", "I;8", 1, 0x01, 0x02, 0x03, 0x04)
self.assert_unpack("I", "I;8S", b"\x01\x83", 1, -125) self.assert_unpack("I", "I;8S", b"\x01\x83", 1, -125)
self.assert_unpack("I", "I;16", 2, 0x0201, 0x0403) self.assert_unpack("I", "I;16", 2, 0x0201, 0x0403)
@ -678,7 +678,7 @@ class TestLibUnpack:
0x01000083, 0x01000083,
) )
def test_F_int(self): def test_F_int(self) -> None:
self.assert_unpack("F", "F;8", 1, 0x01, 0x02, 0x03, 0x04) self.assert_unpack("F", "F;8", 1, 0x01, 0x02, 0x03, 0x04)
self.assert_unpack("F", "F;8S", b"\x01\x83", 1, -125) self.assert_unpack("F", "F;8S", b"\x01\x83", 1, -125)
self.assert_unpack("F", "F;16", 2, 0x0201, 0x0403) self.assert_unpack("F", "F;16", 2, 0x0201, 0x0403)
@ -717,7 +717,7 @@ class TestLibUnpack:
16777348, 16777348,
) )
def test_F_float(self): def test_F_float(self) -> None:
self.assert_unpack( self.assert_unpack(
"F", "F;32F", 4, 1.539989614439558e-36, 4.063216068939723e-34 "F", "F;32F", 4, 1.539989614439558e-36, 4.063216068939723e-34
) )
@ -768,7 +768,7 @@ class TestLibUnpack:
-1234.5, -1234.5,
) )
def test_I16(self): def test_I16(self) -> None:
self.assert_unpack("I;16", "I;16", 2, 0x0201, 0x0403, 0x0605) self.assert_unpack("I;16", "I;16", 2, 0x0201, 0x0403, 0x0605)
self.assert_unpack("I;16", "I;16B", 2, 0x0102, 0x0304, 0x0506) self.assert_unpack("I;16", "I;16B", 2, 0x0102, 0x0304, 0x0506)
self.assert_unpack("I;16B", "I;16B", 2, 0x0102, 0x0304, 0x0506) self.assert_unpack("I;16B", "I;16B", 2, 0x0102, 0x0304, 0x0506)
@ -785,7 +785,7 @@ class TestLibUnpack:
self.assert_unpack("I;16L", "I;16N", 2, 0x0102, 0x0304, 0x0506) self.assert_unpack("I;16L", "I;16N", 2, 0x0102, 0x0304, 0x0506)
self.assert_unpack("I;16N", "I;16N", 2, 0x0102, 0x0304, 0x0506) self.assert_unpack("I;16N", "I;16N", 2, 0x0102, 0x0304, 0x0506)
def test_CMYK16(self): def test_CMYK16(self) -> None:
self.assert_unpack("CMYK", "CMYK;16L", 8, (2, 4, 6, 8), (10, 12, 14, 16)) self.assert_unpack("CMYK", "CMYK;16L", 8, (2, 4, 6, 8), (10, 12, 14, 16))
self.assert_unpack("CMYK", "CMYK;16B", 8, (1, 3, 5, 7), (9, 11, 13, 15)) self.assert_unpack("CMYK", "CMYK;16B", 8, (1, 3, 5, 7), (9, 11, 13, 15))
if sys.byteorder == "little": if sys.byteorder == "little":
@ -793,7 +793,7 @@ class TestLibUnpack:
else: else:
self.assert_unpack("CMYK", "CMYK;16N", 8, (1, 3, 5, 7), (9, 11, 13, 15)) self.assert_unpack("CMYK", "CMYK;16N", 8, (1, 3, 5, 7), (9, 11, 13, 15))
def test_value_error(self): def test_value_error(self) -> None:
with pytest.raises(ValueError): with pytest.raises(ValueError):
self.assert_unpack("L", "L", 0, 0) self.assert_unpack("L", "L", 0, 0)
with pytest.raises(ValueError): with pytest.raises(ValueError):

View File

@ -7,7 +7,7 @@ import pytest
from PIL import Image from PIL import Image
def test_overflow(): def test_overflow() -> None:
# There is the potential to overflow comparisons in map.c # There is the potential to overflow comparisons in map.c
# if there are > SIZE_MAX bytes in the image or if # if there are > SIZE_MAX bytes in the image or if
# the file encodes an offset that makes # the file encodes an offset that makes
@ -25,7 +25,7 @@ def test_overflow():
Image.MAX_IMAGE_PIXELS = max_pixels Image.MAX_IMAGE_PIXELS = max_pixels
def test_tobytes(): def test_tobytes() -> None:
# Note that this image triggers the decompression bomb warning: # Note that this image triggers the decompression bomb warning:
max_pixels = Image.MAX_IMAGE_PIXELS max_pixels = Image.MAX_IMAGE_PIXELS
Image.MAX_IMAGE_PIXELS = None Image.MAX_IMAGE_PIXELS = None
@ -39,7 +39,7 @@ def test_tobytes():
@pytest.mark.skipif(sys.maxsize <= 2**32, reason="Requires 64-bit system") @pytest.mark.skipif(sys.maxsize <= 2**32, reason="Requires 64-bit system")
def test_ysize(): def test_ysize() -> None:
numpy = pytest.importorskip("numpy", reason="NumPy not installed") numpy = pytest.importorskip("numpy", reason="NumPy not installed")
# Should not raise 'Integer overflow in ysize' # Should not raise 'Integer overflow in ysize'

View File

@ -1,5 +1,7 @@
from __future__ import annotations from __future__ import annotations
from pathlib import Path
import pytest import pytest
from PIL import Image from PIL import Image
@ -9,7 +11,7 @@ from .helper import hopper
original = hopper().resize((32, 32)).convert("I") original = hopper().resize((32, 32)).convert("I")
def verify(im1): def verify(im1) -> None:
im2 = original.copy() im2 = original.copy()
assert im1.size == im2.size assert im1.size == im2.size
pix1 = im1.load() pix1 = im1.load()
@ -25,7 +27,7 @@ def verify(im1):
@pytest.mark.parametrize("mode", ("L", "I;16", "I;16B", "I;16L", "I")) @pytest.mark.parametrize("mode", ("L", "I;16", "I;16B", "I;16L", "I"))
def test_basic(tmp_path, mode): def test_basic(tmp_path: Path, mode) -> None:
# PIL 1.1 has limited support for 16-bit image data. Check that # PIL 1.1 has limited support for 16-bit image data. Check that
# create/copy/transform and save works as expected. # create/copy/transform and save works as expected.
@ -75,7 +77,7 @@ def test_basic(tmp_path, mode):
assert im_in.getpixel((0, 0)) == min(512, maximum) assert im_in.getpixel((0, 0)) == min(512, maximum)
def test_tobytes(): def test_tobytes() -> None:
def tobytes(mode): def tobytes(mode):
return Image.new(mode, (1, 1), 1).tobytes() return Image.new(mode, (1, 1), 1).tobytes()
@ -87,7 +89,7 @@ def test_tobytes():
assert tobytes("I") == b"\x01\x00\x00\x00"[::order] assert tobytes("I") == b"\x01\x00\x00\x00"[::order]
def test_convert(): def test_convert() -> None:
im = original.copy() im = original.copy()
for mode in ("I;16", "I;16B", "I;16N"): for mode in ("I;16", "I;16B", "I;16N"):

View File

@ -13,8 +13,8 @@ numpy = pytest.importorskip("numpy", reason="NumPy not installed")
TEST_IMAGE_SIZE = (10, 10) TEST_IMAGE_SIZE = (10, 10)
def test_numpy_to_image(): def test_numpy_to_image() -> None:
def to_image(dtype, bands=1, boolean=0): def to_image(dtype, bands: int = 1, boolean: int = 0):
if bands == 1: if bands == 1:
if boolean: if boolean:
data = [0, 255] * 50 data = [0, 255] * 50
@ -82,7 +82,7 @@ def test_numpy_to_image():
# Based on an erring example at # Based on an erring example at
# https://stackoverflow.com/questions/10854903/what-is-causing-dimension-dependent-attributeerror-in-pil-fromarray-function # https://stackoverflow.com/questions/10854903/what-is-causing-dimension-dependent-attributeerror-in-pil-fromarray-function
def test_3d_array(): def test_3d_array() -> None:
size = (5, TEST_IMAGE_SIZE[0], TEST_IMAGE_SIZE[1]) size = (5, TEST_IMAGE_SIZE[0], TEST_IMAGE_SIZE[1])
a = numpy.ones(size, dtype=numpy.uint8) a = numpy.ones(size, dtype=numpy.uint8)
assert_image(Image.fromarray(a[1, :, :]), "L", TEST_IMAGE_SIZE) assert_image(Image.fromarray(a[1, :, :]), "L", TEST_IMAGE_SIZE)
@ -94,12 +94,12 @@ def test_3d_array():
assert_image(Image.fromarray(a[:, :, 1]), "L", TEST_IMAGE_SIZE) assert_image(Image.fromarray(a[:, :, 1]), "L", TEST_IMAGE_SIZE)
def test_1d_array(): def test_1d_array() -> None:
a = numpy.ones(5, dtype=numpy.uint8) a = numpy.ones(5, dtype=numpy.uint8)
assert_image(Image.fromarray(a), "L", (1, 5)) assert_image(Image.fromarray(a), "L", (1, 5))
def _test_img_equals_nparray(img, np): def _test_img_equals_nparray(img, np) -> None:
assert len(np.shape) >= 2 assert len(np.shape) >= 2
np_size = np.shape[1], np.shape[0] np_size = np.shape[1], np.shape[0]
assert img.size == np_size assert img.size == np_size
@ -109,14 +109,14 @@ def _test_img_equals_nparray(img, np):
assert_deep_equal(px[x, y], np[y, x]) assert_deep_equal(px[x, y], np[y, x])
def test_16bit(): def test_16bit() -> None:
with Image.open("Tests/images/16bit.cropped.tif") as img: with Image.open("Tests/images/16bit.cropped.tif") as img:
np_img = numpy.array(img) np_img = numpy.array(img)
_test_img_equals_nparray(img, np_img) _test_img_equals_nparray(img, np_img)
assert np_img.dtype == numpy.dtype("<u2") assert np_img.dtype == numpy.dtype("<u2")
def test_1bit(): def test_1bit() -> None:
# Test that 1-bit arrays convert to numpy and back # Test that 1-bit arrays convert to numpy and back
# See: https://github.com/python-pillow/Pillow/issues/350 # See: https://github.com/python-pillow/Pillow/issues/350
arr = numpy.array([[1, 0, 0, 1, 0], [0, 1, 0, 0, 0]], "u1") arr = numpy.array([[1, 0, 0, 1, 0], [0, 1, 0, 0, 0]], "u1")
@ -126,7 +126,7 @@ def test_1bit():
numpy.testing.assert_array_equal(arr, arr_back) numpy.testing.assert_array_equal(arr, arr_back)
def test_save_tiff_uint16(): def test_save_tiff_uint16() -> None:
# Tests that we're getting the pixel value in the right byte order. # Tests that we're getting the pixel value in the right byte order.
pixel_value = 0x1234 pixel_value = 0x1234
a = numpy.array( a = numpy.array(
@ -157,7 +157,7 @@ def test_save_tiff_uint16():
("HSV", numpy.uint8), ("HSV", numpy.uint8),
), ),
) )
def test_to_array(mode, dtype): def test_to_array(mode, dtype) -> None:
img = hopper(mode) img = hopper(mode)
# Resize to non-square # Resize to non-square
@ -169,7 +169,7 @@ def test_to_array(mode, dtype):
assert np_img.dtype == dtype assert np_img.dtype == dtype
def test_point_lut(): def test_point_lut() -> None:
# See https://github.com/python-pillow/Pillow/issues/439 # See https://github.com/python-pillow/Pillow/issues/439
data = list(range(256)) * 3 data = list(range(256)) * 3
@ -180,7 +180,7 @@ def test_point_lut():
im.point(lut) im.point(lut)
def test_putdata(): def test_putdata() -> None:
# Shouldn't segfault # Shouldn't segfault
# See https://github.com/python-pillow/Pillow/issues/1008 # See https://github.com/python-pillow/Pillow/issues/1008
@ -207,12 +207,12 @@ def test_putdata():
numpy.float64, numpy.float64,
), ),
) )
def test_roundtrip_eye(dtype): def test_roundtrip_eye(dtype) -> None:
arr = numpy.eye(10, dtype=dtype) arr = numpy.eye(10, dtype=dtype)
numpy.testing.assert_array_equal(arr, numpy.array(Image.fromarray(arr))) numpy.testing.assert_array_equal(arr, numpy.array(Image.fromarray(arr)))
def test_zero_size(): def test_zero_size() -> None:
# Shouldn't cause floating point exception # Shouldn't cause floating point exception
# See https://github.com/python-pillow/Pillow/issues/2259 # See https://github.com/python-pillow/Pillow/issues/2259
@ -222,13 +222,13 @@ def test_zero_size():
@skip_unless_feature("libtiff") @skip_unless_feature("libtiff")
def test_load_first(): def test_load_first() -> None:
with Image.open("Tests/images/g4_orientation_5.tif") as im: with Image.open("Tests/images/g4_orientation_5.tif") as im:
a = numpy.array(im) a = numpy.array(im)
assert a.shape == (88, 590) assert a.shape == (88, 590)
def test_bool(): def test_bool() -> None:
# https://github.com/python-pillow/Pillow/issues/2044 # https://github.com/python-pillow/Pillow/issues/2044
a = numpy.zeros((10, 2), dtype=bool) a = numpy.zeros((10, 2), dtype=bool)
a[0][0] = True a[0][0] = True
@ -237,7 +237,7 @@ def test_bool():
assert im2.getdata()[0] == 255 assert im2.getdata()[0] == 255
def test_no_resource_warning_for_numpy_array(): def test_no_resource_warning_for_numpy_array() -> None:
# https://github.com/python-pillow/Pillow/issues/835 # https://github.com/python-pillow/Pillow/issues/835
# Arrange # Arrange
from numpy import array from numpy import array

Some files were not shown because too many files have changed in this diff Show More