Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/main' into rm-3.8
Browse files Browse the repository at this point in the history
  • Loading branch information
hugovk committed Jul 2, 2024
2 parents 2252f39 + c8df36f commit b7b8e9c
Show file tree
Hide file tree
Showing 19 changed files with 114 additions and 37 deletions.
2 changes: 2 additions & 0 deletions Tests/test_color_lut.py
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,7 @@ def test_overflow(self) -> None:
-1, 2, 2, 2, 2, 2,
])).load()
# fmt: on
assert transformed is not None
assert transformed[0, 0] == (0, 0, 255)
assert transformed[50, 50] == (0, 0, 255)
assert transformed[255, 0] == (0, 255, 255)
Expand All @@ -341,6 +342,7 @@ def test_overflow(self) -> None:
-3, 5, 5, 5, 5, 5,
])).load()
# fmt: on
assert transformed is not None
assert transformed[0, 0] == (0, 0, 255)
assert transformed[50, 50] == (0, 0, 255)
assert transformed[255, 0] == (0, 255, 255)
Expand Down
8 changes: 8 additions & 0 deletions Tests/test_file_pcx.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ def test_pil184() -> None:
def test_1px_width(tmp_path: Path) -> None:
im = Image.new("L", (1, 256))
px = im.load()
assert px is not None
for y in range(256):
px[0, y] = y
_roundtrip(tmp_path, im)
Expand All @@ -84,6 +85,7 @@ def test_1px_width(tmp_path: Path) -> None:
def test_large_count(tmp_path: Path) -> None:
im = Image.new("L", (256, 1))
px = im.load()
assert px is not None
for x in range(256):
px[x, 0] = x // 67 * 67
_roundtrip(tmp_path, im)
Expand All @@ -101,6 +103,7 @@ def _test_buffer_overflow(tmp_path: Path, im: Image.Image, size: int = 1024) ->
def test_break_in_count_overflow(tmp_path: Path) -> None:
im = Image.new("L", (256, 5))
px = im.load()
assert px is not None
for y in range(4):
for x in range(256):
px[x, y] = x % 128
Expand All @@ -110,6 +113,7 @@ def test_break_in_count_overflow(tmp_path: Path) -> None:
def test_break_one_in_loop(tmp_path: Path) -> None:
im = Image.new("L", (256, 5))
px = im.load()
assert px is not None
for y in range(5):
for x in range(256):
px[x, y] = x % 128
Expand All @@ -119,6 +123,7 @@ def test_break_one_in_loop(tmp_path: Path) -> None:
def test_break_many_in_loop(tmp_path: Path) -> None:
im = Image.new("L", (256, 5))
px = im.load()
assert px is not None
for y in range(4):
for x in range(256):
px[x, y] = x % 128
Expand All @@ -130,6 +135,7 @@ def test_break_many_in_loop(tmp_path: Path) -> None:
def test_break_one_at_end(tmp_path: Path) -> None:
im = Image.new("L", (256, 5))
px = im.load()
assert px is not None
for y in range(5):
for x in range(256):
px[x, y] = x % 128
Expand All @@ -140,6 +146,7 @@ def test_break_one_at_end(tmp_path: Path) -> None:
def test_break_many_at_end(tmp_path: Path) -> None:
im = Image.new("L", (256, 5))
px = im.load()
assert px is not None
for y in range(5):
for x in range(256):
px[x, y] = x % 128
Expand All @@ -152,6 +159,7 @@ def test_break_many_at_end(tmp_path: Path) -> None:
def test_break_padding(tmp_path: Path) -> None:
im = Image.new("L", (257, 5))
px = im.load()
assert px is not None
for y in range(5):
for x in range(257):
px[x, y] = x % 128
Expand Down
1 change: 1 addition & 0 deletions Tests/test_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -575,6 +575,7 @@ def test_one_item_tuple(self) -> None:
for mode in ("I", "F", "L"):
im = Image.new(mode, (100, 100), (5,))
px = im.load()
assert px is not None
assert px[0, 0] == 5

def test_linear_gradient_wrong_mode(self) -> None:
Expand Down
9 changes: 7 additions & 2 deletions Tests/test_image_access.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ def test_sanity(self) -> None:
pix1 = im1.load()
pix2 = im2.load()

assert pix1 is not None
assert pix2 is not None
with pytest.raises(TypeError):
pix1[0, "0"]
with pytest.raises(TypeError):
Expand Down Expand Up @@ -89,6 +91,8 @@ def test_sanity_negative_index(self) -> None:
pix1 = im1.load()
pix2 = im2.load()

assert pix1 is not None
assert pix2 is not None
for y in range(-1, -im1.size[1] - 1, -1):
for x in range(-1, -im1.size[0] - 1, -1):
pix2[x, y] = pix1[x, y]
Expand All @@ -98,10 +102,11 @@ def test_sanity_negative_index(self) -> None:
@pytest.mark.skipif(numpy is None, reason="NumPy not installed")
def test_numpy(self) -> None:
im = hopper()
pix = im.load()
px = im.load()

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


class TestImageGetPixel:
Expand Down
2 changes: 2 additions & 0 deletions Tests/test_image_convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,8 +222,10 @@ def test_l_macro_rounding(convert_mode: str) -> None:

converted_im = im.convert(convert_mode)
px = converted_im.load()
assert px is not None
converted_color = px[0, 0]
if convert_mode == "LA":
assert converted_color is not None
converted_color = converted_color[0]
assert converted_color == 1

Expand Down
5 changes: 3 additions & 2 deletions Tests/test_image_load.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@

def test_sanity() -> None:
im = hopper()
pix = im.load()
px = im.load()

assert pix[0, 0] == (20, 20, 70)
assert px is not None
assert px[0, 0] == (20, 20, 70)


def test_close() -> None:
Expand Down
3 changes: 3 additions & 0 deletions Tests/test_image_paste.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ def assert_9points_image(
self, im: Image.Image, expected: list[tuple[int, int, int, int]]
) -> None:
px = im.load()
assert px is not None
actual = [
px[0, 0],
px[self.size // 2, 0],
Expand Down Expand Up @@ -48,6 +49,7 @@ def assert_9points_paste(
def mask_1(self) -> Image.Image:
mask = Image.new("1", (self.size, self.size))
px = mask.load()
assert px is not None
for y in range(mask.height):
for x in range(mask.width):
px[y, x] = (x + y) % 2
Expand All @@ -61,6 +63,7 @@ def mask_L(self) -> Image.Image:
def gradient_L(self) -> Image.Image:
gradient = Image.new("L", (self.size, self.size))
px = gradient.load()
assert px is not None
for y in range(gradient.height):
for x in range(gradient.width):
px[y, x] = (x + y) % 255
Expand Down
4 changes: 4 additions & 0 deletions Tests/test_image_quantize.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ def test_quantize_no_dither2() -> None:
assert tuple(quantized.palette.palette) == data

px = quantized.load()
assert px is not None
for x in range(9):
assert px[x, 0] == (0 if x < 5 else 1)

Expand Down Expand Up @@ -118,10 +119,12 @@ def test_colors() -> None:
def test_transparent_colors_equal() -> None:
im = Image.new("RGBA", (1, 2), (0, 0, 0, 0))
px = im.load()
assert px is not None
px[0, 1] = (255, 255, 255, 0)

converted = im.quantize()
converted_px = converted.load()
assert converted_px is not None
assert converted_px[0, 0] == converted_px[0, 1]


Expand All @@ -139,6 +142,7 @@ def test_palette(method: Image.Quantize, color: tuple[int, ...]) -> None:

converted = im.quantize(method=method)
converted_px = converted.load()
assert converted_px is not None
assert converted_px[0, 0] == converted.palette.colors[color]


Expand Down
14 changes: 13 additions & 1 deletion Tests/test_image_resample.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ def make_sample(self, data: str, size: tuple[int, int]) -> Image.Image:
data = data.replace(" ", "")
sample = Image.new("L", size)
s_px = sample.load()
assert s_px is not None
w, h = size[0] // 2, size[1] // 2
for y in range(h):
for x in range(w):
Expand All @@ -87,6 +88,8 @@ def make_sample(self, data: str, size: tuple[int, int]) -> Image.Image:
def check_case(self, case: Image.Image, sample: Image.Image) -> None:
s_px = sample.load()
c_px = case.load()
assert s_px is not None
assert c_px is not None
for y in range(case.size[1]):
for x in range(case.size[0]):
if c_px[x, y] != s_px[x, y]:
Expand All @@ -98,6 +101,7 @@ def check_case(self, case: Image.Image, sample: Image.Image) -> None:

def serialize_image(self, image: Image.Image) -> str:
s_px = image.load()
assert s_px is not None
return "\n".join(
" ".join(f"{s_px[x, y]:02x}" for x in range(image.size[0]))
for y in range(image.size[1])
Expand Down Expand Up @@ -235,11 +239,14 @@ def make_case(
self, mode: str, fill: tuple[int, int, int] | float
) -> tuple[Image.Image, tuple[int, ...]]:
im = Image.new(mode, (512, 9), fill)
return im.resize((9, 512), Image.Resampling.LANCZOS), im.load()[0, 0]
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:
channel, color = case
px = channel.load()
assert px is not None
for x in range(channel.size[0]):
for y in range(channel.size[1]):
if px[x, y] != color:
Expand Down Expand Up @@ -271,6 +278,7 @@ class TestCoreResampleAlphaCorrect:
def make_levels_case(self, mode: str) -> Image.Image:
i = Image.new(mode, (256, 16))
px = i.load()
assert px is not None
for y in range(i.size[1]):
for x in range(i.size[0]):
pix = [x] * len(mode)
Expand All @@ -280,6 +288,7 @@ def make_levels_case(self, mode: str) -> Image.Image:

def run_levels_case(self, i: Image.Image) -> None:
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])}
assert 256 == len(used_colors), (
Expand Down Expand Up @@ -310,6 +319,7 @@ def make_dirty_case(
) -> Image.Image:
i = Image.new(mode, (64, 64), dirty_pixel)
px = i.load()
assert px is not None
xdiv4 = i.size[0] // 4
ydiv4 = i.size[1] // 4
for y in range(ydiv4 * 2):
Expand All @@ -319,6 +329,7 @@ def make_dirty_case(

def run_dirty_case(self, i: Image.Image, clean_pixel: tuple[int, ...]) -> None:
px = i.load()
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:
Expand Down Expand Up @@ -406,6 +417,7 @@ def test_reduce(self) -> None:
draw.rectangle((0, 0, i.size[0] // 2 - 1, 0), test_color)

px = i.resize((5, i.size[1]), Image.Resampling.BICUBIC).load()
assert px is not None
if px[2, 0] != test_color // 2:
assert test_color // 2 == px[2, 0]

Expand Down
9 changes: 7 additions & 2 deletions Tests/test_imageops.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,10 +165,14 @@ def test_pad() -> None:
def test_pad_round() -> None:
im = Image.new("1", (1, 1), 1)
new_im = ImageOps.pad(im, (4, 1))
assert new_im.load()[2, 0] == 1
px = new_im.load()
assert px is not None
assert px[2, 0] == 1

new_im = ImageOps.pad(im, (1, 4))
assert new_im.load()[0, 2] == 1
px = new_im.load()
assert px is not None
assert px[0, 2] == 1


@pytest.mark.parametrize("mode", ("P", "PA"))
Expand Down Expand Up @@ -223,6 +227,7 @@ def test_expand_palette(border: int | tuple[int, int, int, int]) -> None:
else:
left, top, right, bottom = border
px = im_expanded.convert("RGB").load()
assert px is not None
for x in range(im_expanded.width):
for b in range(top):
assert px[x, b] == (255, 0, 0)
Expand Down
5 changes: 5 additions & 0 deletions Tests/test_imagetk.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ def test_photoimage(mode: str) -> None:
reloaded = ImageTk.getimage(im_tk)
assert_image_equal(reloaded, im.convert("RGBA"))

with pytest.raises(ValueError):
ImageTk.PhotoImage()
with pytest.raises(ValueError):
ImageTk.PhotoImage(mode)


def test_photoimage_apply_transparency() -> None:
with Image.open("Tests/images/pil123p.png") as im:
Expand Down
2 changes: 2 additions & 0 deletions Tests/test_mode_i16.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ def verify(im1: Image.Image) -> None:
assert im1.size == im2.size
pix1 = im1.load()
pix2 = im2.load()
assert pix1 is not None
assert pix2 is not None
for y in range(im1.size[1]):
for x in range(im1.size[0]):
xy = x, y
Expand Down
2 changes: 2 additions & 0 deletions Tests/test_numpy.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ def _test_img_equals_nparray(img: Image.Image, np_img: _typing.NumpyArray) -> No
np_size = np_img.shape[1], np_img.shape[0]
assert img.size == np_size
px = img.load()
assert px is not None
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_img[y, x])
Expand Down Expand Up @@ -141,6 +142,7 @@ def test_save_tiff_uint16() -> None:
img = Image.fromarray(a)

img_px = img.load()
assert img_px is not None
assert img_px[0, 0] == pixel_value


Expand Down
8 changes: 4 additions & 4 deletions src/PIL/FpxImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class FpxImageFile(ImageFile.ImageFile):
format = "FPX"
format_description = "FlashPix"

def _open(self):
def _open(self) -> None:
#
# read the OLE directory and see if this is a likely
# to be a FlashPix file
Expand All @@ -64,7 +64,8 @@ def _open(self):
msg = "not an FPX file; invalid OLE file"
raise SyntaxError(msg) from e

if self.ole.root.clsid != "56616700-C154-11CE-8553-00AA00A1F95B":
root = self.ole.root
if not root or root.clsid != "56616700-C154-11CE-8553-00AA00A1F95B":
msg = "not an FPX file; bad root CLSID"
raise SyntaxError(msg)

Expand Down Expand Up @@ -99,8 +100,7 @@ def _open_index(self, index: int = 1) -> None:

s = prop[0x2000002 | id]

bands = i32(s, 4)
if bands > 4:
if not isinstance(s, bytes) or (bands := i32(s, 4)) > 4:
msg = "Invalid number of bands"
raise OSError(msg)

Expand Down
Loading

0 comments on commit b7b8e9c

Please sign in to comment.