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/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ def fromstring(data: bytes) -> Image.Image:
return Image.open(BytesIO(data))


def tostring(im: Image.Image, string_format: str, **options: dict[str, Any]) -> bytes:
def tostring(im: Image.Image, string_format: str, **options: Any) -> bytes:
out = BytesIO()
im.save(out, string_format, **options)
return out.getvalue()
Expand Down
47 changes: 27 additions & 20 deletions Tests/test_image_access.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import subprocess
import sys
import sysconfig
from types import ModuleType

import pytest

Expand All @@ -23,6 +24,7 @@
except ImportError:
cffi = None

numpy: ModuleType | None
try:
import numpy
except ImportError:
Expand Down Expand Up @@ -71,9 +73,10 @@ def test_sanity(self) -> None:
pix1 = im1.load()
pix2 = im2.load()

for x, y in ((0, "0"), ("0", 0)):
with pytest.raises(TypeError):
pix1[x, y]
with pytest.raises(TypeError):
pix1[0, "0"]
with pytest.raises(TypeError):
pix1["0", 0]

for y in range(im1.size[1]):
for x in range(im1.size[0]):
Expand Down Expand Up @@ -123,12 +126,13 @@ def test_numpy(self) -> None:
im = hopper()
pix = im.load()

assert numpy is not None
assert pix[numpy.int32(1), numpy.int32(2)] == (18, 20, 59)


class TestImageGetPixel(AccessTest):
@staticmethod
def color(mode):
def color(mode: str) -> int | tuple[int, ...]:
bands = Image.getmodebands(mode)
if bands == 1:
return 1
Expand All @@ -138,12 +142,13 @@ def color(mode):
return (16, 32, 49)
return tuple(range(1, bands + 1))

def check(self, mode, expected_color=None) -> None:
def check(self, mode: str, expected_color_int: int | None = None) -> None:
if self._need_cffi_access and mode.startswith("BGR;"):
pytest.skip("Support not added to deprecated module for BGR;* modes")

if not expected_color:
expected_color = self.color(mode)
expected_color = (
self.color(mode) if expected_color_int is None else expected_color_int
)

# check putpixel
im = Image.new(mode, (1, 1), None)
Expand Down Expand Up @@ -222,7 +227,7 @@ def check(self, mode, expected_color=None) -> None:
"YCbCr",
),
)
def test_basic(self, mode) -> None:
def test_basic(self, mode: str) -> None:
self.check(mode)

def test_list(self) -> None:
Expand All @@ -231,14 +236,14 @@ def test_list(self) -> None:

@pytest.mark.parametrize("mode", ("I;16", "I;16B"))
@pytest.mark.parametrize("expected_color", (2**15 - 1, 2**15, 2**15 + 1, 2**16 - 1))
def test_signedness(self, mode, expected_color) -> None:
def test_signedness(self, mode: str, expected_color: int) -> None:
# see https://github.com/python-pillow/Pillow/issues/452
# pixelaccess is using signed int* instead of uint*
self.check(mode, expected_color)

@pytest.mark.parametrize("mode", ("P", "PA"))
@pytest.mark.parametrize("color", ((255, 0, 0), (255, 0, 0, 255)))
def test_p_putpixel_rgb_rgba(self, mode, color) -> None:
def test_p_putpixel_rgb_rgba(self, mode: str, color: tuple[int, ...]) -> None:
im = Image.new(mode, (1, 1))
im.putpixel((0, 0), color)

Expand All @@ -262,7 +267,7 @@ class TestCffiGetPixel(TestImageGetPixel):
class TestCffi(AccessTest):
_need_cffi_access = True

def _test_get_access(self, im) -> None:
def _test_get_access(self, im: Image.Image) -> None:
"""Do we get the same thing as the old pixel access

Using private interfaces, forcing a capi access and
Expand Down Expand Up @@ -299,7 +304,7 @@ def test_get_vs_c(self) -> None:
# im = Image.new('I;32B', (10, 10), 2**10)
# self._test_get_access(im)

def _test_set_access(self, im, color) -> None:
def _test_set_access(self, im: Image.Image, color: tuple[int, ...] | float) -> None:
"""Are we writing the correct bits into the image?

Using private interfaces, forcing a capi access and
Expand Down Expand Up @@ -359,7 +364,7 @@ def test_reference_counting(self) -> None:
assert px[i, 0] == 0

@pytest.mark.parametrize("mode", ("P", "PA"))
def test_p_putpixel_rgb_rgba(self, mode) -> None:
def test_p_putpixel_rgb_rgba(self, mode: str) -> None:
for color in ((255, 0, 0), (255, 0, 0, 127 if mode == "PA" else 255)):
im = Image.new(mode, (1, 1))
with pytest.warns(DeprecationWarning):
Expand All @@ -377,7 +382,7 @@ class TestImagePutPixelError(AccessTest):
INVALID_TYPES = ["foo", 1.0, None]

@pytest.mark.parametrize("mode", IMAGE_MODES1)
def test_putpixel_type_error1(self, mode) -> None:
def test_putpixel_type_error1(self, mode: str) -> None:
im = hopper(mode)
for v in self.INVALID_TYPES:
with pytest.raises(TypeError, match="color must be int or tuple"):
Expand All @@ -400,14 +405,16 @@ def test_putpixel_type_error1(self, mode) -> None:
),
),
)
def test_putpixel_invalid_number_of_bands(self, mode, band_numbers, match) -> None:
def test_putpixel_invalid_number_of_bands(
self, mode: str, band_numbers: tuple[int, ...], match: str
) -> None:
im = hopper(mode)
for band_number in band_numbers:
with pytest.raises(TypeError, match=match):
im.putpixel((0, 0), (0,) * band_number)

@pytest.mark.parametrize("mode", IMAGE_MODES2)
def test_putpixel_type_error2(self, mode) -> None:
def test_putpixel_type_error2(self, mode: str) -> None:
im = hopper(mode)
for v in self.INVALID_TYPES:
with pytest.raises(
Expand All @@ -416,7 +423,7 @@ def test_putpixel_type_error2(self, mode) -> None:
im.putpixel((0, 0), v)

@pytest.mark.parametrize("mode", IMAGE_MODES1 + IMAGE_MODES2)
def test_putpixel_overflow_error(self, mode) -> None:
def test_putpixel_overflow_error(self, mode: str) -> None:
im = hopper(mode)
with pytest.raises(OverflowError):
im.putpixel((0, 0), 2**80)
Expand All @@ -428,7 +435,7 @@ class TestEmbeddable:
def test_embeddable(self) -> None:
import ctypes

from setuptools.command.build_ext import new_compiler
from setuptools.command import build_ext

with open("embed_pil.c", "w", encoding="utf-8") as fh:
fh.write(
Expand Down Expand Up @@ -457,7 +464,7 @@ def test_embeddable(self) -> None:
% sys.prefix.replace("\\", "\\\\")
)

compiler = new_compiler()
compiler = getattr(build_ext, "new_compiler")()
compiler.add_include_dir(sysconfig.get_config_var("INCLUDEPY"))

libdir = sysconfig.get_config_var("LIBDIR") or sysconfig.get_config_var(
Expand All @@ -471,7 +478,7 @@ def test_embeddable(self) -> None:
env["PATH"] = sys.prefix + ";" + env["PATH"]

# do not display the Windows Error Reporting dialog
ctypes.windll.kernel32.SetErrorMode(0x0002)
getattr(ctypes, "windll").kernel32.SetErrorMode(0x0002)

process = subprocess.Popen(["embed_pil.exe"], env=env)
process.communicate()
Expand Down
10 changes: 6 additions & 4 deletions Tests/test_image_array.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 packaging.version import parse as parse_version

Expand All @@ -13,7 +15,7 @@


def test_toarray() -> None:
def test(mode):
def test(mode: str) -> tuple[tuple[int, ...], str, int]:
ai = numpy.array(im.convert(mode))
return ai.shape, ai.dtype.str, ai.nbytes

Expand Down Expand Up @@ -50,14 +52,14 @@ def test_fromarray() -> None:
class Wrapper:
"""Class with API matching Image.fromarray"""

def __init__(self, img, arr_params) -> None:
def __init__(self, img: Image.Image, arr_params: dict[str, Any]) -> None:
self.img = img
self.__array_interface__ = arr_params

def tobytes(self):
def tobytes(self) -> bytes:
return self.img.tobytes()

def test(mode):
def test(mode: str) -> tuple[str, tuple[int, int], bool]:
i = im.convert(mode)
a = numpy.array(i)
# Make wrapper instance for image, new array interface
Expand Down
7 changes: 6 additions & 1 deletion Tests/test_image_draft.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@
pytestmark = skip_unless_feature("jpg")


def draft_roundtrip(in_mode, in_size, req_mode, req_size):
def draft_roundtrip(
in_mode: str,
in_size: tuple[int, int],
req_mode: str | None,
req_size: tuple[int, int] | None,
) -> Image.Image:
im = Image.new(in_mode, in_size)
data = tostring(im, "JPEG")
im = fromstring(data)
Expand Down
2 changes: 1 addition & 1 deletion Tests/test_image_entropy.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@


def test_entropy() -> None:
def entropy(mode):
def entropy(mode: str) -> float:
return hopper(mode).entropy()

assert round(abs(entropy("1") - 0.9138803254693582), 7) == 0
Expand Down
27 changes: 18 additions & 9 deletions Tests/test_image_filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
),
)
@pytest.mark.parametrize("mode", ("L", "I", "RGB", "CMYK"))
def test_sanity(filter_to_apply, mode) -> None:
def test_sanity(filter_to_apply: ImageFilter.Filter, mode: str) -> None:
im = hopper(mode)
if mode != "I" or isinstance(filter_to_apply, ImageFilter.BuiltinFilter):
out = im.filter(filter_to_apply)
Expand All @@ -45,15 +45,15 @@ def test_sanity(filter_to_apply, mode) -> None:


@pytest.mark.parametrize("mode", ("L", "I", "RGB", "CMYK"))
def test_sanity_error(mode) -> None:
def test_sanity_error(mode: str) -> None:
with pytest.raises(TypeError):
im = hopper(mode)
im.filter("hello")


# crashes on small images
@pytest.mark.parametrize("size", ((1, 1), (2, 2), (3, 3)))
def test_crash(size) -> None:
def test_crash(size: tuple[int, int]) -> None:
im = Image.new("RGB", size)
im.filter(ImageFilter.SMOOTH)

Expand All @@ -67,7 +67,10 @@ def test_crash(size) -> None:
("RGB", ((4, 0, 0), (0, 0, 0))),
),
)
def test_modefilter(mode, expected) -> None:
def test_modefilter(
mode: str,
expected: tuple[int, int] | tuple[tuple[int, int, int], tuple[int, int, int]],
) -> None:
im = Image.new(mode, (3, 3), None)
im.putdata(list(range(9)))
# image is:
Expand All @@ -90,7 +93,13 @@ def test_modefilter(mode, expected) -> None:
("F", (0.0, 4.0, 8.0)),
),
)
def test_rankfilter(mode, expected) -> None:
def test_rankfilter(
mode: str,
expected: (
tuple[float, float, float]
| tuple[tuple[int, int, int], tuple[int, int, int], tuple[int, int, int]]
),
) -> None:
im = Image.new(mode, (3, 3), None)
im.putdata(list(range(9)))
# image is:
Expand All @@ -106,7 +115,7 @@ def test_rankfilter(mode, expected) -> None:
@pytest.mark.parametrize(
"filter", (ImageFilter.MinFilter, ImageFilter.MedianFilter, ImageFilter.MaxFilter)
)
def test_rankfilter_error(filter) -> None:
def test_rankfilter_error(filter: ImageFilter.RankFilter) -> None:
with pytest.raises(ValueError):
im = Image.new("P", (3, 3), None)
im.putdata(list(range(9)))
Expand Down Expand Up @@ -137,7 +146,7 @@ def test_kernel_not_enough_coefficients() -> None:


@pytest.mark.parametrize("mode", ("L", "LA", "I", "RGB", "CMYK"))
def test_consistency_3x3(mode) -> None:
def test_consistency_3x3(mode: str) -> None:
with Image.open("Tests/images/hopper.bmp") as source:
reference_name = "hopper_emboss"
reference_name += "_I.png" if mode == "I" else ".bmp"
Expand All @@ -163,7 +172,7 @@ def test_consistency_3x3(mode) -> None:


@pytest.mark.parametrize("mode", ("L", "LA", "I", "RGB", "CMYK"))
def test_consistency_5x5(mode) -> None:
def test_consistency_5x5(mode: str) -> None:
with Image.open("Tests/images/hopper.bmp") as source:
reference_name = "hopper_emboss_more"
reference_name += "_I.png" if mode == "I" else ".bmp"
Expand Down Expand Up @@ -199,7 +208,7 @@ def test_consistency_5x5(mode) -> None:
(2, -2),
),
)
def test_invalid_box_blur_filter(radius) -> None:
def test_invalid_box_blur_filter(radius: int | tuple[int, int]) -> None:
with pytest.raises(ValueError):
ImageFilter.BoxBlur(radius)

Expand Down
2 changes: 1 addition & 1 deletion Tests/test_image_getextrema.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@


def test_extrema() -> None:
def extrema(mode):
def extrema(mode: str) -> tuple[int, int] | tuple[tuple[int, int], ...]:
return hopper(mode).getextrema()

assert extrema("1") == (0, 255)
Expand Down
2 changes: 1 addition & 1 deletion Tests/test_image_getpalette.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@


def test_palette() -> None:
def palette(mode):
def palette(mode: str) -> list[int] | None:
p = hopper(mode).getpalette()
if p:
return p[:10]
Expand Down
Loading