Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
2 changes: 1 addition & 1 deletion Tests/test_decompression_bomb.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@


class TestDecompressionBomb:
def teardown_method(self, method) -> None:
def teardown_method(self) -> None:
Image.MAX_IMAGE_PIXELS = ORIGINAL_LIMIT

def test_no_warning_small_file(self) -> None:
Expand Down
19 changes: 11 additions & 8 deletions Tests/test_file_jpeg.py
Original file line number Diff line number Diff line change
Expand Up @@ -443,7 +443,9 @@ def test_smooth(self) -> None:
assert_image(im1, im2.mode, im2.size)

def test_subsampling(self) -> None:
def getsampling(im: JpegImagePlugin.JpegImageFile):
def getsampling(
im: JpegImagePlugin.JpegImageFile,
) -> tuple[int, int, int, int, int, int]:
layer = im.layer
return layer[0][1:3] + layer[1][1:3] + layer[2][1:3]

Expand Down Expand Up @@ -699,7 +701,7 @@ def test_load_djpeg(self) -> None:
def test_save_cjpeg(self, tmp_path: Path) -> None:
with Image.open(TEST_FILE) as img:
tempfile = str(tmp_path / "temp.jpg")
JpegImagePlugin._save_cjpeg(img, 0, tempfile)
JpegImagePlugin._save_cjpeg(img, BytesIO(), tempfile)
# Default save quality is 75%, so a tiny bit of difference is alright
assert_image_similar_tofile(img, tempfile, 17)

Expand Down Expand Up @@ -917,24 +919,25 @@ def test_icc_after_SOF(self) -> None:
with Image.open("Tests/images/icc-after-SOF.jpg") as im:
assert im.info["icc_profile"] == b"profile"

def test_jpeg_magic_number(self) -> None:
def test_jpeg_magic_number(self, monkeypatch: pytest.MonkeyPatch) -> None:
size = 4097
buffer = BytesIO(b"\xFF" * size) # Many xFF bytes
buffer.max_pos = 0
max_pos = 0
orig_read = buffer.read

def read(n=-1):
def read(n: int | None = -1) -> bytes:
nonlocal max_pos
res = orig_read(n)
buffer.max_pos = max(buffer.max_pos, buffer.tell())
max_pos = max(max_pos, buffer.tell())
return res

buffer.read = read
monkeypatch.setattr(buffer, "read", read)
with pytest.raises(UnidentifiedImageError):
with Image.open(buffer):
pass

# Assert the entire file has not been read
assert 0 < buffer.max_pos < size
assert 0 < max_pos < size

def test_getxmp(self) -> None:
with Image.open("Tests/images/xmp_test.jpg") as im:
Expand Down
2 changes: 1 addition & 1 deletion Tests/test_file_jpeg2k.py
Original file line number Diff line number Diff line change
Expand Up @@ -460,7 +460,7 @@ def test_plt_marker() -> None:
out.seek(length - 2, os.SEEK_CUR)


def test_9bit():
def test_9bit() -> None:
with Image.open("Tests/images/9bit.j2k") as im:
assert im.mode == "I;16"
assert im.size == (128, 128)
2 changes: 1 addition & 1 deletion Tests/test_file_tiff.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ def test_bigtiff(self, tmp_path: Path) -> None:
outfile = str(tmp_path / "temp.tif")
im.save(outfile, save_all=True, append_images=[im], tiffinfo=im.tag_v2)

def test_seek_too_large(self):
def test_seek_too_large(self) -> None:
with pytest.raises(ValueError, match="Unable to seek to frame"):
Image.open("Tests/images/seek_too_large.tif")

Expand Down
2 changes: 1 addition & 1 deletion Tests/test_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ def test_bad_mode(self) -> None:

def test_stringio(self) -> None:
with pytest.raises(ValueError):
with Image.open(io.StringIO()):
with Image.open(io.StringIO()): # type: ignore[arg-type]
pass

def test_pathlib(self, tmp_path: Path) -> None:
Expand Down
6 changes: 5 additions & 1 deletion Tests/test_image_mode.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,11 @@ def test_sanity() -> None:
),
)
def test_properties(
mode, expected_base, expected_type, expected_bands, expected_band_names
mode: str,
expected_base: str,
expected_type: str,
expected_bands: int,
expected_band_names: tuple[str, ...],
) -> None:
assert Image.getmodebase(mode) == expected_base
assert Image.getmodetype(mode) == expected_type
Expand Down
8 changes: 4 additions & 4 deletions Tests/test_image_putdata.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,13 +113,13 @@ def test_array_F() -> None:
def test_not_flattened() -> None:
im = Image.new("L", (1, 1))
with pytest.raises(TypeError):
im.putdata([[0]])
im.putdata([[0]]) # type: ignore[list-item]
with pytest.raises(TypeError):
im.putdata([[0]], 2)
im.putdata([[0]], 2) # type: ignore[list-item]

with pytest.raises(TypeError):
im = Image.new("I", (1, 1))
im.putdata([[0]])
im.putdata([[0]]) # type: ignore[list-item]
with pytest.raises(TypeError):
im = Image.new("F", (1, 1))
im.putdata([[0]])
im.putdata([[0]]) # type: ignore[list-item]
2 changes: 1 addition & 1 deletion Tests/test_image_quantize.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ def test_quantize_dither_diff() -> None:
@pytest.mark.parametrize(
"method", (Image.Quantize.MEDIANCUT, Image.Quantize.MAXCOVERAGE)
)
def test_quantize_kmeans(method) -> None:
def test_quantize_kmeans(method: Image.Quantize) -> None:
im = hopper()
no_kmeans = im.quantize(kmeans=0, method=method)
kmeans = im.quantize(kmeans=1, method=method)
Expand Down
12 changes: 8 additions & 4 deletions Tests/test_image_reduce.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,12 @@ def test_args_factor(size: int | tuple[int, int], expected: tuple[int, int]) ->
@pytest.mark.parametrize(
"size, expected_error", ((0, ValueError), (2.0, TypeError), ((0, 10), ValueError))
)
def test_args_factor_error(size: float | tuple[int, int], expected_error) -> None:
def test_args_factor_error(
size: float | tuple[int, int], expected_error: type[Exception]
) -> None:
im = Image.new("L", (10, 10))
with pytest.raises(expected_error):
im.reduce(size)
im.reduce(size) # type: ignore[arg-type]


@pytest.mark.parametrize(
Expand All @@ -86,10 +88,12 @@ def test_args_box(size: tuple[int, int, int, int], expected: tuple[int, int]) ->
((5, 0, 5, 10), ValueError),
),
)
def test_args_box_error(size: str | tuple[int, int, int, int], expected_error) -> None:
def test_args_box_error(
size: str | tuple[int, int, int, int], expected_error: type[Exception]
) -> None:
im = Image.new("L", (10, 10))
with pytest.raises(expected_error):
im.reduce(2, size).size
im.reduce(2, size).size # type: ignore[arg-type]


@pytest.mark.parametrize("mode", ("P", "1", "I;16"))
Expand Down
2 changes: 1 addition & 1 deletion Tests/test_image_thumbnail.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

def test_sanity() -> None:
im = hopper()
assert im.thumbnail((100, 100)) is None
im.thumbnail((100, 100))

assert im.size == (100, 100)

Expand Down
6 changes: 5 additions & 1 deletion Tests/test_imagedraw.py
Original file line number Diff line number Diff line change
Expand Up @@ -1562,7 +1562,11 @@ def test_compute_regular_polygon_vertices(
],
)
def test_compute_regular_polygon_vertices_input_error_handling(
n_sides, bounding_circle, rotation, expected_error, error_message
n_sides: int,
bounding_circle: int | tuple[int | tuple[int] | str, ...],
rotation: int | str,
expected_error: type[Exception],
error_message: str,
) -> None:
with pytest.raises(expected_error) as e:
ImageDraw._compute_regular_polygon_vertices(bounding_circle, n_sides, rotation)
Expand Down
2 changes: 1 addition & 1 deletion Tests/test_imagefont.py
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ def test_render_multiline(font: ImageFont.FreeTypeFont) -> None:
draw = ImageDraw.Draw(im)
line_spacing = font.getbbox("A")[3] + 4
lines = TEST_TEXT.split("\n")
y = 0
y: float = 0
for line in lines:
draw.text((0, y), line, font=font)
y += line_spacing
Expand Down
2 changes: 1 addition & 1 deletion Tests/test_imageops.py
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,7 @@ def test_autocontrast_cutoff() -> None:
# Test the cutoff argument of autocontrast
with Image.open("Tests/images/bw_gradient.png") as img:

def autocontrast(cutoff: int | tuple[int, int]):
def autocontrast(cutoff: int | tuple[int, int]) -> list[int]:
return ImageOps.autocontrast(img, cutoff).histogram()

assert autocontrast(10) == autocontrast((10, 10))
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) -> bytearray:
def serialize_dib(bi: BITMAPINFOHEADER, pixels: ctypes.c_void_p) -> bytearray:
bf = BITMAPFILEHEADER()
bf.bfType = 0x4D42
bf.bfOffBits = ctypes.sizeof(bf) + bi.biSize
Expand Down
2 changes: 1 addition & 1 deletion Tests/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"args, report",
((["PIL"], False), (["PIL", "--report"], True), (["PIL.report"], True)),
)
def test_main(args, report) -> None:
def test_main(args: list[str], report: bool) -> None:
args = [sys.executable, "-m"] + args
out = subprocess.check_output(args).decode("utf-8")
lines = out.splitlines()
Expand Down
25 changes: 17 additions & 8 deletions Tests/test_numpy.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,27 @@
from __future__ import annotations

import warnings
from typing import TYPE_CHECKING, Any

import pytest

from PIL import Image

from .helper import assert_deep_equal, assert_image, hopper, skip_unless_feature

numpy = pytest.importorskip("numpy", reason="NumPy not installed")
if TYPE_CHECKING:
import numpy
import numpy.typing
else:
numpy = pytest.importorskip("numpy", reason="NumPy not installed")

TEST_IMAGE_SIZE = (10, 10)


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


def _test_img_equals_nparray(img: Image.Image, np) -> None:
assert len(np.shape) >= 2
np_size = np.shape[1], np.shape[0]
def _test_img_equals_nparray(
img: Image.Image, np_img: numpy.typing.NDArray[Any]
) -> None:
assert len(np_img.shape) >= 2
np_size = np_img.shape[1], np_img.shape[0]
assert img.size == np_size
px = img.load()
for x in range(0, img.size[0], int(img.size[0] / 10)):
for y in range(0, img.size[1], int(img.size[1] / 10)):
assert_deep_equal(px[x, y], np[y, x])
assert_deep_equal(px[x, y], np_img[y, x])


def test_16bit() -> None:
Expand Down Expand Up @@ -157,7 +166,7 @@ def test_save_tiff_uint16() -> None:
("HSV", numpy.uint8),
),
)
def test_to_array(mode: str, dtype) -> None:
def test_to_array(mode: str, dtype: numpy.typing.DTypeLike) -> None:
img = hopper(mode)

# Resize to non-square
Expand Down Expand Up @@ -207,7 +216,7 @@ def test_putdata() -> None:
numpy.float64,
),
)
def test_roundtrip_eye(dtype) -> None:
def test_roundtrip_eye(dtype: numpy.typing.DTypeLike) -> None:
arr = numpy.eye(10, dtype=dtype)
numpy.testing.assert_array_equal(arr, numpy.array(Image.fromarray(arr)))

Expand Down
7 changes: 4 additions & 3 deletions Tests/test_shell_injection.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
from __future__ import annotations

import shutil
from io import BytesIO
from pathlib import Path
from typing import Callable
from typing import IO, Callable

import pytest

Expand All @@ -22,11 +23,11 @@ def assert_save_filename_check(
self,
tmp_path: Path,
src_img: Image.Image,
save_func: Callable[[Image.Image, int, str], None],
save_func: Callable[[Image.Image, IO[bytes], str | bytes], None],
) -> None:
for filename in test_filenames:
dest_file = str(tmp_path / filename)
save_func(src_img, 0, dest_file)
save_func(src_img, BytesIO(), dest_file)
# If file can't be opened, shell injection probably occurred
with Image.open(dest_file) as im:
im.load()
Expand Down