Added type hints to tests (#8203)

Co-authored-by: Andrew Murray <radarhere@users.noreply.github.com>
This commit is contained in:
Andrew Murray 2024-07-06 03:56:24 +10:00 committed by GitHub
parent f3c3e52797
commit 4aa24f88d9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 156 additions and 69 deletions

View File

@ -60,9 +60,7 @@ def convert_to_comparable(
return new_a, new_b
def assert_deep_equal(
a: Sequence[Any], b: Sequence[Any], msg: str | None = None
) -> None:
def assert_deep_equal(a: Any, b: Any, msg: str | None = None) -> None:
try:
assert len(a) == len(b), msg or f"got length {len(a)}, expected {len(b)}"
except Exception:

View File

@ -1048,7 +1048,11 @@ class TestFileLibTiff(LibTiffTestCase):
],
)
def test_wrong_bits_per_sample(
self, file_name: str, mode: str, size: tuple[int, int], tile
self,
file_name: str,
mode: str,
size: tuple[int, int],
tile: list[tuple[str, tuple[int, int, int, int], int, tuple[Any, ...]]],
) -> None:
with Image.open("Tests/images/" + file_name) as im:
assert im.mode == mode

View File

@ -1,5 +1,6 @@
from __future__ import annotations
from collections.abc import Generator
from pathlib import Path
import pytest
@ -96,7 +97,9 @@ def test_write_animation_RGB(tmp_path: Path) -> None:
check(temp_file1)
# Tests appending using a generator
def im_generator(ims):
def im_generator(
ims: list[Image.Image],
) -> Generator[Image.Image, None, None]:
yield from ims
temp_file2 = str(tmp_path / "temp_generator.webp")

View File

@ -372,8 +372,9 @@ class TestImage:
img = Image.alpha_composite(dst, src)
# Assert
img_colors = sorted(img.getcolors())
assert img_colors == expected_colors
img_colors = img.getcolors()
assert img_colors is not None
assert sorted(img_colors) == expected_colors
def test_alpha_inplace(self) -> None:
src = Image.new("RGBA", (128, 128), "blue")
@ -670,7 +671,9 @@ class TestImage:
im_remapped = im.remap_palette([1, 0])
assert im_remapped.info["transparency"] == 1
assert len(im_remapped.getpalette()) == 6
palette = im_remapped.getpalette()
assert palette is not None
assert len(palette) == 6
# Test unused transparency
im.info["transparency"] = 2

View File

@ -27,7 +27,9 @@ class TestImagePutPixel:
for y in range(im1.size[1]):
for x in range(im1.size[0]):
pos = x, y
im2.putpixel(pos, im1.getpixel(pos))
value = im1.getpixel(pos)
assert value is not None
im2.putpixel(pos, value)
assert_image_equal(im1, im2)
@ -37,7 +39,9 @@ class TestImagePutPixel:
for y in range(im1.size[1]):
for x in range(im1.size[0]):
pos = x, y
im2.putpixel(pos, im1.getpixel(pos))
value = im1.getpixel(pos)
assert value is not None
im2.putpixel(pos, value)
assert not im2.readonly
assert_image_equal(im1, im2)
@ -50,9 +54,9 @@ class TestImagePutPixel:
assert pix1 is not None
assert pix2 is not None
with pytest.raises(TypeError):
pix1[0, "0"]
pix1[0, "0"] # type: ignore[index]
with pytest.raises(TypeError):
pix1["0", 0]
pix1["0", 0] # type: ignore[index]
for y in range(im1.size[1]):
for x in range(im1.size[0]):
@ -71,7 +75,9 @@ class TestImagePutPixel:
for y in range(-1, -im1.size[1] - 1, -1):
for x in range(-1, -im1.size[0] - 1, -1):
pos = x, y
im2.putpixel(pos, im1.getpixel(pos))
value = im1.getpixel(pos)
assert value is not None
im2.putpixel(pos, value)
assert_image_equal(im1, im2)
@ -81,7 +87,9 @@ class TestImagePutPixel:
for y in range(-1, -im1.size[1] - 1, -1):
for x in range(-1, -im1.size[0] - 1, -1):
pos = x, y
im2.putpixel(pos, im1.getpixel(pos))
value = im1.getpixel(pos)
assert value is not None
im2.putpixel(pos, value)
assert not im2.readonly
assert_image_equal(im1, im2)
@ -219,7 +227,7 @@ class TestImagePutPixelError:
im = hopper(mode)
for v in self.INVALID_TYPES:
with pytest.raises(TypeError, match="color must be int or tuple"):
im.putpixel((0, 0), v)
im.putpixel((0, 0), v) # type: ignore[arg-type]
@pytest.mark.parametrize(
("mode", "band_numbers", "match"),
@ -253,7 +261,7 @@ class TestImagePutPixelError:
with pytest.raises(
TypeError, match="color must be int or single-element tuple"
):
im.putpixel((0, 0), v)
im.putpixel((0, 0), v) # type: ignore[arg-type]
@pytest.mark.parametrize("mode", IMAGE_MODES1 + IMAGE_MODES2)
def test_putpixel_overflow_error(self, mode: str) -> None:

View File

@ -225,7 +225,7 @@ def test_l_macro_rounding(convert_mode: str) -> None:
assert px is not None
converted_color = px[0, 0]
if convert_mode == "LA":
assert converted_color is not None
assert isinstance(converted_color, tuple)
converted_color = converted_color[0]
assert converted_color == 1

View File

@ -54,17 +54,21 @@ def test_pack() -> None:
assert A is None
A = im.getcolors(maxcolors=3)
assert A is not None
A.sort()
assert A == expected
A = im.getcolors(maxcolors=4)
assert A is not None
A.sort()
assert A == expected
A = im.getcolors(maxcolors=8)
assert A is not None
A.sort()
assert A == expected
A = im.getcolors(maxcolors=16)
assert A is not None
A.sort()
assert A == expected

View File

@ -31,7 +31,7 @@ def test_sanity() -> None:
def test_long_integers() -> None:
# see bug-200802-systemerror
def put(value: int) -> tuple[int, int, int, int]:
def put(value: int) -> float | tuple[int, ...] | None:
im = Image.new("RGBA", (1, 1))
im.putdata([value])
return im.getpixel((0, 0))

View File

@ -31,7 +31,9 @@ def test_libimagequant_quantize() -> None:
converted = image.quantize(100, Image.Quantize.LIBIMAGEQUANT)
assert converted.mode == "P"
assert_image_similar(converted.convert("RGB"), image, 15)
assert len(converted.getcolors()) == 100
colors = converted.getcolors()
assert colors is not None
assert len(colors) == 100
def test_octree_quantize() -> None:
@ -39,7 +41,9 @@ def test_octree_quantize() -> None:
converted = image.quantize(100, Image.Quantize.FASTOCTREE)
assert converted.mode == "P"
assert_image_similar(converted.convert("RGB"), image, 20)
assert len(converted.getcolors()) == 100
colors = converted.getcolors()
assert colors is not None
assert len(colors) == 100
def test_rgba_quantize() -> None:
@ -158,4 +162,6 @@ def test_small_palette() -> None:
im = im.quantize(palette=p)
# Assert
assert len(im.getcolors()) == 2
quantized_colors = im.getcolors()
assert quantized_colors is not None
assert len(quantized_colors) == 2

View File

@ -237,13 +237,13 @@ class TestImagingCoreResampleAccuracy:
class TestCoreResampleConsistency:
def make_case(
self, mode: str, fill: tuple[int, int, int] | float
) -> tuple[Image.Image, tuple[int, ...]]:
) -> tuple[Image.Image, float | tuple[int, ...]]:
im = Image.new(mode, (512, 9), fill)
px = im.load()
assert px is not None
return im.resize((9, 512), Image.Resampling.LANCZOS), px[0, 0]
def run_case(self, case: tuple[Image.Image, int | tuple[int, ...]]) -> None:
def run_case(self, case: tuple[Image.Image, float | tuple[int, ...]]) -> None:
channel, color = case
px = channel.load()
assert px is not None
@ -256,6 +256,7 @@ class TestCoreResampleConsistency:
def test_8u(self) -> None:
im, color = self.make_case("RGB", (0, 64, 255))
r, g, b = im.split()
assert isinstance(color, tuple)
self.run_case((r, color[0]))
self.run_case((g, color[1]))
self.run_case((b, color[2]))
@ -290,7 +291,11 @@ class TestCoreResampleAlphaCorrect:
px = i.load()
assert px is not None
for y in range(i.size[1]):
used_colors = {px[x, y][0] for x in range(i.size[0])}
used_colors = set()
for x in range(i.size[0]):
value = px[x, y]
assert isinstance(value, tuple)
used_colors.add(value[0])
assert 256 == len(used_colors), (
"All colors should be present in resized image. "
f"Only {len(used_colors)} on line {y}."
@ -332,12 +337,13 @@ class TestCoreResampleAlphaCorrect:
assert px is not None
for y in range(i.size[1]):
for x in range(i.size[0]):
if px[x, y][-1] != 0 and px[x, y][:-1] != clean_pixel:
value = px[x, y]
assert isinstance(value, tuple)
if value[-1] != 0 and value[:-1] != clean_pixel:
message = (
f"pixel at ({x}, {y}) is different:\n"
f"{px[x, y]}\n{clean_pixel}"
f"pixel at ({x}, {y}) is different:\n{value}\n{clean_pixel}"
)
assert px[x, y][:3] == clean_pixel, message
assert value[:3] == clean_pixel, message
def test_dirty_pixels_rgba(self) -> None:
case = self.make_dirty_case("RGBA", (255, 255, 0, 128), (0, 0, 255, 0))

View File

@ -192,8 +192,9 @@ class TestImageTransform:
im = op(im, (40, 10))
colors = sorted(im.getcolors())
assert colors == sorted(
colors = im.getcolors()
assert colors is not None
assert sorted(colors) == sorted(
(
(20 * 10, opaque),
(20 * 10, transparent),

View File

@ -391,23 +391,25 @@ def test_overlay() -> None:
def test_logical() -> None:
def table(
op: Callable[[Image.Image, Image.Image], Image.Image], a: int, b: int
) -> tuple[int, int, int, int]:
) -> list[float]:
out = []
for x in (a, b):
imx = Image.new("1", (1, 1), x)
for y in (a, b):
imy = Image.new("1", (1, 1), y)
out.append(op(imx, imy).getpixel((0, 0)))
return tuple(out)
value = op(imx, imy).getpixel((0, 0))
assert not isinstance(value, tuple) and value is not None
out.append(value)
return out
assert table(ImageChops.logical_and, 0, 1) == (0, 0, 0, 255)
assert table(ImageChops.logical_or, 0, 1) == (0, 255, 255, 255)
assert table(ImageChops.logical_xor, 0, 1) == (0, 255, 255, 0)
assert table(ImageChops.logical_and, 0, 1) == [0, 0, 0, 255]
assert table(ImageChops.logical_or, 0, 1) == [0, 255, 255, 255]
assert table(ImageChops.logical_xor, 0, 1) == [0, 255, 255, 0]
assert table(ImageChops.logical_and, 0, 128) == (0, 0, 0, 255)
assert table(ImageChops.logical_or, 0, 128) == (0, 255, 255, 255)
assert table(ImageChops.logical_xor, 0, 128) == (0, 255, 255, 0)
assert table(ImageChops.logical_and, 0, 128) == [0, 0, 0, 255]
assert table(ImageChops.logical_or, 0, 128) == [0, 255, 255, 255]
assert table(ImageChops.logical_xor, 0, 128) == [0, 255, 255, 0]
assert table(ImageChops.logical_and, 0, 255) == (0, 0, 0, 255)
assert table(ImageChops.logical_or, 0, 255) == (0, 255, 255, 255)
assert table(ImageChops.logical_xor, 0, 255) == (0, 255, 255, 0)
assert table(ImageChops.logical_and, 0, 255) == [0, 0, 0, 255]
assert table(ImageChops.logical_or, 0, 255) == [0, 255, 255, 255]
assert table(ImageChops.logical_xor, 0, 255) == [0, 255, 255, 0]

View File

@ -691,7 +691,9 @@ def test_rgb_lab(mode: str) -> None:
im = Image.new("LAB", (1, 1), (255, 0, 0))
converted_im = im.convert(mode)
assert converted_im.getpixel((0, 0))[:3] == (0, 255, 255)
value = converted_im.getpixel((0, 0))
assert isinstance(value, tuple)
assert value[:3] == (0, 255, 255)
def test_deprecation() -> None:

View File

@ -1,8 +1,8 @@
from __future__ import annotations
import contextlib
import os.path
from collections.abc import Sequence
from typing import Callable
import pytest
@ -1422,25 +1422,44 @@ def test_default_font_size() -> None:
im = Image.new("RGB", (220, 25))
draw = ImageDraw.Draw(im)
with contextlib.nullcontext() if freetype_support else pytest.raises(ImportError):
def check(func: Callable[[], None]) -> None:
if freetype_support:
func()
else:
with pytest.raises(ImportError):
func()
def draw_text() -> None:
draw.text((0, 0), text, font_size=16)
assert_image_equal_tofile(im, "Tests/images/imagedraw_default_font_size.png")
with contextlib.nullcontext() if freetype_support else pytest.raises(ImportError):
check(draw_text)
def draw_textlength() -> None:
assert draw.textlength(text, font_size=16) == 216
with contextlib.nullcontext() if freetype_support else pytest.raises(ImportError):
check(draw_textlength)
def draw_textbbox() -> None:
assert draw.textbbox((0, 0), text, font_size=16) == (0, 3, 216, 19)
check(draw_textbbox)
im = Image.new("RGB", (220, 25))
draw = ImageDraw.Draw(im)
with contextlib.nullcontext() if freetype_support else pytest.raises(ImportError):
def draw_multiline_text() -> None:
draw.multiline_text((0, 0), text, font_size=16)
assert_image_equal_tofile(im, "Tests/images/imagedraw_default_font_size.png")
with contextlib.nullcontext() if freetype_support else pytest.raises(ImportError):
check(draw_multiline_text)
def draw_multiline_textbbox() -> None:
assert draw.multiline_textbbox((0, 0), text, font_size=16) == (0, 3, 216, 19)
check(draw_multiline_textbbox)
@pytest.mark.parametrize("bbox", BBOX)
def test_same_color_outline(bbox: Coords) -> None:

View File

@ -305,7 +305,7 @@ class TestPyDecoder(CodecsTest):
def test_decode(self) -> None:
decoder = ImageFile.PyDecoder(None)
with pytest.raises(NotImplementedError):
decoder.decode(None)
decoder.decode(b"")
class TestPyEncoder(CodecsTest):

View File

@ -41,11 +41,15 @@ A = string_to_img(
def img_to_string(im: Image.Image) -> str:
"""Turn a (small) binary image into a string representation"""
chars = ".1"
width, height = im.size
return "\n".join(
"".join(chars[im.getpixel((c, r)) > 0] for c in range(width))
for r in range(height)
)
result = []
for r in range(im.height):
line = ""
for c in range(im.width):
value = im.getpixel((c, r))
assert not isinstance(value, tuple) and value is not None
line += chars[value > 0]
result.append(line)
return "\n".join(result)
def img_string_normalize(im: str) -> str:

View File

@ -259,20 +259,26 @@ def test_colorize_2color() -> None:
left = (0, 1)
middle = (127, 1)
right = (255, 1)
value = im_test.getpixel(left)
assert isinstance(value, tuple)
assert_tuple_approx_equal(
im_test.getpixel(left),
value,
(255, 0, 0),
threshold=1,
msg="black test pixel incorrect",
)
value = im_test.getpixel(middle)
assert isinstance(value, tuple)
assert_tuple_approx_equal(
im_test.getpixel(middle),
value,
(127, 63, 0),
threshold=1,
msg="mid test pixel incorrect",
)
value = im_test.getpixel(right)
assert isinstance(value, tuple)
assert_tuple_approx_equal(
im_test.getpixel(right),
value,
(0, 127, 0),
threshold=1,
msg="white test pixel incorrect",
@ -295,20 +301,26 @@ def test_colorize_2color_offset() -> None:
left = (25, 1)
middle = (75, 1)
right = (125, 1)
value = im_test.getpixel(left)
assert isinstance(value, tuple)
assert_tuple_approx_equal(
im_test.getpixel(left),
value,
(255, 0, 0),
threshold=1,
msg="black test pixel incorrect",
)
value = im_test.getpixel(middle)
assert isinstance(value, tuple)
assert_tuple_approx_equal(
im_test.getpixel(middle),
value,
(127, 63, 0),
threshold=1,
msg="mid test pixel incorrect",
)
value = im_test.getpixel(right)
assert isinstance(value, tuple)
assert_tuple_approx_equal(
im_test.getpixel(right),
value,
(0, 127, 0),
threshold=1,
msg="white test pixel incorrect",
@ -339,29 +351,37 @@ def test_colorize_3color_offset() -> None:
middle = (100, 1)
right_middle = (150, 1)
right = (225, 1)
value = im_test.getpixel(left)
assert isinstance(value, tuple)
assert_tuple_approx_equal(
im_test.getpixel(left),
value,
(255, 0, 0),
threshold=1,
msg="black test pixel incorrect",
)
value = im_test.getpixel(left_middle)
assert isinstance(value, tuple)
assert_tuple_approx_equal(
im_test.getpixel(left_middle),
value,
(127, 0, 127),
threshold=1,
msg="low-mid test pixel incorrect",
)
value = im_test.getpixel(middle)
assert isinstance(value, tuple)
assert_tuple_approx_equal(value, (0, 0, 255), threshold=1, msg="mid incorrect")
value = im_test.getpixel(right_middle)
assert isinstance(value, tuple)
assert_tuple_approx_equal(
im_test.getpixel(middle), (0, 0, 255), threshold=1, msg="mid incorrect"
)
assert_tuple_approx_equal(
im_test.getpixel(right_middle),
value,
(0, 63, 127),
threshold=1,
msg="high-mid test pixel incorrect",
)
value = im_test.getpixel(right)
assert isinstance(value, tuple)
assert_tuple_approx_equal(
im_test.getpixel(right),
value,
(0, 127, 0),
threshold=1,
msg="white test pixel incorrect",
@ -444,6 +464,7 @@ def test_exif_transpose_xml_without_xmp() -> None:
del im.info["xmp"]
transposed_im = ImageOps.exif_transpose(im)
assert transposed_im is not None
assert 0x0112 not in transposed_im.getexif()

View File

@ -45,10 +45,12 @@ def test_kw() -> None:
# Test "file"
im = ImageTk._get_image_from_kw(kw)
assert im is not None
assert_image_equal(im, im1)
# Test "data"
im = ImageTk._get_image_from_kw(kw)
assert im is not None
assert_image_equal(im, im2)
# Test no relevant entry

View File

@ -11,7 +11,11 @@ from PIL.TiffImagePlugin import IFDRational
from .helper import hopper, skip_unless_feature
def _test_equal(num, denom, target) -> None:
def _test_equal(
num: float | Fraction | IFDRational,
denom: int,
target: float | Fraction | IFDRational,
) -> None:
t = IFDRational(num, denom)
assert target == t