Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added type hints to additional tests #7816

Merged
merged 3 commits into from
Feb 20, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Tests/test_deprecate.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
),
],
)
def test_version(version, expected) -> None:
def test_version(version: int | None, expected: str) -> None:
with pytest.warns(DeprecationWarning, match=expected):
_deprecate.deprecate("Old thing", version, "new thing")

Expand All @@ -46,7 +46,7 @@ def test_unknown_version() -> None:
),
],
)
def test_old_version(deprecated, plural, expected) -> None:
def test_old_version(deprecated: str, plural: bool, expected: str) -> None:
expected = r""
with pytest.raises(RuntimeError, match=expected):
_deprecate.deprecate(deprecated, 1, plural=plural)
Expand Down Expand Up @@ -76,7 +76,7 @@ def test_replacement_and_action() -> None:
"Upgrade to new thing.",
],
)
def test_action(action) -> None:
def test_action(action: str) -> None:
expected = (
r"Old thing is deprecated and will be removed in Pillow 11 \(2024-10-15\)\. "
r"Upgrade to new thing\."
Expand Down
2 changes: 1 addition & 1 deletion Tests/test_file_ico.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ def test_different_bit_depths(tmp_path: Path) -> None:


@pytest.mark.parametrize("mode", ("1", "L", "P", "RGB", "RGBA"))
def test_save_to_bytes_bmp(mode) -> None:
def test_save_to_bytes_bmp(mode: str) -> None:
output = io.BytesIO()
im = hopper(mode)
im.save(output, "ico", bitmap_format="bmp", sizes=[(32, 32), (64, 64)])
Expand Down
2 changes: 1 addition & 1 deletion Tests/test_file_iptc.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ def test_i() -> None:
assert ret == 97


def test_dump(monkeypatch) -> None:
def test_dump(monkeypatch: pytest.MonkeyPatch) -> None:
# Arrange
c = b"abc"
# Temporarily redirect stdout
Expand Down
2 changes: 1 addition & 1 deletion Tests/test_file_msp.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def test_open_windows_v1() -> None:
assert isinstance(im, MspImagePlugin.MspImageFile)


def _assert_file_image_equal(source_path, target_path) -> None:
def _assert_file_image_equal(source_path: str, target_path: str) -> None:
with Image.open(source_path) as im:
assert_image_equal_tofile(im, target_path)

Expand Down
2 changes: 2 additions & 0 deletions Tests/test_file_png.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import zlib
from io import BytesIO
from pathlib import Path
from types import ModuleType
from typing import Any

import pytest
Expand All @@ -23,6 +24,7 @@
skip_unless_feature,
)

ElementTree: ModuleType | None
try:
from defusedxml import ElementTree
except ImportError:
Expand Down
2 changes: 1 addition & 1 deletion Tests/test_file_psd.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ def test_combined_larger_than_size() -> None:
("Tests/images/timeout-dedc7a4ebd856d79b4359bbcc79e8ef231ce38f6.psd", OSError),
],
)
def test_crashes(test_file, raises) -> None:
def test_crashes(test_file: str, raises) -> None:
with open(test_file, "rb") as f:
with pytest.raises(raises):
with Image.open(f):
Expand Down
4 changes: 2 additions & 2 deletions Tests/test_file_tga.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@


@pytest.mark.parametrize("mode", _MODES)
def test_sanity(mode, tmp_path: Path) -> None:
def roundtrip(original_im) -> None:
def test_sanity(mode: str, tmp_path: Path) -> None:
def roundtrip(original_im: Image.Image) -> None:
out = str(tmp_path / "temp.tga")

original_im.save(out, rle=rle)
Expand Down
6 changes: 4 additions & 2 deletions Tests/test_file_tiff_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,9 @@ def test_iptc(tmp_path: Path) -> None:


@pytest.mark.parametrize("value, expected", ((b"test", "test"), (1, "1")))
def test_writing_other_types_to_ascii(value, expected, tmp_path: Path) -> None:
def test_writing_other_types_to_ascii(
value: bytes | int, expected: str, tmp_path: Path
) -> None:
info = TiffImagePlugin.ImageFileDirectory_v2()

tag = TiffTags.TAGS_V2[271]
Expand All @@ -206,7 +208,7 @@ def test_writing_other_types_to_ascii(value, expected, tmp_path: Path) -> None:


@pytest.mark.parametrize("value", (1, IFDRational(1)))
def test_writing_other_types_to_bytes(value, tmp_path: Path) -> None:
def test_writing_other_types_to_bytes(value: int | IFDRational, tmp_path: Path) -> None:
im = hopper()
info = TiffImagePlugin.ImageFileDirectory_v2()

Expand Down
28 changes: 22 additions & 6 deletions Tests/test_imagecms.py
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ def test_invalid_color_temperature() -> None:


@pytest.mark.parametrize("flag", ("my string", -1))
def test_invalid_flag(flag) -> None:
def test_invalid_flag(flag: str | int) -> None:
with hopper() as im:
with pytest.raises(
ImageCms.PyCMSError, match="flags must be an integer between 0 and "
Expand Down Expand Up @@ -335,12 +335,26 @@ def test_extended_information() -> None:
o = ImageCms.getOpenProfile(SRGB)
p = o.profile

def assert_truncated_tuple_equal(tup1, tup2, digits: int = 10) -> None:
def assert_truncated_tuple_equal(
tup1: tuple[tuple[float, float, float], ...] | tuple[float],
tup2: (
tuple[tuple[tuple[float, float, float], ...], ...]
| tuple[tuple[float, float, float], ...]
| tuple[float]
),
hugovk marked this conversation as resolved.
Show resolved Hide resolved
digits: int = 10,
) -> None:
# Helper function to reduce precision of tuples of floats
# recursively and then check equality.
power = 10**digits

def truncate_tuple(tuple_or_float):
def truncate_tuple(
tuple_or_float: (
tuple[tuple[tuple[float, float, float], ...], ...]
| tuple[tuple[float, float, float], ...]
| tuple[float, ...]
)
) -> tuple[tuple[float, ...], ...]:
return tuple(
(
truncate_tuple(val)
Expand Down Expand Up @@ -504,8 +518,10 @@ def test_profile_typesafety() -> None:
ImageCms.ImageCmsProfile(1).tobytes()


def assert_aux_channel_preserved(mode, transform_in_place, preserved_channel) -> None:
def create_test_image():
def assert_aux_channel_preserved(
mode: str, transform_in_place: bool, preserved_channel: str
) -> None:
def create_test_image() -> Image.Image:
# set up test image with something interesting in the tested aux channel.
# fmt: off
nine_grid_deltas = [
Expand Down Expand Up @@ -633,7 +649,7 @@ def test_auxiliary_channels_isolated() -> None:


@pytest.mark.parametrize("mode", ("RGB", "RGBA", "RGBX"))
def test_rgb_lab(mode) -> None:
def test_rgb_lab(mode: str) -> None:
im = Image.new(mode, (1, 1))
converted_im = im.convert("LAB")
assert converted_im.getpixel((0, 0)) == (0, 128, 128)
Expand Down
22 changes: 12 additions & 10 deletions Tests/test_imagefont.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import sys
from io import BytesIO
from pathlib import Path
from typing import BinaryIO
from typing import Any, BinaryIO

import pytest
from packaging.version import parse as parse_version
Expand Down Expand Up @@ -44,7 +44,7 @@ def test_sanity() -> None:
pytest.param(ImageFont.Layout.RAQM, marks=skip_unless_feature("raqm")),
],
)
def layout_engine(request):
def layout_engine(request: pytest.FixtureRequest) -> ImageFont.Layout:
return request.param


Expand Down Expand Up @@ -535,21 +535,23 @@ def test_unicode_extended(layout_engine: ImageFont.Layout) -> None:
(("linux", "/usr/local/share/fonts"), ("darwin", "/System/Library/Fonts")),
)
@pytest.mark.skipif(is_win32(), reason="requires Unix or macOS")
def test_find_font(monkeypatch, platform, font_directory) -> None:
def test_find_font(
monkeypatch: pytest.MonkeyPatch, platform: str, font_directory: str
) -> None:
def _test_fake_loading_font(path_to_fake: str, fontname: str) -> None:
# Make a copy of FreeTypeFont so we can patch the original
free_type_font = copy.deepcopy(ImageFont.FreeTypeFont)
with monkeypatch.context() as m:
m.setattr(ImageFont, "_FreeTypeFont", free_type_font, raising=False)

def loadable_font(filepath, size, index, encoding, *args, **kwargs):
def loadable_font(
filepath: str, size: int, index: int, encoding: str, *args: Any
):
if filepath == path_to_fake:
return ImageFont._FreeTypeFont(
FONT_PATH, size, index, encoding, *args, **kwargs
FONT_PATH, size, index, encoding, *args
)
return ImageFont._FreeTypeFont(
filepath, size, index, encoding, *args, **kwargs
)
return ImageFont._FreeTypeFont(filepath, size, index, encoding, *args)

m.setattr(ImageFont, "FreeTypeFont", loadable_font)
font = ImageFont.truetype(fontname)
Expand All @@ -563,7 +565,7 @@ def loadable_font(filepath, size, index, encoding, *args, **kwargs):
if platform == "linux":
monkeypatch.setenv("XDG_DATA_DIRS", "/usr/share/:/usr/local/share/")

def fake_walker(path):
def fake_walker(path: str) -> list[tuple[str, list[str], list[str]]]:
if path == font_directory:
return [
(
Expand Down Expand Up @@ -1101,7 +1103,7 @@ def test_oom(test_file: str) -> None:
font.getmask("Test Text")


def test_raqm_missing_warning(monkeypatch) -> None:
def test_raqm_missing_warning(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setattr(ImageFont.core, "HAVE_RAQM", False)
with pytest.warns(UserWarning) as record:
font = ImageFont.truetype(
Expand Down
6 changes: 4 additions & 2 deletions Tests/test_imagegrab.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ def test_grabclipboard(self) -> None:
@pytest.mark.skipif(sys.platform != "win32", reason="Windows only")
def test_grabclipboard_file(self) -> None:
p = subprocess.Popen(["powershell", "-command", "-"], stdin=subprocess.PIPE)
assert p.stdin is not None
p.stdin.write(rb'Set-Clipboard -Path "Tests\images\hopper.gif"')
p.communicate()

Expand All @@ -94,6 +95,7 @@ def test_grabclipboard_file(self) -> None:
@pytest.mark.skipif(sys.platform != "win32", reason="Windows only")
def test_grabclipboard_png(self) -> None:
p = subprocess.Popen(["powershell", "-command", "-"], stdin=subprocess.PIPE)
assert p.stdin is not None
p.stdin.write(
rb"""$bytes = [System.IO.File]::ReadAllBytes("Tests\images\hopper.png")
$ms = new-object System.IO.MemoryStream(, $bytes)
Expand All @@ -113,7 +115,7 @@ def test_grabclipboard_png(self) -> None:
reason="Linux with wl-clipboard only",
)
@pytest.mark.parametrize("ext", ("gif", "png", "ico"))
def test_grabclipboard_wl_clipboard(self, ext) -> None:
def test_grabclipboard_wl_clipboard(self, ext: str) -> None:
image_path = "Tests/images/hopper." + ext
with open(image_path, "rb") as fp:
subprocess.call(["wl-copy"], stdin=fp)
Expand All @@ -128,6 +130,6 @@ def test_grabclipboard_wl_clipboard(self, ext) -> None:
reason="Linux with wl-clipboard only",
)
@pytest.mark.parametrize("arg", ("text", "--clear"))
def test_grabclipboard_wl_clipboard_errors(self, arg):
def test_grabclipboard_wl_clipboard_errors(self, arg: str) -> None:
subprocess.call(["wl-copy", arg])
assert ImageGrab.grabclipboard() is None
8 changes: 5 additions & 3 deletions Tests/test_imagepath.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,9 @@ def test_path() -> None:
ImagePath.Path((0, 1)),
),
)
def test_path_constructors(coords) -> None:
def test_path_constructors(
coords: Sequence[float] | array.array[float] | ImagePath.Path,
) -> None:
# Arrange / Act
p = ImagePath.Path(coords)

Expand Down Expand Up @@ -206,9 +208,9 @@ class Evil:
def __init__(self) -> None:
self.corrupt = Image.core.path(0x4000000000000000)

def __getitem__(self, i):
def __getitem__(self, i: int) -> bytes:
x = self.corrupt[i]
return struct.pack("dd", x[0], x[1])

def __setitem__(self, i, x) -> None:
def __setitem__(self, i: int, x: bytes) -> None:
self.corrupt[i] = struct.unpack("dd", x)
2 changes: 1 addition & 1 deletion Tests/test_imageqt.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def test_rgb() -> None:

assert qRgb(0, 0, 0) == qRgba(0, 0, 0, 255)

def checkrgb(r, g, b) -> None:
def checkrgb(r: int, g: int, b: int) -> None:
val = ImageQt.rgb(r, g, b)
val = val % 2**24 # drop the alpha
assert val >> 16 == r
Expand Down
10 changes: 6 additions & 4 deletions Tests/test_imageshow.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from __future__ import annotations

from typing import Any

import pytest

from PIL import Image, ImageShow
Expand All @@ -24,9 +26,9 @@ def test_register() -> None:
"order",
[-1, 0],
)
def test_viewer_show(order) -> None:
def test_viewer_show(order: int) -> None:
class TestViewer(ImageShow.Viewer):
def show_image(self, image, **options) -> bool:
def show_image(self, image: Image.Image, **options: Any) -> bool:
self.methodCalled = True
return True

Expand All @@ -48,7 +50,7 @@ def show_image(self, image, **options) -> bool:
reason="Only run on CIs; hangs on Windows CIs",
)
@pytest.mark.parametrize("mode", ("1", "I;16", "LA", "RGB", "RGBA"))
def test_show(mode) -> None:
def test_show(mode: str) -> None:
im = hopper(mode)
assert ImageShow.show(im)

Expand All @@ -73,7 +75,7 @@ def test_viewer() -> None:


@pytest.mark.parametrize("viewer", ImageShow._viewers)
def test_viewers(viewer) -> None:
def test_viewers(viewer: ImageShow.Viewer) -> None:
try:
viewer.get_command("test.jpg")
except NotImplementedError:
Expand Down
2 changes: 1 addition & 1 deletion Tests/test_imagewin_pointers.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ class BITMAPINFOHEADER(ctypes.Structure):
]
CreateDIBSection.restype = ctypes.wintypes.HBITMAP

def serialize_dib(bi, pixels):
def serialize_dib(bi, pixels) -> bytearray:
bf = BITMAPFILEHEADER()
bf.bfType = 0x4D42
bf.bfOffBits = ctypes.sizeof(bf) + bi.biSize
Expand Down
6 changes: 3 additions & 3 deletions Tests/test_numpy.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@


def test_numpy_to_image() -> None:
def to_image(dtype, bands: int = 1, boolean: int = 0):
def to_image(dtype, bands: int = 1, boolean: int = 0) -> Image.Image:
if bands == 1:
if boolean:
data = [0, 255] * 50
Expand Down Expand Up @@ -99,7 +99,7 @@ def test_1d_array() -> None:
assert_image(Image.fromarray(a), "L", (1, 5))


def _test_img_equals_nparray(img, np) -> None:
def _test_img_equals_nparray(img: Image.Image, np) -> None:
assert len(np.shape) >= 2
np_size = np.shape[1], np.shape[0]
assert img.size == np_size
Expand Down Expand Up @@ -157,7 +157,7 @@ def test_save_tiff_uint16() -> None:
("HSV", numpy.uint8),
),
)
def test_to_array(mode, dtype) -> None:
def test_to_array(mode: str, dtype) -> None:
img = hopper(mode)

# Resize to non-square
Expand Down
4 changes: 2 additions & 2 deletions Tests/test_qt_image_qapplication.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import pytest

from PIL import ImageQt
from PIL import Image, ImageQt

from .helper import assert_image_equal_tofile, assert_image_similar, hopper

Expand Down Expand Up @@ -37,7 +37,7 @@ def __init__(self) -> None:
lbl.setPixmap(pixmap1.copy())


def roundtrip(expected) -> None:
def roundtrip(expected: Image.Image) -> None:
result = ImageQt.fromqpixmap(ImageQt.toqpixmap(expected))
# Qt saves all pixmaps as rgb
assert_image_similar(result, expected.convert("RGB"), 1)
Expand Down
Loading
Loading